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

« back to all changes in this revision

Viewing changes to demos/toyshop.inf

  • 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
 
! ----------------------------------------------------------------------------
2
 
!  Toyshop 961111                   One of the standard Inform 6 example games
3
 
!
4
 
!  This is not a real game.  The main example game for Inform is "Advent",
5
 
!  a port of Colossal Cave.  Since that's something of an antique, and most
6
 
!  of the objects in it are rather simple, this is a collection of more
7
 
!  exotic features and peculiar objects.  Note that "Advent" has plenty of
8
 
!  interesting doors, a good lantern and bottled oil and water, so those
9
 
!  won't be part of the Toyshop.
10
 
!
11
 
!  Needs Inform 6 with library 6/1 or later to compile.
12
 
!
13
 
!  To win, simply find 6 interesting things to do and leave by the main exit!
14
 
!
15
 
!       Object            Is an example of...
16
 
!
17
 
!  >SA  satchel           Container into which the game silently puts things
18
 
!  >HE  helium balloon    Something moving under the control of a daemon
19
 
!  >CA  little red car    Vehicle, and pushable from place to place
20
 
!  >PF  padded floor      Scenery present in several rooms at once
21
 
!  >GR  hand grenade      Timed events: a grenade and its pin
22
 
!  >MA  matchbook         Simple fire and matches; changing inventory styles
23
 
!  >WC  white candles     A stock of objects identical to each other
24
 
!  >GL  white gloves      Two independent objects which can behave as a pair
25
 
!  >CO  green cone        Easy before and after rules
26
 
!  >HW  high window       Starting and stopping daemons
27
 
!  >BC  bolted cupboard   A typical locked container (with key)
28
 
!  >GB  glass box         Container light can get through
29
 
!  >SB  steel box         Container light can't get through
30
 
!  >BL  building blocks   A complicated class definition; piles of objects
31
 
!  >CH  Christopher       Someone you can talk to, and persuade to do things
32
 
!  >OF  Office            Rules about moving in a particular direction
33
 
!  >TB  toothed bag       A container with ideas about what it will allow
34
 
!  >SL  spirit level      Something to put on top of things
35
 
!  >BB  blackboard        A blackboard to write messages on
36
 
!
37
 
!  (The code is marked with >SA and so on for easy access with a text editor)
38
 
! ----------------------------------------------------------------------------
39
 
Constant DEBUG;
40
 
Constant Story "TOYSHOP";
41
 
Constant Headline "^An Interactive Demonstration^
42
 
             Copyright (c) 1994 by Graham Nelson. All rights given away.^";
43
 
Release 4;
44
 
Serial "961111";   !   This sets the serial date to the date of this source
45
 
                   !   file, not to the date of compilation.
46
 
 
47
 
!   Now we serve notice to Inform that we do not wish to use the standard
48
 
!   routine for the Burn action, and will instead be defining our own:
49
 
 
50
 
Replace BurnSub;
51
 
 
52
 
!   Next include the first of the three standard library files:
53
 
 
54
 
Include "Parser";
55
 
 
56
 
! ----------------------------------------------------------------------------
57
 
! >SA  Ungenerously, the player can only carry at most 4 things, but there's
58
 
!      a satchel to carry other things around in...
59
 
! ----------------------------------------------------------------------------
60
 
 
61
 
Constant MAX_CARRIED = 4;
62
 
Constant SACK_OBJECT = satchel;
63
 
 
64
 
Object satchel "satchel"
65
 
  with description "Big and with a smile painted on it.",
66
 
       name "satchel", article "your",
67
 
       when_closed "Your satchel lies on the floor.",
68
 
       when_open "Your satchel lies open on the floor.",
69
 
  has  container open openable;
70
 
 
71
 
!   We're going to use the most elaborate scoring system the
72
 
!   library provides (even though we're going to make the six tasks all
73
 
!   score only 1 point each), so we define all this...
74
 
 
75
 
Constant TASKS_PROVIDED;
76
 
Constant NUMBER_TASKS = 6;
77
 
Array    task_scores  -> 1 1 1 1 1 1;
78
 
Constant MAX_SCORE = 6;
79
 
 
80
 
!   And include the library of standard verbs and actions.
81
 
 
82
 
Include "VerbLib";
83
 
 
84
 
! ----------------------------------------------------------------------------
85
 
!   Off we go into the Toyshop...
86
 
! ----------------------------------------------------------------------------
87
 
 
88
 
Class Toyroom
89
 
  has  light;
90
 
 
91
 
Toyroom Toyshop "Toyshop"
92
 
  with description
93
 
          "The centre of a long east-west hall. Shelves are lined 
94
 
           with toys, painted clowns face you from the walls and 
95
 
           the floor is lightly padded with colourful mats. A doorway 
96
 
           leads north, with a red warning triangle above it.",
97
 
       name "clowns" "painted" "shelves" "triangle",
98
 
       e_to East_End, w_to West_End, n_to Danger_Zone;
99
 
 
100
 
Object -> chair "high chair"
101
 
  with name "chair" "high"
102
 
  has  supporter enterable;
103
 
 
104
 
! ----------------------------------------------------------------------------
105
 
