~ubuntu-branches/ubuntu/vivid/inform/vivid

« back to all changes in this revision

Viewing changes to info/inform-12

  • Committer: Bazaar Package Importer
  • Author(s): Jan Christoph Nordholz
  • Date: 2008-05-26 22:09:44 UTC
  • mfrom: (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080526220944-ba7phz0d1k4vo7wx
Tags: 6.31.1+dfsg-1
* Remove a considerable number of files from the package
  due to unacceptable licensing terms.
* Repair library symlinks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
This is Info file inform.info, produced by Makeinfo-1.64 from the input
2
 
file inform.texi.
3
 
 
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>.
7
 
 
8
 
Copyright 1996,1997 Graham Nelson and Christopher J. Madsen
9
 
 
10
 
Permission is granted to make and distribute copies of this manual
11
 
provided that:
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.
16
 
 
17
 
 
18
 
File: inform,  Node: Answer 52,  Next: Answer 53,  Prev: Answer 51,  Up: Answers
19
 
 
20
 
Answer to Exercise 52: double inventory
21
 
=======================================
22
 
 
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++; }
28
 
  }
29
 
  if (count1==0) print "nothing.";
30
 
  else
31
 
  WriteListFrom(child(player),
32
 
      FULLINV_BIT + ENGLISH_BIT + RECURSE_BIT + WORKFLAG_BIT);
33
 
 
34
 
  if (count2==0) ".";
35
 
  print ".  In addition, you are wearing ";
36
 
  objectloop (i in player)
37
 
  {   if (i hasnt worn) give i ~workflag; else give i workflag;
38
 
  }
39
 
  WriteListFrom(child(player),
40
 
      ENGLISH_BIT + RECURSE_BIT + WORKFLAG_BIT);
41
 
  ".";
42
 
];
43
 
 
44
 
   *Note Exercise 52: Listing Objects.
45
 
 
46
 
 
47
 
File: inform,  Node: Answer 53,  Next: Answer 54,  Prev: Answer 52,  Up: Answers
48
 
 
49
 
Answer to Exercise 53: Scrabble pieces
50
 
======================================
51
 
 
52
 
Class Letter
53
 
  with list_together
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;
60
 
          }
61
 
          else print " from a Scrabble set";
62
 
       ],
63
 
       short_name
64
 
       [;  if (listing_together ofclass Letter) rfalse;
65
 
           print "letter ", (object) self, " from a Scrabble set"; rtrue;
66
 
       ],
67
 
       article "the";
68
 
 
69
 
and then as many letters as desired, along the lines of
70
 
 
71
 
Letter -> "X" with name "x";
72
 
 
73
 
   *Note Exercise 53: Listing Objects.
74
 
 
75
 
 
76
 
File: inform,  Node: Answer 54,  Next: Answer 55,  Prev: Answer 53,  Up: Answers
77
 
 
78
 
Answer to Exercise 54: three denominations of coin
79
 
==================================================
80
 
 
81
 
Class  Coin
82
 
  with name "coin" "coins//p",
83
 
       description "A round unstamped disc, presumably local currency.",
84
 
       list_together "coins",
85
 
       plural
86
 
       [;  print (string) (self.&name)-->0;
87
 
           if (~~(listing_together ofclass Coin)) print " coins";
88
 
       ],
89
 
       short_name
90
 
       [;  if (listing_together ofclass Coin)
91
 
           {   print (string) (self.&name)-->0; rtrue; }
92
 
       ],
93
 
       article
94
 
       [;  if (listing_together ofclass Coin) print "one"; else print "a";
95
 
       ];
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";
100
 
... and so on
101
 
 
102
 
   *Note Exercise 54: Listing Objects.
103
 
 
104
 
 
105
 
File: inform,  Node: Answer 55,  Next: Answer 56,  Prev: Answer 54,  Up: Answers
106
 
 
107
 
Answer to Exercise 55: I Ching coins
108
 
====================================
109
 
 
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:
112
 
 
113
 
[ Face x; if (x.way_up==1) print "Heads"; else print "Tails"; ];
114
 
 
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:
119
 
 
120
 
[ CoinsTogether cla i x y;
121
 
  objectloop (i ofclass cla)
122
 
  {   x=parent(i);
123
 
      if (y==0) y=x; else { if (x~=y) return 0; }
124
 
  }
125
 
  return y;
126
 
];
127
 
 
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:
131
 
 
132
 
Class  Coin
133
 
  with name "coin" "coins//p",
134
 
       way_up 1, article "the",
135
 
       after
136
 
       [; Drop, PutOn:
137
 
             self.way_up = random(2); print (Face) self;
138
 
             if (CoinsTogether(self.which_class))
139
 
             {   print ". The ";
140
 
                 if (self.which_class == GoldCoin)
141
 
                     print "gold"; else print "silver";
142
 
                 " trigram is now ", (Trigram) self.which_class;
143
 
             }
144
 
             ".";
145
 
       ];
146
 
[ CoinLT k i c;
147
 
  if (inventory_stage==1)
148
 
  {   if (self.which_class == GoldCoin)
149
 
          print "the gold"; else print "the silver";
150
 
      print " coins ";
151
 
      k=CoinsTogether(self.which_class);
152
 
      if (k==location || k has supporter)
153
 
      {   objectloop (i ofclass self.which_class)
154
 
          {   print (name) i;
155
 
              switch(++c)
156
 
              {  1: print ", "; 2: print " and ";
157
 
                 3: print " (showing the trigram ",
158
 
                    (Trigram) self.which_class, ")";
159
 
              }
160
 
          }
161
 
          rtrue;
162
 
      }
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;
167
 
  }
168
 
  rfalse;
169
 
];
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(); ];
176
 
 
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):
193
 
 
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);
204
 
  }
205
 
  if (cla == GoldCoin) i=gold_trigrams; else i=silver_trigrams;
206
 
  print "(", (string) i-->state, ")";
207
 
];
208
 
 
209
 
(These interpretations of the coins are quite bogus.)  Finally, we have
210
 
