1
This is Info file inform.info, produced by Makeinfo-1.64 from the input
4
This is the Inform Designer's Manual, third edition, 4 September 1996,
5
as updated 16 May 1997. It was converted to Info by Christopher J.
6
Madsen <ac608@yfn.ysu.edu>.
8
Copyright 1996,1997 Graham Nelson and Christopher J. Madsen
10
Permission is granted to make and distribute copies of this manual
12
(a) distributed copies are not substantially different from those
13
archived by the author,
14
(b) this and other copyright messages are always retained in full, and
15
(c) no profit is involved.
18
File: inform, Node: Answers, Next: Index, Prev: Appendix, Up: Top
20
Answers to all the exercises
21
****************************
23
World is crazier and more of it than we think,
24
Incorrigibly plural. I peel and portion
25
A tangerine and spit the pips and feel
26
The drunkenness of things being various.
28
-- Louis MacNeice (1907-1963), Snow
32
* Answer 1:: mushroom picking
33
* Answer 2:: opening medicine bottle
34
* Answer 3:: before on second noun
35
* Answer 4:: action validation
36
* Answer 5:: orange cloud surrounding player
37
* Answer 6:: Mayan directions
38
* Answer 7:: reflecting the map east-west
39
* Answer 8:: exchanging "east"/"west"
40
* Answer 9:: acquisitive bag
41
* Answer 10:: television set
42
* Answer 11:: glass and steel boxes
43
* Answer 12:: macrame bag
44
* Answer 13:: plank bridge
45
* Answer 14:: cage to open and enter
46
* Answer 15:: car that won't go east
47
* Answer 16:: pushing pumice ball uphill
48
* Answer 17:: Tyndale's Bible
49
* Answer 18:: bearded psychiatrist
50
* Answer 19:: removing conversation actions
51
* Answer 20:: computer (voice-activated)
52
* Answer 21:: Charlotte playing Simon Says
53
* Answer 22:: Charlotte's clapping game
54
* Answer 23:: Dyslexic Dan
55
* Answer 24:: extensions for one actor only
56
* Answer 25:: alarm clock
57
* Answer 26:: tricorder
58
* Answer 27:: replicator
59
* Answer 28:: communications badge
60
* Answer 29:: Zen flight computer
61
* Answer 30:: Picard and Maharg
62
* Answer 31:: Martha the telepath
63
* Answer 32:: troll afraid of the dark
64
* Answer 33:: pet moth escapes in the dark
65
* Answer 34:: thief who wanders
66
* Answer 35:: weight--watching daemon
67
* Answer 36:: scuttling claws
68
* Answer 37:: Answer to Exercise 37
69
* Answer 38:: midnight
70
* Answer 39:: nightfall and daybreak
71
* Answer 40:: mid-air location
72
* Answer 41:: long time-scale game
73
* Answer 42:: player reacting before
74
* Answer 43:: silencing player
75
* Answer 44:: the player's wayhel
76
* Answer 45:: Giant with conscience
77
* Answer 46:: chessboard of rooms
78
* Answer 47:: varying the prompt
79
* Answer 48:: Answer to Exercise 48
80
* Answer 49:: printing pronouns
81
* Answer 50:: ornate box (inventory inside)
82
* Answer 51:: very verbose mode
83
* Answer 52:: double inventory
84
* Answer 53:: Scrabble pieces
85
* Answer 54:: three denominations of coin
86
* Answer 55:: I Ching coins
87
* Answer 56:: tomato in red or green
88
* Answer 57:: the artiste formerly known as Princess
89
* Answer 58:: drinks machine
90
* Answer 59:: parsing adjectives
91
* Answer 60:: referring to objects by number
92
* Answer 61:: wild-card for a single object
93
* Answer 62:: wild-card for multiple objects
94
* Answer 63:: "fly in amber"
95
* Answer 64:: cherubim plural
96
* Answer 65:: Answer to Exercise 65
97
* Answer 66:: moving to a room by typing its name
98
* Answer 67:: genie muddling black and white
99
* Answer 68:: footnotes
100
* Answer 69:: low numbers in French
101
* Answer 70:: floating-point numbers
102
* Answer 71:: phone numbers
103
* Answer 72:: parsing times of day
104
* Answer 73:: spaceship control panel
105
* Answer 74:: implementing parser primitives
106
* Answer 75:: parsing any quoted text
107
* Answer 76:: tokens which never match
108
* Answer 77:: Answer to Exercise 77
109
* Answer 78:: third noun for parser
110
* Answer 79:: "scope" verb
111
* Answer 80:: "megalook" verb
112
* Answer 81:: putting everything in scope
113
* Answer 82:: room divided by glass window
114
* Answer 83:: dwarf breathing in dark
115
* Answer 84:: nose attached to player
116
* Answer 85:: sterilising machine
117
* Answer 86:: red sticky label
118
* Answer 87:: "lock" and "unlock" inferring keys
119
* Answer 88:: quotations in boxes
120
* Answer 89:: Invisiclues hints
121
* Answer 90:: saving the character
122
* Answer 91:: title page
123
* Answer 92:: status line invisible
124
* Answer 93:: status line showing treasure
125
* Answer 94:: status line with compass rose
126
* Answer 95:: status line with centred room
127
* Answer 96:: printf routine
130
File: inform, Node: Answer 1, Next: Answer 2, Prev: Answers, Up: Answers
132
Answer to Exercise 1: mushroom picking
133
======================================
135
Change the mushroom's after rule to:
138
[; Take: if (self hasnt general)
140
"You pick the mushroom, neatly cleaving its thin stalk.";
142
"You pick up the slowly-disintegrating mushroom.";
143
Drop: "The mushroom drops to the ground, battered slightly.";
146
As mentioned above, general is a general-purpose attribute, free for the
147
designer to use. The `neatly cleaving' message can only happen once,
148
because after that the mushroom object must have general. Note that
149
the mushroom is allowed to call itself self instead of mushroom.
151
*Note Exercise 1: Getting Started.
154
File: inform, Node: Answer 2, Next: Answer 3, Prev: Answer 1, Up: Answers
156
Answer to Exercise 2: opening medicine bottle
157
=============================================
159
Object medicine "guaranteed child-proof medicine bottle" cupboard
160
with name "medicine" "bottle",
161
description "~Antidote only: no preventative effect.~",
163
[; give self open ~locked; "The bottle cracks open!";
165
has container openable locked;
167
Any other code in the game can send the message medicine.openup() to
168
crack open the bottle. For brevity, this solution assumes that the
169
bottle is always visible to the player when it is opened -- if not the
170
printed message will be incongruous.
172
*Note Exercise 2: Messages and Classes.
175
File: inform, Node: Answer 3, Next: Answer 4, Prev: Answer 2, Up: Answers
177
Answer to Exercise 3: before on second noun
178
===========================================
180
Briefly: provide a GamePreRoutine which tests to see if second is an
181
object, rather than nothing or a number. If it is, check whether the
182
object has a second_before rule (i.e. test the condition (object
183
provides second_before)). If it has, send the second_before message to
184
it, and return the reply as the return value from GamePreRoutine.
186
*Note Exercise 3: Actions and Reactions.
189
File: inform, Node: Answer 4, Next: Answer 5, Prev: Answer 3, Up: Answers
191
Answer to Exercise 4: action validation
192
=======================================
194
Put any validation rules desired into the GamePreRoutine. For
195
example, the following will filter out any stray Drop actions for
199
if (action==Drop && noun notin player)
200
"You aren't holding ", (the) noun, ".";
204
*Note Exercise 4: Actions and Reactions.
207
File: inform, Node: Answer 5, Next: Answer 6, Prev: Answer 4, Up: Answers
209
Answer to Exercise 5: orange cloud surrounding player
210
=====================================================
212
Object orange_cloud "orange cloud"
213
with name "orange" "cloud",
215
[; Look: "You can't see for the orange cloud surrounding you.";
216
Go, Exit: "You wander round in circles, choking.";
217
Smell: if (noun==0) "Cinnamon? No, nutmeg.";
221
*Note Exercise 5: Places.
224
File: inform, Node: Answer 6, Next: Answer 7, Prev: Answer 5, Up: Answers
226
Answer to Exercise 6: Mayan directions
227
======================================
229
Define four objects along the lines of:
231
Object white_obj "white wall" compass
232
with name "white" "sac" "wall", article "the", door_dir n_to
235
and add the following line to Initialise:
237
remove n_obj; remove e_obj; remove w_obj; remove s_obj;
239
(We could even alias a new Property called white_to to be n_to, and
240
then enter map directions in the source code using Mayan direction
241
names.) As a fine point of style, turquoise (`yax') is the world colour
242
for `here', so add a grammar line to make this cause a "look":
244
Verb "turquoise" "yax" * -> Look;
246
*Note Exercise 6: Places.
249
File: inform, Node: Answer 7, Next: Answer 8, Prev: Answer 6, Up: Answers
251
Answer to Exercise 7: reflecting the map east-west
252
==================================================
255
x=o1.door_dir; o1.door_dir=o2.door_dir; o2.door_dir=x; ];
257
SwapDirs(e_obj,w_obj); SwapDirs(ne_obj,nw_obj); SwapDirs(se_obj,sw_obj);
260
*Note Exercise 7: Places.
263
File: inform, Node: Answer 8, Next: Answer 9, Prev: Answer 7, Up: Answers
265
Answer to Exercise 8: exchanging "east"/"west"
266
==============================================
268
This is a prime candidate for using variable strings @nn. Briefly:
269
at the head of the source, define
271
Lowstring east_str "east"; Lowstring west_str "west";
273
and then add two more routines to the game,
275
[ NormalWorld; String 0 east_str; String 1 west_str; ];
276
[ ReversedWorld; String 0 west_str; String 1 east_str; ];
278
where NormalWorld is called in Initialise or to go back to normal, and
279
ReversedWorld when the reflection happens. Write @00 in place of east
280
in any double-quoted printable string, and similarly @01 for west. It
281
will be printed as whichever is currently set. (Inform provides up to
282
32 such variable strings.)
284
*Note Exercise 8: Places.
287
File: inform, Node: Answer 9, Next: Answer 10, Prev: Answer 8, Up: Answers
289
Answer to Exercise 9: acquisitive bag
290
=====================================
292
Object -> bag "toothed bag"
293
with name "toothed" "bag",
294
description "A capacious bag with a toothed mouth.",
296
[; LetGo: "The bag defiantly bites itself
297
shut on your hand until you desist.";
298
Close: "The bag resists all attempts to close it.";
302
"The bag wriggles hideously as it swallows ",
307
*Note Exercise 9: Containers.
310
File: inform, Node: Answer 10, Next: Answer 11, Prev: Answer 9, Up: Answers
312
Answer to Exercise 10: television set
313
=====================================
315
Object television "portable television set" lounge
316
with name "tv" "television" "set" "portable",
318
[; SwitchOn: <<SwitchOn power_button>>;
319
SwitchOff: <<SwitchOff power_button>>;
320
Examine: <<Examine screen>>;
323
Object -> power_button "power button"
324
with name "power" "button" "switch",
326
[; SwitchOn, SwitchOff: <<Examine screen>>;
329
Object -> screen "television screen"
332
[; Examine: if (power_button hasnt on) "The screen is black.";
333
"The screen writhes with a strange Japanese cartoon.";
336
*Note Exercise 10: Containers.
339
File: inform, Node: Answer 11, Next: Answer 12, Prev: Answer 10, Up: Answers
341
Answer to Exercise 11: glass and steel boxes
342
============================================
344
Object -> glass_box "glass box with a lid"
345
with name "glass" "box" "with" "lid"
346
has container transparent openable open;
347
Object -> steel_box "steel box with a lid"
348
with name "steel" "box" "with" "lid"
349
has container openable open;
351
*Note Exercise 11: Containers.
354
File: inform, Node: Answer 12, Next: Answer 13, Prev: Answer 11, Up: Answers
356
Answer to Exercise 12: macrame bag
357
==================================
359
(The describe part of this answer but is only decoration.) Note the
360
careful use of inp1 and inp2 rather than noun or second: see the note
361
at the end of *Note Actions and Reactions::.
363
Object -> macrame_bag "macrame bag"
364
with name "macrame" "bag" "string" "net" "sack",
366
[; Examine, Search, Listen, Smell: ;
368
if (inp1>1 && inp1 in self)
369
print_ret (The) inp1, " is tucked away in the bag.";
370
if (inp2>1 && inp2 in self)
371
print_ret (The) inp2, " is tucked away in the bag.";
374
[; print "^A macrame bag hangs from the ceiling, shut tight";
375
if (child(self)==0) ".";
376
print ". Inside you can make out ";
377
WriteListFrom(child(self), ENGLISH_BIT); ".";
379
has container transparent;
380
Object -> -> "gold watch"
381
with name "gold" "watch",
382
description "The watch has no hands, oddly.",
384
[; Listen: if (noun==0 or self) "The watch ticks loudly."; ];
386
*Note Exercise 12: Containers.
389
File: inform, Node: Answer 13, Next: Answer 14, Prev: Answer 12, Up: Answers
391
Answer to Exercise 13: plank bridge
392
===================================
394
The "plank breaking" rule is implemented here in its door_to routine.
395
Note that this returns `true' after killing the player.
397
Object -> PlankBridge "plank bridge"
398
with description "Extremely fragile and precarious.",
399
name "precarious" "fragile" "wooden" "plank" "bridge",
401
"A precarious plank bridge spans the chasm.",
403
[; if (children(player)~=0)
405
"You step gingerly across the plank, which bows under
406
your weight. But your meagre possessions are the straw
407
which breaks the camel's back! There is a horrid crack...";
409
print "You step gingerly across the plank, grateful that
410
you're not burdened.^";
411
if (location==NearSide) return FarSide; return NearSide;
414
[; if (location==NearSide) return s_to; return n_to;
416
found_in NearSide FarSide,
417
has static door open;
419
There might be a problem with this solution if your game also contained
420
a character who wandered about, and whose code was clever enough to run
421
door_to routines for any doors it ran into. If so, door_to could
422
perhaps be modified to check that the actor is the player.
424
*Note Exercise 13: Doors.
427
File: inform, Node: Answer 14, Next: Answer 15, Prev: Answer 13, Up: Answers
429
Answer to Exercise 14: cage to open and enter
430
=============================================
432
Object -> cage "iron cage"
433
with name "iron" "cage" "bars" "barred" "iron-barred",
435
"An iron-barred cage, large enough to stoop over inside,
436
looms ominously here.",
437
when_closed "The iron cage is closed.",
438
inside_description "You stare out through the bars.",
439
has enterable container openable open transparent static;
441
*Note Exercise 14: Things to Enter.
444
File: inform, Node: Answer 15, Next: Answer 16, Prev: Answer 14, Up: Answers
446
Answer to Exercise 15: car that won't go east
447
=============================================
449
Change the car's before to
452
[; Go: if (noun==e_obj)
453
{ print "The car will never fit through your front door.^";
456
if (car has on) "Brmm! Brmm!";
457
print "(The ignition is off at the moment.)^";
460
*Note Exercise 15: Things to Enter.
463
File: inform, Node: Answer 16, Next: Answer 17, Prev: Answer 15, Up: Answers
465
Answer to Exercise 16: pushing pumice ball uphill
466
=================================================
468
Insert these lines into the before rule for PushDir:
470
if (second==u_obj) <<PushDir self n_obj>>;
471
if (second==d_obj) <<PushDir self s_obj>>;
473
*Note Exercise 16: Things to Enter.
476
File: inform, Node: Answer 17, Next: Answer 18, Prev: Answer 16, Up: Answers
478
Answer to Exercise 17: Tyndale's Bible
479
======================================
481
Object -> bible "black Tyndale Bible"
482
with name "bible" "black" "book",
483
initial "A black Bible rests on a spread-eagle lectern.",
484
description "A splendid foot-high Bible, which must have survived
485
the burnings of 1520.",
488
wn = consult_from; w = NextWord();
490
{ 'matthew': x="Gospel of St Matthew";
491
'mark': x="Gospel of St Mark";
492
'luke': x="Gospel of St Luke";
493
'john': x="Gospel of St John";
494
default: "There are only the four Gospels.";
496
if (consult_words==1)
497
"You read the ", (string) x, " right through.";
500
"I was expecting a chapter number in the ",
502
"Chapter ", (number) w, " of the ", (string) x,
503
" is too sacred for you to understand now.";
506
*Note Exercise 17: Reading Matter.
509
File: inform, Node: Answer 18, Next: Answer 19, Prev: Answer 17, Up: Answers
511
Answer to Exercise 18: bearded psychiatrist
512
===========================================
514
Note that whether reacting before or after, the psychiatrist does
515
not cut any actions short, because react_before and react_after both
518
Object -> psychiatrist "bearded psychiatrist"
519
with name "bearded" "doctor" "psychiatrist" "psychologist" "shrink",
520
initial "A bearded psychiatrist has you under observation.",
522
[; "He is fascinated by your behaviour, but makes no attempt to
526
[; Insert: print "~Subject puts ", (name) noun, " in ",
527
(name) second, ". Interesting.~^^";
528
Look: print "~Pretend I'm not here,~ says the psychiatrist.^";
531
[; Take, Remove: print "~Subject feels lack of ", (the) noun,
532
". Suppressed Oedipal complex? Mmm.~^";
536
*Note Exercise 18: Living Creatures.
539
File: inform, Node: Answer 19, Next: Answer 20, Prev: Answer 18, Up: Answers
541
Answer to Exercise 19: removing conversation actions
542
====================================================
544
Add the following lines, after the inclusion of Grammar:
546
[ SayInsteadSub; "[To talk to someone, please type ~someone, something~
547
or else ~ask someone about something~.]"; ];
548
Extend "answer" replace * topic -> SayInstead;
549
Extend "tell" replace * topic -> SayInstead;
551
A slight snag is that this will throw out "nigel, tell me about the
552
grunfeld defence" (which the library will normally convert to an Ask
553
action, but can't if the grammar for "tell" is missing). To avoid
554
this, you could (instead of making the above directives) Replace the
555
TellSub routine (*note Extending the Library::.) by the SayInsteadSub
558
*Note Exercise 19: Living Creatures.
561
File: inform, Node: Answer 20, Next: Answer 21, Prev: Answer 19, Up: Answers
563
Answer to Exercise 20: computer (voice-activated)
564
=================================================
566
There are several ways to do this. The easiest is to add more
567
grammar to the parser and let it do the hard work:
569
Object -> computer "computer"
570
with name "computer",
572
[; Theta: print_ret "~Theta now set to ", noun, ".~";
573
default: print_ret "~Please rephrase.~";
577
[ ThetaSub; "You must tell your computer so."; ];
578
Verb "theta" * "is" number -> Theta;
580
*Note Exercise 20: Living Creatures.
583
File: inform, Node: Answer 21, Next: Answer 22, Prev: Answer 20, Up: Answers
585
Answer to Exercise 21: Charlotte playing Simon Says
586
===================================================
588
Obviously, a slightly wider repertoire of actions might be a good
591
Object -> Charlotte "Charlotte"
592
with name "charlotte" "charlie" "chas",
594
[; give self ~general;
596
if (NextWord()=='simon' && NextWord()=='says')
598
verb_wordnum=verb_wordnum+2;
602
[ i; if (self hasnt general) "Charlotte sticks her tongue out.";
603
WaveHands: "Charlotte waves energetically.";
604
default: "~Don't know how,~ says Charlotte.";
606
initial "Charlotte wants to play Simon Says.",
607
has animate female proper;
609
(The variable i isn't needed yet, but will be used by the code added in
610
the answer to the next exercise.)
612
*Note Exercise 21: Living Creatures.
615
File: inform, Node: Answer 22, Next: Answer 23, Prev: Answer 21, Up: Answers
617
Answer to Exercise 22: Charlotte's clapping game
618
================================================
620
First add a Clap verb (this is easy). Then give Charlotte a number
621
property (initially 0, say) and add these three lines to the end of
622
Charlotte's grammar routine:
624
self.number=TryNumber(verb_wordnum);
625
if (self.number~=-1000)
626
{ action=##Clap; noun=0; second=0; rtrue; }
628
Her orders routine now needs a local variable called i, and the new
631
Clap: if (self.number==0) "Charlotte folds her arms.";
632
for (i=0:i<self.number:i++)
635
print "(You must be regretting this by now.) ";
637
print "(What a determined girl she is.) ";
640
"^^Charlotte is a bit out of breath now.";
641
"^^~Easy!~ says Charlotte.";
643
*Note Exercise 22: Living Creatures.
646
File: inform, Node: Answer 23, Next: Answer 24, Prev: Answer 22, Up: Answers
648
Answer to Exercise 23: Dyslexic Dan
649
===================================
651
The interesting point here is that when the grammar property finds
652
the word "take", it accepts it and has to move verb_wordnum on by one
653
to signal that a word has been parsed succesfully.
655
Object -> Dan "Dyslexic Dan"
656
with name "dan" "dyslexic",
658
[; if (verb_word == 'take') { verb_wordnum++; return 'drop'; }
659
if (verb_word == 'drop') { verb_wordnum++; return 'take'; }
663
Take: "~What,~ says Dan, ~ you want me to take ",
665
Drop: "~What,~ says Dan, ~ you want me to drop ",
667
Inv: "~That I can do,~ says Dan. ~I'm empty-handed.~";
668
No: "~Right you be then.~";
669
Yes: "~I'll be having to think about that.~";
670
default: "~Don't know how,~ says Dan.";
672
initial "Dyslexic Dan is here.",
675
*Note Exercise 23: Living Creatures.
678
File: inform, Node: Answer 24, Next: Answer 25, Prev: Answer 23, Up: Answers
680
Answer to Exercise 24: extensions for one actor only
681
====================================================
683
Suppose Dan's grammar (but nobody else's) for the "examine" verb is
684
to be extended. His grammar routine should also contain:
686
if (verb_word == 'examine' or 'x')
687
{ verb_wordnum++; return -'danx,'; }
689
(Note the crudity of this: it looks at the actual verb word, so you
690
have to check any synonyms yourself.) The verb "danx," must be
693
Verb "danx," * "conscience" -> Inv;
695
and now "Dan, examine conscience" will send him an Inv order: but "Dan,
696
examine cow pie" will still send Examine cow_pie as usual.
698
*Note Exercise 24: Living Creatures.
701
File: inform, Node: Answer 25, Next: Answer 26, Prev: Answer 24, Up: Answers
703
Answer to Exercise 25: alarm clock
704
==================================
706
[ PrintTime x; print (x/60), ":", (x%60)/10, (x%60)%10; ];
707
Object -> alarm_clock "alarm clock"
708
with name "alarm" "clock",
711
[; print "The alarm is ";
712
if (self has general) print "on, "; else print "off, but ";
713
"the clock reads ", (PrintTime) the_time,
714
" and the alarm is set for ", (PrintTime) self.number, ".";
717
[; Inv: if (self in player) { new_line; <<Examine self>>; }
718
Look: if (self in location) { new_line; <<Examine self>>; }
721
[; if (the_time >= self.number && the_time <= self.number+3
722
&& self has general) "^Beep! Beep! The alarm goes off.";
724
grammar [; return 'alarm,'; ],
726
[; SwitchOn: give self general; StartDaemon(self); "~Alarm set.~";
727
SwitchOff: give self ~general; StopDaemon(self); "~Alarm off.~";
728
SetTo: self.number=noun; <<Examine self>>;
729
default: "~Commands are on, off or a time of day only, pliz.~";
732
[; Ask, Answer, Tell:
733
"[Try ~clock, something~ to address the clock.]";
737
and add a new verb to the grammar:
739
Verb "alarm," * "on" -> SwitchOn
741
* TimeOfDay -> SetTo;
743
(using the `TimeOfDay' token from the exercises of *note Grammar
744
Tokens::.). Note that since the word "alarm," can't be matched by
745
anything the player types, this verb is concealed from ordinary
746
grammar. The orders we produce here are not used in the ordinary way
747
(for instance, the action SwitchOn with no noun or second would never
748
ordinarily be produced by the parser) but this doesn't matter: it only
749
matters that the grammar and the orders property agree with each other.
751
*Note Exercise 25: Living Creatures.
754
File: inform, Node: Answer 26, Next: Answer 27, Prev: Answer 25, Up: Answers
756
Answer to Exercise 26: tricorder
757
================================
759
Object -> tricorder "tricorder"
760
with name "tricorder",
761
grammar [; return 'tc,'; ],
763
[; Examine: if (noun==player) "~You radiate life signs.~";
764
print "~", (The) noun, " radiates ";
765
if (noun hasnt animate) print "no ";
767
default: "The tricorder bleeps.";
770
[; Ask, Answer, Tell: "The tricorder is too simple.";
774
Verb "tc," * noun -> Examine;
776
*Note Exercise 26: Living Creatures.
779
File: inform, Node: Answer 27, Next: Answer 28, Prev: Answer 26, Up: Answers
781
Answer to Exercise 27: replicator
782
=================================
784
Object replicator "replicator"
785
with name "replicator",
786
grammar [; return 'rc,'; ],
790
"The replicator serves up a cup of ",
791
(name) noun, " which you drink eagerly.";
792
"~That is not something I can replicate.~";
793
default: "The replicator is unable to oblige.";
796
[; Ask, Answer, Tell: "The replicator has no conversation skill.";
799
Object -> "Earl Grey tea" with name "earl" "grey" "tea";
800
Object -> "Aldebaran brandy" with name "aldebaran" "brandy";
801
Object -> "distilled water" with name "distilled" "water";
803
Verb "rc," * held -> Give;
805
The point to note here is that the `held' token means `held by the
806
replicator' here, as the actor is the replicator, so this is a neat way
807
of getting a `one of the following phrases' token into the grammar.
809
*Note Exercise 27: Living Creatures.
812
File: inform, Node: Answer 28, Next: Answer 29, Prev: Answer 27, Up: Answers
814
Answer to Exercise 28: communications badge
815
===========================================
817
This is similar to the previous exercises. One creates an attribute
818
called crewmember and gives it to the crew objects: the orders property
825
" is no longer aboard this demonstration game.~";
826
"~", (name) noun, " is in ", (name) parent(noun), ".~";
827
default: "The computer's only really good for locating the crew.";
830
and the grammar simply returns 'stc,' which is defined as
835
2: objectloop (i has crewmember) PlaceInScope(i); rtrue;
838
Verb "stc," * "where" "is" scope=Crew -> Examine;
840
An interesting point is that the scope routine doesn't need to do
841
anything at stage 3 (usually used for printing out errors) because the
842
normal error-message printing system is never reached. Something like
843
"computer, where is Comminder Doto" causes a ##NotUnderstood order.
845
*Note Exercise 28: Living Creatures.
848
File: inform, Node: Answer 29, Next: Answer 30, Prev: Answer 28, Up: Answers
850
Answer to Exercise 29: Zen flight computer
851
==========================================
853
Object Zen "Zen" Flight_Deck
854
with name "zen" "flight" "computer",
855
initial "Square lights flicker unpredictably across a hexagonal
856
fascia on one wall, indicating that Zen is on-line.",
857
grammar [; return -'zen,'; ],
859
[; Show: "The main screen shows a starfield,
860
turning through ", noun, " degrees.";
861
Go: "~Confirmed.~ The ship turns to a new bearing.";
862
SetTo: if (noun==0) "~Confirmed.~ The ship comes to a stop.";
863
if (noun>12) "~Standard by ", (number) noun,
864
" exceeds design tolerances.~";
865
"~Confirmed.~ The ship's engines step to
866
standard by ", (number) noun, ".";
867
Take: if (noun~=force_wall) "~Please clarify.~";
868
"~Force wall raised.~";
869
Drop: if (noun~=blasters) "~Please clarify.~";
870
"~Battle-computers on line.
871
Neutron blasters cleared for firing.~";
872
NotUnderstood: "~Language banks unable to decode.~";
873
default: "~Information. That function is unavailable.~";
875
has talkable proper static;
876
Object -> force_wall "force wall" with name "force" "wall" "shields";
877
Object -> blasters "neutron blasters" with name "neutron" "blasters";
879
Verb "zen," * "scan" number "orbital" -> Show
880
* "set" "course" "for" Planet -> Go
881
* "speed" "standard" "by" number -> SetTo
882
* "raise" held -> Take
883
* "clear" held "for" "firing" -> Drop;
885
Dealing with Ask, Answer and Tell are left to the reader.
887
*Note Exercise 29: Living Creatures.
890
File: inform, Node: Answer 30, Next: Answer 31, Prev: Answer 29, Up: Answers
892
Answer to Exercise 30: Picard and Maharg
893
========================================
896
if (action_to_be == ##Examine or ##Show or ##ShowR)
897
PlaceInScope(noslen_maharg);
898
if (scope_reason == TALKING_REASON)
899
PlaceInScope(noslen_maharg);
902
Note that ShowR is a variant form of Show in which the parameters are
903
`the other way round': thus "show maharg the phaser" generates ShowR
904
maharg phaser internally, which is then converted to the more usual
907
*Note Exercise 30: Living Creatures.
910
File: inform, Node: Answer 31, Next: Answer 32, Prev: Answer 30, Up: Answers
912
Answer to Exercise 31: Martha the telepath
913
==========================================
915
Martha and the sealed room are defined as follows:
917
Object sealed_room "Sealed Room"
919
"I'm in a sealed room, like a squash court without a door,
920
maybe six or seven yards across",
922
Object -> ball "red ball" with name "red" "ball";
923
Object -> martha "Martha"
928
if (noun notin r) "~That's beyond my telekinesis.~";
929
if (noun==self) "~Teleportation's too hard for me.~";
931
"~Here goes...~ and Martha's telekinetic talents
932
magically bring ", (the) noun, " to your hands.";
934
print "~", (string) r.description;
935
if (children(r)==1) ". There's nothing here but me.~";
936
print ". I can see ";
937
WriteListFrom(child(r),CONCEAL_BIT+ENGLISH_BIT);
939
default: "~Afraid I can't help you there.~";
942
[; Ask: "~You're on your own this time.~";
943
Tell: "Martha clucks sympathetically.";
944
Answer: "~I'll be darned,~ Martha replies.";
946
has animate female concealed proper;
948
but the really interesting part is the InScope routine to fix things up:
951
if (actor==martha) PlaceInScope(player);
952
if (actor==player && scope_reason==TALKING_REASON)
953
PlaceInScope(martha);
957
Note that since we want two-way communication, the player has to be in
958
scope to Martha too: otherwise Martha won't be able to follow the
959
command "martha, give me the fish", because "me" will refer to
960
something beyond her scope.
962
*Note Exercise 31: Living Creatures.
965
File: inform, Node: Answer 32, Next: Answer 33, Prev: Answer 31, Up: Answers
967
Answer to Exercise 32: troll afraid of the dark
968
===============================================
970
Just test if HasLightSource(gift)==1.
972
*Note Exercise 32: Light and Dark.
975
File: inform, Node: Answer 33, Next: Answer 34, Prev: Answer 32, Up: Answers
977
Answer to Exercise 33: pet moth escapes in the dark
978
===================================================
980
We could solve this using a daemon, but for the sake of
981
demonstrating a feature of thedark we won't. In Initialise, write
982
thedark.initial = GoMothGo; and add the routine:
987
"As your eyes try to adjust, you feel a ticklish sensation
988
and hear a tiny fluttering sound.";
992
*Note Exercise 33: Light and Dark.
995
File: inform, Node: Answer 34, Next: Answer 35, Prev: Answer 33, Up: Answers
997
Answer to Exercise 34: thief who wanders
998
========================================
1000
This is a crude implementation, for brevity (the real Zork thief has
1001
an enormous stock of attached messages). A life routine is omitted,
1002
and of course this particular thief steals nothing. See `The Thief'
1003
for a much fuller, annotated implementation.
1005
Object -> thief "thief"
1006
with name "thief" "gentleman" "mahu" "modo",
1007
each_turn "^The thief growls menacingly.",
1010
if (random(3)~=1) rfalse;
1012
objectloop (i in compass)
1014
if (j ofclass Object && j hasnt door) n++;
1018
objectloop (i in compass)
1020
if (j ofclass Object && j hasnt door) n++;
1023
if (p==location) "^The thief stalks away!";
1024
if (j==location) "^The thief stalks in!";
1031
(Not forgetting to StartDaemon(thief) at some point, for instance in
1032
the game's Initialise routine.) So the thief walks at random but never
1033
via doors, bridges and the like (because these may be locked or have
1034
rules attached); it's only a first approximation, and in a good game
1035
one should occasionally see the thief do something surprising, such as
1036
open a secret door. As for the name, note that `The Prince of darkness
1037
is a gentleman. Modo he's called, and Mahu' (William Shakespeare, `King
1040
*Note Exercise 34: Daemons.
1043
File: inform, Node: Answer 35, Next: Answer 36, Prev: Answer 34, Up: Answers
1045
Answer to Exercise 35: weight--watching daemon
1046
==============================================
1048
We shall use a new property called weight and decide that any object
1049
which doesn't provide any particular weight will weigh 10 units.
1050
Clearly, an object which contains other objects will carry their weight
1054
if (obj provides weight) t = obj.weight; else t = 10;
1055
objectloop (i in obj) t = t + WeightOf(i);
1059
Once every turn we shall check how much the player is carrying and
1060
adjust a measure of the player's fatigue accordingly. There are many
1061
ways we could choose to calculate this: for the sake of example we'll
1062
define two constants:
1064
Constant CARRYING_STRENGTH = 500;
1065
Constant HEAVINESS_THRESHOLD = 100;
1067
Initially the player's strength will be the maximum possible, which
1068
we'll set to 500. Each turn the amount of weight being carried is
1069
substracted from this, but 100 is also added on (without exceeding the
1070
maximum value). So if the player carries more than 100 units, then her
1071
strength declines, but by dropping things to get the weight below 100
1072
she can allow it to recover. If she drops absolutely everything, her
1073
entire strength will recuperate in at most 5 turns. Exhaustion sets in
1074
if her strength reaches 0, and at this point she is forced to drop
1075
something, which gives her strength a slight boost. Anyway, here's an
1076
implementation of all this:
1078
Object weight_monitor
1079
with players_strength,
1082
[; self.players_strength = CARRYING_STRENGTH; StartDaemon(self);
1086
if (location ~= Weights_Room) { StopDaemon(self); return; }
1087
s = self.players_strength
1088
- WeightOf(player) + HEAVINESS_THRESHOLD;
1089
if (s<0) s=0; if (s>CARRYING_STRENGTH) s=CARRYING_STRENGTH;
1090
self.players_strength = s;
1093
objectloop(b in player)
1094
if (WeightOf(b) > bw) { bw = WeightOf(b); w=b; }
1095
self.players_strength = self.players_strength + bw;
1096
print "^Exhausted with carrying so much, you decide
1097
to discard ", (the) w, ": "; <<Drop w>>;
1099
w=s/100; if (w==self.warning_level) return;
1100
self.warning_level = w;
1102
{ 3: "^You are feeling a little tired.";
1103
2: "^You possessions are weighing you down.";
1104
1: "^Carrying so much weight is wearing you out.";
1105
0: "^You're nearly exhausted enough to drop everything
1106
at an inconvenient moment.";
1110
Notice that items are actually dropped with Drop actions: one of them
1111
might be, say, a wild boar, which would bolt away into the forest when
1112
released. The daemon tries to drop the heaviest item. (Obviously a
1113
little improvement would be needed if the game contained, say, an
1114
un-droppable but very heavy ball and chain.) Finally, of course, at
1115
some point the weight monitor has to be sent an activate message to get
1118
*Note Exercise 35: Daemons.
1121
File: inform, Node: Answer 36, Next: Answer 37, Prev: Answer 35, Up: Answers
1123
Answer to Exercise 36: scuttling claws
1124
======================================
1126
See the next answer.
1128
*Note Exercise 36: Daemons.
1131
File: inform, Node: Answer 37, Next: Answer 38, Prev: Answer 36, Up: Answers
1133
Answer to Exercise 37
1134
=====================
1136
Object tiny_claws "sound of tiny claws" thedark
1138
name "tiny" "claws" "sound" "of" "scuttling" "scuttle"
1139
"things" "creatures" "monsters" "insects",
1140
initial "Somewhere, tiny claws are scuttling.",
1142
[; Listen: "How intelligent they sound, for mere insects.";
1143
Touch, Taste: "You wouldn't want to. Really.";
1144
Smell: "You can only smell your own fear.";
1145
Attack: "They easily evade your flailing about in the dark.";
1146
default: "The creatures evade you, chittering.";
1148
each_turn [; StartDaemon(self); ],
1151
[; if (location~=thedark) { self.number=0; StopDaemon(self); rtrue; }
1152
switch(++(self.number))
1153
{ 1: "^The scuttling draws a little nearer, and your breathing
1154
grows loud and hoarse.";
1155
2: "^The perspiration of terror runs off your brow. The
1156
creatures are almost here!";
1157
3: "^You feel a tickling at your extremities and kick outward,
1158
shaking something chitinous off. Their sound alone
1159
is a menacing rasp.";
1161
"^Suddenly there is a tiny pain, of a hypodermic-sharp fang
1162
at your calf. Almost at once your limbs go into spasm,
1163
your shoulders and knee-joints lock, your tongue swells...";
1167
*Note Exercise 37: Daemons.
1170
File: inform, Node: Answer 38, Next: Answer 39, Prev: Answer 37, Up: Answers
1172
Answer to Exercise 38: midnight
1173
===============================
1175
Either set a daemon to watch for the_time suddenly dropping, or put
1176
such a watch in the game's TimePasses routine.
1178
*Note Exercise 38: Daemons.
1181
File: inform, Node: Answer 39, Next: Answer 40, Prev: Answer 38, Up: Answers
1183
Answer to Exercise 39: nightfall and daybreak
1184
=============================================
1186
A minimal solution is as follows:
1188
Constant SUNRISE 360; ! i.e., 6 am
1189
Constant SUNSET 1140; ! i.e., 7 pm
1190
Attribute outdoors; ! Give this to external locations
1191
Attribute lit; ! And this to artificially lit ones
1192
Global day_state = 2;
1194
if (the_time >= SUNRISE && the_time < SUNSET) f=1;
1195
if (day_state == f) rfalse;
1197
{ if (obj has lit) give obj light;
1198
if (obj has outdoors && obj hasnt lit)
1199
{ if (f==0) give obj ~light; else give obj light;
1202
if (day_state==2) { day_state = f; return; }
1203
day_state = f; if (location hasnt outdoors) return;
1204
if (f==1) "^The sun rises, illuminating the landscape!";
1205
"^As the sun sets, the landscape is plunged into darkness.";
1208
In the Initialise routine, set the time (using SetTime) and then call
1209
TimePasses to set all the light attributes accordingly. Note that with
1210
this system, there's no need to set light at all: that's automatic.
1212
*Note Exercise 39: Daemons.
1215
File: inform, Node: Answer 40, Next: Answer 41, Prev: Answer 39, Up: Answers
1217
Answer to Exercise 40: mid-air location
1218
=======================================
1220
Because you don't know what order daemons will run in. A `fatigue'
1221
daemon which makes the player drop something might come after the
1222
`mid-air' daemon has run for this turn. Whereas each_turn happens
1223
after daemons and timers have run their course, and can fairly assume
1224
no further movements will take place this turn.
1226
*Note Exercise 40: Daemons.
1229
File: inform, Node: Answer 41, Next: Answer 42, Prev: Answer 40, Up: Answers
1231
Answer to Exercise 41: long time-scale game
1232
===========================================
1234
It would have to provide its own code to keep track of time, and it
1235
can do this by providing a TimePasses() routine. Providing "time" or
1236
even "date" verbs to tell the player would also be a good idea.
1238
*Note Exercise 41: Daemons.
1241
File: inform, Node: Answer 42, Next: Answer 43, Prev: Answer 41, Up: Answers
1243
Answer to Exercise 42: player reacting before
1244
=============================================
1246
Two reasons. Firstly, there are times when we want to be able to
1247
trap orders to other people, which react_before does not. Secondly,
1248
the player's react_before rule is not necessarily the first to react.
1249
In the case of the player's deafness, a cuckoo may have already used
1250
react_before to sing. But it would have been safe to use
1251
GamePreRoutine, if a little untidy (because a rule about the player
1252
would not be part of the player's definition, which makes for confusing
1253
source code). See *Note Actions and Reactions:: for the exact sequence
1254
of events when actions are processed.
1256
*Note Exercise 42: Player.
1259
File: inform, Node: Answer 43, Next: Answer 44, Prev: Answer 42, Up: Answers
1261
Answer to Exercise 43: silencing player
1262
=======================================
1265
[; if (gasmask hasnt worn) rfalse;
1266
if (actor==self && action~=##Answer or ##Tell or ##Ask) rfalse;
1267
"Your speech is muffled into silence by the gas mask.";
1270
*Note Exercise 43: Player.
1273
File: inform, Node: Answer 44, Next: Answer 45, Prev: Answer 43, Up: Answers
1275
Answer to Exercise 44: the player's wayhel
1276
==========================================
1278
The common man's `wayhel' was a lowly mouse. Since we think much
1279
more highly of the player:
1281
Object hog "Warthog" Caldera
1282
with name "wart" "hog" "warthog", description "Muddy and grunting.",
1284
initial "A warthog snuffles and grunts about in the ash.",
1286
[; Go, Look, Examine, Eat, Smell, Taste, Touch: rfalse;
1287
default: "Warthogs can't do anything as tricky as that!";
1291
and we just ChangePlayer(warthog);. Note that the same orders routine
1292
applies to the player-as-human typing "warthog, listen" as to the
1293
player-as-warthog typing just "listen".
1295
*Note Exercise 44: Player.
1298
File: inform, Node: Answer 45, Next: Answer 46, Prev: Answer 44, Up: Answers
1300
Answer to Exercise 45: Giant with conscience
1301
============================================
1304
[; if (player==self)
1306
"You only become tongue-tied and gabble.";
1309
Attack: "The Giant looks at you with doleful eyes.
1310
~Me not be so bad!~";
1311
default: "The Giant is unable to comprehend your instructions.";
1314
*Note Exercise 45: Player.
1317
File: inform, Node: Answer 46, Next: Answer 47, Prev: Answer 45, Up: Answers
1319
Answer to Exercise 46: chessboard of rooms
1320
==========================================
1322
Give the "chessboard" room a short_name routine (it probably already
1323
has one, to print names like "Chessboard d6") and make it change the
1324
short name to "the gigantic Chessboard" if and only if action is
1325
currently set to ##Places.
1327
*Note Exercise 46: Constants and Scoring.
1330
File: inform, Node: Answer 47, Next: Answer 48, Prev: Answer 46, Up: Answers
1332
Answer to Exercise 47: varying the prompt
1333
=========================================
1335
Put the following definition between inclusion of "Parser" and
1338
Object LibraryMessages
1340
[; Prompt: if (turns==1)
1341
print "What should you, the detective, do now?^>";
1343
print "What next?^>";
1347
*Note Exercise 47: Extending the Library.
1350
File: inform, Node: Answer 48, Next: Answer 49, Prev: Answer 47, Up: Answers
1352
Answer to Exercise 48
1353
=====================
1355
See the `Inform Translator's Manual'. One must provide a new
1356
grammar file (generating the same actions but from different syntax),
1357
tables showing how pronouns, possessives and articles work in the new
1358
language, a sheaf of translated library messages and so on. But it can
1361
*Note Exercise 48: Extending the Library.
1364
File: inform, Node: Answer 49, Next: Answer 50, Prev: Answer 48, Up: Answers
1366
Answer to Exercise 49: printing pronouns
1367
========================================
1369
Simply define the following (for accusative, nominative and
1370
capitalised nominative pronouns, respectively):
1373
if (i hasnt animate) print "it";
1374
else { if (i has female) print "her"; else print "him"; } ];
1376
if (i hasnt animate) print "it";
1377
else { if (i has female) print "she"; else print "he"; } ];
1379
if (i hasnt animate) print "It";
1380
else { if (i has female) print "She"; else print "He"; } ];
1382
*Note Exercise 49: Describing Objects.
1385
File: inform, Node: Answer 50, Next: Answer 51, Prev: Answer 49, Up: Answers
1387
Answer to Exercise 50: ornate box (inventory inside)
1388
====================================================
1390
Use the invent routine to signal to short_name and article routines
1391
to change their usual habits:
1394
[; if (inventory_stage==1) give self general;
1395
else give self ~general;
1398
[; if (self has general) { print "box"; rtrue; } ],
1400
[; if (self has general) { print "that hateful"; rtrue; }
1403
*Note Exercise 50: Describing Objects.
1406
File: inform, Node: Answer 51, Next: Answer 52, Prev: Answer 50, Up: Answers
1408
Answer to Exercise 51: very verbose mode
1409
========================================
1411
This answer is cheating, as it needs to know about the library's
1412
lookmode variable (set to 1 for normal, 2 for verbose or 3 for
1413
superbrief). Simply include:
1416
if (action~=##Look && lookmode==2) <Look>;
1419
*Note Exercise 51: Describing Objects.