Updating the Z-Machine Standard Documents

It looks like at least the Amiga interpreter stops sounds when exiting. Haven’t looked at any others.

Leaving it undefined is fine with me, but yeah some indicator that games shouldn’t rely on it seems justified. Weird that sounds in Frotz weren’t stopped on restart/restore. I thought those were the obvious scenarios and only quit seemed ambiguous.

A weird case: should sounds (ideally) be stopped on restore_undo?

1 Like

That’s a good one I hadn’t thought of. My thoughts are that yes, they should be.

Internally (to the z-machine) a restore_undo is no different than a restore and games should probably be checking in their restore routines to see if there are any sounds that need to be re-started.
While undo didn’t exist in V3, I know The Lurking Horror does this for normal restores if a looping sound should be playing.

1 Like

14.2.1 says:

“However, extended opcodes in the range EXT:29 to EXT:255
should be simply ignored (perhaps with a warning message somewhere
off-screen).”

Is this really correct? EXT:29 buffer_screen seems to be a valid instruction, just as valid as as say EXT:11 print_unicode.

2 Likes

Yeah, that’s a mistake (text not updated properly from the 1.0 standard)

3 Likes

Question: if the output buffer to an array overflows, what happens? Does that cause a fatal error? Or does it just output to nowhere?

If it writes more than intended then you get corrupt data, so you have to be careful. Or if you mean it overflows out of the RAM area, then the interpreter should detect that and stop.

1 Like

An alternative I use for my interpreter library is to detect the situation and issue what I call a fault to the the front-end. The front-end can decide what to do, e.g. issue a warning, halt, or continue: “Damn the torpedoes, full speed ahead!”.

Faults are useful for detecting misbehaving story files, but sometimes you just want to play a game. Maybe the game will just go off the rails and stop working…but maybe it won’t.

I decided to take this approach after trying to play one too many DOS games that refused to work because of some silly hardware test that failed due to 30 years of hardware changes. The player has no control over the correctness of a game, they just want to play. It makes sense to allow a best effort to do so in spite of any faults that crop up.

1 Like

So if I need to catch a lot of text, I just have a massive array. Or I, at points throughout the parsing, refresh (turn off buffer output and restart).

3.8.2.2 and 3.8.3.1 seem to be confused about the name of character 8, referring to it as “delete” rather than “backspace”, and then claiming that character 127 is “‘delete’ in some forms of ASCII.”

This confusion seems to originate from the behaviour of the DEC video terminals.

At least the original sources of Journey, Zork Zero, and Shogun check for both values in their input code:

https://github.com/the-infocom-files/journey/blob/1b689ae9ec8808304a24ab57644d052160c409f5/input.zil#L17-L18

https://github.com/the-infocom-files/zork0/blob/ee8197d97d3947a71fbdf14904ffd91f71ac96be/input.zil#L255

https://github.com/historicalsource/shogun/blob/38a0cd0a798207933761f652a8bf242d48e6fcf2/menu.zap#L142

My proposal would be for the standard to define both character values for input under their proper names, i.e. “delete” for character 127 and “backspace” for character 8.

I don’t see any confusion.

3.8.2.2 is defining ZSCII character 8 as “delete”.

3.8.3.1 is leaving ZSCII 127 as undefined.

To rename them to match ASCII now would lead to more confusion, I think. A similar thing is done with ZSCII newline, which uses the ASCII value for carriage return.

A possible harm I can see in accepting both 8 and 127 is what happens if not all games support both. This would lead to confusion and frustration for players trying to play a game which doesn’t support the key they’re used to.

Edit: Another problem is: What happens if a game comes along that only recognizes 127, or uses 8 and 127 differently? I’m guessing a lot of existing interpreters wouldn’t recognize 127 at all.

Well, it is confusing when trying to make sense of the original Infocom sources, which use both.

It is also confusing to name a key “delete” which does not behave like a delete key, that is, it deletes the character to the left of the cursor like a backspace key would. I wouldn’t expect many people to use the delete key at all when entering commands in a parser game. This is unlike the newline and carriage return keys, which are pretty much equivalent on modern systems.

It’s definitely decades too late to try to introduce ZSCII 127 into the standard.

I don’t think it’s too confusing, you delete things by pressing the backspace key. Forward deletion is probably the more obscure concept and key, and I’d bet there’d be many people who are barely aware their keyboard even has such a key (any lots of people whose keyboards don’t have one!)

I’m fine with not introducing ZSCII 127 into the standard, but I still think the standards document should make clear that what it calls “delete” is in fact ASCII (and Unicode) backspace. The current wording is confusing.

In fact, 3.8.2.5 already does the sensible thing and calls ZSCII code 13 “carriage return” and not “newline”.

I agree the use of newline/carriage return is not optimal. Table 2 in section 8.2 lists 13 as newline. Several locations in the opcode descriptions use the term carriage return, and the naming of the new_line opcode speaks for itself. These could be cleaned up.

I think the takeaway is clear though: Because 8 and 13 are known to work for all stories, interpreters should be passing them and not 10 or 127. There’s nothing stopping an interpreter from accepting 10 and 127 from hardware, as long as they map it correctly before handing it to a story.

1 Like

I think the crucial part is the terminology. As you point out, ZSCII 13 is also referred to in an inconsistent way, but that is less confusing, as ASCII 10 is called “linefeed” or LF, not “newline”. Simply making clear when they are introduced what their ASCII/Unicode equivalents are would be an improvement.

Originally yes (ASCII is very old). But newline is common modern usage to refer to the same character. Almost every programming language has a ‘\n’ escape character called “newline” which represents ASCII 10. It is referred to and used as such in operating systems, applications, etc. Even Windows, the perennial odd duck, uses ‘\r\n’, read as carriage return + newline, as a line terminator.

I think it is more correct to say that \n is an programming language abstraction which is not necessarily the same as the control character LF. Writing \n to an output stream in text mode on Windows, for example, will result in the two-character sequence CR+LF.

Anyway, back to the problem at hand.

To clarify: We have two different ASCII control characters, 8, “backspace”, and 127, “delete”, with different meaning and behaviour. ZSCII 8 uses the value and the behaviour of ASCII backspace, but is referred to in the standard document as “delete”. To me, this seems like an obvious mix-up, a bit like mixing up the codes for “a” (97) and “b” (98).

An example of the kind of problems this can cause, from the current source code of Bocfel:

constexpr uint16_t UNICODE_DELETE          = 8;

Here, the mix-up in the Z-Machine standard document has made the programmer mistakenly define 8 as Unicode Delete rather than Unicode Backspace.

I’m sorry, I don’t understand this. In what way would it lead to more confusion? What am I missing?

1 Like

Couldn’t the backspace/delete confusion be in a footnote that explains the historical context and current use (much like the last couple of posts)?

1 Like

It’s definitely a lot more than that. While Linefeed is technically the name of ASCII 10, Newline is very commonly used as equivalent. The wikipedia page for ASCII links to the characters, and the link for 13 is to a page called “Carriage return” while the link for 10 is to a page called “Newline” where it discusses a lot of minutia regarding line endings. Printing a ‘\n’ character in most languages gives you a ‘newline’ i.e. a Linefeed character. You need to use ‘\r\n’ (13 then 10) to get a carriage return followed by a newline, the terminator desired by Windows. Windows itself, as usual, is tricky. When developing applications, in some cases Windows will start a new line properly if you just use ‘\n’, but in others it will not.

To people who’ve followed the standard for the last couple decades. I think a historical footnote like Henrik suggested would be better than renaming things at this point.