! >HE  The balloon is completely self-contained as a piece of code, except
106
 
!      that it does not set itself going (though even this could have been
107
 
!      arranged): it is set going in the Initialise() routine.
108
 
!
109
 
!   Notice that the "after" for Drop takes away the "moved" attribute.
110
 
!   This is one way to ensure that the "initial" message will always be
111
 
!   the one displayed.  (Alternatively, we could have given it a "describe"
112
 
!   property.)
113
 
! ----------------------------------------------------------------------------
114
 
 
115
 
Object -> balloon "helium balloon"
116
 
  with description "Blue, with a yellow smile.",
117
 
       name "helium" "balloon" "blue" "string",
118
 
       initial "A balloon nestles on the ceiling, its long string hanging.",
119
 
       before
120
 
       [; Attack: remove self; StopDaemon(self);
121
 
                "Easily, you burst the balloon. Pop!^^
122
 
                 Shame it was irreplaceable, really.";
123
 
       ],
124
 
       after
125
 
       [; Take: "You take the balloon by its string. It's buoyant!";
126
 
          Drop: give balloon ~moved;
127
 
                "The balloon rises gracefully to the ceiling.";
128
 
       ],
129
 
       daemon
130
 
       [ from_room to_room;
131
 
          if (random(3)~=1) rfalse;
132
 
          from_room=parent(self);
133
 
          if (from_room==East_End or West_End) to_room=Toyshop;
134
 
          if (from_room==Toyshop)
135
 
          {   if (random(2)==1) to_room=East_End;
136
 
              else to_room=West_End;
137
 
          }
138
 
          if (to_room==0) rfalse;
139
 
          move self to to_room;
140
 
          if (location==from_room)
141
 
            "^A breeze blows the balloon away to the ", (name) to_room, ".";
142
 
          if (location==to_room)
143
 
            "^A breeze blows the balloon in from the ", (name) from_room, ".";
144
 
       ];
145
 
 
146
 
! ----------------------------------------------------------------------------
147
 
! >CA  There are two exceptions to the ordinary before/after rules, for
148
 
!      vehicles and things which can be pushed from place to place: this car
149
 
!      demonstrates both at once.
150
 
!
151
 
!   The "before" for PushDir (push in a named direction) must call
152
 
!   AllowPushDir and then return true to signify that the push is legal.
153
 
!
154
 
!   The "before" for Go must return true to signify that travelling in
155
 
!   the object is legal.  (Note that it must also be enterable.)
156
 
! ----------------------------------------------------------------------------
157
 
 
158
 
Object -> car "little red car"
159
 
  with name "little" "red" "car" "kar1",
160
 
       description "Large enough to sit inside. Among the controls is a 
161
 
                 prominent on/off switch. The numberplate is KAR 1.",
162
 
       when_on  "The red car sits here, its engine still running.",
163
 
       when_off "A little red car is parked here.",
164
 
       before
165
 
       [; PushDir: AllowPushDir(); rtrue;
166
 
          Go: if (car has on) { Achieved(1); "Brmm!  Brmm!"; }
167
 
              print "(The ignition is off at the moment.)^";
168
 
       ],
169
 
       after
170
 
       [; PushDir: "The car rolls very slowly as you push it.";
171
 
       ],
172
 
  has  switchable enterable static container open;
173
 
 
174
 
Object -> -> "small note"
175
 
  with name "small" "note",
176
 
       description
177
 
           "  !!!! FROBOZZ MAGIC CAR COMPANY !!!!^
178
 
           ^Hello, Driver!^
179
 
           ^Instructions for use:^
180
 
           ^Switch on the ignition and off you go!^
181
 
           ^Warranty:^
182
 
           ^This car is guaranteed against all defects for a period of 
183
 
            76 milliseconds from date of purchase or until used, 
184
 
            whichever comes first.^
185
 
           ^Good Luck!";
186
 
 
187
 
! ----------------------------------------------------------------------------
188
 
! >PF  An example of an object spread across several (three) rooms:
189
 
! ----------------------------------------------------------------------------
190
 
 
191
 
Object padded_floor "padded floor"
192
 
  with name "padded" "floor" "mats" "padding",
193
 
       description "To protect little children and adventurers.",
194
 
       before
195
 
       [; Take: "It is protected from little children and adventurers.";
196
 
       ],
197
 
       found_in East_End Toyshop West_End
198
 
  has  scenery;
199
 
 
200
 
! ----------------------------------------------------------------------------
201
 
 
202
 
Toyroom Danger_Zone "Danger Zone"
203
 
  with description
204
 
          "This is the Danger Zone, which you should know better 
205
 
           than to go into. A single door leads back south.",
206
 
       s_to Toyshop;
207
 
 
208
 
! ----------------------------------------------------------------------------
209
 
! >GR  A classic example of a timer (or, as some people call them and
210
 
!      appropriately so in this case, a fuse).  To demonstrate stopping
211
 
!      a timer before the alarm (and for fun), there is also a pin:
212
 
! ----------------------------------------------------------------------------
213
 
 
214
 
Object -> grenade "nasty-looking hand grenade"
215
 
  with name "hand" "grenade" "nasty" "nasty-looking",
