Vorple and Z-machine 1.2

In light of the new Z-machine 1.2 spec suggestion, here’s a rough outline of how Vorple would work with the proposed stream 5.

First, the story file would have to find out if it’s being run on a Vorple-enabled interpreter. At the start of the game it would send this to stream 5:

javascript:try {
	return vorple.core.requireRelease( x );
} catch(e) {
	return false;
}

where x is the Vorple library version compatible with this story file. If it returns false, the story file disables all Vorple features and won’t use stream 5 anymore. The above code would be valid even on hypothetical non-Vorple interpreters that support JavaScript evaluation from stream 5. I suggest using “javascript:” to signify JavaScript data, which would be in line with what browsers use (i.e. the code above is valid JavaScript even with the identifier).

If there must be an end-of-transmit signifier, I don’t know what it could be that would also be valid JavaScript (which I think it should be); perhaps a special comment like /* END */ or something like that.

For simplicity’s sake before evaluation the interpreter should wrap the code to a function and write the return value to the input array (this should be Vorple-specific though, not something that should be in the Z-machine spec). The return value should be either an integer, a string or a boolean value. (Not entirely sure how to deal with boolean values: perhaps write their string representation “true” or “false”?) If the return value is undefined (i.e. nothing is returned) the interpreter does nothing.

There are basically 3 general cases where the interpreter might want to pass data to the story file. The first is a synchronous response to JavaScript code passed through stream 5. This is relatively straightforward: The interpreter writes the response to the array and closes the stream, and the story file picks up the data from the array, as per the 1.2 spec proposal.

The second case is passing simple events from the interpreter or UI to the story file and the interpreter doesn’t expect to receive a direct answer (e.g. the player pushed a button in the UI); this is the simplest case and can be handled with hidden commands sent through the command line.

The third case is asynchronous responses (interpreter must wait for a response from a third-party service, for example) and other spontaneous data the interpreter wants to send (e.g. player submitting information through a form in the UI). In this case the interpreter must first tell the story file that it has information to pass. According to the 1.2 proposal, the input array is unavailable unless stream 5 is open. Therefore, AFAICT, the procedure would be this:

  1. The interpreter has data to pass. It stores the data temporarily into an object with a unique id as the key.
  2. The interpreter waits for the story to be idle (waiting for player input).
  3. The interpreter sends a hidden command through the command line that tells the story file to prepare for data transfer. The command includes the id of the data it wants to pass.
  4. The story file sends javascript:return vorple.parser.retrieveData(x) (where x is the id) through stream 5 and closes the stream.
  5. The interpreter evaluates the JavaScript code which returns the requested data. The data is then written to the input array.
  6. The story file reads the data from the input array.

Does this seem like a sensible approach? Also, for actually implementing this I would need the I6 code for reading the input array. I have practically no idea how arrays work in I6.

I’ll go over some other bits of this idea later, but I spent some time thinking about how the interpreter can send information back to the game whenever it wants, and I came up with an idea:

Interrupt routine.

The Z-Machine uses interrupt routines to do stuff when sounds finish, or to implement timed input, but we could use it here. Basically, the game puts a routine address at a specific point in the extension header (probably word 7), and whenever the interpreter wants to send information to the game, it looks at that word, and calls an interrupt routine at that address.

It is then the game’s responsibility to open output stream 5 with a valid array for input, and close it again. While it’s open, the interpreter writes the data it needs to in the array. The routine then finishes, and the game goes back to whatever it was doing before.

Does this sound workable?

No, please don’t add interrupts. Parchment doesn’t even support them yet. A poll function is so much more straightforward. (Look to Glk!)

I’m not sure about this. A poll function (and I totally didn’t read this properly) appears to essentially just be the game calling a routine occasionally to check if the interpreter has something to say. I already considered that idea.

The problem with that is, what if the interpreter wants to do something while the game is waiting for the player to type something? The game isn’t reading any more instructions, it’s just sitting there waiting for something to happen. Making something happen at that point is the sort of thing interrupt routines are designed for.

Now, if the interpreter doesn’t want to use the interrupt routines, it doesn’t have to. Having the game call a routine every so often requires no changes to my proposal at all, so if Parchment doesn’t support interrupts yet, this doesn’t actually affect it.

Remember that Parchment is the only interpreter supporting Vorple, and the only terp supporting 1.2 yet too for that matter.

Hmm, that is a bit of a tricky issue. My first thought would be to follow Glulx/Glk, and use a generic event polling system rather than @read. Those using Vorple could make the input be returned through Javascript rather than @read, and then there wouldn’t be a problem. They’d have to do a bit of work to change how input is requested and returned, but Vorple already intercepts the input box anyway so it might not be as big a change as you’d think.

