Updating the Z-Machine Standard Documents

I strongly disagree. That requirement is vague and can be interpreted in multiple ways. For the two store ops, the requirement to be within dynamic memory indicates a possible error condition. But when that is triggered will be different depending on how you interpret the signedness of the operands, handle overflow, and with what bit precision your arithmetic is done in. For the other two ops, the requirement to stay within dynamic and static memory can still be smaller than 64K if the story file is also and suffers from the same problems as above.

Explicitly saying all math operations in those ops must be wrapped modulo 16-bit and the final result interpreted as unsigned before checking against the limits of dynamic memory or the story file removes any ambiguity and makes whether or not the operands are signed or unsigned completely moot.

4 Likes

In my ideal world, we would do the exact opposite and specify that addresses >64KB should not be wrapped to 16-bit. This would instantly allow games to address more than 64KB of static data, alleviating one of the Z-machine’s principal limitations while breaking few (if any) existing games.

In practice, of course, this would go against the Z-machine’s original design and be impractical for 8-bit terps to implement. A controversial compromise might be to specify this as recommended behavior only, with the understanding that any games relying on it may not run on all interpreters (as indeed is already the case).

In theory I agree, although that ship has sailed.

Breaking any existing games would be a good reason not to do it. I’m also not a fan of adding more behavior that is interpreter dependent.

1 Like

I would appreciate it if the whole document could be put on a single page. Right now it is always a bit tedious to find some information if you don’t already know where to look.

For print_obj it says:

Print short name of object (the Z-encoded string in the object header, not a property). If the object number is invalid, the interpreter should halt with a suitable error message.

However according to section 12. The object table the object’s short name is in the property header.

It is strangely worded.

The short name of the object is in the header of the property table, but is not itself a property.

Maybe this should be changed to

Print short name of object (the Z-encoded string in the object’s property header, not a property). If the object number is invalid, the interpreter should halt with a suitable error message.

2 Likes

ZLR’s debugging console uses a heuristic to guess the number of globals: in games compiled by ZILCH and ZILF, the globals table is followed by the property defaults, and in games compiled by Inform, it’s followed by either the dictionary or the terminating characters table. So the globals are assumed to end at the lowest of those addresses that’s past the globals table.

Bit 4 of Flags 2 is used for indicating that game wants to use sound for v3? This is later moved to bit 7 in v5+. See discussion here: Bit 7 set for sound in v3 story files Ā· Issue #346 Ā· DavidKinder/Inform6 Ā· GitHub

I’d like to get consensus on this sound-flag question before I adjust the I6 compiler code.

Currently the compiler sets FLAGS2 bit 7 whenever it encounters a @sound_effect opcode, regardless of Z-machine version.

From the discussion in that thread, Windows Frotz checks for bit 4 in v3, bit 7 in v4+. Specifically because the Amiga Lurking Horror (v3) game file has bit 4 set. I don’t know if any other interpreters check this way.

Seems like the options are:

  • Do nothing, I6 is fine the way it is.
  • In v3, set bit 4 instead of bit 7 when @sound_effect is encountered.
  • Add a compiler option $ZCODE_HEADER_FLAGS_2 which lets you set any darn bit you want. (Or clear a bit, so two options, I guess.) Use at your own risk. This seems like a good idea in general, but the v3-sound-effect case is the first time someone’s specifically wanted it.

Since FLAGS2 bit 7 is undefined in v3, would setting both bits 4 and 7 be a safe compromise?

That would be safe, but I don’t know if it’s better.

Interestingly enough, as far as I can tell, Infocom’s specs for Z3, Z4, and Z5 make no mention of a flag for sound usage. Z3 specifies only two bits in Flags 2 (0 for transcript, 1 for fixed-pitch), while Z4 and Z5 specify 0 through 6 (transcript, fixed-pitch, status line refresh, graphics needed, undo needed, mouse needed, color needed). It seems that Infocom’s usage of these bits for ā€œsound support neededā€ postdates the surviving spec documents!

The purpose of the capability bits in Flags 2, according to those specs, is to alert interpreters at startup time so they can make necessary preparations. If a game wants pictures, for example, the terp might need to put the screen in graphics mode instead of text mode. But for sounds, the @sound_effect opcode with argument 1 already exists to handle this. So I guess they didn’t consider a flag bit necessary.

Curiously enough, these specs say that Z4 only allows for a beep and a boop, defined as a morse code dot and dash. But Z5 and Z3 allow for a wider range of sound support. It looks like the sound technology was developed for Z5, then backported to the Amiga Z3 interpreter specifically.

(Does this actually matter? Not really. Infocom’s specs are a cool historical curiosity, but the modern specs are defined based on the behavior of existing game files, and that doesn’t always match the Infocom spec. But it’s interesting to see how they conceived of these things.)

1 Like

Damn this is a long thread. Anyway, I ran into this issue a few days ago when fixing my save support.

ā€œOn Versions 3 and 4, attempts to save the game (all questions about filenames are asked by interpreters) and branches if successful. From Version 5 it is a store rather than a branch instruction;ā€

In the opcode table, it shows that version 4 writes a result, and does not branch like in version 3.

So either the opcode table is wrong, or that description above should be adjusted to

ā€œOn Version 3, attempts to save the game (all questions about filenames are asked by interpreters) and branches if successful. From Version 4 it is a store rather than a branch instruction;ā€

(I just checked the current version listed somewhat earlier in this thread)

EDIT: Okay, the versions of the spec widely available on the web (from google hits or the inform6 web page in particular) all seem to be out of date relative to the github version, which I see has fixed the documentation for the save opcode.

2 Likes

Likely because the save opcode changed from 0OP:181 to EXT:0 in version 5. The opcode table shows the correct behavior for version 4 even though the text in the opcode dictionary is wrong.

Yeah, I also noticed those specs only mention a bit set for sound in ā€˜Flags 1’, where the terp tells the game if it is possible to play sounds. They never mention setting a bit in ā€˜Flags 2’ anywhere that I can find.

Looking at the Amiga story files, bit 4 is the only Flags 2 bit set in Lurking Horror story files which play sound, and bits 4 and 7 are set in Sherlock (bit 4 meaning the game will use UNDO in this game’s case).

I presume someone checked all the v5 story files, found bit 7 was only set in Sherlock when it provided sounds, and reasonably deduced that bit 7 is for sound, and the same with bit 4 in v3?

That’s my guess. The modern specs were reverse-engineered from the available files and the available interpreters, so some combination of ā€œthe files with sound support set this flagā€ and ā€œthe interpreters check this flag for sound supportā€.

1 Like

That’s most certainly the explanation.

I’ll also add that Zilf set bit 4 for v3, and bit 7 for v4+.

One problem, though, is that the standards currently states that it’s bit 7 for all versions so there can be interpreters out there built on that. The standards should incorporate this, but maybe state that both 4 and 7 should be set to support all interpreters built on the information in the current standards.

1 Like

How many modern interpreters depend on the header bits to decide if they should support audio, though? I would think nowadays the presence of @sound_effect would be enough of an indication—it’s not like they have to initialize the sound hardware before launching the game any more.

1 Like

Seems like the right question.

I see that Windows Frotz does do a FrotzSound::Init() call at startup if the bit is set. This could fail, in which case it displays an error dialog. I suppose it’s better to do this at startup than the first time a sound plays.

1 Like