Inform - Resources - Examples

Back to List

Inventory
Complete

Plain
Coloured
Gaudy

Browsing Toyshop.inf

This is the complete source code of the example game Toyshop.inf.

001  ! ----------------------------------------------------------------------------
002  !  Toyshop 961111                   One of the standard Inform 6 example games
003  !
004  !  This is not a real game.  The main example game for Inform is "Advent",
005  !  a port of Colossal Cave.  Since that's something of an antique, and most
006  !  of the objects in it are rather simple, this is a collection of more
007  !  exotic features and peculiar objects.  Note that "Advent" has plenty of
008  !  interesting doors, a good lantern and bottled oil and water, so those
009  !  won't be part of the Toyshop.
010  !
011  !  Needs Inform 6 with library 6/1 or later to compile.
012  !
013  !  To win, simply find 6 interesting things to do and leave by the main exit!
014  !
015  !       Object            Is an example of...
016  !
017  !  >SA  satchel           Container into which the game silently puts things
018  !  >HE  helium balloon    Something moving under the control of a daemon
019  !  >CA  little red car    Vehicle, and pushable from place to place
020  !  >PF  padded floor      Scenery present in several rooms at once
021  !  >GR  hand grenade      Timed events: a grenade and its pin
022  !  >MA  matchbook         Simple fire and matches; changing inventory styles
023  !  >WC  white candles     A stock of objects identical to each other
024  !  >GL  white gloves      Two independent objects which can behave as a pair
025  !  >CO  green cone        Easy before and after rules
026  !  >HW  high window       Starting and stopping daemons
027  !  >BC  bolted cupboard   A typical locked container (with key)
028  !  >GB  glass box         Container light can get through
029  !  >SB  steel box         Container light can't get through
030  !  >BL  building blocks   A complicated class definition; piles of objects
031  !  >CH  Christopher       Someone you can talk to, and persuade to do things
032  !  >OF  Office            Rules about moving in a particular direction
033  !  >TB  toothed bag       A container with ideas about what it will allow
034  !  >SL  spirit level      Something to put on top of things
035  !  >BB  blackboard        A blackboard to write messages on
036  !
037  !  (The code is marked with >SA and so on for easy access with a text editor)
038  ! ----------------------------------------------------------------------------
039  Constant DEBUG;
040  Constant Story "TOYSHOP";
041  Constant Headline "^An Interactive Demonstration^
042               Copyright (c) 1994 by Graham Nelson. All rights given away.^";
043  Release 4;
044  Serial "961111";   !   This sets the serial date to the date of this source
045                     !   file, not to the date of compilation.
046   
047  !   Now we serve notice to Inform that we do not wish to use the standard
048  !   routine for the Burn action, and will instead be defining our own:
049   
050  Replace BurnSub;
051   
052  !   Next include the first of the three standard library files:
053   
054  Include "Parser";
055   
056  ! ----------------------------------------------------------------------------
057  ! >SA  Ungenerously, the player can only carry at most 4 things, but there's
058  !      a satchel to carry other things around in...
059  ! ----------------------------------------------------------------------------
060   
061  Constant MAX_CARRIED = 4;
062  Constant SACK_OBJECT = satchel;
063   
064  Object satchel "satchel"
065    with description "Big and with a smile painted on it.",
066         name "satchel", article "your",
067         when_closed "Your satchel lies on the floor.",
068         when_open "Your satchel lies open on the floor.",
069    has  container open openable;
070   
071  !   We're going to use the most elaborate scoring system the
072  !   library provides (even though we're going to make the six tasks all
073  !   score only 1 point each), so we define all this...
074   
075  Constant TASKS_PROVIDED;
076  Constant NUMBER_TASKS = 6;
077  Array    task_scores  -> 1 1 1 1 1 1;
078  Constant MAX_SCORE = 6;
079   
080  !   And include the library of standard verbs and actions.
081   
082  Include "VerbLib";
083   
084  ! ----------------------------------------------------------------------------
085  !   Off we go into the Toyshop...
086  ! ----------------------------------------------------------------------------
087   
088  Class Toyroom
089    has  light;
090   
091  Toyroom Toyshop "Toyshop"
092    with description
093            "The centre of a long east-west hall. Shelves are lined 
094             with toys, painted clowns face you from the walls and 
095             the floor is lightly padded with colourful mats. A doorway 
096             leads north, with a red warning triangle above it.",
097         name "clowns" "painted" "shelves" "triangle",
098         e_to East_End, w_to West_End, n_to Danger_Zone;
099   
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  ! ----------------------------------------------------------------------------


Last updated 23 June 2004. This web site has not been fully supported since April 2008. Information may be out of date. This page was originally managed by Graham Nelson (graham@gnelson.demon.co.uk) assisted by C Knight.