216
 
       initial "A nasty-looking hand grenade (there is no other kind) 
217
 
                rolls about irresponsibly on the floor.",
218
 
       description "Not recommended for children under 90.",
219
 
       before
220
 
       [; Pull: if (self has general) "Too late for that.";
221
 
              StartTimer(self, 5); give self general;
222
 
              move the_pin to player;
223
 
              "You pull the pin out, an irrevocable act.";
224
 
       ],
225
 
       time_left 0,
226
 
       time_out
227
 
       [;  deadflag=1;
228
 
           "^An immense explosion suddenly demolishes the toyshop!^^
229
 
             Will you never learn?";
230
 
       ],
231
 
  has  transparent;
232
 
 
233
 
Object -> -> the_pin "pin"
234
 
  with name "pin",
235
 
       description "The pin is designed to be easy to pull.",
236
 
       before
237
 
       [; Take, Pull: if (self in grenade) <<Pull grenade>>;
238
 
          Insert:
239
 
              if (self notin grenade && second==grenade)
240
 
              {   StopTimer(grenade); move self to grenade;
241
 
                  give grenade ~general;
242
 
                  "Amazing!  You got the pin back into the grenade!";
243
 
              }
244
 
       ];
245
 
 
246
 
! ----------------------------------------------------------------------------
247
 
! >MA  This is a matchbook of five matches, which is quite simple in that you
248
 
!      can only actually have one match at a time: otherwise, it's quite
249
 
!      a full implementation.  Note that the inventory lines for the match
250
 
!      and the matchbook are coded here.  Note also that the "match" object
251
 
!      returns to the book even when the book is empty, so that the parser
252
 
!      will still understand requests for matches - which the "before" rule,
253
 
!      which automatically removes matches when needed, can then turn down.
254
 
!
255
 
!      The matchbook has a daemon whose job is to tidy up lost matches.  One
256
 
!      might expect this rule to be coded with an "after" routine, to trap
257
 
!      the player dropping matches.  But suppose there were a magpie in the
258
 
!      game, and it flew down and stole the match but left the matchbook!
259
 
!      As it happens there isn't, but this is better form.
260
 
! ----------------------------------------------------------------------------
261
 
 
262
 
Object -> matchbook "matchbook"
263
 
  with name "matchbook" "book" "matches",
264
 
       number 5,
265
 
       before
266
 
       [; Burn: if (match has light)
267
 
                {   remove match; remove matchbook;
268
 
                    "What a waste of matches!";
269
 
                }
270
 
       ],
271
 
       invent
272
 
       [;  if (inventory_stage==2)
273
 
           {   switch(self.number)
274
 
               {   0: print " (empty)";
275
 
                   1: print " (1 match left)";
276
 
                   default: print " (", self.number, " matches left)";
277
 
               }
278
 
           }
279
 
       ],
280
 
       description
281
 
       [;  print "The cover advertisement reads 
282
 
                  ~Curses - Adventure of a Lunchtime~. The book ";
283
 
           switch(self.number)
284
 
           {   0: "is empty.";
285
 
               1: "has a single match left.";
286
 
               default:
287
 
                   print_ret "contains ", self.number, " matches.";
288
 
           }
289
 
       ],
290
 
       daemon
291
 
       [;   if (match notin matchbook && match notin player)
292
 
            {   move match to matchbook;
293
 
                if (match has light)
294
 
                {   give match ~light; StopTimer(match); }
295
 
                StopDaemon(self);
296
 
            }
297
 
       ],
298
 
  has  transparent;
299
 
 
300
 
Object -> -> match "match"
301
 
  with parse_name
302
 
       [ i j;   if (self has light) j='burning'; else j='unlit';
303
 
                while (NextWord()=='match' or j) i++;
304
 
                return i;
305
 
       ],
306
 
       article "an",
307
 
       before
308
 
       [ i; if (self in matchbook)
309
 
            {   i=matchbook.number;
310
 
                if (i==0) "There are no matches left in the book.";
311
 
                i--; matchbook.number=i;
312
 
                move self to player; StartDaemon(matchbook);
313
 
                print "(taking a match from the book, which ";
314
 
                if (i==0) print "is now empty)^";
315
 
                if (i==1) print "has one more left)^";
316
 
                if (i>1)  print "has ", i, " left)^";
317
 
                self.article = "an";
318
 
            }
319
 
            Take, Remove: if (self in player) "Done.";
320
 
            Burn:
321
 
                if (self has light) "The match is already alight.";
322
 
                if (matchbook notin player)
323
 
                   "You need the matchbook to strike the match.";
324
 
                give self light; StartTimer(self, 2+random(3));
325
 
                self.article = "a";
326
 
                "You strike the match.";
327
 
       ],
328
 
       short_name
329
 
       [;   if (self has light) print "burning match";
330
 
                           else print "unlit match";
331
 
            rtrue;
332
 
       ],
333
 
 
334
 
       time_left,
335
 
       time_out
336
 
       [;   move self to matchbook; give self ~light;
337
 
            "^You drop the match as the flame reaches your finger.";
338
 
       ];
339
 
 
340
 
! ----------------------------------------------------------------------------
341
 
! >WC  A box of eight candles.
342
 
!
343
 