Alternatively the terp could make @read return immediately with blank data, and the game would interpret that as indicating it needs to check for javascript events.

Juhana, what do you think? I could help from the I6 side if you want.

I understand that there’s only one interpreter currently supporting any use of Output Stream 5, and it’s the only one likely to use it in the near future. That doesn’t mean I should design entirely around Parchment’s limitations. If a feature is useful but Parchment can’t use it, that’s fine. If you want to ignore the feature and figure out a different, non-Standard way to get input into the game, that’s fine too.

I have no idea what any of that means, but as long as there’s a general consensus and the story file would be compatible with existing interpreters, it’s good enough for me.

I’ve just read this again, and I’m not sure I understand what you’re saying. I wasn’t suggesting that the interpreter input data through @read at all. What I’m saying is, when the interpreter wants to input data, it initiates a call to a game routine that opens output stream 5 so that it can input the data. Is it particularly difficult to make Vorple call a routine without the game asking it to?

Layman butting in.

Often, it’s when games make use of non-standard features that the interpreters are updated to make use of them. “Moments out of Time” famously abused this. Who knows, maybe even Frotz and Glulx will be Vorple-compliant simply because games started using features which have become standard.

Accourse, until that happens, it’s just hugely frustrating; it’s like a game made for a machine that doesn’t exist.

Layman butting out.

Moments Out of Time used non-standard features?

IIRC it required a lot of the less-used Z6 features.

I would have to change a lot. I’m sure I could do it, but I don’t particularly want to yet.

Remember that Glulx will be getting JS stuff sometime in the future. My goal has been to introduce small changes to the Z-Machine so that they can be on the same page, so we’ve added @gestalt, we’re using streams to send data to JS. A poll function hasn’t been specified because it hasn’t needed to be. Interrupts on the other hand don’t exist in Glulx, and are messy in the Z-Machine. If you want consensus to go for interrupts, then make your argument for them.

You know what, I thought about it a bit more. If the interpreter wants to be able to run a routine to get access to game memory while the game is waiting for input, the interpreter can just go ahead and support timed input.

All we need now is a method for the interpreter to tell the game it has information it wants to send. I don’t much like the idea of the interpreter having to send secret messages through the command line. I should say, this is for the asynchronous example, not the ‘passing simple events’ idea. If you want the interpreter to send simple command to the game while the game is at the command line, the command line is the way to do it. But if you want to just send the message ‘I have something to send to you’, there should be a standard way to do that.

z6 games have a special bit in the header. When the interpreter thinks that the game needs to redraw the screen (because the user has resized the interpreter window, for instance) the interpreter can set this bit in the header. The game should check it every so often, and take appropriate action.

We can adapt this idea. When the the interpreter has information it wants to give the game by editing an array in memory, it will set a bit in Flags 2. The game should notice sometime before @read is called, and run a routine opening output stream 5 with an array address argument, then close output stream 5. Since the interpreter should already have the data ready to go, this should work quickly and effectively. The interpreter, once it has sent the information, needs to clear the flag in the header.

Well, here’s a quote from in-game help. In my memory’s eye I thought it was a bit more obvious than it actually is, or maybe it registered more heavily on me than it’s actually written, but anyway.

Of course, later MooT games were Glulx (hardly a surprise). But MooT 1 is still quite interesting. Uses arrow keys, function keys, and in-game menus with verb lists and noun lists et al. And the z6 support at the time was lacking, from what I read in the quote; and currently it isn’t. I assume that’s because there got to be an increase in demand, however slight. Maybe it was just to play the Infocom games properly, I dunno.

z6 support was okay, if I recall correctly. Blorb support, on the other hand, was terrible. I think the only Blorb-capable z6 interpreter at the time was for RISC OS. MooT certainly went some way towards fixing that. I think Inform 7 and the Treaty of Babel were what really lead to more interpreters having at least basic Blorb support, though.

The header bit is a decent idea, although I’m not sure what advantage it has over simply polling stream 5 every turn anyway.

If the interpreter can’t push the data to the story at any arbitrary point, it’s not that big deal. I assume for most uses checking it at the start of a turn should be enough and if not the interpreter can force the check by sending a hidden command to the parser that by itself does nothing.

There only needs to be an end identifier if you’re planning on ever opening and shutting output stream 5 several times before expecting the interpreter to execute the data being sent. Whether that’s true or not depends on the type of data being sent, and the game code (probably in a library somewhere). But yes, “/* END */” would work just fine.