The Z-Machine Standard 1.2 (draft)

Effectively the only Z-Machine extension to ever gain traction was the introduction of the unicode opcodes. The 1.1 proposal wasn’t ever fully ratified, possibly in part because there was no way to detect the new opcodes other than by checking whether the VM set the version to 1.1, which it couldn’t do unless it fully implemented the new spec. There was no way to partially implement the proposal.

I suggest that we introduce a feature testing function, ie, a gestalt opcode. It would have the same syntax as Glulx’s @gestalt, and an opcode number of EXT:127: @“EXT:127S”. Opcodes EXT:128-255 would then be available for further extensions.

But, how can we detect whether this gestalt opcode will exist or not?

Following David Kinder’s suggestion we will set the VM interpreter number to 20, but only for games with a serial number of 100000-820000 (ie, from 2010 until 2082, when serial numbers will start overlapping with the original infocom ones.) This means that old games which actually cared about interpreter numbers will not run the risk of getting confused.

Now, I just need to decide where a good place for a registry of gestalt selectors and new opcodes should be. I’ll be taking submissions and will be happy to assign codes to those with reasonable extension proposals.

I intend to implement this in Gnusto. I hope other VM maintainers will get on board too.

Edit: The draft proposal has been posted at

The 1.1 specification did tail off rather, but (after some pushing from Graham) I did get round to just removing all the controversial features from 1.1 and calling that (which is the version on the IF-Archive) final. I don’t think a minimal implementation of the 1.1 specification (excluding anything V6 related) is at all a bad idea: most of the non-V6 parts of it are really just clarifications of the 1.0 specification.

After some more thought, the really elegant way to implement this would be to have your opcode be part of a “1.2” specification, so that games could test the header fields to see if the opcode was there. Adding 1.1 to Parchment would be a good idea and should not be significant work.

However, the real question is whether there’s any real demand for this, now there’s a web-based Glulx interpreter.

I like what you’re suggesting, and have started working to add 1.1 support to Gnusto. Well, firstly by writing test cases for it ( … 411c93d417)

Do we need to check that we’re running on a 1.1 terp for the updates/clarification section? I ask because I haven’t found any terps that return 0 for @get_prop_len 0.

I think there might still be use for extensions to the Z-Machine, even though Quixe is useable. For the moment the Z-Machine is still quite popular, and the lack of mobile support for it is a problem. And the extensions that we’ll make will probably be quite small, such as the gestalt selector in the transcripts proposal.

