-
Notifications
You must be signed in to change notification settings - Fork 4
/
sect06.html
312 lines (263 loc) · 12.4 KB
/
sect06.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
<!DOCTYPE html>
<html>
<head><title>The Z-Machine Standards Document</title>
<link rel="stylesheet" type="text/css" href="zspec.css">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
</head>
<body>
<img class="icon" src="images/icon06.gif" alt="">
<h1>6. The game state: storage and routine calls</h1>
<hr>
<p>6.1 <a href="6.1">Saved states</a> /
6.2 <a href="6.2">Storage of global variables</a> /
6.3 <a href="6.3">The stack</a> /
6.4 <a href="6.4">Routine calls</a> /
6.5 <a href="6.5">Stack frames</a> /
6.6 <a href="6.6">User stacks (V6)</a>
</p>
<hr>
<h2 id="6.1">6.1</h2>
<p>The "state of play" is defined as the following: the contents
of dynamic memory; the contents of the stack; the value of the program
counter (PC), and the "routine call state" (that is, the chain of routines
which have called each other in sequence, and the values of their local
variables). Note that the routine call state, the stack and the PC
must be stored outside the Z-machine memory map, in the interpreter's
private memory.
</p>
<h2 id="6.1.1">6.1.1</h2>
<p> The entire state of play must be stored when the game is saved.</p>
<h2 id="6.1.1.1">6.1.1.1</h2>
<p> The format of a saved game file is not specified.</p>
<h2 id="6.1.1.2">6.1.1.2</h2>
<p>An internal saved game for "undo" purposes (if there is one) is
not part of the state of play. This is important: if a saved game file also
contained the internal saved game at the time of saving, it would be
impossible to undo the act of restoration. It also prevents internal
saved games from growing larger and larger as they include their
predecessors.
</p>
<h2 id="6.1.1.3">6.1.1.3</h2>
<p>It is illegal to save the game (either with <a href="sect15.html#save">
<strong>save</strong></a> or <a href="sect15.html#save_undo">
<strong>save_undo</strong></a>) during an "interrupt routine"
(one coming about through timed input, sound effect termination or
newline interrupts). Therefore saved games need not store information
capable of restoring such a position.
</p>
<h2 id="6.1.2">6.1.2</h2>
<p>On a "restore" or "undo" (which restores a game saved into
internal memory), the entire state of play is written back except that
'Flags 2' in the header is preserved. (This information includes whether
the game is being transcribed to printer and whether a fixed-pitch
font is being used.)
</p>
<h2 id="6.1.2.1">6.1.2.1</h2>
<p>Before a "restore", an interpreter should check that the
file to be used has been saved from the same game currently being played.
(See remark below.)
</p>
<h2 id="6.1.2.2">6.1.2.2</h2>
<p>After a "restore" or "undo", an interpreter should reset
the header values marked <strong>Rst</strong> in the header table of
<a href="sect11.html"><strong>§</strong> 11</a>. (It should
not be assumed that the game was saved by the same interpreter.)
</p>
<h2 id="6.1.3">6.1.3</h2>
<p>A "restart" is similar: the entire state is restored from the
original story file, and the stack is emptied; but 'Flags 2' is
preserved; and the interpreter should reset the <strong>Rst</strong> parts of the header.
</p>
<h2 id="6.1.4">6.1.4</h2>
<p>In Versions 5 and later, an interpreter unable to save the game
state into internal memory (for "undo" purposes) must clear bit 4 of
'Flags 2' in the header.
</p>
<h2 id="6.2">6.2</h2>
<p>Global variables (variable numbers <strong>$10</strong> to <strong>$ff</strong>) are stored
in a table in the Z-machine's dynamic memory, at a byte address given in
word 6 of the header. The table consists of 240 2-byte words and the
initial values of the global variables are the values initially contained in
the table. (It is legal for a program to alter the table's contents
directly in play, though not for it to change the table's address.)
</p>
<h2 id="6.3">6.3</h2>
<p>Writing to the stack pointer (variable number <strong>$00</strong>) pushes a
value onto the stack; reading from it pulls a value off. Stack entries
are 2-byte words as usual.
</p>
<h2 id="6.3.1">6.3.1</h2>
<p>The stack is considered as empty at the start of each routine:
it is illegal to pull values from it unless values have first been pushed
on.
</p>
<h2 id="6.3.2">6.3.2</h2>
<p>The stack is left empty at the end of each routine: when a
return occurs, any values pushed during the routine are thrown away.
</p>
<h2 id="6.3.3">6.3.3</h2>
<p>The absolute minimum standard for stack size is defined as:</p>
<p>let the 'usage' of a routine call be 4 plus the number of local
variables it has. During a game the total of the usages for each
routine in the recursive chain of routines being called, plus the
game's own stack usage, can be assumed to never reach 1024.
</p>
<p>However, more recent games have required a much larger stack
size than this allows for. It is advised that allow for these games
by having a larger stack size if at all possible.
</p>
<p>Two examples of modern interpreters with increased stack size are
<strong>Windows Frotz</strong>, with 32768,
and <strong>nfrotz</strong> with 61440.
</p>
<h2 id="6.3.4">6.3.4</h2>
<p>In the seven opcodes that take indirect variable references
<a href="sect15.html#inc">(<strong>inc</strong></a>,
<a href="sect15.html#dec"><strong>dec</strong></a>,
<a href="sect15.html#inc_chk"><strong>inc_chk</strong></a>,
<a href="sect15.html#dec_chk"><strong>dec_chk</strong></a>,
<a href="sect15.html#load"><strong>load</strong></a>,
<a href="sect15.html#store"><strong>store</strong></a>,
<a href="sect15.html#pull"><strong>pull</strong>)</a>,
an indirect reference to the stack pointer does not push or pull the top
item of the stack - it is read or written in place.
</p>
<h2 id="6.4">6.4</h2>
<p>Routine calls occur in the following circumstances: when one
of the <strong>call...</strong> opcodes is executed; in Versions 4 and later, when
timed keyboard input is being monitored; in Versions 5 and later,
when a sound effect finishes; in Version 6, when the game begins
(to call the "main" routine); in Version 6, when a "newline
interrupt" occurs.
</p>
<h2 id="6.4.1">6.4.1</h2>
<p>A routine call may have any number of arguments, from 0 to
3 (in Versions 1 to 3) or 0 to 7 (Versions 4 and later). All
routines return a value (though sometimes this value is thrown away
afterward: for example by opcodes in the form <strong>call_vn*</strong>).
</p>
<h2 id="6.4.2">6.4.2</h2>
<p>Routine calls preserve local variables and the stack
(except when the return value is stored in a local variable or onto
the top of the stack).
</p>
<h2 id="6.4.3">6.4.3</h2>
<p>A routine call to packed address 0 is legal: it does nothing
and returns false (0). Otherwise it is illegal to call a packed
address where no routine is present.
</p>
<h2 id="6.4.4">6.4.4</h2>
<p>When a routine is called, its local variables are created
with initial values taken from the routine header (Versions 1 to
4) or with initial value 0 (Versions 5 and later). Next, the
arguments are written into the local variables (argument 1 into
local 1 and so on).
</p>
<h2 id="6.4.4.1">6.4.4.1</h2>
<p>It is legal for there to be more arguments than local
variables (any spare arguments are thrown away) or for there to
be fewer.
</p>
<h2 id="6.4.5">6.4.5</h2>
<p>The return value of a routine can be any Z-machine number.
Returning 'false' means returning 0; returning 'true' means
returning 1.
</p>
<h2 id="6.5">6.5</h2>
<p>A "stack frame" is an index to the routine call state
(that is, the call-stack of return addresses from routines currently
running, and values of local variables within them). This index
is a Z-machine number. The interpreter must be able to produce the
current value and to set a value further down the call-stack than
the current one, effectively throwing away its recent history
(see <a href="sect15.html#catch"><strong>catch</strong></a> and
<a href="sect15.html#throw"><strong>throw</strong></a>).
</p>
<h2 id="6.6">6.6</h2>
<p>In Version 6, the Z-machine understands a third kind of stack: a
"user stack", which is a table of words in dynamic memory. The first word
in this table always holds the number of spare slots on the stack (so the
initial value is the capacity of the stack). The Z-machine makes no
check on stack under-flow (i.e., pulling more values than were pushed)
which would over-run the length of the table if the program allowed it
to happen.
</p>
<hr>
<h2 id="remarks">Remarks</h2>
<p>Some interpreters store the whole of dynamic memory to disc as part of their
saved game files, which can make them as much as 45K or so long. A player
making a serious attack on a game may end up wasting a whole megabyte, more
than convenient without a hard disc. A technique invented by Bryan
Scattergood, taken up by most modern interpreters, greatly reduces file size
by only saving bytes of dynamic memory which differ from the initial
state of the game.
</p>
<p>It is unspecified how an interpreter should decide whether a saved game file
belongs to the game currently being played. It is normal to insist that the
release numbers, serial codes and checksums all match. The <strong>Pinfocom</strong>
interpreter deliberately checks only the release number, so that saved games
can be exchanged between different editions of 'Seastalker' (presumably
compiled to handle the sonarscope differently).
</p>
<p>These issues are taken up in great detail in Martin Frost's
<a href="quetzal/index.html"><strong>Quetzal</strong></a>
standard for saved game files, created to allow different interpreters
to exchange saved games. This Standard doesn't require compliance with
<strong>Quetzal</strong>, but interpreter writers are urged to consider it: it can only
help authors if players can send them saved games where bugs seem to
have appeared.
</p>
<p>Given the existence of <strong>Quetzal</strong>, it is quite
possible that after loading, the game may be running on a different
interpreter to that on which the game started. As a result, it is strongly
advisable for games to recheck any interpreter capabilities (eg Standard version,
unicode support, etc) after loading.
</p>
<p>The stack is stored in the interpreter's own memory, not anywhere in the
Z-machine. The game program has no direct access to the stack memory or
stack pointer; on some implementations the game's main stack is also used to
store the routine call state (i.e. the game stack and the call-stack are the
same) but this need not be true.
</p>
<p>The stack size specification guarantees in particular that if the game
itself never uses more than 32 stack entries at once then it can have
a recursive depth of at least 90 routine calls. The author believes
that old Infocom games will all run with a stack size of 512 words.
</p>
<p>Note that the "state of play" does not include numerous input/output
settings (the current window, cursor position, splitness or otherwise,
which streams are selected, etc.): neither does it include the state
of the random-number generator. (Games with elaborate status lines
must redraw them after a restore has taken place.)
</p>
<p><strong>Zip</strong> provides "undo" but most versions of the <strong>ITF</strong>
interpreter do not (and <strong>save_undo</strong> returns 0, unfortunately).
This is probably its greatest
failing. Some Infocom-written interpreters will only provide "undo" to a
game which has bit 4 of 'Flags 2' set: but Inform 5.5 doesn't set this bit,
so modern interpreters should be more generous.
</p>
<hr>
<p>
<a href="index.html">Contents</a> /
<a href="preface.html">Preface</a> /
<a href="overview.html">Overview</a>
</p>
<p>Section
<a href="sect01.html">1</a> / <a href="sect02.html">2</a> /
<a href="sect03.html">3</a> / <a href="sect04.html">4</a> /
<a href="sect05.html">5</a> / <a href="sect06.html">6</a> /
<a href="sect07.html">7</a> / <a href="sect08.html">8</a> /
<a href="sect09.html">9</a> / <a href="sect10.html">10</a> /
<a href="sect11.html">11</a> / <a href="sect12.html">12</a> /
<a href="sect13.html">13</a> / <a href="sect14.html">14</a> /
<a href="sect15.html">15</a> / <a href="sect16.html">16</a>
</p>
<p>Appendix
<a href="appa.html">A</a> / <a href="appb.html">B</a> /
<a href="appc.html">C</a> / <a href="appd.html">D</a> /
<a href="appe.html">E</a> / <a href="appf.html">F</a>
</p>
<hr>
</body>
</html>