Z-Machine 1.2 Proposal

Bocfel’s behavior is identical to Marvin’s proposed change. I always figured that @print_table was assumed to be an upper-window feature, since it seems to be useful only with a fixed-width font, but decided that there was no reason not to just do something sensible in the main window. It doesn’t appear as a rectangle (impossible to guarantee with proportional fonts), but at least you see the text.

As such I’d have no problem with it being unspecified/undefined behavior, especially since a search through a bunch of disassembled comp games yielded zero uses of @print_table. But if it does get specified, the proposed wording is about the most useful interpretation I can see.

The reason I want to specify print_table for the lower window actually has to do with the new Unicode strings. At the moment, if you print arbitrary unicode characters that aren’t defined for output to output stream 3, they get written into memory as ? characters. With the proposed unicode strings, there’s no reason they can’t get written into memory as a unicode escape character followed by utf-8, followed by a 0 byte.

The only problem with this is printing them back out. At the moment, if you want to print an array of characters from memory in the lower window, you have to loop over each character and print them one at a time. This will totally not work with utf-8.
If you want to print an array of characters from memory in the upper window, you can just call print_table and the interpreter does it for you. This can totally work with utf-8. So it seems sensible to allow for print_table to work in the lower window, with slightly changed behaviour. But only as a 1.2 feature.

Makes sense.

I’ve uploaded a 5th draft to frobnitz.co.uk/zmachine/1.2/draft5.html

Changes:

  • Unicode escape are illegal in @print and @print_ret
  • Changed the Unicode escape character.
  • Added a new flag in Flags 3 for font size changes
  • Clarification on the font size information in the header and window properties
  • Added a bit for the interpreter to ask for output stream 5 to be opened

I think I’ve covered everything that was brought up since the last draft. The output stream section now links to a draft page for the interpreter identifiers list.

Right now I’m working on an addition to the sound system to allow volume control for sound effects while they’re playing (so that the sound can be faded in and out nicely).

This would probably reuse the @sound_channel opcode, so that it looks something like this:

In addition to this, I’ve been wondering if it’s worthwhile giving the Z-Machine better external file access capabilities. Currently, the Z-Machine can read a section of a file to memory, but the start of the section is always the start of the file. It can also write a section of memory to a file, but it always overwrites the entire file.

It seems to me it would be useful to allow appending of data to files, and reading of any arbitrary section of a file. I haven’t figured out the best way to do this, yet. It would probably involve entirely new opcodes, though.

Okay, my idea to add better external file access:

Just a quick update on what I’m doing with this. At this point, I’m actually working on adding these features to my Z-Machine interpreter. The idea is to see if there are any unforeseen problems with making theoretical features into something interpreters can actually do, before we make them standard and they turn out to make no sense. This may take a while, not least because my interpreter is kinda buggy to start with.

So far, I’ve implemented gestalt (which seems to work fine), print_table for the lower window (no problems), and half implemented the new Unicode strings, which seem to only not work because handling Unicode in Python makes my brain hurt.

I also implemented output stream 5 with a rather silly test that simply mangles text sent to it a bit, and then sends it back to the game. This seems to work, although the current proposal says that the interpreter should leave the ‘size word’ of the table it prints back to alone, but it would be useful to know how many bytes the interpreter put into the array. So I’m thinking the interpreter should actually update the size word, or possibly print the number of bytes set into the second word of the array.

I ran into some serious problems with @font_size almost immediately, when I realised I have no idea how the interpreter should align the text to avoid rows overlapping each other when font size changes are involved, especially when buffering is turned off (as it always is in the upper window).

Once I get these problems sorted out (and fix the various errors introduced into the 1.1 Standard), hopefully we will be ready to create a complete 1.2 Standard Document.

So, after a fair amount of thought as to how interpreters would actually handle font size changes, I’ve come up with the following:

(version 5 model)

(version 6 model)

Does anyone see any problems with this?

It sounds like for the upper window that it would stop being a grid of characters and turn into a window where text is printed at pixel coordinates. I’d implement font sizes for the lower window, but not for the upper window if they were like that. And I still think there should instructions for what the numbers mean.

Playing devil’s advocate … if in V6 the interpreter is not responsible for lining up the text base-line, then who is? The game won’t know enough about fonts to, so you’re always going to have rather ragged looking text if you change the font size during a line. Given that sort of limitation, you might as well make it simpler by saything that font size changes are only allowed at the start of lines.