Was there a Z-Machine developers mailing list? I thought there was one (hosted at but I can’t find it anymore.

Test cases are a good thing :slight_smile: I did create a test Z-code file for Windows Frotz for this work: it’s in the Windows Frotz zip file on the Archive.

I don’t think games really need to test for 1.1 for the updates/clarifications bit: it’s just making absolutely clear a few bits that were left vague in the 1.0 spec. I suspect if you dig around the really old interpreters in the Archive you can find some with odd behaviour on these points, but at this stage they’re so archaic that it’s not really an issue any more: everyone is using something Frotz-based or Gnusto-based :slight_smile:

There was a Z-machine mailing list, but I can’t remember where: I’d have to check my old emails at home. In any case it’s pretty much dead - I don’t recall getting a message from it for a few years.

That was my thinking, that the clarifications part of the 1.1 spec should be followed by all 1.0 terps while it was only the 1.1 terps that would implement the new stuff. But I guess the ones who ship, win, and the de facto standard is still Frotz, whatever it actually implements. (Though Gargoyle stating it’s a 1.1 terp while not supporting the new opcodes is a worry…)

Is that something specific that you know of, or just a vague concern? Without actually looking at the Frotz code in Gargoyle, I know that Ben imported the work done from Windows Frotz to get Unicode support, which should (or at least could) have provided 1.1 support too. If it claims 1.1 but fails on the opcode, we should definitely hassle Ben to fix it one way or the other.

I did just import all your work from Windows Frotz, and it seems rather likely that I missed the fact that it now claims to be a 1.1 terp as a consequence.

Is this governed by these values in main.c?

zbyte h_standard_high = 1;
zbyte h_standard_low = 1;

If so I will patch the source right away. I haven’t done an official release based on the changes yet, so there should be relatively few instances of this in the wild.

Well someone commented out the two opcodes in process.c, so if it wasn’t you… :wink:

I think those lines are the ones that matter, but David could tell you for sure.

Well, I’m sure it was me. I figured I had not implemented @set_true_colour or @buffer_screen, so it was safe to comment them out.

I did consider trying for full 1.1 support, but the requisite changes to @set_text_style put me off. Combining text styles would require even more mangling on the Glk side, though the functionality would admittedly be useful for other interpreters (such as Hugo) which expect an equivalent level of control.

Demona allows combining text styles - between my color patch and the full set of Glk styles, I think there should already be enough functionality.

You’re right, of course. I’d been thinking that the permutations of fixed, italic, bold, and reverse pushed it outside the 11 style bounds. But since reverse gets treated differently, we only need 8 static styles.

Which should have been obvious, since Gargoyle only allows 8 font styles in the first place. :blush:

All of a sudden, it looks like support for the 1.1 standard will make the next release after all. Thanks!

Ah, that makes sense. Yes, it’s controlled by h_standard_high and h_standard_low: changing the latter to 0 will fix the problem. Having said that…

Having full 1.1 support (at least for everything other than V6) with a minimal implementation should be possible without much work. From the section on @set_text_style:

It would be nice to have Gargoyle on spec 1.1, as that makes the idea of having a spec 1.2 for Dannii’s gestalt opcode more feasible: if Gargoyle won’t support it, it won’t get that far. :slight_smile:

Oh, I see. The earlier wording threw me off the track:

I assumed that “supported” meant “honored” rather than simply allowed, and that “see below” referred to a list of Infocom interpreters that had included such support.

Clearly the whole episode was not a shining moment in the annals of reading comprehension, but I can make amends.

I am basically done with the necessary changes to support 1.1:

  • @set_true_colour is fully supported
  • @buffer_screen does nothing and stores 0
  • @set_text_style supports all combinations of styles, either all at once or from a succession of calls

The remaining hurdle is @set_font; the 1.0 standard implies that it’s optional, though the 1.1 standard appears to assume it is supported.

Is it OK to punt and just store 0 for all @set_font calls? @set_text_style seems to offer a superset of the functionality and the interactions between the two are not rigorously specified in the 1.0 standard.

I think you can get away with that under the specification, but I’d be surprised if no games make use of it. Most Frotz ports respect the call, I think: Windows Frotz uses the fixed width font if either the font has been set by @set_font, or the style has been set, or the header bit has been set.

OK, I’ve added support for @set_font as well.

I’ve published my draft 1.2 proposal:

Comments, concerns etc?

I guess the @gestalt is super-minimal to encourage its implementation? But without any reason to actually call the @gestalt opcode, no game would ever include it, even if it were widely implemented. And if no game ever includes it, why should an interpreter implement it?

Collect some of the extensions that have been implemented and add selectors for them. The benchmark opcodes from Zoom come to mind. I’m sure there’s been others.

Well there should be a few new selectors quite soon actually. The transcripts collection proposal for example will need one, and I’m planning on adding some for experimenting with Parchment.

It would make sense to add selectors for existing extensions (it would also be good to have a list of them in one place!) I’ll go looking for the Zoom ones you mentioned, but I’m unaware of any others. If you know of more, please do share them.

Hmm, ok, so it looks like Zoom adds EXT:128-132. It also has @sound_data, an opcode removed from the final 1.1 spec, though it looks like a nop. I’ll change the range referred to in the private use area so that there’s no possibility of conflicts. And if we assign selectors for the Zoom opcodes then other interpreters could add them too, which might be good.

A minor point: the canonical link for the 1.1 spec should probably be

More fundamentally, are you planning on assigning ranges of opcodes to have a particular meaning if some given selectors return a non-zero value? It seems to me that pretty soon you’ll run out of spare opcodes that way. Glulx handles this rather neatly by isolating the VM layer from the I/O layer with the use of a single @glk opcode. Any such Z-machine system should probably be very cautious about assigning away more than a few of the remaining opcodes.

I also have to disagree with nitfol’s suggestion of including any other past Z-machine extensions that a trawl of interpreters drags up. If it’s to be of real use, rather than historical interest, a specification has to contain stuff that people will use, and the fact that no-one has used such past attempts suggests to me that the demand really isn’t there for them. The specification shouldn’t be a dumping ground for past ideas - if the 1.1 spec business has any lesson for us, it ought to be that specs based around hopeful guesses about what will be useful don’t get much support.

I still have my doubts about whether any of this will be useful. If it is to be useful, though, the only way I can see this working is if you use Parchment to prototype ideas, and once you’ve got something that people are actually using in games, then codify it in a spec. Doing the spec first won’t work.