This section covers the only opcodes which designers are likely to have
occasional need of: those which drive powerful and otherwise inaccessible
features of the Z-machine's “hardware”, such as sound,
graphics, menus and the mouse. There's no need to be fluent in assembly
language to use these opcodes, which work just as well if used as
incantations from a unfamiliar tongue.
▲
WARNING
Some of these incantations may not work well if a story file is played
on old interpreters which do not adhere to the Z-Machine Standard.
Standard interpreters are very widely available, but if seriously worried
you can test in an Initialise routine whether your game
is running on a good interpreter, as in the following code.
if (standard_interpreter == 0) {
print "This game must be played on an interpreter obeying the
Z-Machine Standard.^";
@quit;
}
The library variable standard_interpreter
holds the version number of the standard obeyed, with the upper byte
holding the major and the lower byte the minor version number, or
else zero if the interpreter isn't standard-compliant. Thus $002
means 0.2 and $100 means 1.0. Any standard interpreter will
carry out the opcodes in this chapter correctly, or else provide fair
warning that they cannot. (For instance, an interpreter running on a
palm-top personal organiser without a loudspeaker cannot provide sound
effects.) Here is how to tell whether a standard interpreter can or
can't provide the feature you need.
| Feature | Versions | Available if |
| auxiliary files | 5,6,8 | (true) |
| coloured text | 5,6,8 | ((0->1) & 1 ~= 0) |
| input streams | 5,6,8 | (true) |
| menus | 6 | (($10-->0) & 256 ~= 0) |
| mouse | 5,6 | (($10-->0) & 32 ~= 0) |
| output streams | 5,6,8 | (true) |
| pictures | 6 | (($10-->0) & 8 ~= 0) |
| sounds | 5,6,8 | (($10-->0) & 128 ~= 0) |
| throw/catch stack frames | 5,6,8 | (true) |
| timed keyboard interrupts | 5,6,8 | ((0->1) & 128 ~= 0) |
For instance, if coloured text is essential (for instance
if red and black letters have to look different because it's a vital clue
to some puzzle), you may want to add a test like the following to your
Initialise routine:
if ((0->1) & 1 == 0)
print "*** This game is best appreciated on an interpreter
capable of displaying colours, unlike the present
one. Proceed at your own risk! ***^";
· · · · ·
▲ Text flows in and out of the Z-machine continuously: the player's commands flow in, responses flow out. Commands can come in from two different “input streams”, only one of which is selected at any given time: stream 0 is the keyboard and stream 1 is a file on the host computer. The stream is selected with:
@input_stream number
The Inform debugging verb “replay” basically does no more than switch input to stream 1.
▲
There are four output streams for text, numbered 1 to 4. These are:
(1) the screen, (2) the transcript file, (3) an array in memory and
(4) a file of commands on the host computer. These can be active in
any combination, except that at all times either stream 1 or stream 3
is active and not both. Inform uses stream 3 when the message
print_to_array is sent to a string, and streams 2 and 4
in response to commands typed by the player: “script on”
switches stream 2 on, “script on” switches it off;
“recording on” and “off” switch stream 4 on and
off. The relevant opcode is:
@output_stream number arr
If number is 0 this does nothing.
+n switches stream n on,
-n switches it off. The arr operand is
omitted except for stream 3, when it's a table array holding the text
printed: that is, arr-->0 contains the number of characters
printed and the text printed is stored as ZSCII characters in
arr->2, arr->3, …
▲ As the designer, you cannot choose the filename of the file of commands used by input stream 1 or output stream 4. Whoever is playing the story file will choose this: perhaps after being prompted by the interpreter, perhaps through a configuration setting on that interpreter.
•▲▲
EXERCISE 122
Implement an Inform version of the standard ‘C’ routine
printf, taking the form
printf(format, arg1, ...)
to print out the format string but with escape sequences
like %d replaced by the arguments (printed in various ways).
For example,
printf("The score is %e out of %e.", score, MAX_SCORE);
should print something like “The score is five out of ten.”
▲
In Version 6 story files, only, @output_stream can take
an optional third operand when output stream 3 is being enabled. That is:
@output_stream 3 arr width
If width is positive, the text streamed
into the array will be word-wrapped as if it were on a screen width
characters wide; if width is negative, then as if on
a screen -width pixels wide. The text going into arr
is in the form of a sequence of lines, each consisting of a word containing
the number of characters and then the ZSCII characters themselves in
bytes. The sequence of lines finishes with a zero word. Such an array
is exactly what is printed out by the opcode @print_form arr.
· · · · ·
▲ The Z-machine has two kinds of “screen model”, or specification for what can and can't be done to the contents of the screen. Version 6 has an advanced graphical model, whereas other versions have much simpler textual arrangements. Early versions of the Z-machine are generally less capable here, so this section will document only the Version 5 and Version 6 models. (Versions 7 and 8 have the same model as Version 5.)
The version 5 screen model. The screen is divided into an upper window, normally used for a status line and sometimes also for quotations or menus, and a lower window, used for ordinary text. At any given time the upper window has a height H, which is a whole number of lines: and H can be zero, making the upper window invisible. (The story file can vary H from time to time and many do.) When text in the upper and lower windows occupy the same screen area, it's the upper window text that's visible. This often happens when quotation boxes are displayed.
@split_window H
Splits off an upper-level window of the given number of lines H in height from the main screen. Be warned that the upper window doesn't scroll, so you need to make H large enough for all the text you need to fit at once.
@set_window window
Selects which window text is to be printed into: (0) the lower one or (1) the upper one. Printing on the upper window overlies printing on the lower, is always done in a fixed-pitch font and does not appear in a printed transcript of the game.
@set_cursor line column
Places the cursor inside the upper window, where (1, 1) is the top left character.
@buffer_mode flag
This turns on (flag==true) or off
(flag==false) word-breaking for the current window: that is,
the practice of printing new-lines only at the ends of words, so that
text is neatly formatted.
@erase_window window
Blanks out window 0 (lower), window 1 (upper) or the
whole screen (if window=-1).
Using fixed-pitch measurements, the screen has dimensions
X characters across by Y characters down, where
X and Y are stored in bytes $21 and $20
of the header respectively. It's sometimes useful to know this when formatting
tables:
print "My screen has ", 0->$20, " rows and ", 0->$21, " columns.^";
Be warned: it might be 80 × 210 or then again it might be 7 × 40. Text printing has a given foreground and background colour at all times. The standard stock of colours is:
| 0 | current colour | 5 | yellow |
| 1 | default colour | 6 | blue |
| 2 | black | 7 | magenta |
| 3 | red | 8 | cyan |
| 4 | green | 9 | white |
@set_colour foreground background
If coloured text is available, this opcode sets text
to be foreground against background.
(But bear in mind that not all interpreters can display coloured text,
and not all players enjoy reading it.) Even in a monochrome game, text
can be set to print in “reverse colours”: background on
foreground rather than vice versa. Status lines are almost always printed
in reverse-colour, but this is only a convention and is not required
by the Z-machine. Reverse is one of five possible text styles: roman,
bold, underline (which many interpreters will render with italic),
reverse and fixed-pitch. (Inform's style statement chooses
between these.)
•▲
EXERCISE 123
Design a title page for ‘Ruins’, displaying a more or
less apposite quotation and waiting for a key to be pressed. (For
this last part, see below.)
•▲
EXERCISE 124
Change the status line so that it has the usual score/moves appearance
except when a variable invisible_status is set to
true, when it's invisible.
•▲
EXERCISE 125
Alter the ‘Advent’ example game to display the number of
treasures found instead of the score and turns on the status line.
•▲
EXERCISE 126
(From code by Joachim Baumann.) Put a compass rose on the status line,
displaying the directions in which the room can be left.
•▲▲
EXERCISE 127
(Cf. ‘Trinity’.) Make the status line consist only of
the name of the current location, centred in the top line of the screen.
The version 6 screen model. We are now in the realm of graphics, and the screen is considered to be a grid of pixels: coordinates are usually given in the form (y,x), with (1,1) at the top left. y and x are measured in units known, helpfully enough, as “units”. The interpreter decides how large “1 unit” is, and it's not safe to assume that 1 unit equals 1 pixel. All you can tell is what the screen dimensions are, in units:
print "The screen measures ", $22-->0, " units across and ",
$22-->1, " units down.^";
There are eight windows, numbered 0 to 7, which text and pictures can currently be printing to: what actually appears on the screen is whatever shows through the boundaries of the window at the time the printing or plotting happens. Window number −3 means “the current one”. Windows have no visible borders and usually lie on top of each other. Subsequent movements of the window do not move what was printed and there is no sense in which characters or graphics “belong” to any particular window once printed. Each window has a position (in units), a size (in units), a cursor position within it (in units, relative to its own origin), a number of flags called “attributes” and a number of variables called “properties”. If you move a window so that the cursor is left outside, the interpreter automatically moves the cursor back to the window's new top left. If you only move the cursor, it's your responsibility to make sure it doesn't leave the window.
The attributes are (0) “wrapping”, (1) “scrolling”, (2) “copy text to output stream 2 if active” and (3) “buffer printing”. Wrapping means that when text reaches the right-hand edge it continues from the left of the next line down. Scrolling means scrolling the window upwards when text printing reaches the bottom right corner, to make room for more. Output stream 2 is the transcript file, so the question here is whether you want text in the given window to appear in a transcript: for instance, for a status line the answer is probably “no”, but for normal conversation it would be “yes”. Finally, buffering is a more sophisticated form of wrapping, which breaks lines of text in between words, but which (roughly speaking) means that no line is printed until complete. Note that ordinary printing in the lower window has all four of these attributes.
@window_style window attrs operation
Changes window attributes. attrs is a
bitmap in which bit 0 means “wrapping”, bit 1 means “scrolling”,
etc. operation is 0 to set to these settings, 1 to set only
those attributes which you specify in the bitmap, 2 to clear only those
and 3 to reverse them. For instance,
@window_style 2 $$1011 0
sets window 2 to have wrapping, scrolling and buffering but not to be copied to output stream 2, and
@window_style 1 $$1000 2
clears the buffer printing attribute of window 1.
Windows have 16he text you need to fit at once.
@set_window window
Selects which window text is to be printed into: (0) the lower one or (1) the upper one. Printing on the upper window overlies printing on the lower, is always done in a fixed-pitch font and does not appear in a printed transcript of the game.
@set_cursor line column
Places the cursor inside the upper window, where (1, 1) is the top left character.
@buffer_mode flag
This turns on (flag==true) or off
(flag==false) word-breaking for the current window: that is,
the practice of printing new-lines only at the ends of words, so that
text is neatly formatted.
@erase_window window
Blanks out window 0 (lower), window 1 (upper) or the
whole screen (if window=-1).
Using fixed-pitch measurements, the screen has dimensions
X characters across by Y characters down, where
X and Y are stored in bytes $21 and $20
of the header respectively. It's sometimes useful to know this when formatting
tables:
print "My screen has ", 0->$20, " rows and ", 0->$21, " columns.^";
Be warned: it might be 80 × 210 or then again it might be 7 × 40. Text printing has a given foreground and background colour at all times. The standard stock of colours is:
| 0 | current colour | 5 | yellow |
| 1 | default colour | 6 | blue |
| 2 | black | 7 | magenta |
| 3 | red | 8 | cyan |
| 4 | green | 9 | white |
@set_colour foreground background
If coloured text is available, this opcode sets text
to be foreground against background.
(But bear in mind that not all interpreters can display coloured text,
and not all players enjoy reading it.) Even in a monochrome game, text
can be set to print in “reverse colours”: background on
foreground rather than vice versa. Status lines are almost always printed
in reverse-colour, but this is only a convention and is not required
by the Z-machine. Reverse is one of five possible text styles: roman,
bold, underline (which many interpreters will render with italic),
reverse and fixed-pitch. (Inform's style statement chooses
between these.)
•▲
EXERCISE 123
Design a title page for ‘Ruins’, displaying a more or
less apposite quotation and waiting for a key to be pressed. (For
this last part, see below.)
•▲
EXERCISE 124
Change the status line so that it has the usual score/moves appearance
except when a variable invisible_status is set to
true, when it's invisible.
•▲
EXERCISE 125
Alter the ‘Advent’ example game to display the number of
treasures found instead of the score and turns on the status line.
•▲
EXERCISE 126
(From code by Joachim Baumann.) Put a compass rose on the status line,
displaying the directions in which the room can be left.
•▲▲
EXERCISE 127
(Cf. ‘Trinity’.) Make the status line consist only of
the name of the current location, centred in the top line of the screen.
The version 6 screen model. We are now in the realm of graphics, and the screen is considered to be a grid of pixels: coordinates are usually given in the form (y,x), with (1,1) at the top left. y and x are measured in units known, helpfully enough, as “units”. The interpreter decides how large “1 unit” is, and it's not safe to assume that 1 unit equals 1 pixel. All you can tell is what the screen dimensions are, in units:
print "The screen measures ", $22-->0, " units across and ",
$22-->1, " units down.^";
There are eight windows, numbered 0 to 7, which text and pictures can currently be printing to: what actually appears on the screen is whatever shows through the boundaries of the window at the time the printing or plotting happens. Window number −3 means “the current one”. Windows have no visible borders and usually lie on top of each other. Subsequent movements of the window do not move what was printed and there is no sense in which characters or graphics “belong” to any particular window once printed. Each window has a position (in units), a size (in units), a cursor position within it (in units, relative to its own origin), a number of flags called “attributes” and a number of variables called “properties”. If you move a window so that the cursor is left outside, the interpreter automatically moves the cursor back to the window's new top left. If you only move the cursor, it's your responsibility to make sure it doesn't leave the window.
The attributes are (0) “wrapping”, (1) “scrolling”, (2) “copy text to output stream 2 if active” and (3) “buffer printing”. Wrapping means that when text reaches the right-hand edge it continues from the left of the next line down. Scrolling means scrolling the window upwards when text printing reaches the bottom right corner, to make room for more. Output stream 2 is the transcript file, so the question here is whether you want text in the given window to appear in a transcript: for instance, for a status line the answer is probably “no”, but for normal conversation it would be “yes”. Finally, buffering is a more sophisticated form of wrapping, which breaks lines of text in between words, but which (roughly speaking) means that no line is printed until complete. Note that ordinary printing in the lower window has all four of these attributes.
@window_style window attrs operation
Changes window attributes. attrs is a
bitmap in which bit 0 means “wrapping”, bit 1 means “scrolling”,
etc. operation is 0 to set to these settings, 1 to set only
those attributes which you specify in the bitmap, 2 to clear only those
and 3 to reverse them. For instance,
@window_style 2 $$1011 0
sets window 2 to have wrapping, scrolling and buffering but not to be copied to output stream 2, and
@window_style 1 $$1000 2
clears the buffer printing attribute of window 1.
Windows have 16he text you need to fit at once.
@set_window window
Selects which window text is to be printed into: (0) the lower one or (1) the upper one. Printing on the upper window overlies printing on the lower, is always done in a fixed-pitch font and does not appear in a printed transcript of the game.
@set_cursor line column
Places the cursor inside the upper window, where (1, 1) is the top left character.
@buffer_mode flag
This turns on (flag==true) or off
(flag==false) word-breaking for the current window: that is,
the practice of printing new-lines only at the ends of words, so that
text is neatly formatted.
@erase_window window
Blanks out window 0 (lower), window 1 (upper) or the
whole screen (if window=-1).
Using fixed-pitch measurements, the screen has dimensions
X characters across by Y characters down, where
X and Y are stored in bytes $21 and $20
of the header respectively. It's sometimes useful to know this when formatting
tables:
print "My screen has ", 0->$20, " rows and ", 0->$21, " columns.^";
Be warned: it might be 80 × 210 or then again it might be 7 × 40. Text printing has a given foreground and background colour at all times. The standard stock of colours is:
| 0 | current colour | 5 | yellow |
| 1 | default colour | 6 | blue |
| 2 | black | 7 | magenta |
| 3 | red | 8 | cyan |
| 4 | green | 9 | white |
@set_colour foreground background
If coloured text is available, this opcode sets text
to be foreground against background.
(But bear in mind that not all interpreters can display coloured text,
and not all players enjoy reading it.) Even in a monochrome game, text
can be set to print in “reverse colours”: background on
foreground rather than vice versa. Status lines are almost always printed
in reverse-colour, but this is only a convention and is not required
by the Z-machine. Reverse is one of five possible text styles: roman,
bold, underline (which many interpreters will render with italic),
reverse and fixed-pitch. (Inform's style statement chooses
between these.)
•▲
EXERCISE 123
Design a title page for ‘Ruins’, displaying a more or
less apposite quotation and waiting for a key to be pressed. (For
this last part, see below.)
•▲
EXERCISE 124
Change the status line so that it has the usual score/moves appearance
except when a variable invisible_status is set to
true, when it's invisible.
•▲
EXERCISE 125
Alter the ‘Advent’ example game to display the number of
treasures found instead of the score and turns on the status line.
•▲
EXERCISE 126
(From code by Joachim Baumann.) Put a compass rose on the status line,
displaying the directions in which the room can be left.
•▲▲
EXERCISE 127
(Cf. ‘Trinity’.) Make the status line consist only of
the name of the current location, centred in the top line of the screen.
The version 6 screen model. We are now in the realm of graphics, and the screen is considered to be a grid of pixels: coordinates are usually given in the form (y,x), with (1,1) at the top left. y and x are measured in units known, helpfully enough, as “units”. The interpreter decides how large “1 unit” is, and it's not safe to assume that 1 unit equals 1 pixel. All you can tell is what the screen dimensions are, in units:
print "The screen measures ", $22-->0, " units across and ",
$22-->1, " units down.^";
There are eight windows, numbered 0 to 7, which text and pictures can currently be printing to: what actually appears on the screen is whatever shows through the boundaries of the window at the time the printing or plotting happens. Window number −3 means “the current one”. Windows have no visible borders and usually lie on top of each other. Subsequent movements of the window do not move what was printed and there is no sense in which characters or graphics “belong” to any particular window once printed. Each window has a position (in units), a size (in units), a cursor position within it (in units, relative to its own origin), a number of flags called “attributes” and a number of variables called “properties”. If you move a window so that the cursor is left outside, the interpreter automatically moves the cursor back to the window's new top left. If you only move the cursor, it's your responsibility to make sure it doesn't leave the window.
The attributes are (0) “wrapping”, (1) “scrolling”, (2) “copy text to output stream 2 if active” and (3) “buffer printing”. Wrapping means that when text reaches the right-hand edge it continues from the left of the next line down. Scrolling means scrolling the window upwards when text printing reaches the bottom right corner, to make room for more. Output stream 2 is the transcript file, so the question here is whether you want text in the given window to appear in a transcript: for instance, for a status line the answer is probably “no”, but for normal conversation it would be “yes”. Finally, buffering is a more sophisticated form of wrapping, which breaks lines of text in between words, but which (roughly speaking) means that no line is printed until complete. Note that ordinary printing in the lower window has all four of these attributes.
@window_style window attrs operation
Changes window attributes. attrs is a
bitmap in which bit 0 means “wrapping”, bit 1 means “scrolling”,
etc. operation is 0 to set to these settings, 1 to set only
those attributes which you specify in the bitmap, 2 to clear only those
and 3 to reverse them. For instance,
@window_style 2 $$1011 0
sets window 2 to have wrapping, scrolling and buffering but not to be copied to output stream 2, and
@window_style 1 $$1000 2
clears the buffer printing attribute of window 1.
Windows have 16he text you need to fit at once.
@set_window window
Selects which window text is to be printed into: (0) the lower one or (1) the upper one. Printing on the upper window overlies printing on the lower, is always done in a fixed-pitch font and does not appear in a printed transcript of the game.
@set_cursor line column
Places the cursor inside the upper window, where (1, 1) is the top left character.
@buffer_mode flag
This turns on (flag==true) or off
(flag==false) word-breaking for the current window: that is,
the practice of printing new-lines only at the ends of words, so that
text is neatly formatted.
@erase_window window
Blanks out window 0 (lower), window 1 (upper) or the
whole screen (if window=-1).
Using fixed-pitch measurements, the screen has dimensions
X characters across by Y characters down, where
X and Y are stored in bytes $21 and $20
of the header respectively. It's sometimes useful to know this when formatting
tables:
print "My screen has ", 0->$20, " rows and ", 0->$21, " columns.^";
Be warned: it might be 80 × 210 or then again it might be 7 × 40. Text printing has a given foreground and background colour at all times. The standard stock of colours is:
| 0 | current colour | 5 | yellow |
| 1 | default colour | 6 | blue |
| 2 | black | 7 | magenta |
| 3 | red | 8 | cyan |
| 4 | green | 9 | white |
@set_colour foreground background
If coloured text is available, this opcode sets text
to be foreground against background.
(But bear in mind that not all interpreters can display coloured text,
and not all players enjoy reading it.) Even in a monochrome game, text
can be set to print in “reverse colours”: background on
foreground rather than vice versa. Status lines are almost always printed
in reverse-colour, but this is only a convention and is not required
by the Z-machine. Reverse is one of five possible text styles: roman,
bold, underline (which many interpreters will render with italic),
reverse and fixed-pitch. (Inform's style statement chooses
between these.)
•▲
EXERCISE 123
Design a title page for ‘Ruins’, displaying a more or
less apposite quotation and waiting for a key to be pressed. (For
this last part, see below.)
•▲
EXERCISE 124
Change the status line so that it has the usual score/moves appearance
except when a variable invisible_status is set to
true, when it's invisible.
•▲
EXERCISE 125
Alter the ‘Advent’ example game to display the number of
treasures found instead of the score and turns on the status line.
•▲
EXERCISE 126
(From code by Joachim Baumann.) Put a compass rose on the status line,
displaying the directions in which the room can be left.
•▲▲
EXERCISE 127
(Cf. ‘Trinity’.) Make the status line consist only of
the name of the current location, centred in the top line of the screen.
The version 6 screen model. We are now in the realm of graphics, and the screen is considered to be a grid of pixels: coordinates are usually given in the form (y,x), with (1,1) at the top left. y and x are measured in units known, helpfully enough, as “units”. The interpreter decides how large “1 unit” is, and it's not safe to assume that 1 unit equals 1 pixel. All you can tell is what the screen dimensions are, in units:
print "The screen measures ", $22-->0, " units across and ",
$22-->1, " units down.^";
There are eight windows, numbered 0 to 7, which text and pictures can currently be printing to: what actually appears on the screen is whatever shows through the boundaries of the window at the time the printing or plotting happens. Window number −3 means “the current one”. Windows have no visible borders and usually lie on top of each other. Subsequent movements of the window do not move what was printed and there is no sense in which characters or graphics “belong” to any particular window once printed. Each window has a position (in units), a size (in units), a cursor position within it (in units, relative to its own origin), a number of flags called “attributes” and a number of variables called “properties”. If you move a window so that the cursor is left outside, the interpreter automatically moves the cursor back to the window's new top left. If you only move the cursor, it's your responsibility to make sure it doesn't leave the window.
The attributes are (0) “wrapping”, (1) “scrolling”, (2) “copy text to output stream 2 if active” and (3) “buffer printing”. Wrapping means that when text reaches the right-hand edge it continues from the left of the next line down. Scrolling means scrolling the window upwards when text printing reaches the bottom right corner, to make room for more. Output stream 2 is the transcript file, so the question here is whether you want text in the given window to appear in a transcript: for instance, for a status line the answer is probably “no”, but for normal conversation it would be “yes”. Finally, buffering is a more sophisticated form of wrapping, which breaks lines of text in between words, but which (roughly speaking) means that no line is printed until complete. Note that ordinary printing in the lower window has all four of these attributes.
@window_style window attrs operation
Changes window attributes. attrs is a
bitmap in which bit 0 means “wrapping”, bit 1 means “scrolling”,
etc. operation is 0 to set to these settings, 1 to set only
those attributes which you specify in the bitmap, 2 to clear only those
and 3 to reverse them. For instance,
@window_style 2 $$1011 0
sets window 2 to have wrapping, scrolling and buffering but not to be copied to output stream 2, and
@window_style 1 $$1000 2