Updating the Z-Machine Standard Documents

(Taking this to private chat)

Flags 1 is a bit of a mess.

bit #  Infocom v4 spec  Infocom v5 spec     Z-Machine Standard v4  Z-Machine Standard v5
    0  Upper window     Colors              undefined              Colours 
    1  Inverse video    Display operations  undefined              undefined
    2  Bold             Bold                Bold                   Bold 
    3  Italic           Italic              Italic                 Italic 
    4  Cursor control   Monospace           Monospace              Monospace 
    5  Sound            Sound               undefined              undefined
    6  undefined        undefined           undefined              undefined
    7  undefined        undefined           Timed input            Timed input

Infocom’s v4 games all check bit 3 to test for italic, and make no other checks.

Beyond Zork tests bit 3 for italic, and bit 0 for colour. The only other Infocom v5 game which checks Flags 1 is the Solid Gold release of Zork 1, which thinks bit 3 is still the Tandy bit, and uses it to decide whether or not to advertise Zork II and Zork III when you complete the game.

Meanwhile, early versions of Inform (I think this no longer happens) use bit 1 to decide whether to display the time or the score in the statusline.

1 Like

The places where the Standard conflicts with Infocom’s specs over Flags 1 are situations Infocom games never made use of. We can either fill in the undefined areas from Infocom’s spec, or leave them undefined in this Standard and just note them in the Remarks.

Either way, the Standard needs to mention Inform’s use of bit 1 which we call, uh, game-specific (kinda like the Tandy bit).

Solid Gold Zork using the italic flag to change the ending text is just a bug, but it should be mentioned in the Remarks (interpreters may want to turn off italic support for that game, in order to get the full text).

It might be useful to clarify the expected behavior of background colors on nonstandard screen borders (i.e., the negative space around the text windows by interpreters like Gargoyle or Parchment, or screen borders such as those on the Commodore 64 - not the Version 6 window margins). This was relatively unimportant in the early days of fullscreen terps, but is now a significant player-experience consideration for some games.

Interpreter behavior is inconsistent. Parchment sets the border color on executing @erase_window 0 (CLEAR 0), effectively matching the border color to the color of the lower window. This seems like the most sensible expected behavior. Gargoyle, by contrast, does not respect the background color when executing @erase_window at all (which actually seems like a bug); instead, it sets the background color of all windows and borders to the current background color when an input opcode is executed (@read, @read_char). In practice most games with non-default background colors will both clear the screen and subsequently wait for input before changing the background color again, giving either approach similar results, but the inconsistency could cause issues for any particularly psychedelic usages of color.

Proposal: add a sentence to § reading something like “For interpreters that display additional whitespace around the game windows for layout reasons, it is recommended that erasing window 0 also set the background color of this whitespace.”

1 Like

Appendix B says, about bit 10 of Flags 2:

Possibly set by interpreter to indicate an error with the printer during transcription

I realise that the likelihood of mentioning this here yielding any useful information is practically zero, but:

What is this? Where did it come from? What evidence was there ever for it?

Inform seems to have stopped using the bit in the header to determine statusline type as of library 6/11.

Whoops, I think that’s backwards. The release notes in 6/11 says:

  • A conflict between DrawStatusLine() and DisplayStatus() on how to determine whether to display turns or time is settled in favour of checking a header flag. [L60709] (see patch note)

In 6/10, DrawStatusLine() checked (0->1)&2 whereas DisplayStatus() checked the_time.

In 6/11. they both check the global sys_statusline_flag, which is initialized as ( (HDR_TERPFLAGS->0) & 2 ) / 2. (The HDR_TERPFLAGS constant is 1.) So it is checking the header bit after all.

(Note for onlookers: In I6, (0->1) is the same as (1->0). C flashbacks, right?)

Okay, yes, after some checking, it turns out Inform is still using this header bit to this day.


Fixed/clarified description of text-buffer in v1-v4 as per Description of read opcode for versions 1-4 · Issue #76 · iftechfoundation/Z-Machine-Standard · GitHub

The index page now links to https://www.inform-fiction.org/zmachine/standards/current/ as the latest current version (although this doesn’t actually work yet), and the 1.0 standard has a note saying it’s not the latest version.

Replaced S with § for section notation.

Added ids to all sections, so they can be linked straight to.

Merged Appendix B with Section 11, and also pulled Flags 1 and Flags 2 information out of the main header table into their own sections.

Noted Inform’s use of bit 1 of Flags 1 in the Remarks for section 11.


I’ve been thinking about some sound related issues:

What happens if you Unload a sound that is currently playing? Does it do an implicit Stop? Infocom’s interpreters seem to have code to do this.

What happens if you issue a Stop command for a sound that isn’t currently playing…or doesn’t even exist? At first I thought the former should be an error but it wouldn’t be too difficult to set up a situation where a Stop command could succeed or fail based purely on timing, which seems wrong.

Part of the description of the opcode scan_table in section 15 says

The form is optional (and only used in Version 5?)

The Infocom zip specs confirm that while scan_table is available from version 4, the form operand is only added in version 5.

However, the table in section 14 has the form operand available from version 4, Inform will compile code using the extra operand for version 4, and Frotz recognises it in a v4 gamefile.

Should we make it definitively illegal in v4, (it’s unlikely to have been used as post-Infocom v4 games are incredibly rare), or allow it, since that’s the actual implementation seems to have gone?

No strong feelings one way or the other. On one had it’s nice to keep things consistent with Infocom’s specs, but on the other it’s apparently been de facto legal for who knows how long. Like you said, z4 is rare enough that it likely doesn’t hurt to make it illegal, but it seems someone would have to validate the existing games.

Okay, so, I did this. There is a single z4 file on the if-archive, and none of the blorb files contain z4 files. The only v4 game on the archive does not use scan_table at all.


Now I’m curious. Which one?


1 Like

The same art show also had the only v7 game I’m aware of as an entry.

And just to be sure, I’ve gone through all the Infocom z4 files, and those that don’t just crash txd only use the three-operand scan_table.

Unless there’s any objections, I’m going to change this to make the form operand v5 and later.


Section was not updated to reflect the addition of the two true_colour properties.

There are 16 properties, numbered as follows:

There are 18 properties, numbered as follows:

There should be a note that some Infocom titles require a [More] with a pause, or else need to be patched. See this for details

1 Like

Section 4.5 states

The operands are given next. Operand counts of 0OP, 1OP or 2OP require 0, 1 or 2 operands to be given, respectively. If the count is VAR, there must be as many operands as there were types other than ‘omitted’.

This is not true. An ‘Operand count’ of 2OP compiled in variable form can have more than two operands.

Rather than rewrite the description completely as I did last time I tried to fix this problem, I propose changing this to:

The operands are given next. Operand counts of 0OP or 1OP require 0 or 1 operands to be given, respectively. If the count is VAR, there must be as many operands as there were types other than ‘omitted’.

If the count is 2OP, the number of operands depends on the form. In long form, 2 operands must be given. However in variable form, it is possible to specify more than 2 operands (although only je and set_colour can use more than 2), and there must be as many operands as there were types other than ‘omitted’, as with a count of VAR.

This is significantly longer, and makes a bit of a mess of the term ‘operand count’, but it seems the simplest change to the text that actually explains the issue.

1 Like