The spec has a line “While the stream is selected, the table’s contents are unspecified (and a game cannot safely read or write to it)”. Extend that to include “cannot safely start a new stream that writes to overlapping memory” – which is, after all, part of “writing to it”.
Interpreters may (but do not have to) handle the stream-writing with a separate, non-VM buffer that is pasted back into VM memory when the stream closes. When the spec allows for this, it pretty much has to throw up its hands and leave the result unspecified.
I was thinking along the lines of: The contents can’t be read/written by the story, but what the interpreter can do is fair game, or at least unspecified.
Edit: It probably is best if overlapping tables are undefined/illegal. I was trying to imagine there might be some legitimate uses for them and not rule them out entirely.
Making overlapping stream 3 tables illegal allows an interpreter implementation the extra freedom to use the table in Z-machine memory to hold the printed characters and running total while the stream is open, instead of requiring a separate buffer.
Edit: It’s a shame that V6 requires a separate buffer be maintained for the total printing width in pixels. As always, V6 irritates me.
One thing I’ve never understood: when output stream 3 has a table with something already in it, does it overwrite that information when something is written to it, or does it write to the next empty position?
It overwrites. It’s the only thing it can do, as the standard states that even the initial size word is ignored by the interpreter. Without size information, there is no way to know what if anything is in the table. It just writes bytes until you close the stream then writes the count in the initial word. The interpreter has no clue how big the table even is, and will happily write past the end.
The runic font used in Beyond Zork seems to be slightly different in the Mac version. So far, the only difference I’ve noticed is that the ‘bar filling up’ characters which run from O (empty) to W (full) on other platforms only run from O (empty) to U (full) on the Mac. Beyond Zork assumes this to be true, and prints not-quite-full bar characters if the interpreter claims to be on a Mac.
Here’s an issue that is probably academic and unlikely to happen practically.
The description for the tokenise opcode says: Parsing a user dictionary is slightly different. A user dictionary should look just like the main one but need not be alphabetically sorted. If the number of entries is given as -n, then the interpreter reads this as “n entries unsorted”.
The main dictionary theoretically must be sorted and therefore cannot have a negative number of entries, but the entry count for it is a 16-bit word. What happens if the entry count for the main dictionary is greater than 32767? Should it be treated as a large positive number (likely unavoidably exceeding byte accesible memory), a small negative number (and unsorted?) or just give up and crash .
Edit: It is theoretically possible for the main dictionary to have greater than 32767 entries and not exceed the limits of byte accessible memory, but only if the entry size is smaller than the dictionary word length, which should also be an error.
Here’s something I had never considered before, but might be nice to clarify: If a game starts a sound effect, even a looping one, and then executes a quit instruction, should the sound be cut off or continue playing?
Imagine a game starting some game ending theme music, printing some end credits, and then halting. It may sound silly but I actually ran into this as a bug in my interpreter library where the front-end could report the end of a sound effect after the machine had halted, thereby triggering a scheduled interrupt routine and setting the machine running again! Clearly this is Bad™. While considering the best way to fix the bug, I realized it wasn’t clear if asynchronous sounds should be cut off when the machine halts, or be allowed to continue.
I think “what the system does after halting” is a good place to keep some behavior undefined by the standard. A terminal program and a web page will have very different conceptions of “the right way” to halt, and canonizing one of those ways will make headaches for one (or both!) of those devs for no real gain.
Perhaps, but in a way that ship has sailed already. I’m certain we have games that print text and then immediately halt. To accomodate these, an interpeter should not close the window/display upon halting. Frotz displays a “[Hit any key to exit.]” message instead of immediately closing the window.
…although the z-machine halting isn’t necessarily synonymous with the entire application exiting.
Absolutely. I just meant that assuming everything after halting should be undefined is already not possible. Personally I’m leaning towards saying the sound should stop, or at least that it be declared as implementation defined and not relied upon.
My initial reaction is that it’s undefined, and it’s fine to leave it undefined, with maybe a note that games should not rely on any specific behaviour.
However, there’s also (I think) no explicit mention of what happens to currently playing sounds on restart or restore. It may be easiest to just say “All currently playing sounds must be stopped on restart, restore or quit”.
Is that what interpreters are already doing though? While some clarity would be nice on things like this, I don’t think we should be trying to effect change.
I imagine this is what most or all interpreters that support sound already do. As the only asynchronous piece of the z-machine I think it’s worth specifying.
I’ve tested Frotz on ubuntu and it doesn’t stop sounds on restart or quit opcodes. A quick look through the Infocom source for their terps indicates (as far as I can tell) that they don’t, either.
If we’re going to avoid mandating new behaviour, which I agree is a good idea, perhaps the best idea is to say that interpreter behaviour is not defined, with perhaps a note somewhere saying that ideally interpreters should stop sounds on restart, restore or quit, but it’s not a requirement, and games absolutely shouldn’t rely on it.