to make the six actual coins:
211
 
 
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";
218
 
 
219
 
   *Note Exercise 55: Listing Objects.
220
 
 
221
 
 
222
 
File: inform,  Node: Answer 56,  Next: Answer 57,  Prev: Answer 55,  Up: Answers
223
 
 
224
 
Answer to Exercise 56: tomato in red or green
225
 
=============================================
226
 
 
227
 
parse_name
228
 
[ i j w; if (self has general) j='red'; else j='green';
229
 
         w=NextWord();
230
 
         while (w==j or 'fried')
231
 
         {   w=NextWord(); i++;
232
 
         }
233
 
         if (w=='tomato') return i+1;
234
 
         return 0;
235
 
],
236
 
 
237
 
   *Note Exercise 56: Parsing Nouns.
238
 
 
239
 
 
240
 
File: inform,  Node: Answer 57,  Next: Answer 58,  Prev: Answer 56,  Up: Answers
241
 
 
242
 
Answer to Exercise 57: the artiste formerly known as Princess
243
 
=============================================================
244
 
 
245
 
Object -> "/?%?/ (the artiste formerly known as Princess)"
246
 
  with name "princess" "artiste" "formerly" "known" "as",
247
 
       short_name
248
 
       [;   if (self hasnt general) { print "Princess"; rtrue; }
249
 
       ],
250
 
       react_before
251
 
       [;  Listen: print_ret (name) self, " sings a soft siren song.";
252
 
       ],
253
 
       initial
254
 
       [;  print_ret (name) self, " is singing softly.";
255
 
       ],
256
 
       parse_name
257
 
       [ x n; if (self hasnt general)
258
 
            {   if (NextWord()=='princess') return 1;
259
 
                return 0;
260
 
            }
261
 
            x=WordAddress(wn);
262
 
            if (   x->0 == '/' && x->1 == '?' && x->2 == '%'
263
 
                && x->3 == '?' && x->4 == '/')
264
 
            {   while (wn<=parse->1 && WordAddress(wn++)<x+5) n++;
265
 
                return n;
266
 
            }
267
 
            return -1;
268
 
       ],
269
 
       life
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 ~/?%?/~.";
274
 
       ],
275
 
  has  animate proper female;
276
 
 
277
 
   *Note Exercise 57: Parsing Nouns.
278
 
 
279
 
 
280
 
File: inform,  Node: Answer 58,  Next: Answer 59,  Prev: Answer 57,  Up: Answers
281
 
 
282
 
Answer to Exercise 58: drinks machine
283
 
=====================================
284
 
 
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
289
 
it" works nicely.
290
 
 
291
 
Object -> drinksmat "drinks machine",
292
 
  with name "drinks" "machine",
293
 
       initial
294
 
          "A drinks machine here has buttons for Cola, Coffee and Tea.",
295
 
  has  static;
296
 
Object -> thebutton "drinks machine button"
297
 
  has  scenery
298
 
 with  parse_name
299
 
       [ i flag type;
300
 
            for (: flag == 0: i++)
301
 
            {   flag = 1;
302
 
                switch(NextWord())
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; }
307
 
                }
308
 
            }
309
 
            if (type==drink.number && i==2 && type~=0 && drink in player)
310
 
                return 0;
311
 
            self.number=type; return i-1;
312
 
        ],
313
 
        number 0,
314
 
        before
315
 
        [; Push, SwitchOn:
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 \
321
 
                 glad hands.";
322
 
           Attack: "The machine shudders and squirts cola at you.";
323
 
           Drink:  "You can't drink until you've worked the machine.";
324
 
        ];
325
 
Object  drink "drink"
326
 
  with  parse_name
327
 
        [ i flag type;
328
 
            for (: flag == 0: i++)
329
 
            {   flag = 1;
330
 
                switch(NextWord())
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; }
335
 
                }
336
 
            }
337
 
            if (type ~= 0 && type ~= self.number) return 0;
338
 
            return i-1;
339
 
        ],
340
 
        short_name
341
 
        [;  print "cup of ";
342
 
            switch (self.number)
343
 
            { 1: print "coffee"; 2: print "tea"; 3: print "cola"; }
344
 
            rtrue;
345
 
        ],
346
 
        number 0,
347
 
        before
348
 
        [; Drink: remove self;
349
 
            "Ugh, that was awful.  You crumple the cup and responsibly \
350
 
             dispose of it.";
351
 
        ];
352
 
 
353
 
   *Note Exercise 58: Parsing Nouns.
354
 
 
355
 
 
356
 
File: inform,  Node: Answer 59,  Next: Answer 60,  Prev: Answer 58,  Up: Answers
357
 
 
358
 
Answer to Exercise 59: parsing adjectives
359
 
=========================================
360
 
 
361
 
   Create a new property adjective, and move names which are adjectives
362
 
to it: for instance,
363
 
 
364
 
    name "tomato" "vegetable", adjective 'fried' 'green' 'cooked',
365
 
 
366
 
(Recall that dictionary words can only be written in " quotes for the
367
 
name property.)  Then (using the same IsAWordIn routine),
368
 
 
369
 
[ ParseNoun obj n m;
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;
373
 
];
374
 
 
375
 
   *Note Exercise 59: Parsing Nouns.
376
 
 
377
 
 
378
 
File: inform,  Node: Answer 60,  Next: Answer 61,  Prev: Answer 59,  Up: Answers
379
 
 
380
 
Answer to Exercise 60: referring to objects by number
381
 
=====================================================
382
 
 
383
 
[ ParseNoun obj;
384
 
  if (NextWord() == 'object' && TryNumber(wn) == obj) return 2;
385
 
  wn--; return -1;
386
 
];
387
 
 
388
 
   *Note Exercise 60: Parsing Nouns.
389
 
 
390
 
 
391
 
File: inform,  Node: Answer 61,  Next: Answer 62,  Prev: Answer 60,  Up: Answers
392
 
 
393
 
Answer to Exercise 61: wild-card for a single object
394
 
====================================================
395
 
 
396
 
