1
<HTML><HEAD><TITLE>Section 33: Descending into assembly language</TITLE></HEAD>
2
<BODY BGCOLOR="#FFFFFF">
5
<TR><TD Valign="top"><A HREF="contents.html">Contents</A><BR><A HREF="section32.html">Back</A><BR><A HREF="chapterA.html">Forward</A><TD bgcolor="#F5DEB3"><BLOCKQUOTE><H3>33. Descending into assembly language</H3></BLOCKQUOTE><TR><TD><TD>
8
<P><TR><TD Valign="top"><IMG SRC="icons/dddbend.gif" ALT="/\/\/\"><TD bgcolor="#EEEEEE"><SMALL> Some dirty tricks require bypassing all of Inform's higher levels
9
to program the Z-machine directly with assembly language. There is an
10
element of danger in this, in that some combinations of unusual opcodes
11
might look ugly on some incomplete or wrongly-written interpreters:
12
so if you're doing anything complicated, test it as widely as possible.
16
<P><TR><TD><TD bgcolor="#EEEEEE"><SMALL>
17
The best-researched and most reliable interpreters available by far are Mark
18
Howell's Zip and Stefan Jokisch's Frotz: they are also faster than their
19
only serious rival, the InfoTaskForce, a historically important work which
20
is fairly thorough (and should give little trouble in practice) but which was
21
written when the format was a little less well understood. In some ports,
22
ITF gets rarer screen effects wrong, and it lacks an "undo'' feature, so the
23
Inform "undo'' verb won't work under ITF.
24
(The other two publically-available interpreters are pinfocom and zterp,
25
but these are unable to run Advanced games. In the last resort, sometimes it's
26
possible to use one of Infocom's own supplied interpreters with a different game
27
from that it came with; but only sometimes, as they may have inconvenient
28
filenames 'wired into them'.)
31
Interpreters conforming to the Z-Machine Standard, usually but not always
32
derived from Frotz or Zip, are reliable and widely available.
33
But remember that one source of unportability is inevitable.
34
Your game may be running on a screen which is anything from a
35
64 characters by 9 pocket organiser LCD display, up to a 132 by 48 window
39
Anyone wanting to really push the outer limits (say, by implementing
40
Space Invaders or NetHack) will need to refer to <I> The Z-Machine
41
Standards Document</I>. This is much more detailed (the
42
definition of <TT>aread</TT> alone runs for two pages) and covers the whole range
43
of assembly language. However, this section does document all those features
44
which can't be better obtained with higher-level code.
47
Lines of assembly language must begin with an <TT>@</TT> character and then the
48
name of the "opcode'' (i.e., assembly language statement). A number of
49
arguments, or "operands'' follow (how many depends on the opcode): these
50
may be any Inform constants, local or global variables or the stack pointer <TT>sp</TT>,
51
but may not be compound expressions. <TT>sp</TT> does not behave like a variable:
52
writing a value to it pushes that value onto the stack, whereas reading
53
the value of it (for instance, by giving it as an operand) pulls the top
54
value off the stack. Don't use <TT>sp</TT> unless you have to. After the operands,
55
some opcodes require a variable (or <TT>sp</TT>) to write a result into.
56
The opcodes documented in this section are as follows:
60
@set_cursor line column
63
@set_colour foreground background
64
@aread text parse time function <result>
65
@read_char 1 time function <result>
66
@tokenise text parse dictionary
67
@encode_text ascii-text length from coded-text
68
@output_stream number table
70
@catch <result>
71
@throw value stack-frame
72
@save buffer length filename <result>
73
@restore buffer length filename <result>
82
Splits off an upper-level window of the given number of lines
83
in height from the main screen. This upper window usually holds the
84
status line and can be resized at any time: nothing visible happens
85
until the window is printed to. Warning: make the upper window
86
tall enough to include all the lines you want to write to it, as it
87
should not be allowed to scroll.
92
The text part of the screen (the lower window) is "window 0'',
93
the status line (the upper one) is window 1; this opcode selects
94
which one text is to be printed into. Each window has a "cursor
95
position'' at which text is being printed, though it can only
96
be set for the upper window. Printing on the upper window
97
overlies printing on the lower, is always done in a fixed-pitch font
98
and does not appear in a printed transcript of the game.
99
Note that before printing to the upper window, it is wise
100
to use <TT>@buffer_mode</TT> to turn off word-breaking.
102
@set_cursor line column
105
Places the cursor inside the upper window,
106
where $(1,1)$ is the top left character.
112
This turns on (<TT>flag=1</TT>) or off (<TT>flag=0</TT>) word-breaking for the
113
current window (that is, the practice of printing new-lines only
114
at the ends of words, so that text is neatly formatted). It is
115
wise to turn off word-breaking while printing to the upper window.
120
This opcode is unfortunately incorrectly implemented
121
on some interpreters and so it can't safely be used to erase
122
individual windows. However, it can be used with <TT>window=-1</TT>,
123
and then clears the entire screen. Don't do this in
124
reverse video mode, as a bad interpreter may (incorrectly) wipe the
125
entire screen in reversed colours.
127
@set_colour foreground background
130
If coloured text is available, set text to be
131
foreground-against-background. The colour numbers are borrowed
134
2 = black, 3 = red, 4 = green, 5 = yellow,
135
6 = blue, 7 = magenta, 8 = cyan, 9 = white
136
0 = the current setting, 1 = the default.
139
On many machines coloured text is not available: the opcode will
142
@aread text parse time function <result>
145
The keyboard can be read in remarkably flexible ways. This opcode
146
reads a line of text from the keyboard, writing it into the <TT>text</TT>
147
string array and 'tokenising' it into a word stream, with
148
details stored in the <TT>parse</TT> string array (unless this is zero,
149
in which case no tokenisation happens). (See the end of <A HREF="section27.html">Section 27</A> for
150
the format of <TT>text</TT> and <TT>parse</TT>.)
151
While it is doing this, it calls <TT>function(time)</TT>
152
every <TT>time</TT> tenths of a second while the user is thinking:
153
the process ends if ever this function returns true.
154
<TT><result></TT> is to be a variable, but the value
155
written in it is only meaningful if you're using a "terminating
156
characters table''. Thus (by <TT>Replace</TT>ing the <TT>Keyboard</TT>
157
routine in the library files) you could, say, move around all the characters every
158
ten seconds of real time.
159
Warning: not every interpreter supports this real-time feature, and
160
most of those that do count in seconds instead of tenths of seconds.
165
@read_char 1 time function <result>
168
results in the ASCII value of a single keypress. Once again, the <TT>function</TT> is
169
called every <TT>time</TT> tenths of a second and may stop this process early.
171
special values from 129 onwards, in the order: cursor up, down, left, right,
172
function key f1, ..., f12, keypad digit 0, ..., 9.
173
The first operand must be 1 (used by Infocom as a device number to identify
176
@tokenise text parse dictionary
179
This takes the text in the <TT>text</TT> buffer (in the format produced by <TT>aread</TT>)
180
and tokenises it (i.e. breaks it up into words, finds their addresses in the
181
dictionary) into the <TT>parse</TT> buffer in the usual way but using the given
182
<TT>dictionary</TT> instead of the game's usual one. (See the <I> Z-Machine Standards
183
Document</I> for the dictionary format.)
185
@encode_text ascii-text length from coded-text
188
Translates an ASCII word to the internal (Z-encoded) text format
189
suitable for use in a <TT>@tokenise</TT> dictionary. The text begins at
190
<TT>from</TT> in the <TT>ascii-text</TT> and is <TT>length</TT> characters long, which
191
should contain the right length value (though in fact the interpreter
192
translates the word as far as a 0 terminator). The result is 6 bytes
193
long and usually represents between 1 and 9 letters.
195
@output_stream number table
198
Text can be output to a variety of different 'streams',
199
possibly simultaneously. If <TT>number</TT> is 0 this does nothing.
200
$+n$ switches stream <I>n</I> on, $-n$ switches it off.
201
The output streams are: 1 (the screen),
202
2 (the game transcript), 3 (memory) and 4 (script of
203
player's commands). The <TT>table</TT> can be omitted except for stream
204
3, when it's a <TT>table</TT> array holding the text printed; printing
205
to this stream is never word-broken, whatever the state of
206
<TT>@buffer_mode</TT>.
211
Switches the 'input stream' (the source of the player's commands).
212
0 is the keyboard, and 1 a command file (the idea is that a list of
213
commands produced by <TT>output_stream 4</TT> can be fed back in again).
215
@catch <result>
218
The opposite of <TT>throw</TT>, <TT>catch</TT> preserves the "stack frame'' of the
219
current routine: meaning, roughly, the current position of which routine
220
is being run and which ones have called it so far.
222
@throw value stack-frame
225
This causes the program to execute a return with <TT>value</TT>,
226
but as if it were returning from the routine which was running
227
when the <TT>stack-frame</TT> was caught (see <TT>catch</TT>). Any routines
228
which were called in the mean time and haven't returned yet
229
(because each one called the next) are forgotten about.
230
This is useful to get the program out of large recursive tangles
233
@save buffer length filename <result>
236
Saves the byte array <TT>buffer</TT> (of size <TT>length</TT>) to a file,
237
whose (default) name is given in the <TT>filename</TT> (a <TT>string</TT>
238
array). Afterwards, <TT>result</TT> holds 1 on success, 0 on failure.
243
@restore buffer length filename <result>
246
Loads in the byte array <TT>buffer</TT> (of size <TT>length</TT>) from a file,
247
whose (default) name is given in the <TT>filename</TT> (a <TT>string</TT>
248
array). Afterwards, <TT>result</TT> holds the number of bytes successfully
252
<P><TR><TD Valign="top"><IMG SRC="icons/warning.gif" ALT="!!"><TD><B>WARNING:</B><BR>
253
Some of these features may not work well on obsolete interpreters
254
which do not adhere to the Z-Machine Standard. Standard
255
interpreters are widely available, but if seriously worried
256
you can test whether your game is running on a good interpreter:
258
if (standard_interpreter == 0)
259
{ print "This game must be played on an interpreter obeying the
260
Z-Machine Standard.^";
267
<P><TR><TD Valign="top"><IMG SRC="icons/exercise.gif" ALT="??"><TD bgcolor="#FBB9AC"><A NAME="ex90"><B>EXERCISE 90:</B><BR>(link to <A HREF="answers2/answer90.html">the answer</A>)<TR><TD><TD> In a role-playing game campaign, you might want several
268
scenarios, each implemented as a separate Inform game. How could
269
the character from one be saved and loaded into another?
274
<P><TR><TD Valign="top"><IMG SRC="icons/dexercise.gif" ALT="??/\"><TD bgcolor="#FBB9AC"><A NAME="ex91"><B>EXERCISE 91:</B><BR>(link to <A HREF="answers2/answer91.html">the answer</A>)<TR><TD><TD> Design a title page for 'Ruins', displaying
275
a more or less apposite quotation and waiting for a key to be
279
<P><TR><TD Valign="top"><IMG SRC="icons/dexercise.gif" ALT="??/\"><TD bgcolor="#FBB9AC"><A NAME="ex92"><B>EXERCISE 92:</B><BR>(link to <A HREF="answers2/answer92.html">the answer</A>)<TR><TD><TD> Change the status line so that it has the usual
280
score/moves appearance except when a variable <TT>invisible_status</TT>
281
is set, when it's invisible.
285
<P><TR><TD Valign="top"><IMG SRC="icons/dexercise.gif" ALT="??/\"><TD bgcolor="#FBB9AC"><A NAME="ex93"><B>EXERCISE 93:</B><BR>(link to <A HREF="answers2/answer93.html">the answer</A>)<TR><TD><TD> Alter the 'Advent' example game to display the number
286
of treasures found instead of the score and turns on the status
290
<P><TR><TD Valign="top"><IMG SRC="icons/dexercise.gif" ALT="??/\"><TD bgcolor="#FBB9AC"><A NAME="ex94"><B>EXERCISE 94:</B><BR>(link to <A HREF="answers2/answer94.html">the answer</A>)<TR><TD><TD> (From code by Joachim Baumann.) Put a compass rose
291
on the status line, displaying the directions in which the room can be
295
<P><TR><TD Valign="top"><IMG SRC="icons/ddexercise.gif" ALT="??/\/\"><TD bgcolor="#FBB9AC"><A NAME="ex95"><B>EXERCISE 95:</B><BR>(link to <A HREF="answers2/answer95.html">the answer</A>)<TR><TD><TD> (Cf.
297
Make the status line consist only of the name of the current
298
location, centred in the top line of the
302
<P><TR><TD Valign="top"><IMG SRC="icons/ddexercise.gif" ALT="??/\/\"><TD bgcolor="#FBB9AC"><A NAME="ex96"><B>EXERCISE 96:</B><BR>(link to <A HREF="answers2/answer96.html">the answer</A>)<TR><TD><TD> Implement an Inform version of the standard 'C'
303
routine <TT>printf</TT>, taking the form
305
printf(format, arg1, ...)
308
to print out the format string but with escape sequences like
309
<TT>%d</TT> replaced by the arguments (printed in various ways). For
312
printf("The score is %e out of %e.", score, MAX_SCORE);
315
should print something like "The score is five out of ten.''
318
<P><TR><TD Valign="top"><IMG SRC="icons/refs.gif" ALT="*"><TD bgcolor="#EEEEEE"><B>REFERENCES:</B><BR><SMALL> The assembly-language connoisseur will appreciate 'Freefall'
319
by Andrew Plotkin and 'Robots' by
321
although the present lack of on-line hints make these difficult games
324
<HR><A HREF="contents.html">Contents</A> / <A HREF="section32.html">Back</A> / <A HREF="chapterA.html">Forward</A> <BR>
325
<A HREF="chapter1.html">Chapter I</A> / <A HREF="chapter2.html">Chapter II</A> / <A HREF="chapter3.html">Chapter III</A> / <A HREF="chapter4.html">Chapter IV</A> / <A HREF="chapter5.html">Chapter V</A> / <A HREF="chapter6.html">Chapter VI</A> / <A HREF="chapterA.html">Appendix</A><HR><SMALL><I>Mechanically translated to HTML from third edition as revised 16 May 1997. Copyright © Graham Nelson 1993, 1994, 1995, 1996, 1997: all rights reserved.</I></SMALL></BODY></HTML>