The upper window is technically already not a grid of characters, it is a window where text is printed at unit coordinates. Units just happen to be the same size as characters in pretty much all modern interpreters. This is why I plan to add a header flag for font size operations, so that the interpreter knows that the game is going to probably want pixel-level control.

The game surely need only to know the height of the already-printed text and the height of the text it’s about to print? Which it can find out fairly easily. The easiest option (and basically the only option in z5 upper window) is to work this out ahead of time, and make sure you print the smaller text a little lower than the larger text. I think in theory in z6 you could use a window to scroll the already-printed text down a few pixels.

This is some quickly thrown-together code that I have absolutely no way to test, so I may have made a few mistakes, but the concept should work:

Array cpos --> 0 0;

[ font_size size;
  @font_size 1 ?nowhere;
  rfalse;
  .nowhere;
  rtrue;
];

[ main small_fheight large_fheight x y;
  @get_wind_prop 0 13 -> x;
  @log_shift x 8 -> small_fheight;
  font_size(1);
  @get_wind_prop 0 13 -> x;
  @log_shift x 8 -> large_fheight;
  y = largefheight - small_fheight + 1;
  x = 1;
  font_size(0);
  @set_cursor x y;
  print "This is a bunch of text. "; 
  font_size(1);
  @get_cursor cpos;
  x = cpos --> 1;
  y = 1;
  @set_cursor x y;  
  print "This is some larger text.^"
];

I admit this is a lot of code for just making the font size change a bit, but it does make it possible.

I’d be rather inclined to go with the Glk model for font size changes, which is:

Any specifics beyond that do nothing more than limiting interpreters if they can’t control font sizes that exactly.

Okay, thinking this through again: I think that an interpreter which allowed font size changes in the lower window but not the upper window, and left unit size as character size, would be legal. ‘Character size’ in the lower window has always been an approximation, and you can’t usefully use it to do any calculations about where text will end up, so it doesn’t matter how many pixels those characters take up. I should throw some notes in there about this, but I don’t think it’s a problem.

That sounds reasonable. They’re style suggestions anyway.

It depends on how neat you want the printing to look, but if you want it to look seamless, that’s not enough. Consider the attached PNG, which has the letters “ph” in 36 point and then in 72 point type. For proper typography, we want the letters aligned so that the baseline (the blue line) is the same for all characters, but that means that the larger text extends both above and below the smaller text. Knowing the height of the font (i.e. the heights of the red boxes) is not enough: to do layout right you need to know the baseline relative to the font height.

You are, of course, completely correct. I knew I was going to miss something when I started thinking about this.

It wouldn’t be difficult to add this information to the Z-Machine. Another word for the header extension with the ascent and descent of the current font for the current window, and another window property for z6 with the same information for that window. The interpreter would be free to set both to 0 if it was not capable of presenting this information.

This is getting very complicated for a feature which I haven’t seen anyone request before. Just remember everyone’s got to come to a consensus before this becomes a standard.

It is indeed becoming rather complicated. However, consider it requested. I put font size changes in the initial proposal because I’d like it for a game I’m working on. I thought it would be a fairly simple change. Silly me.

I do not, in fact, personally have any plans that involve enlarging words in the middle of a line. However, this does seem like a reasonable thing for someone to want to do if they find that font size is something they can change. Making these changes neat is simply not something the interpreter can reliably handle with z6 or the upper window in z5. Any attempt by the interpreter to intelligently move already-printed text about runs the risk of interfering with other parts of the display the game writer does not wish to be disturbed.

If the writer doesn’t want to alter text size in the middle of a line, the code remains simple. If the game requires this, the game code becomes more complex. We gain control at the cost of complexity. The alternatives are to either say ‘you can only ever control text size under certain very specific circumstances’ or just just cut the feature completely. I’d not be very happy with either.

Font sizes are very straight forward in a web context when you let the web browser control handle the reflows, but very few intepreters work that way. I’m not sure how this kind of thing works in Glk… I think WindowsGlk might support different font sizes, it would be worth checking out.

Despite making 1.2 features myself, I think anything too big should be left for Glulx. So I’d support making font sizes only valid before starting new lines.