!      This is a simple way to code up duplicate objects.  For one thing,
344
 
!      > take candles
345
 
!      does not quite behave as we would hope: it'll only pick up one candle
346
 
!      (though "> take four candles" will work).  See the "Block" class
347
 
!      below for a way to make good.
348
 
!
349
 
!      If we had needed a much greater number of candles, we could have used
350
 
!      object creation and destruction during play.  See the "Ticket" class
351
 
!      from the "Balances" example game.
352
 
! ----------------------------------------------------------------------------
353
 
 
354
 
Class  Candle
355
 
  with name "wax" "candle" "candles",
356
 
       short_name "wax candle", plural "wax candles",
357
 
       description "It looks just like all the other candles.",
358
 
       before
359
 
       [; Burn: "Disappointingly, the wick refuses to burn."; ];
360
 
 
361
 
Object -> "grey tin box"
362
 
  with name "tin" "box" "grey",
363
 
       description
364
 
           "A grey tin box of ~Major's Candles~.",
365
 
  has  container openable;
366
 
 
367
 
Candle -> ->;
368
 
Candle -> ->;
369
 
Candle -> ->;
370
 
Candle -> ->;
371
 
Candle -> ->;
372
 
Candle -> ->;
373
 
Candle -> ->;
374
 
Candle -> ->;
375
 
 
376
 
Toyroom East_End "East End"
377
 
  with name "dolls" "nurses",
378
 
       description
379
 
          "The eastern end of the toyshop is pink, and dolls and 
380
 
           nurses line the shelves right up to the high window. 
381
 
           A dark doorway leads to a northern side chamber.",
382
 
       w_to Toyshop, n_to DarkRoom;
383
 
 
384
 
! ----------------------------------------------------------------------------
385
 
! >GL  The following example, suggested to the author by Richard Tucker,
386
 
!      demonstrates an apparently tricky case of objects with associated
387
 
!   sub-objects.  The pair of white gloves behaves just like any other item
388
 
!   of clothing - but the player can also use the left and right gloves
389
 
!   independently, can take away or wear only one and so on.  When they
390
 
!   come back together (even in a cupboard, say, or on a mantelpiece)
391
 
!   they are called a pair again.
392
 
!
393
 
!   We can do this with only three objects, one daemon and one rule.
394
 
!   
395
 
!   When the gloves are together, and the player refers to an individual
396
 
!   glove, the before rule splits up the pair and starts the daemon.
397
 
!   Once active, the daemon tries every turn to re-join them into a pair.
398
 
!   (If it succeeds, it turns itself off.)
399
 
!
400
 
!   Note that the "pair of gloves" object has the "general" attribute exactly
401
 
!   when the gloves are apart.  Otherwise the pair-object contains both
402
 
!   glove objects, and has "transparent" so that the parser knows the player
403
 
!   can see and refer to them.
404
 
! ----------------------------------------------------------------------------
405
 
 
406
 
Object -> gloves "white gloves"
407
 
  with article "a pair of",
408
 
       name "white" "gloves" "pair" "of",
409
 
       daemon
410
 
       [;  if (parent(right_glove) ~= parent(left_glove)) return;
411
 
           if ((left_glove has worn && right_glove hasnt worn)
412
 
               || (left_glove hasnt worn && right_glove has worn)) return;
413
 
           if (left_glove has worn) give gloves worn; else give gloves ~worn;
414
 
           move gloves to parent(right_glove); give gloves ~general;
415
 
 
416
 
           move right_glove to gloves; move left_glove to gloves;
417
 
           give right_glove ~worn;     give left_glove ~worn;
418
 
           
419
 
           StopDaemon(self);
420
 
       ],
421
 
  has  clothing transparent;
422
 
 
423
 
Class  Glove
424
 
  with article "the",
425
 
       name "white" "glove",
426
 
       before
427
 
       [;  if (self notin gloves) rfalse;
428
 
           move left_glove to parent(gloves); move right_glove to parent(gloves);
429
 
           if (gloves has worn)
430
 
           {   give left_glove worn; give right_glove worn;
431
 
           }
432
 
           give gloves general; remove gloves;
433
 
           StartDaemon(gloves);
434
 
       ],
435
 
  has  clothing;
436
 
 
437
 
Glove -> -> left_glove "left glove"
438
 
  with description "White silk, monogrammed with a scarlet R.",
439
 
       name "left";
440
 
Glove -> -> right_glove "right glove"
441
 
  with description "White silk, monogrammed with a scarlet T.",
442
 
       name "right";
443
 
 
444
 
! ----------------------------------------------------------------------------
445
 
!   ...and that's all: the "gloves" code is self-contained.
446
 
!
447
 
!   Exercise for the reader: hide a (sharp) jewel inside the left glove.
448
 
!     (Alter the glove class to make them containers open only when not worn.
449
 
!      Add two "after" rules to warn the player if there's something sharp
450
 
!      to the touch, one for putting on the pair of gloves, one for putting on
451
 
!      an individual glove.)
452
 
! ----------------------------------------------------------------------------
453
 
 
454
 
 
455
 
! ----------------------------------------------------------------------------
456
 
! >CO  A traditional Inform example object:
457
 