[ ParseNoun;
397
 
  if (WordLength(wn)==1 && WordAddress(wn)->0 == '#') return 1;
398
 
  return -1;
399
 
];
400
 
 
401
 
   *Note Exercise 61: Parsing Nouns.
402
 
 
403
 
 
404
 
File: inform,  Node: Answer 62,  Next: Answer 63,  Prev: Answer 61,  Up: Answers
405
 
 
406
 
Answer to Exercise 62: wild-card for multiple objects
407
 
=====================================================
408
 
 
409
 
[ ParseNoun;
410
 
  if (WordLength(wn)==1 && WordAddress(wn)->0 == '#') return 1;
411
 
  if (WordLength(wn)==1 && WordAddress(wn)->0 == '*')
412
 
  {   parser_action = ##PluralFound; return 1; }
413
 
  return -1;
414
 
];
415
 
 
416
 
   *Note Exercise 62: Parsing Nouns.
417
 
 
418
 
 
419
 
File: inform,  Node: Answer 63,  Next: Answer 64,  Prev: Answer 62,  Up: Answers
420
 
 
421
 
Answer to Exercise 63: "fly in amber"
422
 
=====================================
423
 
 
424
 
   The trick is to convert "fly in amber" into "fly fly amber" (a
425
 
harmless name) before the parser gets under way.
426
 
 
427
 
[ BeforeParsing i j;
428
 
  for (i=parse->1,j=2:j<i:j++)
429
 
  {   wn=j-1;
430
 
      if (NextWord()=='fly' && NextWord()=='in' && NextWord()=='amber')
431
 
          parse-->(j*2-1) = 'fly';
432
 
  }
433
 
];
434
 
 
435
 
   *Note Exercise 63: Parsing Nouns.
436
 
 
437
 
 
438
 
File: inform,  Node: Answer 64,  Next: Answer 65,  Prev: Answer 63,  Up: Answers
439
 
 
440
 
Answer to Exercise 64: cherubim plural
441
 
======================================
442
 
 
443
 
Global c_warned = false;
444
 
Class  Cherub
445
 
  with parse_name
446
 
       [ i j flag;
447
 
         for (flag=true:flag:flag=false)
448
 
         {   j=NextWord();
449
 
             if (j=='cherub' or j==self.name) flag=true;
450
 
             if (j=='cherubs' && (~~c_warned))
451
 
             {   c_warned=true;
452
 
                 parser_action=##PluralFound; flag=true;
453
 
 print "(I'll let this go once, but the plural of cherub is cherubim.)^";
454
 
             }
455
 
             if (j=='cherubim')
456
 
             {   parser_action=##PluralFound; flag=true; }
457
 
             i++;
458
 
         }
459
 
         return i-1;
460
 
       ];
461
 
 
462
 
Then again, Shakespeare even wrote "cherubins" in `Twelfth Night', so
463
 
who are we to censure?
464
 
 
465
 
   *Note Exercise 64: Plural Names.
466
 
 
467
 
 
468
 
File: inform,  Node: Answer 65,  Next: Answer 66,  Prev: Answer 64,  Up: Answers
469
 
 
470
 
Answer to Exercise 65
471
 
=====================
472
 
 
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.
476
 
 
477
 
   *Note Exercise 65: Parsing Verbs.
478
 
 
479
 
 
480
 
File: inform,  Node: Answer 66,  Next: Answer 67,  Prev: Answer 65,  Up: Answers
481
 
 
482
 
Answer to Exercise 66: moving to a room by typing its name
483
 
==========================================================
484
 
 
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
492
 
 
493
 
to_places Bedquilt Slab_Room Twopit_Room;
494
 
 
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).
499
 
 
500
 
Global goto_room;
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';
506
 
        }
507
 
    rfalse;
508
 
];
509
 
[ PrintVerb word;
510
 
    if (word=='go#room')
511
 
    {   print "go to ", (name) goto_room; rtrue; }
512
 
    rfalse;
513
 
];
514
 
 
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:
519
 
 
520
 
[ GoRoomSub;
521
 
    if (goto_room hasnt visited) "But you have never been there.";
522
 
    PlayerTo(goto_room);
523
 
];
524
 
Verb "go#room"  *                                -> GoRoom;
525
 
 
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'.
530
 
 
531
 
   *Note Exercise 66: Parsing Verbs.
532
 
 
533
 
 
534
 
File: inform,  Node: Answer 67,  Next: Answer 68,  Prev: Answer 66,  Up: Answers
535
 
 
536
 
Answer to Exercise 67: genie muddling black and white
537
 
=====================================================
538
 
 
539
 
Object -> genies_lamp "brass lamp"
540
 
  with name "brass" "lamp",
541
 
       before
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.";
548
 
       ];
549
 
Object -> white_stone "white stone" with name "white" "stone";
550
 
Object -> black_stone "black stone" with name "black" "stone";
551
 
...
552
 
[ BeforeParsing;
553
 
   if (genies_lamp hasnt general) return;
554
 
   for (wn=1::)
555
 
   {   switch(NextWordStopped())
556
 
       {   'white': parse->(wn*2-3) = 'black';
557
 
           'black': parse->(wn*2-3) = 'white';
558
 
           -1: return;
559
 
       }
560
 
   }
561
 
];
562
 
 
563
 
   *Note Exercise 67: Parsing Verbs.
564
 
 
565
 
 
566
 
File: inform,  Node: Answer 68,  Next: Answer 69,  Prev: Answer 67,  Up: Answers
567
 
 
568
 
Answer to Exercise 68: footnotes
569
 
================================
570
 
 
571
 
Constant MAX_FOOTNOTES 10;
572
 
Array footnotes_seen -> MAX_FOOTNOTES;
573
 
Global footnote_count;
574
 
[ Note n i pn;
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; }
579
 
    print " [",pn+1,"]";
580
 
];
581
 
[ FootnoteSub 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);
586
 
    print "[",noun,"]  ";
587
 
    switch(n)
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.";
591
 
    }
592
 
];
593
 
Verb "footnote" "note" * number              -> Footnote;
594
 
 
595
 
And then you can code, for instance,
596
 
 
597
 
    print "Her claim to the throne is in every pocket ", (Note) 1,
598
 
       ", her portrait in every wallet.";
599
 
 
600
 
   *Note Exercise 68: Grammar Tokens.
601
 
 
602
 
 
603
 
File: inform,  Node: Answer 69,  Next: Answer 70,  Prev: Answer 68,  Up: Answers
604
 
 
605
 
Answer to Exercise 69: low numbers in French
606
 
============================================
607
 
 
608
 
   The general parsing routine needed is:
609
 
 
610
 
[ FrenchNumber n;
611
 
    switch(NextWord())
612
 
    {   'un', 'une': n=1;
613
 
        'deux': n=2;
614
 
        'trois': n=3;
615
 
        'quatre': n=4;
616
 
        'cinq': n=5;
617
 
        default: return -1;
618
 
    }
619
 
    parsed_number = n; return 1;
620
 
];
621
 
 
622
 
   *Note Exercise 69: Grammar Tokens.
623
 
 
624
 
 
625
 
File: inform,  Node: Answer 70,  Next: Answer 71,  Prev: Answer 69,  Up: Answers
626
 
 
627
 
Answer to Exercise 70: floating-point numbers
628
 
=============================================
629
 
 
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.
633
 
 
634
 
[ DigitNumber n type x;
635
 
  x = NextWordStopped(); if (x==-1) return -1; wn--;
636
 
  if (type==0)
637
 
  {   x = WordAddress(wn);
638
 
      if (x->n>='0' && x->n<='9') return (x->n) - '0';
639
 
      return -1;
640
 
  }
641
 
  if (x=='nought' or 'oh') { wn++; return 0; }
642
 
  x = TryNumber(wn++); if (x==-1000 || x>=10) x=-1; return x;
643
 
];
644
 
[ FloatingPoint a x b w d1 d2 d3 type;
645
 
  a = TryNumber(wn++);
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;
650
 
  else
651
 
  {   if (WordAddress(wn-1)->0~='.' || WordLength(wn-1)~=1)
652
 
          return -1;
653
 
  }
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;
658
 
  if (type==1)
659
 
  {   x=1; while (DigitNumber(x,type)>=0) x++; wn--;
660
 
  }
661
 
  else wn++;
662
 
  parsed_number = a*100 + b;
663
 
  if (d3>=5) parsed_number++;
664
 
  return 1;
665
 
];
666
 
 
667
 
   *Note Exercise 70: Grammar Tokens.
668
 
 
669
 
 
670
 
File: inform,  Node: Answer 71,  Next: Answer 72,  Prev: Answer 70,  Up: Answers
671
 
 
672
 
Answer to Exercise 71: phone numbers
673
 
====================================
674
 
 
675
 
   Again, the first question is how to store the number dialled: in
676
 
this case, into a string array.  The token is:
677
 
 
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;
682
 
  do
683
 
  {   a=WordAddress(wn-1); l=WordLength(wn-1);
684
 
      for (i=0:i<l:i++)
685
 
      {   ch=a->i;
686
 
          if (ch<'0' || ch>'9')
687
 
          {   if (ch~='-') { f=1; if (i~=0) return -1; } }
688
 
          else
689
 
          {   if (pp<MAX_PHONE_LENGTH)
690
 
                  dialled_number->(pp++)=ch-'0';
691
 
          }
692
 
      }
693
 
  } until (f==1 || NextWordStopped()==-1);
694
 
  if (pp==1) return -1;
695
 
  dialled_number->0 = pp-1;
696
 
  return 0;
697
 
];
698
 
 
699
 
To demonstrate this in use,
700
 
 
701
 
[ DialPhoneSub i;
702
 
  print "You dialled <";
703
 
  for (i=1:i<=dialled_number->0:i++) print dialled_number->i;
704
 
  ">";
705
 
];
706
 
Verb "dial"  * PhoneNumber -> DialPhone;
707
 
 
708
 
   *Note Exercise 71: Grammar Tokens.
709
 
 
710
 
 
711
 
File: inform,  Node: Answer 72,  Next: Answer 73,  Prev: Answer 71,  Up: Answers
712
 
 
713
 
Answer to Exercise 72: parsing times of day
714
 
===========================================
715
 
 
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).
719
 
 
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;
727
 
  return x;
728
 
];
729
 
[ MyTryNumber wordnum i j;
730
 
  i=wn; wn=wordnum; j=NextWordStopped(); wn=i;
731
 
  switch(j)
732
 
  {   'twenty-five': return 25;
733
 
      'thirty': return 30;
734
 
      default: return TryNumber(wordnum);
735
 
  }
736
 
];
737
 
[ TimeOfDay i j k flag loop ch hr mn;
738
 
  i=NextWord();
739
 
  switch(i)
740
 
  {  'midnight': parsed_number=0; return 1;
741
 
     'midday', 'noon': parsed_number=TWELVE_HOURS; return 1;
742
 
  }
743
 
  !   Next try the format 12:02
744
 
  j=WordAddress(wn-1); k=WordLength(wn-1);
745
 
  flag=0;
746
 
  for (loop=0:loop<k:loop++)
747
 
  {   ch=j->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; }
750
 
  }
751
 
  if (k<3) flag=0; if (k>5) flag=0;
752
 
  if (flag==1)
753
 
  {   for (loop=0:j->loop~=':':loop++, hr=hr*10)
754
 
          hr=hr+j->loop-'0';
755
 
      hr=hr/10;
756
 
      for (loop++:loop<k:loop++, mn=mn*10)
757
 
          mn=mn+j->loop-'0';
758
 
      mn=mn/10;
759
 
      j=NextWordStopped();
760
 
      parsed_number=NumericTime(hr, mn, j);
761
 
      if (parsed_number<0) return -1;
762
 
      if (j~='pm' or 'am') wn--;
763
 
      return 1;
764
 
  }
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;
769
 
  k=NextWordStopped();
770
 
  if (k==-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);
776
 
      if (hr<=0)
777
 
      {   switch(NextWordStopped())
778
 
          {   'noon', 'midday': hr=12;
779
 
              'midnight': hr=0;
780
 
              default: return -1;
781
 
          }
782
 
      }
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();
786
 
      jump TimeFound;
787
 
  }
788
 
  hr=j; mn=MyTryNumber(--wn);
789
 
  if (mn<0) return -1; if (mn>=60) return -1;
790
 
  wn++; k=NextWordStopped();
791
 
 .TimeFound;
792
 
  parsed_number = NumericTime(hr, mn, k);
793
 
  if (parsed_number<0) return -1;
794
 
  if (k~='pm' or 'am' or 'o^clock') wn--;
795
 
  return 1;
796
 
];
797
 
 
798
 
   *Note Exercise 72: Grammar Tokens.
799
 
 
800
 
 
801
 
File: inform,  Node: Answer 73,  Next: Answer 74,  Prev: Answer 72,  Up: Answers
802
 
 
803
 
Answer to Exercise 73: spaceship control panel
804
 
==============================================
805
 
 
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.
810
 
 
811
 
[ ASlide w n;
812
 
   if (location~=Machine_Room) return -1;
813
 
   w=NextWord(); if (w=='slide') w=NextWord();
814
 
   switch(w)
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!
821
 
   }
822
 
   w=NextWord(); if (w~='slide') wn--;    !  (Leaving word counter at the
823
 
                                          !  first misunderstood word)
824
 
   parsed_number=n;
825
 
   return 1;                              !  Success!
826
 
];
827
 
Global slide_settings --> 5;              !  A five-word array
828
 
[ SetSlideSub;
829
 
   slide_settings-->(noun-1) = second;
830
 
   print_ret "You set slide ", (number) noun,
831
 
             " to the value ", second, ".";
832
 
];
833
 
[ XSlideSub;
834
 
   print_ret "Slide ", (number) noun, " currently stands at ",
835
 
       slide_settings-->(noun-1), ".";
836
 
];
837
 
Extend "set" first
838
 
           * ASlide "to" number                  -> SetSlide;
839
 
Extend "push" first
840
 
           * ASlide "to" number                  -> SetSlide;
841
 
Extend "examine" first
842
 
           * ASlide                              -> XSlide;
843
 
 
844
 
   *Note Exercise 73: Grammar Tokens.
845
 
 
846
 
 
847
 
File: inform,  Node: Answer 74,  Next: Answer 75,  Prev: Answer 73,  Up: Answers
848
 
 
849
 
Answer to Exercise 74: implementing parser primitives
850
 
=====================================================
851
 
 
852
 
   (See the Parser file.)  NextWord roughly returns parse-->(w*2-1)
853
 
(but it worries a bit about commas and full stops).
854
 
 
855
 
[ WordAddress w; return buffer + parse->(w*4+1); ];
856
 
[ WordLength w; return parse->(w*4); ];
857
 
 
858
 
   *Note Exercise 74: Grammar Tokens.
859
 
 
860
 
 
861
 
File: inform,  Node: Answer 75,  Next: Answer 76,  Prev: Answer 74,  Up: Answers
862
 
 
863
 
Answer to Exercise 75: parsing any quoted text
864
 
==============================================
865
 
 
866
 
   (Cf. the blackboard code in `Toyshop'.)
867
 
 
868
 
Global from_char; Global to_char;
869
 
[ QuotedText i j f;
870
 
   i = parse->((++wn)*4-3);
871
 
   if (buffer->i=='"')
872
 
   {   for (j=i+1:j<=(buffer->1)+1:j++)
873
 
           if (buffer->j=='"') f=j;
874
 
       if (f==0) return -1;
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++;
878
 
       return 0;
879
 
   }
880
 
   return -1;
881
 
];
882
 
 
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.)
891
 
 
892
 
   *Note Exercise 75: Grammar Tokens.
893
 
 
894
 
 
895
 
File: inform,  Node: Answer 76,  Next: Answer 77,  Prev: Answer 75,  Up: Answers
896
 
 
897
 
Answer to Exercise 76: tokens which never match
898
 
===============================================
899
 
 
900
 
[ NeverMatch; return -1; ];
901
 
 
902
 
   *Note Exercise 76: Grammar Tokens.
903
 
 
904
 
 
905
 
File: inform,  Node: Answer 77,  Next: Answer 78,  Prev: Answer 76,  Up: Answers
906
 
 
907
 
Answer to Exercise 77
908
 
=====================
909
 
 
910
 
   Perhaps to arrange better error messages when the text has failed
911
 
all the `real' grammar lines of a verb (see `Encyclopaedia Frobozzica'
912
 
for an example).
913
 
 
914
 
   *Note Exercise 77: Grammar Tokens.
