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: Answer 52, Next: Answer 53, Prev: Answer 51, Up: Answers
20
Answer to Exercise 52: double inventory
21
=======================================
23
[ DoubleInvSub i count1 count2;
24
print "You are carrying ";
25
objectloop (i in player)
26
{ if (i hasnt worn) { give i workflag; count1++; }
27
else { give i ~workflag; count2++; }
29
if (count1==0) print "nothing.";
31
WriteListFrom(child(player),
32
FULLINV_BIT + ENGLISH_BIT + RECURSE_BIT + WORKFLAG_BIT);
35
print ". In addition, you are wearing ";
36
objectloop (i in player)
37
{ if (i hasnt worn) give i ~workflag; else give i workflag;
39
WriteListFrom(child(player),
40
ENGLISH_BIT + RECURSE_BIT + WORKFLAG_BIT);
44
*Note Exercise 52: Listing Objects.
47
File: inform, Node: Answer 53, Next: Answer 54, Prev: Answer 52, Up: Answers
49
Answer to Exercise 53: Scrabble pieces
50
======================================
54
[; if (inventory_stage==1)
55
{ print "the letters ";
56
if (~~(c_style & ENGLISH_BIT)) c_style = c_style + ENGLISH_BIT;
57
if (~~(c_style & NOARTICLE_BIT)) c_style = c_style + NOARTICLE_BIT;
58
if (c_style & NEWLINE_BIT) c_style = c_style - NEWLINE_BIT;
59
if (c_style & INDENT_BIT) c_style = c_style - INDENT_BIT;
61
else print " from a Scrabble set";
64
[; if (listing_together ofclass Letter) rfalse;
65
print "letter ", (object) self, " from a Scrabble set"; rtrue;
69
and then as many letters as desired, along the lines of
71
Letter -> "X" with name "x";
73
*Note Exercise 53: Listing Objects.
76
File: inform, Node: Answer 54, Next: Answer 55, Prev: Answer 53, Up: Answers
78
Answer to Exercise 54: three denominations of coin
79
==================================================
82
with name "coin" "coins//p",
83
description "A round unstamped disc, presumably local currency.",
84
list_together "coins",
86
[; print (string) (self.&name)-->0;
87
if (~~(listing_together ofclass Coin)) print " coins";
90
[; if (listing_together ofclass Coin)
91
{ print (string) (self.&name)-->0; rtrue; }
94
[; if (listing_together ofclass Coin) print "one"; else print "a";
96
Class Gold_coin class Coin with name "gold";
97
Class Silver_coin class Coin with name "silver";
98
Class Bronze_coin class Coin with name "bronze";
99
SilverCoin -> "silver coin";
102
*Note Exercise 54: Listing Objects.
105
File: inform, Node: Answer 55, Next: Answer 56, Prev: Answer 54, Up: Answers
107
Answer to Exercise 55: I Ching coins
108
====================================
110
Firstly, a printing rule to print the state of coins. Coin-objects
111
will have a property called way_up which is always either 1 or 2:
113
[ Face x; if (x.way_up==1) print "Heads"; else print "Tails"; ];
115
There are two kinds of coin but we'll implement them with three
116
classes: Coin and two sub-categories, GoldCoin and SilverCoin. Since
117
the coins only join up into trigrams when present in groups of three,
118
we need a routine to detect this:
120
[ CoinsTogether cla i x y;
121
objectloop (i ofclass cla)
123
if (y==0) y=x; else { if (x~=y) return 0; }
128
Thus CoinsTogether(cla) decides whether all objects of class cla are in
129
the same place. (cla will always be either GoldCoin or SilverCoin.)
130
We must now write the class definitions:
133
with name "coin" "coins//p",
134
way_up 1, article "the",
137
self.way_up = random(2); print (Face) self;
138
if (CoinsTogether(self.which_class))
140
if (self.which_class == GoldCoin)
141
print "gold"; else print "silver";
142
" trigram is now ", (Trigram) self.which_class;
147
if (inventory_stage==1)
148
{ if (self.which_class == GoldCoin)
149
print "the gold"; else print "the silver";
151
k=CoinsTogether(self.which_class);
152
if (k==location || k has supporter)
153
{ objectloop (i ofclass self.which_class)
156
{ 1: print ", "; 2: print " and ";
157
3: print " (showing the trigram ",
158
(Trigram) self.which_class, ")";
163
if (~~(c_style & ENGLISH_BIT)) c_style = c_style + ENGLISH_BIT;
164
if (~~(c_style & NOARTICLE_BIT)) c_style = c_style + NOARTICLE_BIT;
165
if (c_style & NEWLINE_BIT) c_style = c_style - NEWLINE_BIT;
166
if (c_style & INDENT_BIT) c_style = c_style - INDENT_BIT;
170
Class GoldCoin class Coin
171
with name "gold", which_class GoldCoin,
172
list_together [; return CoinLT(); ];
173
Class SilverCoin class Coin
174
with name "silver", which_class SilverCoin,
175
list_together [; return CoinLT(); ];
177
(There are two unusual points here. Firstly, the CoinsLT routine is
178
not simply given as the common list_together value in the coin class
179
since, if it were, all six coins would be grouped together: we want two
180
groups of three, so the gold and silver coins have to have different
181
list_together values. Secondly, if a trigram is together and on the
182
floor, it is not good enough to simply append text like "showing Tails,
183
Heads, Heads (change)" at inventory_stage 2 since the coins may be
184
listed in a funny order: for example, in the order snake, robin, bison.
185
In that event, the order the coins are listed in doesn't correspond to
186
the order their values are listed in, which is misleading. So instead
187
CoinsLT takes over entirely at inventory_stage 1 and prints out the
188
list of three itself, returning true to stop the list from being
189
printed out by the library as well.) To resume: whenever coins are
190
listed together, they are grouped into gold and silver. Whenever
191
trigrams are visible they are to be described by either
192
Trigram(GoldClass) or Trigram(SilverClass):
194
Array gold_trigrams --> "fortune" "change" "river flowing" "chance"
195
"immutability" "six stones in a circle"
196
"grace" "divine assistance";
197
Array silver_trigrams --> "happiness" "sadness" "ambition" "grief"
198
"glory" "charm" "sweetness of nature"
199
"the countenance of the Hooded Man";
200
[ Trigram cla i k state;
201
objectloop (i ofclass cla)
202
{ print (Face) i; if (k++<2) print ","; print " ";
203
state=state*2 + (i.way_up-1);
205
if (cla == GoldCoin) i=gold_trigrams; else i=silver_trigrams;
206
print "(", (string) i-->state, ")";
209
(These interpretations of the coins are quite bogus.) Finally, we have
210
to make the six actual coins:
212
GoldCoin -> "goat" with name "goat";
213
GoldCoin -> "deer" with name "deer";
214
GoldCoin -> "chicken" with name "chicken";
215
SilverCoin -> "robin" with name "robin";
216
SilverCoin -> "snake" with name "snake";
217
SilverCoin -> "bison" with name "bison";
219
*Note Exercise 55: Listing Objects.
222
File: inform, Node: Answer 56, Next: Answer 57, Prev: Answer 55, Up: Answers
224
Answer to Exercise 56: tomato in red or green
225
=============================================
228
[ i j w; if (self has general) j='red'; else j='green';
230
while (w==j or 'fried')
233
if (w=='tomato') return i+1;
237
*Note Exercise 56: Parsing Nouns.
240
File: inform, Node: Answer 57, Next: Answer 58, Prev: Answer 56, Up: Answers
242
Answer to Exercise 57: the artiste formerly known as Princess
243
=============================================================
245
Object -> "/?%?/ (the artiste formerly known as Princess)"
246
with name "princess" "artiste" "formerly" "known" "as",
248
[; if (self hasnt general) { print "Princess"; rtrue; }
251
[; Listen: print_ret (name) self, " sings a soft siren song.";
254
[; print_ret (name) self, " is singing softly.";
257
[ x n; if (self hasnt general)
258
{ if (NextWord()=='princess') return 1;
262
if ( x->0 == '/' && x->1 == '?' && x->2 == '%'
263
&& x->3 == '?' && x->4 == '/')
264
{ while (wn<=parse->1 && WordAddress(wn++)<x+5) n++;
270
[; Kiss: give self general; self.life = NULL;
271
"In a fairy-tale transformation, the Princess
272
steps back and astonishes the world by announcing
273
that she will henceforth be known as ~/?%?/~.";
275
has animate proper female;
277
*Note Exercise 57: Parsing Nouns.
280
File: inform, Node: Answer 58, Next: Answer 59, Prev: Answer 57, Up: Answers
282
Answer to Exercise 58: drinks machine
283
=====================================
285
Something to note here is that the button can't be called just
286
"coffee" when the player's holding a cup of coffee: this means the game
287
responds sensibly to the sequence "press coffee" and "drink coffee".
288
Also note the way itobj is set to the delivered drink, so that "drink
291
Object -> drinksmat "drinks machine",
292
with name "drinks" "machine",
294
"A drinks machine here has buttons for Cola, Coffee and Tea.",
296
Object -> thebutton "drinks machine button"
300
for (: flag == 0: i++)
303
{ 'button', 'for': flag = 0;
304
'coffee': if (type == 0) { flag = 0; type = 1; }
305
'tea': if (type == 0) { flag = 0; type = 2; }
306
'cola': if (type == 0) { flag = 0; type = 3; }
309
if (type==drink.number && i==2 && type~=0 && drink in player)
311
self.number=type; return i-1;
316
if (self.number == 0)
317
"You'll have to say which button to press.";
318
if (parent(drink) ~= 0) "The machine's broken down.";
319
drink.number = self.number; move drink to player; itobj = drink;
320
print_ret "Whirr! The machine puts ", (a) drink, " into your \
322
Attack: "The machine shudders and squirts cola at you.";
323
Drink: "You can't drink until you've worked the machine.";
328
for (: flag == 0: i++)
331
{ 'drink', 'cup', 'of': flag = 0;
332
'coffee': if (type == 0) { flag = 0; type = 1; }
333
'tea': if (type == 0) { flag = 0; type = 2; }
334
'cola': if (type == 0) { flag = 0; type = 3; }
337
if (type ~= 0 && type ~= self.number) return 0;
343
{ 1: print "coffee"; 2: print "tea"; 3: print "cola"; }
348
[; Drink: remove self;
349
"Ugh, that was awful. You crumple the cup and responsibly \
353
*Note Exercise 58: Parsing Nouns.
356
File: inform, Node: Answer 59, Next: Answer 60, Prev: Answer 58, Up: Answers
358
Answer to Exercise 59: parsing adjectives
359
=========================================
361
Create a new property adjective, and move names which are adjectives
364
name "tomato" "vegetable", adjective 'fried' 'green' 'cooked',
366
(Recall that dictionary words can only be written in " quotes for the
367
name property.) Then (using the same IsAWordIn routine),
370
while (IsAWordIn(NextWord(),obj,adjective) == 1) n++; wn--;
371
while (IsAWordIn(NextWord(),obj,noun) == 1) m++;
372
if (m==0) return 0; return n+m;
375
*Note Exercise 59: Parsing Nouns.
378
File: inform, Node: Answer 60, Next: Answer 61, Prev: Answer 59, Up: Answers
380
Answer to Exercise 60: referring to objects by number
381
=====================================================
384
if (NextWord() == 'object' && TryNumber(wn) == obj) return 2;
388
*Note Exercise 60: Parsing Nouns.
391
File: inform, Node: Answer 61, Next: Answer 62, Prev: Answer 60, Up: Answers
393
Answer to Exercise 61: wild-card for a single object
394
====================================================
397
if (WordLength(wn)==1 && WordAddress(wn)->0 == '#') return 1;
401
*Note Exercise 61: Parsing Nouns.
404
File: inform, Node: Answer 62, Next: Answer 63, Prev: Answer 61, Up: Answers
406
Answer to Exercise 62: wild-card for multiple objects
407
=====================================================
410
if (WordLength(wn)==1 && WordAddress(wn)->0 == '#') return 1;
411
if (WordLength(wn)==1 && WordAddress(wn)->0 == '*')
412
{ parser_action = ##PluralFound; return 1; }
416
*Note Exercise 62: Parsing Nouns.
419
File: inform, Node: Answer 63, Next: Answer 64, Prev: Answer 62, Up: Answers
421
Answer to Exercise 63: "fly in amber"
422
=====================================
424
The trick is to convert "fly in amber" into "fly fly amber" (a
425
harmless name) before the parser gets under way.
428
for (i=parse->1,j=2:j<i:j++)
430
if (NextWord()=='fly' && NextWord()=='in' && NextWord()=='amber')
431
parse-->(j*2-1) = 'fly';
435
*Note Exercise 63: Parsing Nouns.
438
File: inform, Node: Answer 64, Next: Answer 65, Prev: Answer 63, Up: Answers
440
Answer to Exercise 64: cherubim plural
441
======================================
443
Global c_warned = false;
447
for (flag=true:flag:flag=false)
449
if (j=='cherub' or j==self.name) flag=true;
450
if (j=='cherubs' && (~~c_warned))
452
parser_action=##PluralFound; flag=true;
453
print "(I'll let this go once, but the plural of cherub is cherubim.)^";
456
{ parser_action=##PluralFound; flag=true; }
462
Then again, Shakespeare even wrote "cherubins" in `Twelfth Night', so
463
who are we to censure?
465
*Note Exercise 64: Plural Names.
468
File: inform, Node: Answer 65, Next: Answer 66, Prev: Answer 64, Up: Answers
470
Answer to Exercise 65
471
=====================
473
Because the parser might go on to reject the line it's working on:
474
for instance, if the player typed "shazam splurge" then the message
475
"Shazam!" followed by a parser complaint will be somewhat unedifying.
477
*Note Exercise 65: Parsing Verbs.
480
File: inform, Node: Answer 66, Next: Answer 67, Prev: Answer 65, Up: Answers
482
Answer to Exercise 66: moving to a room by typing its name
483
==========================================================
485
The scheme will work like this: any room that ought to have a name
486
should have a place_name property set to a dictionary word; say, the
487
Bedquilt cave could be called 'bedquilt'. Clearly you should only be
488
allowed to type this from adjacent rooms. So we'll implement the
489
following: you can only move by name to those rooms listed in the
490
current room's to_places property. For instance, the Soft Room might
491
have to_places set to
493
to_places Bedquilt Slab_Room Twopit_Room;
495
Now the code: if the player's verb is not otherwise understood, we'll
496
check it to see if it's a place name of a nearby room, and if so store
497
that room's object number in goto_room, converting the verb to
498
'go#room' (which we'll deal with below).
501
[ UnknownVerb word p i;
502
p = location.&to_places; if (p==0) rfalse;
503
for (i=0:(2*i)<location.#to_places:i++)
504
if (word==(p-->i).place_name)
505
{ goto_room = p-->i; return 'go#room';
511
{ print "go to ", (name) goto_room; rtrue; }
515
(The supplied PrintVerb is icing on the cake: so the parser can say
516
something like "I only understood you as far as wanting to go to
517
Bedquilt." in reply to, say, "bedquilt the nugget".) It remains only
518
to create the dummy verb:
521
if (goto_room hasnt visited) "But you have never been there.";
524
Verb "go#room" * -> GoRoom;
526
Note that if you don't know the way, you can't go there! A purist might
527
prefer instead to not recognise the name of an unvisited room, back at
528
the UnknownVerb stage, to avoid the player being able to deduce names
529
of nearby rooms from this `error message'.
531
*Note Exercise 66: Parsing Verbs.
534
File: inform, Node: Answer 67, Next: Answer 68, Prev: Answer 66, Up: Answers
536
Answer to Exercise 67: genie muddling black and white
537
=====================================================
539
Object -> genies_lamp "brass lamp"
540
with name "brass" "lamp",
542
[; Rub: if (self hasnt general) give self general;
543
else give self ~general;
544
"A genie appears from the lamp, declaring:^^
545
~Mischief is my sole delight:^
546
If white means black, black means white!~^^
547
She vanishes away with a vulgar wink.";
549
Object -> white_stone "white stone" with name "white" "stone";
550
Object -> black_stone "black stone" with name "black" "stone";
553
if (genies_lamp hasnt general) return;
555
{ switch(NextWordStopped())
556
{ 'white': parse->(wn*2-3) = 'black';
557
'black': parse->(wn*2-3) = 'white';
563
*Note Exercise 67: Parsing Verbs.
566
File: inform, Node: Answer 68, Next: Answer 69, Prev: Answer 67, Up: Answers
568
Answer to Exercise 68: footnotes
569
================================
571
Constant MAX_FOOTNOTES 10;
572
Array footnotes_seen -> MAX_FOOTNOTES;
573
Global footnote_count;
575
for (i=0:i<footnote_count:i++)
576
if (n==footnotes_seen->i) pn=i;
577
if (footnote_count==MAX_FOOTNOTES) "** MAX_FOOTNOTES exceeded! **";
578
if (pn==0) { pn=footnote_count++; footnotes_seen->pn=n; }
582
if (noun>footnote_count)
583
"No footnote [", noun, "] has been mentioned.";
584
if (noun==0) "Footnotes count upward from 1.";
585
n=footnotes_seen->(noun-1);
588
{ 0: "This is a footnote.";
589
1: "D.G.REG.F.D is inscribed around English coins.";
590
2: "~Jackdaws love my big sphinx of quartz~, for example.";
593
Verb "footnote" "note" * number -> Footnote;
595
And then you can code, for instance,
597
print "Her claim to the throne is in every pocket ", (Note) 1,
598
", her portrait in every wallet.";
600
*Note Exercise 68: Grammar Tokens.
603
File: inform, Node: Answer 69, Next: Answer 70, Prev: Answer 68, Up: Answers
605
Answer to Exercise 69: low numbers in French
606
============================================
608
The general parsing routine needed is:
619
parsed_number = n; return 1;
622
*Note Exercise 69: Grammar Tokens.
625
File: inform, Node: Answer 70, Next: Answer 71, Prev: Answer 69, Up: Answers
627
Answer to Exercise 70: floating-point numbers
628
=============================================
630
First we must decide how to store floating-point numbers internally:
631
in this case we'll simply store 100x to represent x, so that "5.46"
632
will be parsed as 546.
634
[ DigitNumber n type x;
635
x = NextWordStopped(); if (x==-1) return -1; wn--;
637
{ x = WordAddress(wn);
638
if (x->n>='0' && x->n<='9') return (x->n) - '0';
641
if (x=='nought' or 'oh') { wn++; return 0; }
642
x = TryNumber(wn++); if (x==-1000 || x>=10) x=-1; return x;
644
[ FloatingPoint a x b w d1 d2 d3 type;
646
if (a==-1000) return -1;
647
w = NextWordStopped(wn); if (w==-1) return a*100;
648
x = NextWordStopped(wn); if (x==-1) return -1; wn--;
649
if (w=='point') type=1;
651
{ if (WordAddress(wn-1)->0~='.' || WordLength(wn-1)~=1)
654
d1 = DigitNumber(0,type);
655
if (d1==-1) return -1;
656
d2 = DigitNumber(1,type); d3 = DigitNumber(2,type);
657
b=d1*10; if (d2>=0) b=b+d2; else d3=0;
659
{ x=1; while (DigitNumber(x,type)>=0) x++; wn--;
662
parsed_number = a*100 + b;
663
if (d3>=5) parsed_number++;
667
*Note Exercise 70: Grammar Tokens.
670
File: inform, Node: Answer 71, Next: Answer 72, Prev: Answer 70, Up: Answers
672
Answer to Exercise 71: phone numbers
673
====================================
675
Again, the first question is how to store the number dialled: in
676
this case, into a string array. The token is:
678
Constant MAX_PHONE_LENGTH = 30;
679
Array dialled_number string MAX_PHONE_LENGTH;
680
[ PhoneNumber f a l ch pp i;
681
pp=1; if (NextWordStopped()==-1) return 0;
683
{ a=WordAddress(wn-1); l=WordLength(wn-1);
686
if (ch<'0' || ch>'9')
687
{ if (ch~='-') { f=1; if (i~=0) return -1; } }
689
{ if (pp<MAX_PHONE_LENGTH)
690
dialled_number->(pp++)=ch-'0';
693
} until (f==1 || NextWordStopped()==-1);
694
if (pp==1) return -1;
695
dialled_number->0 = pp-1;
699
To demonstrate this in use,
702
print "You dialled <";
703
for (i=1:i<=dialled_number->0:i++) print dialled_number->i;
706
Verb "dial" * PhoneNumber -> DialPhone;
708
*Note Exercise 71: Grammar Tokens.
711
File: inform, Node: Answer 72, Next: Answer 73, Prev: Answer 71, Up: Answers
713
Answer to Exercise 72: parsing times of day
714
===========================================
716
The time of day will be returned as a number in the usual Inform
717
time format: as hours times 60 plus minutes (on the 24-hour clock, so
718
that the `hour' part is between 0 and 23).
720
Constant TWELVE_HOURS = 720;
721
[ NumericTime hr mn word x;
722
if (hr>=24) return -1;
723
if (mn>=60) return -1;
724
x=hr*60+mn; if (hr>=13) return x;
725
x=x%TWELVE_HOURS; if (word=='pm') x=x+TWELVE_HOURS;
726
if (word~='am' or 'pm' && hr==12) x=x+TWELVE_HOURS;
729
[ MyTryNumber wordnum i j;
730
i=wn; wn=wordnum; j=NextWordStopped(); wn=i;
732
{ 'twenty-five': return 25;
734
default: return TryNumber(wordnum);
737
[ TimeOfDay i j k flag loop ch hr mn;
740
{ 'midnight': parsed_number=0; return 1;
741
'midday', 'noon': parsed_number=TWELVE_HOURS; return 1;
743
! Next try the format 12:02
744
j=WordAddress(wn-1); k=WordLength(wn-1);
746
for (loop=0:loop<k:loop++)
748
if (ch==':' && flag==0 && loop~=0 && loop~=k-1) flag=1;
749
else { if (ch<'0') flag=-1; if (ch>'9') flag=-1; }
751
if (k<3) flag=0; if (k>5) flag=0;
753
{ for (loop=0:j->loop~=':':loop++, hr=hr*10)
756
for (loop++:loop<k:loop++, mn=mn*10)
760
parsed_number=NumericTime(hr, mn, j);
761
if (parsed_number<0) return -1;
762
if (j~='pm' or 'am') wn--;
765
! Next the format "half past 12"
766
j=-1; if (i=='half') j=30; if (i=='quarter') j=15;
767
if (j<0) j=MyTryNumber(wn-1); if (j<0) return -1;
768
if (j>=60) return -1;
771
{ hr=j; if (hr>12) return -1; jump TimeFound; }
772
if (k=='o^clock' or 'am' or 'pm')
773
{ hr=j; if (hr>12) return -1; jump TimeFound; }
774
if (k=='to' or 'past')
775
{ mn=j; hr=MyTryNumber(wn);
777
{ switch(NextWordStopped())
778
{ 'noon', 'midday': hr=12;
783
if (hr>=13) return -1;
784
if (k=='to') { mn=60-mn; hr=hr-1; if (hr==-1) hr=23; }
785
wn++; k=NextWordStopped();
788
hr=j; mn=MyTryNumber(--wn);
789
if (mn<0) return -1; if (mn>=60) return -1;
790
wn++; k=NextWordStopped();
792
parsed_number = NumericTime(hr, mn, k);
793
if (parsed_number<0) return -1;
794
if (k~='pm' or 'am' or 'o^clock') wn--;
798
*Note Exercise 72: Grammar Tokens.
801
File: inform, Node: Answer 73, Next: Answer 74, Prev: Answer 72, Up: Answers
803
Answer to Exercise 73: spaceship control panel
804
==============================================
806
Here goes: we could implement the buttons with five separate
807
objects, essentially duplicates of each other. (And by using a class
808
definition, this wouldn't look too bad.) But if there were 500 slides
809
this would be less reasonable.
812
if (location~=Machine_Room) return -1;
813
w=NextWord(); if (w=='slide') w=NextWord();
815
{ 'first', 'one': n=1;
816
'second', 'two': n=2;
817
'third', 'three': n=3;
818
'fourth', 'four': n=4;
819
'fifth', 'five': n=5;
820
default: return -1; ! Failure!
822
w=NextWord(); if (w~='slide') wn--; ! (Leaving word counter at the
823
! first misunderstood word)
827
Global slide_settings --> 5; ! A five-word array
829
slide_settings-->(noun-1) = second;
830
print_ret "You set slide ", (number) noun,
831
" to the value ", second, ".";
834
print_ret "Slide ", (number) noun, " currently stands at ",
835
slide_settings-->(noun-1), ".";
838
* ASlide "to" number -> SetSlide;
840
* ASlide "to" number -> SetSlide;
841
Extend "examine" first
844
*Note Exercise 73: Grammar Tokens.
847
File: inform, Node: Answer 74, Next: Answer 75, Prev: Answer 73, Up: Answers
849
Answer to Exercise 74: implementing parser primitives
850
=====================================================
852
(See the Parser file.) NextWord roughly returns parse-->(w*2-1)
853
(but it worries a bit about commas and full stops).
855
[ WordAddress w; return buffer + parse->(w*4+1); ];
856
[ WordLength w; return parse->(w*4); ];
858
*Note Exercise 74: Grammar Tokens.
861
File: inform, Node: Answer 75, Next: Answer 76, Prev: Answer 74, Up: Answers
863
Answer to Exercise 75: parsing any quoted text
864
==============================================
866
(Cf. the blackboard code in `Toyshop'.)
868
Global from_char; Global to_char;
870
i = parse->((++wn)*4-3);
872
{ for (j=i+1:j<=(buffer->1)+1:j++)
873
if (buffer->j=='"') f=j;
875
from_char = i+1; to_char=f-1;
876
if (from_char>to_char) return -1;
877
while (f> (parse->(wn*4-3))) wn++; wn++;
883
Note that in the case of success, the word marker wn is moved beyond the
884
last word accepted (since the Z-machine automatically tokenises a
885
double-quote as a single word). The text is treated as though it were
886
a preposition, and the positions where the quoted text starts and
887
finishes in the raw text buffer are recorded, so that an action routine
888
can easily extract the text and use it later. (Note that "" with no
889
text inside is not matched by this routine but only because the last if
890
statement throws out that one case.)
892
*Note Exercise 75: Grammar Tokens.
895
File: inform, Node: Answer 76, Next: Answer 77, Prev: Answer 75, Up: Answers
897
Answer to Exercise 76: tokens which never match
898
===============================================
900
[ NeverMatch; return -1; ];
902
*Note Exercise 76: Grammar Tokens.
905
File: inform, Node: Answer 77, Next: Answer 78, Prev: Answer 76, Up: Answers
907
Answer to Exercise 77
908
=====================
910
Perhaps to arrange better error messages when the text has failed
911
all the `real' grammar lines of a verb (see `Encyclopaedia Frobozzica'
914
*Note Exercise 77: Grammar Tokens.
917
File: inform, Node: Answer 78, Next: Answer 79, Prev: Answer 77, Up: Answers
919
Answer to Exercise 78: third noun for parser
920
============================================
922
(See the NounDomain specification in *Note Objects and Routines::.)
923
This routine passes on any REPARSE_CODE, as it must, but keeps a
924
matched object in its own third variable, returning the `skip this
925
text' code to the parser. Thus the parser never sees any third
930
x=NounDomain(player,location,0);
931
if (x==REPARSE_CODE) return x; if (x==0) return -1; third = x;
935
*Note Exercise 78: Grammar Tokens.
938
File: inform, Node: Answer 79, Next: Answer 80, Prev: Answer 78, Up: Answers
940
Answer to Exercise 79: "scope" verb
941
===================================
944
[ PrintIt obj; print_ret ++scope_count, ": ", (a) obj, " (", obj, ")"; ];
945
[ ScopeSub; LoopOverScope(PrintIt);
946
if (scope_count==0) "Nothing is in scope.";
948
Verb meta "scope" * -> Scope;
950
*Note Exercise 79: Scope.
953
File: inform, Node: Answer 80, Next: Answer 81, Prev: Answer 79, Up: Answers
955
Answer to Exercise 80: "megalook" verb
956
======================================
958
[ MegaExam obj; print "^", (a) obj, ": "; <Examine obj>; ];
959
[ MegaLookSub; <Look>; LoopOverScope(MegaExam); ];
960
Verb meta "megalook" * -> MegaLook;
962
*Note Exercise 80: Scope.
965
File: inform, Node: Answer 81, Next: Answer 82, Prev: Answer 80, Up: Answers
967
Answer to Exercise 81: putting everything in scope
968
==================================================
970
A slight refinement of such a "purloin" verb is already defined in
971
the library (if the constant DEBUG is defined), so there's no need.
972
But here's how it could be done:
975
if (scope_stage==1) rfalse;
977
{ objectloop (i ofclass Object) PlaceInScope(i); rtrue; }
981
(This disallows multiple matches for efficiency reasons -- the parser
982
has enough work to do with such a huge scope definition as it is.) Now
983
the token scope=Anything will match anything at all, even things like
984
the abstract concept of `east'.
986
*Note Exercise 81: Scope.
989
File: inform, Node: Answer 82, Next: Answer 83, Prev: Answer 81, Up: Answers
991
Answer to Exercise 82: room divided by glass window
992
===================================================
994
Note the sneaky way looking through the window is implemented, and
995
that the `on the other side' part of the room description isn't printed
1001
"This is one end of a long east/west room.",
1003
[; Examine, Search: ;
1005
if (inp1~=1 && noun~=0 && noun in self.far_side)
1006
print_ret (The) noun, " is on the far side of
1008
if (inp2~=1 && second~=0 && second in self.far_side)
1009
print_ret (The) second, " is on the far side of
1014
if (ggw has general) rfalse;
1015
print "^The room is divided by a great glass window";
1016
if (location.far_side hasnt light) " onto darkness.";
1017
print ", stretching from floor to ceiling.^";
1018
if (Locale(location.far_side,
1019
"Beyond the glass you can see",
1020
"Beyond the glass you can also see")~=0) ".";
1023
Window_Room window_w "West of Window"
1024
with far_side window_e;
1025
Window_Room window_e "East of Window"
1026
with far_side window_w;
1027
Object ggw "great glass window"
1028
with name "great" "glass" "window",
1030
[ place; Examine, Search: place=location;
1031
if (place.far_side hasnt light)
1032
"The other side is dark.";
1034
PlayerTo(place.far_side,1); <Look>; PlayerTo(place,1);
1036
give place.far_side ~visited; rtrue;
1038
found_in window_w window_e,
1041
A few words about inp1 and inp2 are in order. noun and second can hold
1042
either objects or numbers, and it's sometimes useful to know which.
1043
inp1 is equal to noun if that's an object, or 1 if that's a number;
1044
likewise for inp2 and second. (In this case we're just being careful
1045
that the action SetTo eggtimer 35 wouldn't be stopped if object 35
1046
happened to be on the other side of the glass.) We also need:
1049
if (actor in window_w && window_e has light) ScopeWithin(window_e);
1050
if (actor in window_e && window_w has light) ScopeWithin(window_w);
1054
*Note Exercise 82: Scope.
1057
File: inform, Node: Answer 83, Next: Answer 84, Prev: Answer 82, Up: Answers
1059
Answer to Exercise 83: dwarf breathing in dark
1060
==============================================
1062
For good measure, we'll combine this with the previous rule about
1063
moved objects being in scope in the dark. The following can be
1064
inserted into the `Shell' game:
1066
Object coal "dull coal" Blank_Room
1067
with name "dull" "coal";
1069
Object Dark_Room "Dark Room"
1070
with description "An empty room with a west exit.",
1072
[; if (self has general) self.each_turn=0;
1073
else "^You hear the breathing of a dwarf.";
1077
Object -> light_switch "light switch"
1078
with name "light" "switch",
1079
initial "On one wall is the light switch.",
1081
[; SwitchOn: give Dark_Room light;
1082
SwitchOff: give Dark_Room ~light;
1084
has switchable static;
1086
Object -> diamond "shiny diamond"
1087
with name "shiny" "diamond"
1090
Object -> dwarf "dwarf"
1091
with name "voice" "dwarf",
1093
[; Order: if (action==##SwitchOn && noun==light_switch)
1094
{ give Dark_Room light general;
1095
give light_switch on; "~Right you are, squire.~";
1101
if (parent(person)==Dark_Room)
1102
{ if (person==dwarf || Dark_Room has general)
1103
PlaceInScope(light_switch);
1105
if (person==player && location==thedark)
1106
objectloop (i near player)
1107
if (i has moved || i==dwarf)
1112
Note that the routine puts the light switch in scope for the dwarf --
1113
if it didn't, the dwarf would not be able to understand "dwarf, turn
1114
light on", and that was the whole point.
1116
*Note Exercise 83: Scope.
1119
File: inform, Node: Answer 84, Next: Answer 85, Prev: Answer 83, Up: Answers
1121
Answer to Exercise 84: nose attached to player
1122
==============================================
1124
In the Initialise routine, move newplay somewhere and ChangePlayer
1127
Object newplay "yourself"
1128
with description "As good-looking as ever.", number 0,
1132
[; Inv: if (nose has general) print "You're holding your nose. ";
1133
Smell: if (nose has general)
1134
"You can't smell a thing with your nose held.";
1136
has concealed animate proper transparent;
1139
with name "nose", article "your",
1141
[; Take: if (self has general)
1142
"You're already holding your nose.";
1143
if (children(player) > 1) "You haven't a free hand.";
1144
give self general; player.capacity=1;
1145
"You hold your nose with your spare hand.";
1146
Drop: if (self hasnt general) "But you weren't holding it!";
1147
give self ~general; player.capacity=5;
1148
print "You release your nose and inhale again. ";
1153
*Note Exercise 84: Scope.
1156
File: inform, Node: Answer 85, Next: Answer 86, Prev: Answer 84, Up: Answers
1158
Answer to Exercise 85: sterilising machine
1159
==========================================
1161
Object steriliser "sterilising machine"
1162
with name "washing" "sterilising" "machine",
1163
add_to_scope top_of_wm go_button,
1165
[; PushDir: AllowPushDir(); rtrue;
1167
if (receive_action==##PutOn)
1168
<<PutOn noun top_of_wm>>;
1169
SwitchOn: <<Push go_button>>;
1172
[; PushDir: "It's hard work, but the steriliser does roll.";
1175
[; print "There is a sterilising machine on casters here (a kind of
1176
chemist's washing machine) with a ~go~ button. ";
1177
if (children(top_of_wm)~=0)
1179
WriteListFrom(child(top_of_wm), ISARE_BIT + ENGLISH_BIT);
1182
if (children(self)~=0)
1184
WriteListFrom(child(self), ISARE_BIT + ENGLISH_BIT);
1188
has static container open openable;
1189
Object top_of_wm "top of the sterilising machine",
1191
has static supporter;
1192
Object go_button "~go~ button"
1193
with name "go" "button",
1194
before [; Push, SwitchOn: "The power is off."; ],
1197
*Note Exercise 85: Scope.
1200
File: inform, Node: Answer 86, Next: Answer 87, Prev: Answer 85, Up: Answers
1202
Answer to Exercise 86: red sticky label
1203
=======================================
1205
The label object itself is not too bad:
1207
Object -> label "red sticky label"
1208
with name "red" "sticky" "label",
1213
{ print "(first removing the label from ",
1214
(the) self.number, ")^"; self.number=0; move self to player;
1216
if (second==self) "That would only make a red mess.";
1217
self.number=second; remove self;
1218
print_ret "You affix the label to ", (the) second, ".";
1221
[ x; x=self.number; if (x==0) rfalse;
1222
Look: if (x in location)
1223
print "^The red sticky label is stuck to ", (the) x, ".^";
1224
Inv: if (x in player)
1225
print "^The red sticky label is stuck to ", (the) x, ".^";
1228
[; if (parent(self)~=0) self.number=0; ];
1230
Note that label.number holds the object the label is stuck to, or 0 if
1231
it's unstuck: and that when it is stuck, it is removed from the object
1232
tree. It therefore has to be moved into scope, so we need the rule: if
1233
the labelled object is in scope, then so is the label.
1235
Global disable_self;
1236
[ InScope actor i1 i2;
1237
if (label.number==0) rfalse; if (disable_self==1) rfalse;
1239
i1 = TestScope(label, actor);
1240
i2 = TestScope(label.number, actor);
1243
if (i2~=0) PlaceInScope(label);
1247
This routine has two interesting points: firstly, it disables itself
1248
while testing scope (since otherwise the game would go into an endless
1249
recursion), and secondly it only puts the label in scope if it isn't
1250
already there. This is just a safety precaution to prevent the label
1251
reacting twice to actions (and isn't really necessary since the label
1252
can't already be in scope, but is included for the sake of example).
1254
*Note Exercise 86: Scope.
1257
File: inform, Node: Answer 87, Next: Answer 88, Prev: Answer 86, Up: Answers
1259
Answer to Exercise 87: "lock" and "unlock" inferring keys
1260
=========================================================
1262
Firstly, create an attribute is_key and give it to all the keys in
1267
print "(with ", (the) assumed_key, ")^"; <<Lock noun assumed_key>>;
1269
[ DefaultLockTest i count;
1270
if (noun hasnt lockable) rfalse;
1271
objectloop (i in player)
1272
if (i has is_key) { count++; assumed_key = i; }
1273
if (count==1) rtrue; rfalse;
1275
Extend "lock" first * noun = DefaultLockTest -> DefaultLock;
1277
(and similar code for "unlock"). Note that "lock strongbox" is matched
1278
by this new grammar line only if the player only has one key: the
1279
DefaultLock strongbox action is generated: which is converted to, say,
1280
Lock strongbox brass_key.
1282
*Note Exercise 87: Helping the Parser.
1285
File: inform, Node: Answer 88, Next: Answer 89, Prev: Answer 87, Up: Answers
1287
Answer to Exercise 88: quotations in boxes
1288
==========================================
1290
Array quote_done -> 50;
1291
Global next_quote = -1;
1293
if (quote_done->i==0) { quote_done->i = 1; next_quote = i; }
1297
{ 0: box "His stride is wildernesses of freedom:"
1298
"The world rolls under the long thrust of his heel."
1299
"Over the cage floor the horizons come."
1301
"-- Ted Hughes, ~The Jaguar~";
1307
*Note Exercise 88: Boxes.
1310
File: inform, Node: Answer 89, Next: Answer 90, Prev: Answer 88, Up: Answers
1312
Answer to Exercise 89: Invisiclues hints
1313
========================================
1315
Note the magic line of assembly code here, which only works for
1318
[ GiveHint hint keypress;
1319
print (string) hint; new_line; new_line;
1320
@read_char 1 0 0 keypress;
1321
if (keypress == 'H' or 'h') rfalse;
1325
And a typical menu item using it:
1328
{ print "(Press ENTER to return to menu, or H for another hint.)^^";
1329
if (GiveHint("(1/3) What kind of bird is it, exactly?")==1) return 2;
1330
if (GiveHint("(2/3) Magpies are attracted by shiny items.")==1) return 2;
1331
"(3/3) Wave at the magpie with the kitchen foil.";
1334
*Note Exercise 89: Boxes.
1337
File: inform, Node: Answer 90, Next: Answer 91, Prev: Answer 89, Up: Answers
1339
Answer to Exercise 90: saving the character
1340
===========================================
1342
By encoding the character into a byte array and using @save and
1343
@restore. The numbers in this array might contain the character's
1344
name, rank and abilities, together with some coding system to show what
1345
possessions the character has (a brass lamp, 50 feet of rope, etc.)
1347
*Note Exercise 90: Assembly Language.
1350
File: inform, Node: Answer 91, Next: Answer 92, Prev: Answer 90, Up: Answers
1352
Answer to Exercise 91: title page
1353
=================================
1355
Note that we wait for a space character (32) or either kind of
1356
new-line which typical ASCII keyboards produce (10 or 13), just to be
1360
@erase_window -1; print "^^^^^^^^^^^^^";
1361
i = 0->33; if (i==0) i=80; i=(i-50)/2;
1362
style bold; font off; spaces(i);
1364
style roman; print "^^"; spaces(i);
1365
print " [Please press SPACE to begin.]^";
1367
box "And make your chronicle as rich with praise"
1368
"As is the ooze and bottom of the sea"
1369
"With sunken wreck and sumless treasures."
1371
"-- William Shakespeare, ~Henry V~ I. ii. 163";
1372
do { @read_char 1 0 0 i; } until (i==32 or 10 or 13);
1376
*Note Exercise 91: Assembly Language.
1379
File: inform, Node: Answer 92, Next: Answer 93, Prev: Answer 91, Up: Answers
1381
Answer to Exercise 92: status line invisible
1382
============================================
1384
First put the directive Replace DrawStatusLine; before including the
1385
library; define the global variable invisible_status somewhere. Then
1386
give the following redefinition:
1388
[ DrawStatusLine i width posa posb;
1389
if (invisible_status==1) return;
1390
@split_window 1; @set_window 1; @set_cursor 1 1; style reverse;
1391
width = 0->33; posa = width-26; posb = width-13;
1393
@set_cursor 1 2; PrintShortName(location);
1395
{ @set_cursor 1 posa; print "Score: ", sline1;
1396
@set_cursor 1 posb; print "Moves: ", sline2;
1398
if (width > 63 && width <= 76)
1399
{ @set_cursor 1 posb; print sline1, "/", sline2;
1401
@set_cursor 1 1; style roman; @set_window 0;
1404
*Note Exercise 92: Assembly Language.
1407
File: inform, Node: Answer 93, Next: Answer 94, Prev: Answer 92, Up: Answers
1409
Answer to Exercise 93: status line showing treasure
1410
===================================================
1412
First put the directive Replace DrawStatusLine; before including the
1413
library. Then add the following routine anywhere after treasures_found,
1414
an `Advent' variable, is defined:
1417
@split_window 1; @set_window 1; @set_cursor 1 1; style reverse;
1419
@set_cursor 1 2; PrintShortName(location);
1420
if (treasures_found > 0)
1421
{ @set_cursor 1 50; print "Treasure: ", treasures_found;
1423
@set_cursor 1 1; style roman; @set_window 0;
1426
*Note Exercise 93: Assembly Language.
1429
File: inform, Node: Answer 94, Next: Answer 95, Prev: Answer 93, Up: Answers
1431
Answer to Exercise 94: status line with compass rose
1432
====================================================
1434
Replace with the following. (Note the use of @@92 as a string
1435
escape, to include a literal backslash character, and @@124 for a
1438
Constant U_POS 28; Constant W_POS 30; Constant C_POS 31;
1439
Constant E_POS 32; Constant IN_POS 34;
1441
@split_window 3; @set_window 1; style reverse; font off;
1442
@set_cursor 1 1; spaces (0->33)-1;
1443
@set_cursor 2 1; spaces (0->33)-1;
1444
@set_cursor 3 1; spaces (0->33)-1;
1445
@set_cursor 1 2; print (name) location;
1446
@set_cursor 1 51; print "Score: ", sline1;
1447
@set_cursor 1 64; print "Moves: ", sline2;
1448
if (location ~= thedark)
1450
if (location.u_to ~= 0) { @set_cursor 1 U_POS; print "U"; }
1451
if (location.nw_to ~= 0) { @set_cursor 1 W_POS; print "@@92"; }
1452
if (location.n_to ~= 0) { @set_cursor 1 C_POS; print "@@124"; }
1453
if (location.ne_to ~= 0) { @set_cursor 1 E_POS; print "/"; }
1454
if (location.in_to ~= 0) { @set_cursor 1 IN_POS; print "I"; }
1456
if (location.w_to ~= 0) { @set_cursor 2 W_POS; print "-"; }
1457
@set_cursor 2 C_POS; print "o";
1458
if (location.e_to ~= 0) { @set_cursor 2 E_POS; print "-"; }
1460
if (location.d_to ~= 0) { @set_cursor 3 U_POS; print "D"; }
1461
if (location.sw_to ~= 0) { @set_cursor 3 W_POS; print "/"; }
1462
if (location.s_to ~= 0) { @set_cursor 3 C_POS; print "@@124"; }
1463
if (location.se_to ~= 0) { @set_cursor 3 E_POS; print "@@92"; }
1464
if (location.out_to ~= 0){ @set_cursor 3 IN_POS; print "O"; }
1466
@set_cursor 1 1; style roman; @set_window 0; font on;
1469
*Note Exercise 94: Assembly Language.
1472
File: inform, Node: Answer 95, Next: Answer 96, Prev: Answer 94, Up: Answers
1474
Answer to Exercise 95: status line with centred room
1475
====================================================
1477
The tricky part is working out the number of characters in the
1478
location name, and this is where @output_stream is so useful. This
1481
Array printed_text table 64;
1482
[ DrawStatusLine i j;
1483
i = 0->33; if (i==0) i=80;
1485
@split_window 1; @buffer_mode 0; @set_window 1;
1486
style reverse; @set_cursor 1 1; spaces(i);
1487
printed_text-->0 = 64;
1488
@output_stream 3 printed_text;
1489
print (name) location;
1491
j=(i-(printed_text-->0))/2;
1492
@set_cursor 1 j; print (name) location; spaces(j-1);
1494
@buffer_mode 1; @set_window 0; font on;
1497
Note that the table can hold 128 characters (plenty for this purpose),
1498
and that these are stored in printed_text->2 to printed_text->129; the
1499
length printed is held in printed_text-->0. (`Trinity' actually does
1500
this more crudely, storing away the width of each location name.)
1502
*Note Exercise 95: Assembly Language.
1505
File: inform, Node: Answer 96, Prev: Answer 95, Up: Answers
1507
Answer to Exercise 96: printf routine
1508
=====================================
1510
The following implementation is limited to a format string 2 * 64 =
1511
128 characters long, and six subsequent arguments. %d becomes a
1512
decimal number, %e an English one; %c a character, %% a (single)
1513
percentage sign and %s a string.
1515
Array printed_text table 64;
1516
Array printf_vals --> 6;
1517
[ Printf format p1 p2 p3 p4 p5 p6 pc j k;
1518
printf_vals-->0 = p1; printf_vals-->1 = p2; printf_vals-->2 = p3;
1519
printf_vals-->3 = p4; printf_vals-->4 = p5; printf_vals-->5 = p6;
1520
printed_text-->0 = 64; @output_stream 3 printed_text;
1521
print (string) format; @output_stream -3;
1524
{ if (printed_text->k == '%')
1525
{ switch(printed_text->(++k))
1527
'c': print (char) printf_vals-->pc++;
1528
'd': print printf_vals-->pc++;
1529
'e': print (number) printf_vals-->pc++;
1530
's': print (string) printf_vals-->pc++;
1531
default: print "<** Unknown printf escape **>";
1534
else print (char) printed_text->k;
1538
*Note Exercise 96: Assembly Language.
1541
File: inform, Node: Index, Next: Concept Index, Prev: Answers, Up: Top
1543
Index of Attributes, Properties, Objects, and Routines
1544
******************************************************
1548
* absent: Attributes.
1549
* Achieved: Objects and Routines.
1550
* AddToScope: Objects and Routines.
1551
* add_to_scope: Properties.
1552
* after: Properties.
1553
* AfterLife: Entry Points.
1554
* AfterPrompt: Entry Points.
1555
* AllowPushDir: Objects and Routines.
1556
* Amusing: Entry Points.
1557
* animate: Attributes.
1558
* article: Properties.
1559
* articles: Properties.
1560
* autosearch: Attributes.
1561
* before: Properties.
1562
* BeforeParsing: Entry Points.
1563
* cant_go: Properties.
1564
* capacity: Properties.
1565
* CDefArt: Objects and Routines.
1566
* ChangeDefault: Objects and Routines.
1567
* ChangePlayer: Objects and Routines.
1568
* ChooseObjects: Entry Points.
1569
* clothing: Attributes.
1570
* compass: Objects and Routines.
1571
* concealed: Attributes.
1572
* container: Attributes.
1573
* daemon: Properties.
1574
* DarkToDark: Entry Points.
1575
* DeathMessage: Entry Points.
1576
* DefArt: Objects and Routines.
1577
* describe: Properties.
1578
* description: Properties.
1579
* DoMenu: Objects and Routines.
1581
* door_dir: Properties.
1582
* door_to: Properties.
1583
* each_turn: Properties.
1584
* edible: Attributes.
1585
* EnglishNumber: Objects and Routines.
1586
* enterable: Attributes.
1587
* female: Attributes.
1588
* found_in: Properties.
1589
* GamePostRoutine: Entry Points.
1590
* GamePreRoutine: Entry Points.
1591
* general: Attributes.
1592
* grammar: Properties.
1593
* HasLightSource: Objects and Routines.
1594
* InDefArt: Objects and Routines.
1595
* initial: Properties.
1596
* Initialise: Entry Points.
1597
* InScope: Entry Points.
1598
* inside_description: Properties.
1599
* invent: Properties.
1601
* light: Attributes.
1602
* list_together: Properties.
1603
* Locale: Objects and Routines.
1604
* lockable: Attributes.
1605
* locked: Attributes.
1606
* LookRoutine: Entry Points.
1607
* LoopOverScope: Objects and Routines.
1609
* moved: Attributes.
1611
* neuter: Attributes.
1612
* NewRoom: Entry Points.
1613
* NextWord: Objects and Routines.
1614
* NextWordStopped: Objects and Routines.
1615
* NounDomain: Objects and Routines.
1616
* number: Properties.
1617
* ObjectIsUntouchable: Objects and Routines.
1618
* OffersLight: Objects and Routines.
1621
* openable: Attributes.
1622
* orders: Properties.
1623
* ParseNoun: Entry Points.
1624
* ParseNumber: Entry Points.
1625
* ParserError: Entry Points.
1626
* parse_name: Properties.
1627
* PlaceInScope: Objects and Routines.
1628
* PlayerTo: Objects and Routines.
1629
* plural: Properties.
1630
* pluralname: Attributes.
1631
* PrintRank: Entry Points.
1632
* PrintShortName: Objects and Routines.
1633
* PrintTaskName: Entry Points.
1634
* PrintVerb: Entry Points.
1635
* PronounNotice: Objects and Routines.
1636
* PronounValue: Objects and Routines.
1637
* proper: Attributes.
1638
* react_after: Properties.
1639
* react_before: Properties.
1640
* REPARSE_CODE: Objects and Routines.
1641
* scenery: Attributes.
1642
* ScopeWithin: Objects and Routines.
1643
* scored: Attributes.
1644
* selfobj: Objects and Routines.
1645
* SetPronoun: Objects and Routines.
1646
* SetTime: Objects and Routines.
1647
* short_name: Properties.
1648
* short_name_indef: Properties.
1649
* StartDaemon: Objects and Routines.
1650
* StartTimer: Objects and Routines.
1651
* static: Attributes.
1652
* StopDaemon: Objects and Routines.
1653
* StopTimer: Objects and Routines.
1654
* supporter: Attributes.
1655
* switchable: Attributes.
1656
* talkable: Attributes.
1657
* TestScope: Objects and Routines.
1658
* thedark: Objects and Routines.
1659
* TimePasses: Entry Points.
1660
* time_left: Properties.
1661
* time_out: Properties.
1662
* transparent: Attributes.
1663
* TryNumber: Objects and Routines.
1664
* UnknownVerb: Entry Points.
1665
* UnsignedCompare: Objects and Routines.
1666
* visited: Attributes.
1667
* when_closed: Properties.
1668
* when_off: Properties.
1669
* when_on: Properties.
1670
* when_open: Properties.
1671
* with_key: Properties.
1672
* WordAddress: Objects and Routines.
1673
* WordLength: Objects and Routines.
1674
* workflag: Attributes.
1676
* WriteListFrom: Objects and Routines.
1677
* YesOrNo: Objects and Routines.
1678
* ZRegion: Objects and Routines.