Inventory This is the complete source code of the example game Toyshop.inf.
Back to List
Complete
Browsing 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 site is no longer supported; information may be out of date.
Maintained as a historical archive by the Interactive Fiction Technology Foundation.
Copyright 1993-2018 IFTF, CC-BY-SA unless otherwise noted.
This page was originally managed by Graham Nelson (graham@gnelson.demon.co.uk) assisted by C Knight.