915
 
 
916
 
 
917
 
File: inform,  Node: Answer 78,  Next: Answer 79,  Prev: Answer 77,  Up: Answers
918
 
 
919
 
Answer to Exercise 78: third noun for parser
920
 
============================================
921
 
 
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
926
 
parameter.
927
 
 
928
 
Global third;
929
 
[ ThirdNoun x;
930
 
  x=NounDomain(player,location,0);
931
 
  if (x==REPARSE_CODE) return x; if (x==0) return -1; third = x;
932
 
  return 0;
933
 
];
934
 
 
935
 
   *Note Exercise 78: Grammar Tokens.
936
 
 
937
 
 
938
 
File: inform,  Node: Answer 79,  Next: Answer 80,  Prev: Answer 78,  Up: Answers
939
 
 
940
 
Answer to Exercise 79: "scope" verb
941
 
===================================
942
 
 
943
 
Global scope_count;
944
 
[ PrintIt obj; print_ret ++scope_count, ": ", (a) obj, " (", obj, ")"; ];
945
 
[ ScopeSub; LoopOverScope(PrintIt);
946
 
  if (scope_count==0) "Nothing is in scope.";
947
 
];
948
 
Verb meta "scope" *                              -> Scope;
949
 
 
950
 
   *Note Exercise 79: Scope.