! ----------------------------------------------------------------------------
458
 
 
459
 
Object -> cone "green cone"
460
 
  with name "green" "cone" "emerald" "marzipan",
461
 
       describe
462
 
       [; if (cone has moved)
463
 
              "^A misshapen cone of green marzipan sits here.";
464
 
          "^Nearby is an emerald green cone, one foot high.";
465
 
       ],
466
 
       description "The cone seems to be made of emerald-coloured 
467
 
                    marzipan.",
468
 
       before
469
 
       [; Eat: if (random(100) <= 30)
470
 
               {   deadflag = 1;
471
 
                   "Unfortunately, you seem to be allergic to almonds.";
472
 
               }
473
 
               "You nibble at a corner of the cone.";
474
 
       ],
475
 
       after
476
 
       [; Take: "Taken. (Your hands are smeared with marzipan.)";
477
 
          Drop: cone.description = "The cone is a vague green mess.";
478
 
                "The cone drops to the floor and sags a little.";
479
 
       ],
480
 
  has  edible;
481
 
 
482
 
! ----------------------------------------------------------------------------
483
 
! >HW  It's the draught from this slightly-concealed window which propels the
484
 
!      balloon:
485
 
! ----------------------------------------------------------------------------
486
 
 
487
 
Object -> "high window"
488
 
  with name "high" "window",
489
 
       description
490
 
       [;  print "A narrow, high window ";
491
 
           if (self has open) "through which a draught blows.";
492
 
           "which is closed.";
493
 
       ],
494
 
       after
495
 
       [; Open: StartDaemon(balloon);
496
 
          Close: Achieved(2); StopDaemon(balloon);
497
 
       ],
498
 
  has  scenery openable open;
499
 
 
500
 
! ----------------------------------------------------------------------------
501
 
! >BC  A typical locked container, containing a rather pathetic prize...
502
 
! ----------------------------------------------------------------------------
503
 
 
504
 
Object -> "bolted cupboard"
505
 
  with name "bolted" "cupboard",
506
 
       describe
507
 
       [; if (self hasnt open) "^A shut cupboard is bolted to one wall.";
508
 
          "^Bolted up on one wall is an open cupboard.";
509
 
       ],
510
 
       with_key key
511
 
  has  locked container openable lockable static;
512
 
 
513
 
Object -> -> "boiled sweet"
514
 
  with name "boiled" "sweet",
515
 
       after
516
 
       [; Eat: Achieved(0);
517
 
               "It takes an irritatingly long time to eat.";
518
 
       ],
519
 
  has  edible;
520
 
 
521
 
! ----------------------------------------------------------------------------
522
 
! >GB  This is really to demonstrate "transparent".  Shutting up the glowing
523
 
! >SB  ball in the glass box does not make the room go dark: shutting it up
524
 
!      in the steel box does.  Also, you can examine things in the glass box
525
 
!   even when the glass box is shut.
526
 
!   (Note also that the Dark Room is explicitly told not to have "light",
527
 
!   which it would otherwise inherit from the "Toyroom" class.)
528
 
! ----------------------------------------------------------------------------
529
 
 
530
 
Toyroom DarkRoom "Dark Room"
531
 
  with description "A featureless storage room, hardly worth illumination.",
532
 
       cant_go "The only exit is back south.",
533
 
       s_to East_End
534
 
  has  ~light;
535
 
 
536
 
Object -> "glass box with a lid"
537
 
  with name "glass" "box" "with" "lid"
538
 
  has  container transparent openable open;
539
 
 
540
 
Object -> "steel box with a lid"
541
 
  with name "steel" "box" "with" "lid"
542
 
  has  container openable open;
543
 
 
544
 
 
545
 
Toyroom West_End "West End"
546
 
  with name "soldiers" "model" "aircraft" "planes",
547
 
       description
548
 
          "The western end of the toyshop is blue, and soldiers and 
549
 
           model aircraft line the shelves. A small office lies to 
550
 
           the south.",
551
 
       e_to Toyshop, s_to Office;
552
 
 
553
 
! ----------------------------------------------------------------------------
554
 
! >BL  The class Block provides for stackable building blocks.
555
 
!
556
 
!   Note that with the "describe" routine missing, the game would still
557
 
!   correctly describe stacks of blocks: just a little less elegantly.
558
 
! ----------------------------------------------------------------------------
559
 
 
560
 
Class  Block
561
 
  with description "Just a child's building block, four inches on a side.",
562
 
 
563
 
       !   The parse_name routine below ensures that "take blocks"
564
 
       !   works correctly:
565
 
 
566
 
       parse_name
