-
Notifications
You must be signed in to change notification settings - Fork 0
/
s21.html
496 lines (431 loc) · 22.6 KB
/
s21.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
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>DM4 §21: Starting, moving, changing and killing the player</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="dm4.css">
</head>
<body>
<p class="navbar">
<a href="index.html">home</a> /
<a href="contents.html">contents</a> /
<a href="ch3.html" title="Chapter III: The Model World">chapter III</a> /
<a href="s20.html" title="§20: Daemons and the passing of time">prev</a> /
<a href="s22.html" title="§22: Miscellaneous constants, scoring, quotations">next</a> /
<a href="dm4index.html">index</a>
</p>
<div class="page">
<a id="p162" name="p162"></a>
<h2>§21 Starting, moving, changing and killing the player</h2>
<blockquote>Life's but a walking shadow, a poor player<br>
That struts and frets his hour upon the stage<br>
And then is heard no more; it is a tale<br>
Told by an idiot, full of sound and fury,<br>
Signifying nothing.<br>
— William Shakespeare (1564–1616), <i>Macbeth</i> V v</blockquote>
<p class="normal"><span class="atleft"><img src="dm4-162_1.jpg" alt=""></span>
To recap on <a href="s4.html">§4</a>, an “entry point
routine” is one provided by your own source code which the
library may call from time to time. There are about twenty of these,
listed in <a href="sa5.html">§A5</a>, and all of them are
optional but one: <code>Initialise</code>. This routine is called
before any text of the game is printed, and it can do many things:
start timers and daemons, set the time of day, equip the player with
possessions, make any random settings needed and so on. It <em>usually</em>
prints out some welcoming text, though not the name and author of
the game, because that appears soon after when the “game
banner” is printed. The only thing it must do is to set the
<code>location</code> variable to where the player begins.</p>
<p class="indent">This is usually a room, possibly in darkness, but
might instead be an <code>enterable</code> object inside a room,
such as a chair or a bed. Like medieval romance epics, interactive
fiction games often start by waking the player from sleep, sometimes by
way of a dream sequence. If your game begins with verbose instructions
before the first opportunity for a player to type a command, you may
want to offer the chance to restore a saved game at once:</p>
<p class="lynxonly"></p>
<pre class="code">
print "Would you like to restore a game? >";
if (YesOrNo()) <Restore>;
</pre>
<p class="normal">To equip the player with possessions, simply move
the relevant objects to <code>player</code>.</p>
<p class="indent">The return value from <code>Initialise</code> is
ordinarily ignored, whether <code>true</code> or <code>false</code>,
and the library goes on to print the game banner. If, however, you
return 2, the game banner is suppressed for now. This feature is
provided for games like ‘Sorcerer’ and ‘Seastalker’
which play out a short prelude first. If you do suppress the banner
from <code>Initialise</code>, you should print it no more than a
few turns later on by calling the library routine <code>Banner</code>.
The banner is familiar to players, reassuringly traditional and
useful when testing, because it identifies which version of a game
is giving trouble. Like an imprint page with an ISBN, it is invaluable
to bibliographers and collectors of story files.</p>
<a id="p163" name="p163"></a>
<hr class="section-break" />
<p class="normal">‘Ruins’ opens in classical fashion:</p>
<p class="lynxonly"></p>
<pre class="code">
[ Initialise;
TitlePage();
location = Forest;
move map to player;
move sodium_lamp to player;
move dictionary to player;
thedark.description = "The darkness of ages presses in on you, and
you feel claustrophobic.";
"^^^Days of searching, days of thirsty hacking through the briars of
the forest, but at last your patience was rewarded. A discovery!^";
];
</pre>
<p class="normal">For the source code of the ‘Ruins’
<code>TitlePage</code> routine, see the exercises in
<a href="s42.html">§42</a>.</p>
<hr class="section-break" />
<p class="normal">The question “where is the player?”
can be answered in three different ways. Looking at <code>parent(player)</code>
tells you the object immediately containing the player, which can
be a location but might instead be a chair or vehicle. So a condition
such as:</p>
<p class="lynxonly"></p>
<pre class="code">if (player in Bridleway) ...</pre>
<p class="normal">would be <code>false</code> if the player were riding
a horse through the Bridleway. The safer alternative is:</p>
<p class="lynxonly"></p>
<pre class="code">if (location == Bridleway) ...</pre>
<p class="normal">but even this would be <code>false</code> if the
Bridleway were in darkness, because then <code>location</code> would
be the special object <code>thedark</code> (see <a href="s19.html">§19</a>).
The definitive location value is stored in <code>real_location</code>,
so that:</p>
<p class="lynxonly"></p>
<pre class="code">if (real_location == Bridleway) ...</pre>
<p class="normal">works in all cases. The condition for “is
the player in a dark Bridleway?” is:</p>
<p class="lynxonly"></p>
<pre class="code">if (location == thedark && real_location == Bridleway) ...</pre>
<p class="normal">Except for the one time in <code>Initialise</code>,
you should not attempt to change either of these variables, nor to move
the player-object by hand. One safe way to move the player in your
own source code is to cause actions like</p>
<p class="lynxonly"></p>
<pre class="code"><Go n_obj>;</pre>
<a id="p164" name="p164"></a>
<p class="normal">but for moments of teleportation it's easier to
use the library routine <code>PlayerTo</code>. Calling <code>PlayerTo(somewhere)</code>
makes the parent-object of the player <code>somewhere</code> and
adjusts the <code>location</code> variables accordingly: it also runs
through a fair number of standard game rules, for instance checking
the light level and performing a <code>Look</code> action to print
out the new room description. The value <code>somewhere</code> can
be a room, or an <code>enterable</code> object such as a cage or
a traction-engine, provided that the cardinal rule is always observed:</p>
<p class="aside" style="margin-left:30px">The parent of the player
object must at all times be “location-like”. An object
is “location-like” if either it is a location, or it has
<code>enterable</code> and its parent is location-like.</p>
<p class="normal">In other words, you can't put the player in an
<code>enterable</code> cardboard box if that box is itself shut up in
a free-standing safe which isn't <code>enterable</code>. And you
can't <code>PlayerTo(nothing)</code> or <code>PlayerTo(thedark)</code>
because <code>nothing</code> is not an object and <code>thedark</code>
is not location-like.</p>
<p class="aside"><span class="warning">▲</span>
Calling <code>PlayerTo(somewhere,1)</code> moves the player without
printing any room description. All other standard game rules are applied.</p>
<p class="aside"><span class="warning">▲</span>
Calling <code>PlayerTo(somewhere,2)</code> is just like <code>PlayerTo(somewhere)</code>
except that the room description is in the form the player would expect
from typing “go east” rather than from typing “look”.
The only difference is that in the former case the room is (normally)
given an abbreviated description if it has been visited before, whereas
in the latter case the description is always given in full.</p>
<hr class="section-break" />
<p class="aside"><span class="warning">▲▲</span>
It's perhaps worth taking a moment to say what the standard rules upon
changing location are. The following rules are applied whenever a <code>Look</code>
action or a call to <code>PlayerTo</code> take place.</p>
<ol type="1" start="0">
<li><!-- (0) -->If <code>PlayerTo</code> has been called then the <code>parent</code>
of the player, <code>location</code> and <code>real_location</code>
are set.</li>
<li><!-- (1) -->Any object providing <code>found_in</code> is checked. If it
claims to be <code>found_in</code> the location, it is moved to that
location. If not, or if it has <code>absent</code>, it is removed
from the object tree. (See <a href="s8.html">§8</a>.)</li>
<li><!-- (2) -->The availability of light is checked (see <a href="s19.html">§19</a>),
and <code>location</code> is set to <code>thedark</code> if necessary.</li>
<li><!-- (3) -->The “visibility ceiling” of the player is determined.
For instance, the <i>VC</i> for a player in a closed wooden box is
the box, but for a player in a closed glass box it's the location.
To be more exact:
<ol type="a">
<li><!-- (a) -->The <i>VC</i> of a room is the value of <code>location</code>,
i.e., either <code>thedark</code> or the room object.</li>
<li><!-- (b) -->If the parent of an object is a room or is “see-through” (see
<a href="s19.html">§19</a> for this definition), the <i>VC</i>
of the object is the <i>VC</i> of the parent.</li>
<li><a id="p165" name="p165"></a><!-- (c) -->If not, the <i>VC</i> of the object is its parent.</li>
</ol></li>
<li><!-- (4) -->If the <i>VC</i> is <code>thedark</code> or (say) a box, skip
this rule. Otherwise: if the <i>VC</i> has changed since the
<em>previous</em> time that rule (3) produced a <i>VC</i> which wasn't
an <code>enterable</code> object, then:
<ol type="a">
<li><!-- (a) -->The message <code>location.initial()</code> is sent, if
the location provides an <code>initial</code> rule. If the library finds that the
player has been moved in the course of running <code>initial</code>, it
goes back to rule (3).</li>
<li><!-- (b) -->The game's entry point routine <code>NewRoom</code> is
called, if it provides one.</li>
</ol></li>
<li><!-- (5) -->The room description is printed out, unless these rules are
being gone through by <code>PlayerTo(somewhere,1)</code>. For exactly
what happens in printing a room description, see <a href="s26.html">§26</a>.</li>
<li><!-- (6) -->If the <code>location</code> doesn't have <code>visited</code>,
give it this attribute and award the player <code>ROOM_SCORE</code>
points if the <code>location</code> has <code>scored</code>.
(See <a href="s22.html">§22</a>.) Note that this rule looks
at <code>location</code>, not <code>real_location</code>, so no points
unless the room is visible.</li>
</ol>
<hr class="section-break" />
<p class="normal">In the course of this chapter, rules to interfere
with actions have been attached to items, rooms and people, but not
yet to the player. In <a href="s18.html">§18</a> it was set out
that an order like “austin, eat tuna” would result in the
action <code>Eat tuna</code> being passed to <code>austin.orders</code>,
and heavy hints were dropped that orders and actions are more or
less the same thing. This is indeed so, and the player's own object
has an <code>orders</code> routine. This normally does nothing and
always returns <code>false</code> to mean “carry on as usual”,
but you can install a rule of your own instead:</p>
<p class="lynxonly"></p>
<pre class="code">player.orders = MyNewRule;</pre>
<p class="normal">where <code>MyNewRule</code> is a new <code>orders</code>
rule. This rule is applied to every action or order issued by the player.
The variable actor holds the person asked to do something, usually
but not always <code>player</code>, and the variables <code>action</code>,
<code>noun</code> and <code>second</code> are set up as usual. For
instance:</p>
<p class="lynxonly"></p>
<table border="1">
<tr><td><i>Example command</i></td>
<td><code>actor</code></td>
<td><code>action</code></td>
<td><code>noun</code></td>
<td><code>second</code></td></tr>
<tr><td>“put tuna in dish”</td>
<td><code>player</code></td>
<td><code>Insert</code></td>
<td><code>tuna</code></td>
<td><code>dish</code></td></tr>
<tr><td>“austin, eat tuna”</td>
<td><code>Austin</code></td>
<td><code>Eat</code></td>
<td><code>tuna</code></td>
<td><code>nothing</code></td></tr>
</table>
<p class="normal">For instance, if a cannon goes off right next to the
player, a period of partial deafness might ensue:</p>
<p class="lynxonly"></p>
<pre class="code">
[ MyNewRule;
if (actor ~= player) rfalse;
Listen: "Your hearing is still weak from all that cannon-fire.";
default: rfalse;
];
</pre>
<a id="p166" name="p166"></a>
<p class="normal">The <code>if</code> statement needs to be there
to prevent commands like “helena, listen” from being
ruled out – after all, the player can still speak.</p>
<a id="ex51" name="ex51"></a>
<p class="aside"><span class="warning"><b>•</b>▲
<b><a href="sa6.html#ans51">EXERCISE 51</a></b></span><br>
Why not achieve the same effect by giving the player a <code>react_before</code>
rule instead?</p>
<a id="ex52" name="ex52"></a>
<p class="aside"><span class="warning"><b>•</b>
<b><a href="sa6.html#ans52">EXERCISE 52</a></b></span><br>
(Cf. ‘Curses’.) Write an <code>orders</code> routine for
the player so that wearing a gas mask will prevent speech.</p>
<hr class="section-break" />
<p class="normal">The <code>player</code> object can not only be
altered but switched altogether, allowing the player to play from
the perspective of someone or something else at any point in the
game. The player who tampers with Dr Frankenstein's brain transference
machine may suddenly become the Monster strapped to the table. A
player who drinks too much wine could become a drunk player object
to whom many different rules apply. The “snavig” spell
of ‘Spellbreaker’, which transforms the player to an
animal like the one cast upon, could be implemented thus. Similarly
the protagonist of ‘Suspended’, who telepathically runs
a weather-control station by acting through six sensory robots,
Iris, Waldo, Sensa, Auda, Poet and Whiz. In a less original setting,
a player might have a team of four adventurers exploring a labyrinth,
and be able to switch the one being controlled by typing the name.
In this case, an <code>AfterLife</code> routine (see below) may be
needed to switch the focus back to a still-living member of the team
after one has met a sticky end.</p>
<p class="indent">The library routine <code>ChangePlayer(obj)</code> transforms
the player to <code>obj</code>. Any object can be used for this. There's
no need to give it any name, as the parser always understands pronouns
like “me” and “myself” to refer to the current
player-object. You may want to set its description, as this is the text
printed if the player types “examine myself”, or its
<code>capacity</code>, the maximum number of items which this form
of the player can carry. Finally, this player-object can have its
own <code>orders</code> property and thus its own rules about what
it can and can't do.</p>
<p class="indent">As <code>ChangePlayer</code> prints nothing, you
may want to follow the call with a <code><<Look>>;</code> action.</p>
<p class="aside"><span class="warning">▲</span>
You can call <code>ChangePlayer</code> as part of a game's <code>Initialise</code>
routine, but if so then you should do this before setting <code>location</code>.</p>
<p class="aside"><span class="warning">▲</span>
Calling <code>ChangePlayer(obj,1);</code> does the same except that
it makes the game print “(as Whoever)” during subsequent
room descriptions.</p>
<a id="p167" name="p167"></a>
<p class="aside"><span class="warning">▲</span>
The body dispossessed remains where it was, in play, unless you move
it away or otherwise dispose of it. The player-object which the player
begins with is a library-defined object called <code>selfobj</code>, and is
described in room descriptions as “your former self”.</p>
<a id="ex53" name="ex53"></a>
<p class="aside"><span class="warning"><b>•</b>
<b><a href="sa6.html#ans53">EXERCISE 53</a></b></span><br>
In Central American legend, a sorceror can transform himself into a
<i>nagual</i>, a familiar such as a spider-monkey; indeed, each individual
has an animal self or <i>wayhel</i>, living in a volcanic land over
which the king, as a jaguar, rules. Turn the player into <i>wayhel</i>
form.</p>
<a id="ex54" name="ex54"></a>
<p class="aside"><span class="warning"><b>•</b>
<b><a href="sa6.html#ans54">EXERCISE 54</a></b></span><br>
Alter the Wormcast of ‘Ruins’ (previously defined in
<a href="s9.html">§9</a>) so that when in <i>wayhel</i> form,
the player can pass through into a hidden burial shaft.</p>
<a id="ex55" name="ex55"></a>
<p class="aside"><span class="warning"><b>•</b>
<b><a href="sa6.html#ans55">EXERCISE 55</a></b></span><br>
To complete the design of this sequence from ‘Ruins’,
place a visible iron cage above the hidden burial shaft. The cage
contains skeletons and a warning written in glyphs, but the player
who enters it despite these (and they all will) passes into <i>wayhel</i>
life. (The transformed body is unable to move the sodium lamp, but
has nocturnal vision, so doesn't need to.) Unfortunately the player
is now outside a cage which has closed around the human self which
must be returned to, while the <i>wayhel</i> lacks the dexterity
to open the cage. The solution is to use the Wormcast to reach the
Burial Chamber, then bring its earthen roof down, opening a connection
between the chamber below and the cage above. Recovering human form,
the player can take the grave goods, climb up into the cage, open it
from the inside and escape. Lara Croft would be proud.</p>
<hr class="section-break" />
<p class="aside"><span class="warning">▲▲</span>
The situation becomes a little complicated if the same <code>orders</code>
routine has to do service in two situations: once while its owner is a
character met in the course of play, and then a second time when the
player has changed into it. This could be done simply by changing the
value of <code>orders</code> when the transformation takes place,
but an alternative is to arrange code for a single <code>orders</code>
routine like so:</p>
<p class="lynxonly"></p>
<pre class="code">
orders [;
if (player == self) {
if (actor == self) {
! I give myself an action
}
else {
! I give someone else an order
}
}<a id="p168" name="p168"></a>
else {
! Someone else gives me an order
}
],
</pre>
<a id="ex56" name="ex56"></a>
<p class="aside"><span class="warning"><b>•</b>▲▲
<b><a href="sa6.html#ans56">EXERCISE 56</a></b></span><br>
Write an <code>orders</code> routine for a Giant with a conscience,
who will refuse to attack even a mouse, but so that a player who
becomes the Giant can be wantonly cruel.</p>
<hr class="section-break" />
<p class="normal">“There are only three events in a man's life;
birth, life and death; he is not conscious of being born, he dies in
pain and he forgets to live.” (Jean de la Bruyère again.)
Death is indeed the usual conclusion of an adventure game, and occurs
when the source code sets the library variable <code>deadflag</code>
to <code>true</code>: in normal play <code>deadflag</code> is always
<code>false</code>. The “standard Inform rules” never
lead to the player's death, so this is something the designer must
explicitly do.</p>
<p class="indent">Unlike life, however, interactive fiction offers
another way out: the player can win. This happens if and when the
variable <code>deadflag</code> is set to 2.</p>
<p class="indent">Any higher values of <code>deadflag</code> are
considered to be more exotic ways the game can end, requiring text
beyond “You have died” or “You have won”.
The Inform library doesn't know what this text should be, so it
calls the <code>DeathMessage</code> entry point routine, which
is expected to look at <code>deadflag</code> and can then print
something suitable. For instance, ‘Ruins’ has a chasm
subject to the following <code>before</code> rule:</p>
<p class="lynxonly"></p>
<pre class="code">
before [;
Enter: deadflag = 3;
"You plummet through the silent void of darkness, cracking
your skull against an outcrop of rock. Amid the pain and
redness, you dimly make out the God with the
Owl-Headdress...";
JumpOver: "It is far too wide.";
],
</pre>
<p class="normal">and this means that it needs a <code>DeathMessage</code>
routine like so:</p>
<p class="lynxonly"></p>
<pre class="code">
[ DeathMessage;
if (deadflag == 3)
print "You have been captured";
];
</pre>
<p class="normal">Capture was about the worst fate that could befall
you in the unspeakably inhumane world of Maya strife.</p>
<a id="p169" name="p169"></a>
<p class="indent">‘Ruins’ doesn't, but many games allow
reincarnation or, as David M. Baggett points out, in fact resurrection.
You too can allow this, by providing an <code>AfterLife</code> entry
point routine. This gets the chance to do as it pleases before
any “death message” is printed, and it can even reset
<code>deadflag</code> to <code>false</code>, causing the game to
resume as though nothing had happened. Such <code>AfterLife</code>
routines can be tricky to write, though, because the game often has
to be altered to reflect what has happened.</p>
<p class="aside"><span class="warning"><b>•</b>
<b>REFERENCES</b></span><br>
The magic words “xyzzy” and “plugh” in
‘Advent’ employ <code>PlayerTo</code>.
<span class="warning"><b>•</b></span>‘Advent’ has an
amusing <code>AfterLife</code> routine: for instance, try collapsing
the bridge by leading the bear across, then returning to the scene
after resurrection. ‘Balances’ has one which only
slightly penalises death.</p>
</div>
<p class="navbar">
<a href="index.html">home</a> /
<a href="contents.html">contents</a> /
<a href="ch3.html" title="Chapter III: The Model World">chapter III</a> /
<a href="s20.html" title="§20: Daemons and the passing of time">prev</a> /
<a href="s22.html" title="§22: Miscellaneous constants, scoring, quotations">next</a> /
<a href="dm4index.html">index</a>
</p>
</body>
</html>