951
 
 
952
 
 
953
 
File: inform,  Node: Answer 80,  Next: Answer 81,  Prev: Answer 79,  Up: Answers
954
 
 
955
 
Answer to Exercise 80: "megalook" verb
956
 
======================================
957
 
 
958
 
[ MegaExam obj; print "^", (a) obj, ": "; <Examine obj>; ];
959
 
[ MegaLookSub; <Look>; LoopOverScope(MegaExam); ];
960
 
Verb meta "megalook" *                           -> MegaLook;
961
 
 
962
 
   *Note Exercise 80: Scope.
963
 
 
964
 
 
965
 
File: inform,  Node: Answer 81,  Next: Answer 82,  Prev: Answer 80,  Up: Answers
966
 
 
967
 
Answer to Exercise 81: putting everything in scope
968
 
==================================================
969
 
 
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:
973
 
 
974
 
[ Anything i;
975
 
  if (scope_stage==1) rfalse;
976
 
  if (scope_stage==2)
977
 
  {   objectloop (i ofclass Object) PlaceInScope(i); rtrue; }
978
 
  "No such in game.";
979
 
];
980
 
 
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'.
985
 
 
986
 
   *Note Exercise 81: Scope.
987
 
 
988
 
 
989
 
File: inform,  Node: Answer 82,  Next: Answer 83,  Prev: Answer 81,  Up: Answers
990
 
 
991
 