567
 
       [ i j;
568
 
         for (::)
569
 
         {   j=NextWord();
570
 
             if (j=='block' or 'cube' or 'building' or (self.name)) i++;
571
 
             else
572
 
             {   if (j=='blocks' or 'cubes')
573
 
                 {   parser_action=##PluralFound; i++; }
574
 
                 else return i;
575
 
             }
576
 
         }
577
 
       ],
578
 
 
579
 
       describe
580
 
       [ c d e;
581
 
           d = child(self);
582
 
           while (d~=0 && d ofclass Block)
583
 
           {   c++; e=d; d=child(d); }
584
 
           if (c==0) rfalse;
585
 
           print "^There is a pile of building blocks here, ";
586
 
           while (c>=0)
587
 
           {   print (address) e.name;  ! Sneaky: print the "name" out
588
 
               if (c>0) print " on ";   ! using its dictionary address
589
 
               c--; e=parent(e);
590
 
           }
591
 
           ".";
592
 
       ],
593
 
       before
594
 
       [ c;
595
 
         PutOn:
596
 
           if (second ofclass Block)
597
 
           {   if (child(second)~=0 && child(second) ofclass Block)
598
 
                   "There's no room on the top of one cube for two more, side 
599
 
                    by side.";
600
 
           }
601
 
           else
602
 
               print "(They're really intended 
603
 
                      to be piled on top of each other.)^";
604
 
           c=second; while (c ofclass Block) c=parent(c);
605
 
           if (c~=location or mantelpiece) "Too unsteady a base.";
606
 
       ],
607
 
       after
608
 
       [ c stack;
609
 
         PutOn:
610
 
           stack=noun;
611
 
           while (parent(stack) ofclass Block) { stack=parent(stack); c++; }
612
 
           if (c<2)
613
 
           {   if (Chris has general) rtrue;
614
 
               rfalse;
615
 
           }
616
 
           if (c==2) "The pile of three cubes is unsteady, but viable.";
617
 
           if (Chris has general)
618
 
           {   Achieved(3);
619
 
               "^Expertly he keeps the pile of four cubes stable.";
620
 
           }
621
 
           stack=noun;
622
 
           while (parent(stack) ofclass Block)
623
 
           {   c=stack; stack=parent(stack); move c to location; }
624
 
           "The pile of four cubes wobbles, wobbles, steadies... and suddenly 
625
 
            collapses!";
626
 
         Take:
627
 
           stack=child(noun); if (stack==0) rfalse;
628
 
           while (stack~=0)
629
 
           { c=stack; stack=child(stack); move c to location; }
630
 
           "Your pile of cubes is collapsed as a result.";
631
 
       ],
632
 
  has  supporter;
633
 
 
634
 
Block -> "green cube"
635
 
  with name "green";
636
 
Block -> "red cube"
637
 
  with name "red";
638
 
Block -> "yellow cube"
639
 
  with name "yellow";
640
 
Block -> "blue cube"
641
 
  with name "blue";
642
 
 
643
 
! ----------------------------------------------------------------------------
644
 
! >CH  A guest appearance by my cousin Christopher, aged six (*), who plays
645
 
!      with one thing at a time (easily forgetting which). Being "transparent"
646
 
!      (no reflection on him!) means the parser allows the player to examine
647
 
!      whatever he's playing with... but not to take it from him.
648
 
!      (* In 1993, when this game was first written.)
649
 
! ----------------------------------------------------------------------------
650
 
 
651
 
Object -> Chris "Christopher"
652
 
  with name "child" "boy" "chris" "christopher",
653
 
       describe
654
 
       [;  print "^A boy called Christopher sits here";
655
 
           if (child(Chris) ~= nothing)
656
 
               print ", playing with ", (a) child(Chris);
657
 
           ".";
658
 
       ],
659
 
       life
660
 
       [ x;
661
 
           Ask:
662
 
              switch(second)
663
 
              {   'juggling', 'fluorescent', 'ball': "~That's mine!~";
664
 
                  'helium', 'balloon': "Christopher yawns.";
665
 
                  'cube', 'cubes': "~Bet I can make a higher tower than you.~";
666
 
                  'toys', 'toyshop': "~Isn't it fabulous here?~";
667
 
                  default: "~Dunno.~";
668
 
              }
669
 
           Answer:
670
 
              switch(noun)
671
 
              {   'hello', 'hallo', 'hi':
672
 
                       "~Hello,~ says Christopher cheerfully.";
673
 
                  default: "Christopher seems preoccupied.";
674
 
              }
675
 
           Attack: remove self;
676
 
             "Christopher makes a run for it, effortlessly slipping past you!";
677
 
           Kiss: "~That's soppy, that is.~";
678
 
           Give:
679
 
             if (noun==balloon) "He's too bored by the balloon.";
680
 
             x=child(Chris);
681
 
             if (x~=0)
682
 
             {   move x to location;
683
 
                 print "He forgets about ", (the) x, " and ";
684
 
             }
685
 
             else print "He ";
686
 
             print "eagerly grabs ", (the) noun; move noun to Chris; ".";
687
 
       ],
688
 
       orders
689
 
       [;  Drop: if (noun in Chris) "~Won't!  It's mine!~";
690
 
           Take: "Christopher can't be bothered.";
691
 
           Give: if (second==player) "~Get your own!~";
692
 
           Go: "~But I like it here!~";
693
 
           PutOn: if (noun notin Chris) "He is mightily confused.";
694
 
                 if (~~(noun ofclass Block && second ofclass Block))
695
 
                     "He can't see the point of this.";
696
 
                 print "Christopher leans over with great concentration 
697
 
                     and does so.^";
698
 
                 move noun to player; give self general;
699
 
                 <PutOn noun second>;
700
 
                 give self ~general; rtrue;
701
 
       ],