Answer to Exercise 82: room divided by glass window
992
 
===================================================
993
 
 
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
996
 
in that case.
997
 
 
998
 
Property far_side;
999
 
Class  Window_Room
1000
 
  with description
1001
 
          "This is one end of a long east/west room.",
1002
 
       before
1003
 
       [;  Examine, Search: ;
1004
 
           default:
1005
 
             if (inp1~=1 && noun~=0 && noun in self.far_side)
1006
 
                 print_ret (The) noun, " is on the far side of
1007
 
                    the glass.";
1008
 
             if (inp2~=1 && second~=0 && second in self.far_side)
1009
 
                 print_ret (The) second, " is on the far side of
1010
 
                    the glass.";
1011
 
       ],
1012
 
       after
1013
 
       [;  Look:
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) ".";
1021
 
       ],
1022
 
  has  light;
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",
1029
 
       before
1030
 
       [ place; Examine, Search: place=location;
1031
 
               if (place.far_side hasnt light)
1032
 
                   "The other side is dark.";
1033
 
               give self general;
1034
 
               PlayerTo(place.far_side,1); <Look>; PlayerTo(place,1);
1035
 
               give self ~general;
1036
 
               give place.far_side ~visited; rtrue;
1037
 
       ],
1038
 
       found_in window_w window_e,
1039
 
  has  scenery;
1040
 
 
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:
1047
 
 
1048
 
[ InScope actor;
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);
1051
 
   rfalse;
1052
 
];
1053
 
 
1054
 
   *Note Exercise 82: Scope.
1055
 
 
1056
 
 
1057
 
File: inform,  Node: Answer 83,  Next: Answer 84,  Prev: Answer 82,  Up: Answers
1058
 
 
1059
 
Answer to Exercise 83: dwarf breathing in dark
1060
 
==============================================
1061
 
 
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:
1065
 
 
1066
 
Object coal "dull coal" Blank_Room
1067
 
  with name "dull" "coal";
1068
 
 
1069
 
Object Dark_Room "Dark Room"
1070
 
  with description "An empty room with a west exit.",
1071
 
       each_turn
1072
 
       [; if (self has general) self.each_turn=0;
1073
 
          else "^You hear the breathing of a dwarf.";
1074
 
       ],
1075
 
       w_to Blank_Room;
1076
 
 
1077
 
Object -> light_switch "light switch"
1078
 
  with name "light" "switch",
1079
 
       initial "On one wall is the light switch.",
1080
 
       after
1081
 
       [; SwitchOn: give Dark_Room light;
1082
 
          SwitchOff: give Dark_Room ~light;
1083
 
       ],
1084
 
  has  switchable static;
1085
 
 
1086
 
Object -> diamond "shiny diamond"
1087
 
  with name "shiny" "diamond"
1088
 
  has  scored;
1089
 
 
1090
 
Object -> dwarf "dwarf"
1091
 
  with name "voice" "dwarf",
1092
 
       life
1093
 
       [; Order: if (action==##SwitchOn && noun==light_switch)
1094
 
                 {   give Dark_Room light general;
1095
 
                     give light_switch on; "~Right you are, squire.~";
1096
 
                 }
1097
 
       ],
1098
 
  has  animate;
1099
 
 
1100
 
[ InScope person i;
1101
 
  if (parent(person)==Dark_Room)
1102
 
  {   if (person==dwarf || Dark_Room has general)
1103
 
          PlaceInScope(light_switch);
1104
 
  }
1105
 
  if (person==player && location==thedark)
1106
 
      objectloop (i near player)
1107
 
          if (i has moved || i==dwarf)
1108
 
              PlaceInScope(i);
1109
 
  rfalse;
1110
 
];
1111
 
 
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.
1115
 
 
1116
 
   *Note Exercise 83: Scope.
1117
 
 
1118
 
 
1119
 
File: inform,  Node: Answer 84,  Next: Answer 85,  Prev: Answer 83,  Up: Answers
1120
 
 
1121
 
Answer to Exercise 84: nose attached to player
1122
 
==============================================
1123
 
 
1124
 
   In the Initialise routine, move newplay somewhere and ChangePlayer
1125
 
to it, where:
1126
 
 
1127
 
Object newplay "yourself"
1128
 
  with description "As good-looking as ever.", number 0,
1129
 
       add_to_scope nose,
1130
 
       capacity 5,
1131
 
       before
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.";
1135
 
       ],
1136
 
  has  concealed animate proper transparent;
1137
 
 
1138
 
Object nose "nose"
1139
 
  with name "nose", article "your",
1140
 
       before
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.  ";
1149
 
                <<Smell>>;
1150
 
       ],
1151
 
  has  scenery;
1152
 
 
1153
 
   *Note Exercise 84: Scope.
1154
 
 
1155
 
 
1156
 
File: inform,  Node: Answer 85,  Next: Answer 86,  Prev: Answer 84,  Up: Answers
1157
 
 
1158
 
Answer to Exercise 85: sterilising machine
1159
 
==========================================
1160
 
 
1161
 
Object steriliser "sterilising machine"
1162
 
  with name "washing" "sterilising" "machine",
1163
 
       add_to_scope  top_of_wm  go_button,
1164
 
       before
1165
 
       [;  PushDir: AllowPushDir(); rtrue;
1166
 
               Receive:
1167
 
                   if (receive_action==##PutOn)
1168
 
                       <<PutOn noun top_of_wm>>;
1169
 
           SwitchOn: <<Push go_button>>;
1170
 
       ],
1171
 
       after
1172
 
       [;  PushDir: "It's hard work, but the steriliser does roll.";
1173
 
       ],
1174
 
       initial
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)
1178
 
           {   print "On top";
1179
 
               WriteListFrom(child(top_of_wm), ISARE_BIT + ENGLISH_BIT);
1180
 
               print ".  ";
1181
 
           }
1182
 
           if (children(self)~=0)
1183
 
           {   print "Inside";
1184
 
               WriteListFrom(child(self), ISARE_BIT + ENGLISH_BIT);
1185
 
               print ".  ";
1186
 
           }
1187
 
       ],
1188
 
  has  static container open openable;
1189
 
Object top_of_wm "top of the sterilising machine",
1190
 
  with article "the",
1191
 
  has  static supporter;
1192
 
Object go_button "~go~ button"
1193
 
  with name "go" "button",
1194
 
       before [; Push, SwitchOn: "The power is off."; ],
1195
 
  has  static;
1196
 
 
1197
 
   *Note Exercise 85: Scope.
1198
 
 
1199
 
 
1200
 
File: inform,  Node: Answer 86,  Next: Answer 87,  Prev: Answer 85,  Up: Answers
1201
 
 
1202
 
Answer to Exercise 86: red sticky label
1203
 
=======================================
1204
 
 
1205
 
   The label object itself is not too bad:
1206
 
 
1207
 
Object -> label "red sticky label"
1208
 
  with name "red" "sticky" "label",
1209
 
       number 0,
1210
 
       before
1211
 
       [;  PutOn, Insert:
1212
 
               if (self.number~=0)
1213
 
               {   print "(first removing the label from ",
1214
 
                   (the) self.number, ")^"; self.number=0; move self to player;
1215
 
               }
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, ".";
1219
 
       ],
1220
 
       react_after
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, ".^";
1226
 
       ],
1227
 
       each_turn
1228
 
       [;  if (parent(self)~=0) self.number=0; ];
1229
 
 
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.
1234
 
 
1235
 
Global disable_self;
1236
 
[ InScope actor i1 i2;
1237
 
  if (label.number==0) rfalse; if (disable_self==1) rfalse;
1238
 
  disable_self=1;
1239
 
  i1 = TestScope(label, actor);
1240
 
  i2 = TestScope(label.number, actor);
1241
 
  disable_self=0;
1242
 
  if (i1~=0) rfalse;
1243
 
  if (i2~=0) PlaceInScope(label);
1244
 
  rfalse;
1245
 
];
1246
 
 
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).
1253
 
 
1254
 
   *Note Exercise 86: Scope.
1255
 
 
1256
 
 
1257
 
File: inform,  Node: Answer 87,  Next: Answer 88,  Prev: Answer 86,  Up: Answers
1258
 
 
1259
 
Answer to Exercise 87: "lock" and "unlock" inferring keys
1260
 
=========================================================
1261
 
 
1262
 
   Firstly, create an attribute is_key and give it to all the keys in
1263
 
the game.  Then:
1264
 
 
1265
 
Global assumed_key;
1266
 
[ DefaultLockSub;
1267
 
  print "(with ", (the) assumed_key, ")^"; <<Lock noun assumed_key>>;
1268
 
];
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;
1274
 
];
1275
 
Extend "lock" first * noun = DefaultLockTest -> DefaultLock;
1276
 
 
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.
1281
 
 
1282
 
   *Note Exercise 87: Helping the Parser.
1283
 
 
1284
 
 
1285
 
File: inform,  Node: Answer 88,  Next: Answer 89,  Prev: Answer 87,  Up: Answers
1286
 
 
1287
 
Answer to Exercise 88: quotations in boxes
1288
 
==========================================
1289
 
 
1290
 
Array quote_done -> 50;
1291
 
Global next_quote = -1;
1292
 
[ Quote i;
1293
 
  if (quote_done->i==0) { quote_done->i = 1; next_quote = i; }
1294
 
];
1295
 
[ AfterPrompt;
1296
 
  switch(next_quote)
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."
1300
 
             ""
1301
 
             "-- Ted Hughes, ~The Jaguar~";
1302
 
      1: ...
1303
 
  }
1304
 
  next_quote = -1;
1305
 
];
1306
 
 
1307
 
   *Note Exercise 88: Boxes.
1308
 
 
1309
 
 
1310
 
File: inform,  Node: Answer 89,  Next: Answer 90,  Prev: Answer 88,  Up: Answers
1311
 
 
1312
 
Answer to Exercise 89: Invisiclues hints
1313
 
========================================
1314
 
 
1315
 
   Note the magic line of assembly code here, which only works for
1316
 
Advanced games:
1317
 
 
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;
1322
 
  rtrue;
1323
 
];
1324
 
 
1325
 
And a typical menu item using it:
1326
 
 
1327
 
 if (menu_item==1)
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.";
1332
 
 }
1333
 
 
1334
 
   *Note Exercise 89: Boxes.
1335
 
 
1336
 
 
1337
 
File: inform,  Node: Answer 90,  Next: Answer 91,  Prev: Answer 89,  Up: Answers
1338
 
 
1339
 
Answer to Exercise 90: saving the character
1340
 
===========================================
1341
 
 
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.)
1346
 
 
1347
 
   *Note Exercise 90: Assembly Language.
1348
 
 
1349
 
 
1350
 