702
 
       each_turn
703
 
       [;  if (random(3)~=1) rtrue;
704
 
           print "^Christopher ";
705
 
           switch(random(4))
706
 
           {  1: "yawns.";     2: "frowns.";
707
 
              3: "stretches."; 4: "hums tonelessly.";
708
 
           }
709
 
       ],
710
 
  has  animate proper transparent;
711
 
 
712
 
Object "fluorescent juggling ball" Chris
713
 
  with initial "On the floor is a fluorescent juggling ball!",
714
 
       name "fluorescent" "juggling" "ball",
715
 
       description "It glows with soft light."
716
 
  has  light;
717
 
 
718
 
! ----------------------------------------------------------------------------
719
 
! >OF  A simple movement rule.
720
 
! ----------------------------------------------------------------------------
721
 
 
722
 
Toyroom Office "Office"
723
 
  with description
724
 
          "A small, grey office, with a broad stone mantelpiece. 
725
 
           In the east wall is a doorway marked ~Exit~, and the Toyshop, 
726
 
           of course, lies north.",
727
 
       cant_go "The Toyshop floor lies north.",
728
 
       n_to West_End,
729
 
       e_to
730
 
       [; if (score~=MAX_SCORE)
731
 
              "A gong sounds. ~You cannot leave the Toyshop until 
732
 
               you have done six interesting things!~";
733
 
          deadflag=2;
734
 
          "A gong sounds. ~Congratulations!  You may now leave the Toyshop 
735
 
           and begin writing your own Inform game!~";
736
 
       ];
737
 
 
738
 
! ----------------------------------------------------------------------------
739
 
! >TB  A somewhat acquisitive container... but it can be taught to behave.
740
 
! ----------------------------------------------------------------------------
741
 
 
742
 
Object -> "toothed bag"
743
 
  with name "toothed" "bag",
744
 
       initial "In one corner is a curious, toothed bag.",
745
 
       description "A capacious bag with a toothed mouth.",
746
 
       before
747
 
       [; LetGo: "The bag defiantly bites itself 
748
 
                  shut on your hand until you desist.";
749
 
       ],
750
 
       after
751
 
       [; Receive:
752
 
              if (noun==cone)
753
 
              {   self.before=0; self.after=0;
754
 
                  "The bag wriggles interminably as it tries 
755
 
                   to eat the enormous mass of marzipan. That'll 
756
 
                   teach it.";
757
 
              }
758
 
              "The bag wriggles hideously as it swallows ", (the) noun, ".";
759
 
       ],
760
 
  has  container open;
761
 
 
762
 
! ----------------------------------------------------------------------------
763
 
! >SL  Which can be put on the mantelpiece: the first time this is done, the
764
 
!      game randomly decides which end is higher, and sticks to this decision.
765
 
! ----------------------------------------------------------------------------
766
 
 
767
 
Object -> -> spirit_level "spirit level"
768
 
  with name "spirit" "level" "wood" "flask",
769
 
       number 0,
770
 
       description "A length of wood containing a flask of viscous 
771
 
           green liquid, in which a bubble is trapped.",
772
 
       before
773
 
       [; Examine:
774
 
          if (spirit_level in mantelpiece)
775
 
          {   print "The bubble is at the ";
776
 
              if (self.number==1) "northeast end.";
777
 
              "southeast end.";
778
 
          } 
779
 
       ],
780
 
       after
781
 
       [; PutOn: if (second~=mantelpiece) rfalse;
782
 
           if (spirit_level hasnt general) self.number=random(2);
783
 
           give spirit_level general; Achieved(4);
784
 
           print "You put the spirit level on the mantelpiece, 
785
 
                  and the bubble slowly drifts towards the ";
786
 
           if (self.number==1) "northeast.";
787
 
           "southwest.";
788
 
       ];
789
 
 
790
 
Object -> mantelpiece "mantelpiece"
791
 
  with name "mantel" "mantle" "piece" "mantelpiece"
792
 
  has  scenery supporter;
793
 
 
794
 
Object -> -> key "iron key"
795
 
  with name "iron" "key", article "an";
796
 
 
797
 
! ----------------------------------------------------------------------------
798
 
! >BB  A blackboard which can be written on or wiped clear.
799
 
! ----------------------------------------------------------------------------
800
 
 
801
 
Object -> -> chalk "stick of chalk"
802
 
  with name "stick" "of" "chalk";
803
 
 
804
 
Array boardtext string 64;
805
 
 
806
 
Object -> blackboard "blackboard"
807
 
  with name "board" "blackboard" "black",
808
 
       describe
809
 
       [;  <<Examine self>>; ],
810
 
       before
811
 
       [ i f;
812
 
           Examine:
813
 
               for (i=1:i<=boardtext->0:i++)
814
 
                   if (boardtext->i~=' ' or 0) f=1;
815
 
               if (f==0)
816
 
               {   print "^The office blackboard is wiped clean.^";
817
 
                   if (self hasnt general)
818
 
                   {   give self general;
819
 
                       "^[To write on it, try   > write ~message...~]";
820
 
                   }
821
 
                   rtrue;
822
 
               }
823
 
               print "^The office blackboard bears the message:^    ";
824
 
               for (i=1:i<=boardtext->0:i++)
825
 
               {   f=boardtext->i;
826
 
                   if (f~=0) print (char) f;
827
 
               }
828
 
               new_line; rtrue;
829
 
           Rub: for (i=1:i<=boardtext->0:i++) boardtext->i = ' ';
830
 
                  "You wipe the blackboard clean.";
831
 
       ],