File: inform,  Node: Answer 91,  Next: Answer 92,  Prev: Answer 90,  Up: Answers
1351
 
 
1352
 
Answer to Exercise 91: title page
1353
 
=================================
1354
 
 
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
1357
 
on the safe side:
1358
 
 
1359
 
[ TitlePage i;
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);
1363
 
   print "                     RUINS^";
1364
 
   style roman; print "^^"; spaces(i);
1365
 
   print "         [Please press SPACE to begin.]^";
1366
 
   font on;
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."
1370
 
       ""
1371
 
       "-- William Shakespeare, ~Henry V~ I. ii. 163";
1372
 
   do { @read_char 1 0 0 i; } until (i==32 or 10 or 13);
1373
 
   @erase_window -1;
1374
 
];
1375
 
 
1376
 
   *Note Exercise 91: Assembly Language.
1377
 
 
1378
 
 
1379
 
File: inform,  Node: Answer 92,  Next: Answer 93,  Prev: Answer 91,  Up: Answers
1380
 
 
1381
 
Answer to Exercise 92: status line invisible
1382
 
============================================
1383
 
 
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:
1387
 
 
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;
1392
 
   spaces (width-1);
1393
 
   @set_cursor 1 2;  PrintShortName(location);
1394
 
   if (width > 76)
1395
 
   {   @set_cursor 1 posa; print "Score: ", sline1;
1396
 
       @set_cursor 1 posb; print "Moves: ", sline2;
1397
 
   }
1398
 
   if (width > 63 && width <= 76)
1399
 
   {   @set_cursor 1 posb; print sline1, "/", sline2;
1400
 
   }
1401
 
   @set_cursor 1 1; style roman; @set_window 0;
1402
 
];
1403
 
 
1404
 
   *Note Exercise 92: Assembly Language.
1405
 
 
1406
 
 
1407
 
File: inform,  Node: Answer 93,  Next: Answer 94,  Prev: Answer 92,  Up: Answers
1408
 
 
1409
 
Answer to Exercise 93: status line showing treasure
1410
 
===================================================
1411
 
 
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:
1415
 
 
1416
 
[ DrawStatusLine;
1417
 
   @split_window 1; @set_window 1; @set_cursor 1 1; style reverse;
1418
 
   spaces (0->33)-1;
1419
 
   @set_cursor 1 2;  PrintShortName(location);
1420
 
   if (treasures_found > 0)
1421
 
   {   @set_cursor 1 50; print "Treasure: ", treasures_found;
1422
 
   }
1423
 
   @set_cursor 1 1; style roman; @set_window 0;
1424
 
];
1425
 
 
1426
 
   *Note Exercise 93: Assembly Language.
1427
 
 
1428
 
 
1429
 
File: inform,  Node: Answer 94,  Next: Answer 95,  Prev: Answer 93,  Up: Answers
1430
 
 
1431
 
Answer to Exercise 94: status line with compass rose
1432
 
====================================================
1433
 
 
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
1436
 
vertical line.)
1437
 
 
1438
 
Constant U_POS 28; Constant W_POS 30; Constant C_POS 31;
1439
 
Constant E_POS 32; Constant IN_POS 34;
1440
 
[ DrawStatusLine i;
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)
1449
 
    {   ! First line
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"; }
1455
 
        ! Second line
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 "-"; }
1459
 
        ! Third line
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"; }
1465
 
    }
1466
 
    @set_cursor 1 1; style roman; @set_window 0; font on;
1467
 
];
1468
 
 
1469
 
   *Note Exercise 94: Assembly Language.
1470
 
 
1471
 
 
1472
 
File: inform,  Node: Answer 95,  Next: Answer 96,  Prev: Answer 94,  Up: Answers
1473
 
 
1474
 
Answer to Exercise 95: status line with centred room
1475
 
====================================================
1476
 
 
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
1479
 
time Replace with:
1480
 
 
1481
 
Array printed_text table 64;
1482
 
[ DrawStatusLine i j;
1483
 
  i = 0->33; if (i==0) i=80;
1484
 
  font off;
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;
1490
 
  @output_stream -3;
1491
 
  j=(i-(printed_text-->0))/2;
1492
 
  @set_cursor 1 j; print (name) location; spaces(j-1);
1493
 
  style roman;
1494
 
  @buffer_mode 1; @set_window 0; font on;
1495
 
];
1496
 
 
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.)
1501
 
 
1502
 
   *Note Exercise 95: Assembly Language.
1503
 
 
1504
 
 
1505
 
File: inform,  Node: Answer 96,  Prev: Answer 95,  Up: Answers
1506
 
 
1507
 
Answer to Exercise 96: printf routine
1508
 
=====================================
1509
 
 
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.
1514
 
 
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;
1522
 
  j=printed_text-->0;
1523
 
  for (k=2:k<j+2:k++)
1524
 
  {   if (printed_text->k == '%')
1525
 
      {   switch(printed_text->(++k))
1526
 
          {   '%': print "%";
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 **>";
1532
 
          }
1533
 
      }
1534
 
      else print (char) printed_text->k;
1535
 
  }
1536
 
];
1537
 
 
1538
 
   *Note Exercise 96: Assembly Language.
1539
 
 
1540
 
 
1541
 
File: inform,  Node: Index,  Next: Concept Index,  Prev: Answers,  Up: Top
1542
 
 
1543
 
Index of Attributes, Properties, Objects, and Routines
1544
 
******************************************************
1545
 
 
1546
 
* Menu:
1547
 
 
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.
1580
 
* door:                                 Attributes.
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.
1600
 
* life:                                 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.
1608
 
* male:                                 Attributes.
1609
 
* moved:                                Attributes.
1610
 
* name:                                 Properties.
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.
1619
 
* on:                                   Attributes.
1620
 
* open:                                 Attributes.
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.
1675
 
* worn:                                 Attributes.
1676
 
* WriteListFrom:                        Objects and Routines.
1677
 
* YesOrNo:                              Objects and Routines.
1678
 
* ZRegion:                              Objects and Routines.