832
 
  has  static;
833
 
 
834
 
Global from_char; Global to_char;
835
 
[ QuotedText i j f;
836
 
   i = WordAddress(wn++); i=i-buffer;
837
 
   if (buffer->i=='"')
838
 
   {   for (j=i+1:j<=(buffer->1)+1:j++)
839
 
           if (buffer->j=='"') f=j;
840
 
       if (f==0) return -1;
841
 
       from_char = i+1; to_char=f-1;
842
 
       if (from_char>to_char) return -1;
843
 
       while (buffer+f > WordAddress(wn)) wn++; wn++;
844
 
       return 1;
845
 
   }
846
 
   return -1;
847
 
];
848
 
 
849
 
[ WriteSub i j;
850
 
   if (chalk notin player) "You're holding nothing to write with.";
851
 
   if (blackboard notin location) "The blackboard is elsewhere.";
852
 
   for (i=from_char,j=1:i<=to_char && j<boardtext->0:i++,j++)
853
 
       boardtext->j = buffer->i;
854
 
   for (:j<boardtext->0:j++) boardtext->j=0;
855
 
   Achieved(5);
856
 
   <<Examine blackboard>>;
857
 
];
858
 
 
859
 
! ----------------------------------------------------------------------------
860
 
!   End of object definitions.
861
 
! ----------------------------------------------------------------------------
862
 
!
863
 
!   Routines and Entry Points
864
 
!
865
 
!   (Fuller examples of which can be found in the "Advent" example game.)
866
 
!
867
 
!   Initialise() just sets up the initial state of the game.
868
 
!   We are required to set "location" to the start location of the
869
 
!   player; the rest is optional.
870
 
!
871
 
!   StartDaemon(balloon)  starts the process which blows the balloon back
872
 
!   and forth.
873
 
! ----------------------------------------------------------------------------
874
 
 
875
 
[ Initialise;
876
 
  location=chair;  move satchel to player;
877
 
 
878
 
  print "^^^^^~What's so special about Inform,~ is the last thing you 
879
 
         remember saying to the mad alchemist. Big mistake...^^";
880
 
 
881
 
  StartDaemon(balloon);
882
 
];
883
 
 
884
 
! ----------------------------------------------------------------------------
885
 
!   Print names of tasks out (when the library asks us to).  Note that they
886
 
!   are numbered from 0 to NUMBER_TASKS-1.
887
 
! ----------------------------------------------------------------------------
888
 
 
889
 
[ PrintTaskName achievement;
890
 
  switch(achievement)
891
 
  {   0: "eating a sweet";
892
 
      1: "driving the car";
893
 
      2: "shutting out the draught";
894
 
      3: "building a tower of four";
895
 
      4: "seeing which way the mantelpiece leans";
896
 
      5: "writing on the blackboard";
897
 
  }
898
 
];
899
 
 
900
 
[ PrintRank;
901
 
  print ", earning you the rank of ";
902
 
  if (score >= 6)  "Toyshop manager.";
903
 
  if (score >= 5)  "management trainee.";
904
 
  if (score >= 4)  "undergraduate.";
905
 
  if (score >= 3)  "schoolchild.";
906
 
  if (score >= 2)  "nursery-school child.";
907
 
  if (score >= 1)  "toddler.";
908
 
  "newborn baby.";
909
 
];
910
 
 
911
 
! ----------------------------------------------------------------------------
912
 
!   Now (as promised earlier) we provide the replacement for BurnSub,
913
 
!   specially adapted to the rules of the Toyshop:
914
 
! ----------------------------------------------------------------------------
915
 
 
916
 
[ BurnSub;
917
 
    if (match hasnt light) "You have no source of flame.";
918
 
    if (noun has animate) <<Attack noun>>;
919
 
    if (noun==padded_floor)
920
 
    {   deadflag=1;
921
 
        "A gong sounds, but before a sepulchral voice finishes clearing 
922
 
         its throat, the whole padded floor goes up in an inferno.";
923
 
    }
924
 
    "A gong sounds, and a sepulchral, rather disappointed voice says: 
925
 
     ~It is forbidden to play with fire in the Toyshop.~";
926
 
];
927
 
 
928
 
! ----------------------------------------------------------------------------
929
 
!   And we provide one new action, "Burst", which in fact just passes over to
930
 
!   "Attack", plus one for writing on the board:
931
 
! ----------------------------------------------------------------------------
932
 
 
933
 
[ BurstSub; <<Attack noun>>; ];
934
 
 
935
 
Include "Grammar";
936
 
 
937
 
Verb "burst" "pop" "prick" "stab" "pierce"
938
 
                * noun                           -> Burst;
939
 
 
940
 
Verb "write"    * QuotedText -> Write;
941
 
 
942
 
! ----------------------------------------------------------------------------