! ---------------------------------------------------------------------------- ! Toyshop... of Evil! ! ! This is a Platypus "port" of Graham's original Toyshop example game. ! ! Needs Inform 6 with Platypus release 4 to compile. ! ! To win, simply find 6 interesting things to do and leave by the main exit! ! ! Object Is an example of... ! ! >SA satchel Container into which the game automatically puts ! things ! >HE helium balloon Something moving under the control of a daemon ! >CA little red car Vehicle, and pushable from place to place ! >PF padded floor Scenery present in several rooms at once ! >GR hand grenade Timed events: a grenade and its pin ! >MA matchbook Simple fire and matches; changing inventory styles ! >WC white candles A stock of objects identical to each other ! >GL white gloves Two independent objects which can behave as a pair ! >CO green cone Easy respond and respond_late rules ! >HW high window Starting and stopping daemons ! >BC bolted cupboard A typical locked container (with key) ! >GB glass box Container light can get through ! >SB steel box Container light can't get through ! >BL building blocks A complicated class definition; piles of objects ! >CH Christopher Someone you can talk to, and persuade to do things ! >OF Office Rules about moving in a particular direction ! >TB toothed bag A container with ideas about what it will allow ! >SL spirit level Something to put on top of things ! >BB blackboard A blackboard to write messages on ! ! (The code is marked with >SA and so on for easy access with a text editor) ! ---------------------------------------------------------------------------- !Constant DEBUG; Constant Story "TOYSHOP... OF EVIL!"; Constant Headline "^An Interactive Demonstration^ Not copyright (@@126@@126c) 2001 by Anson Turner, based on the original by Graham Nelson (1994). All rights given away.^"; Release 4; Serial "010831"; ! This sets the serial date to the date of this source ! file, not to the date of compilation. Constant MAX_CARRIED = 4; ! Default carrying capacity for all actors. ! Now we serve notice to Inform that we do not wish to use the standard ! routine for the Burn action, and will instead be defining our own: Replace BurnSub; ! Next include the first and second of the three Platypus library files: Include "First"; Include "Middle"; ! And the scenery addition: Include "scenery"; ! ---------------------------------------------------------------------------- ! >SA This satchel is ofclass Sacks, so items will automatically be put in ! it if an actor is carrying it and tries to take something with a ! full inventory. ! ! when_closed and when_open are not used by Platypus, except in ! MAX_COMPATIBILITY mode, so we use describe instead. We return 2 if ! the satchel is open so that the library will list its contents ! (if any). We see this again with other objects in the game. ! ! The satchel's startup routine ensures that it starts out in the ! player's inventory. We could have called MoveTo(self, player), but ! in this case it isn't really necessary, since no position attribute ! need be set. ! ---------------------------------------------------------------------------- Sacks satchel "satchel" has container open openable, with name 'satchel', article "your", description "Big and with a smile painted on it.", describe [; if (self has open) { print "^Your satchel lies open on the floor."; return 2; } "^Your satchel lies on the floor."; ], startup [; move self to player; ]; ! Platypus has an object-based task-scoring system. These are the ! objects to represent the player's (possible) achievements. Object eat_sweet "eating a sweet" with points 1; Object drive_car "driving a car" with points 1; Object close_window "shutting out the draught" with points 1; Object build_tower "building a tower of four" with points 1; Object test_mantelpiece "seeing which way the mantelpiece leans" with points 1; Object write_blackboard "writing on the blackboard" with points 1; ! ---------------------------------------------------------------------------- ! Off we go into the Toyshop... ! ! The Toyroom class inherits from the Rooms class, which among other ! things provides the fpsa property needed to allow the player to use ! the GO TO (room) command. Also, the name (and, optionally, adjective) ! property holds the actual name of the room, with the scenery property ! used to hold names of unimportant things (handled by "scenery.h"). ! ---------------------------------------------------------------------------- Class Toyroom class Rooms, has light; Toyroom Toyshop "Toyshop" with name 'toyshop', description "The centre of a long east-west hall. Shelves are lined with toys, painted clowns face you from the walls and the floor is lightly padded with colourful mats. A doorway leads north, with a red warning triangle above it.", shared padded_floor, scenery 'painted' 'clowns' 'shelves' 'toys' 1 0 'triangle' 0 0, dirs edir East_end wdir West_End ndir Danger_Zone; Object -> chair "high chair" has supporter, with name 'chair' 'highchair', adjective 'high', allow_entry [; rtrue; ]; ! ---------------------------------------------------------------------------- ! >HE The balloon is completely self-contained as a piece of code. It is ! defined as having activedaemon, so its daemon is running as soon as ! the program starts. ! ---------------------------------------------------------------------------- Object -> balloon "helium balloon" has activedaemon, with name 'balloon', adjective 'helium' 'blue' 'string', description "Blue, with a yellow smile.", describe "^A balloon nestles on the ceiling, its long string hanging.", respond [; Attack: remove self; give self ~activedaemon; "Easily, you burst the balloon. Pop!^^ Shame it was irreplaceable, really."; Drop, Insert, PutOn: MoveTo(self, actor.location); print "The balloon rises gracefully to the ceiling"; if (action == ##Insert or ##Puton && self hasnt general) { give self general; " (it is filled with helium, after all)."; } "."; ], respond_late [; Take: "You take the balloon by its string. It's buoyant!"; ], daemon [ from_room to_room; if (random(3)~=1) rfalse; from_room = parent(self); if (from_room == East_End or West_End) to_room = Toyshop; if (from_room == Toyshop) { if (random(2) == 1) to_room = East_End; else to_room = West_End; } if (to_room == 0) rfalse; move self to to_room; if (player.location == from_room) "^A breeze blows the balloon away to the ", (name) to_room, "."; if (player.location == to_room) "^A breeze blows the balloon in from the ", (name) from_room, "."; ]; ! ---------------------------------------------------------------------------- ! >CA The car provides allow_push, which is used to allow it to be pushed ! from room to room. It is passed a direction object as a parameter, ! but we ignore that here. ! ! The respond_early for Go must return true to signify that travelling ! in the object is legal. (Note that it must also be enterable.) ! ---------------------------------------------------------------------------- Object -> car "little red car" has switchable static container open, with name 'car' 'kar1', adjective 'little' 'red', description "Large enough to sit inside. Among the controls is a prominent on/off switch. The numberplate is KAR 1.", describe [; if (self has on) print "^The red car sits here, its engine still running."; else print "^A little red car is parked here."; return 2; ], allow_entry [; rtrue; ], allow_push [; rtrue; ], respond_early [; Go: if (car has on) { Achieved(drive_car); "Brmm! Brmm!"; } print "(The ignition is off at the moment.)^"; ], respond_late [; PushDir: "The car rolls very slowly as you push it."; ]; Object -> -> "small note" with name 'note', adjective 'small', description " !!!! FROBOZZ MAGIC CAR COMPANY !!!!^ ^Hello, Driver!^ ^Instructions for use:^ ^Switch on the ignition and off you go!^ ^Warranty:^ ^This car is guaranteed against all defects for a period of 76 milliseconds from date of purchase or until used, whichever comes first.^ ^Good Luck!"; ! ---------------------------------------------------------------------------- ! >PF An example of an object spread across several (three) rooms. It is ! listed in the shared property of East_End, Toyshop, and West_End, ! though we could also have used its own found_in (as in the original). ! ! Note that we have to put its special Take message in respond_early ! -- since it has static, an attempt to take it will be thwarted by the ! library before it reaches the respond stage. ! ---------------------------------------------------------------------------- Object padded_floor "padded floor" has concealed static, with name 'floor' 'mats' 'padding', adjective 'padded', describe "^The padded floor extends through this room.", description "To protect little children and adventurers.", respond_early [; Take: "It is protected from little children and adventurers."; ]; ! ---------------------------------------------------------------------------- Toyroom Danger_Zone "Danger Zone" with name 'danger' 'zone', description "This is the Danger Zone, which you should know better than to go into. A single door leads back south.", dirs sdir Toyshop; ! ---------------------------------------------------------------------------- ! >GR A classic example of a timer (or, as some people call them and ! appropriately so in this case, a fuse). To demonstrate stopping ! a timer before the alarm (and for fun), there is also a pin: ! ! Because we want the pin to be "in" the grenade without making the ! latter a container, we indulge in a little trickery with a ! respond_early property for the pin. Because the grenade is transparent, ! all of its children are in scope whenever it is, even though it is ! not a container, supporter, or hider. ! ---------------------------------------------------------------------------- Object -> grenade "nasty-looking hand grenade" with name 'grenade', adjective 'hand' 'nasty' 'nasty-looking', add_to_scope the_pin, description "Not recommended for children under 90.", describe [; if (self hasnt moved) "^A nasty-looking hand grenade (there is no other kind) rolls about irresponsibly on the floor."; ], respond [; Pull: if (self has general) "Too late for that."; StartTimer(self, 5); give self general; MoveTo(the_pin, player); "You pull the pin out, an irrevocable act."; ], time_left 0, time_out [; deadflag = 1; "^An immense explosion suddenly demolishes the toyshop!^^ Will you never learn?"; ]; Object -> -> the_pin "pin" with name 'pin', adjective 'grenade', description "The pin is designed to be easy to pull.", respond_early [; Take, Pull: if (self in grenade && AttemptToHoldObject(grenade) == false) <>; Insert: if (self notin grenade && second == grenade && AttemptToHoldObject(grenade) == false) { StopTimer(grenade); move self to grenade; give grenade ~general; "Amazing! You got the pin back into the grenade!"; } ], meddle [; Jump: "No you may not jump! HAHAHAHA!"; ], each_turn [; "The pin hums a jaded tune."; ]; ! ---------------------------------------------------------------------------- ! >MA This is a matchbook of five matches, which is quite simple in that you ! can only actually have one match at a time. Again we use add_to_scope ! to avoid making the matchbook into a container. ! ! This is less than an ideal implementation: a match disappears when ! no longer held by the player. A better approach would be to define ! a Matches(5) class. ! ! Again we are manually setting and unsetting the activedaemon ! attribute. You could also call StartDaemon(matchbook) and ! StopDaemon(matchbook), if desired. ! ---------------------------------------------------------------------------- Object -> matchbook "matchbook" has with name 'matchbook' 'book' 'matches', number 5, add_to_scope [; if (self.number) PlaceInScope(match); ], respond [; Burn: if (match has light) { remove match; remove matchbook; "What a waste of matches!"; } ], invent [; if (inventory_stage==2) { switch(self.number) { 0: print " (empty)"; 1: print " (1 match left)"; default: print " (", self.number, " matches left)"; } } ], description [; print "The cover advertisement reads ~Curses - Adventure of a Lunchtime~. The book "; switch(self.number) { 0: "is empty."; 1: "has a single match left."; default: print_ret "contains ", self.number, " matches."; } ], daemon [; if (match notin matchbook && match notin player) { move match to matchbook; if (match has light) { give match ~light; StopTimer(match); } give self ~activedaemon; } ]; Object -> -> match "match" with parse_name [ w rv; if (self has light) w = 'burning'; else w = 'unlit'; while (NextWord()=='match' or w) rv++; return rv; ], respond_early [ i; if (self in matchbook) { i = matchbook.number; if (i == 0) "There are no matches left in the book."; i--; matchbook.number = i; move self to player; give matchbook activedaemon; print "(taking a match from the book, which "; if (i == 0) print "is now empty)^"; if (i == 1) print "has one more left)^"; if (i > 1) print "has ", i, " left)^"; } Take: if (self in player) "Done."; Burn: if (self has light) "The match is already alight."; if (matchbook notin player) "You need the matchbook to strike the match."; give self light; StartTimer(self, 2+random(3)); "You strike the match."; ], short_name [; if (self has light) print "burning match"; else print "unlit match"; rtrue; ], time_left, time_out [; move self to matchbook; give self ~light; "^You drop the match as the flame reaches your finger."; ]; ! ---------------------------------------------------------------------------- ! >WC A box of eight candles. ! ! If we had needed a much greater number of candles, we could have used ! object creation and destruction during play. See the "Ticket" class ! from the "Balances" example game. ! ---------------------------------------------------------------------------- Class Candle with name 'candle' 'candles//p', adjective 'wax', short_name "wax candle", plural "wax candles", description "It looks just like all the other candles.", respond [; Burn: "Disappointingly, the wick refuses to burn."; ]; Object -> "grey tin box" has container openable, with name 'box', adjective 'tin' 'grey' 'gray', description "A grey tin box of ~Major's Candles~."; Candle -> ->; Candle -> ->; Candle -> ->; Candle -> ->; Candle -> ->; Candle -> ->; Candle -> ->; Candle -> ->; Toyroom East_End "East End" with name 'end', adjective 'east', scenery 'dolls' 'nurses' 1 0, description "The eastern end of the toyshop is pink, and dolls and nurses line the shelves right up to the high window. A dark doorway leads to a northern side chamber.", shared padded_floor, dirs wdir Toyshop ndir DarkRoom; ! ---------------------------------------------------------------------------- ! >GL The following example, suggested to Graham by Richard Tucker, ! demonstrates an apparently tricky case of objects with associated ! sub-objects. The pair of white gloves behaves just like any other item ! of clothing - but the player can also use the left and right gloves ! independently, can take away or wear only one and so on. When they ! come back together (even in a cupboard, say, or on a mantelpiece) ! they are called a pair again. ! ! We can do this with only three objects, one daemon and one rule. ! ! When the gloves are together, and the player refers to an individual ! glove, the respond_early rule splits up the pair and starts the daemon. ! Once active, the daemon tries every turn to re-join them into a pair. ! (If it succeeds, it turns itself off.) ! ! Note that the "pair of gloves" object has the "general" attribute exactly ! when the gloves are apart. Otherwise the pair-object contains both ! glove objects, and has add_to_scope so that the parser knows the player ! can see and refer to them. ! ---------------------------------------------------------------------------- Object -> gloves "white gloves" has clothing, with article "a pair of", name 'gloves' 'pair', adjective 'of' 'white', add_to_scope left_glove right_glove, daemon [; if ((parent(right_glove) ~= parent(left_glove)) || (PositionOf(right_glove) ~= PositionOf(left_glove))) return; if (left_glove has worn) give gloves worn; else give gloves ~worn; move gloves to parent(right_glove); give gloves ~general ~activedaemon; move right_glove to gloves; move left_glove to gloves; give right_glove ~worn; give left_glove ~worn; ]; Class Glove has clothing, with article "the", name 'glove', adjective 'white', respond_early [; if (self notin gloves) rfalse; MoveTo(left_glove, parent(gloves), positionof(gloves)); MoveTo(right_glove, parent(gloves), positionof(gloves)); give gloves general activedaemon; remove gloves; ]; Glove -> -> left_glove "left glove" with description "White silk, monogrammed with a scarlet R.", adjective 'left'; Glove -> -> right_glove "right glove" with description "White silk, monogrammed with a scarlet T.", adjective 'right'; ! ---------------------------------------------------------------------------- ! ...and that's all: the "gloves" code is self-contained. ! ! Exercise for the reader: hide a (sharp) jewel inside the left glove. ! (Alter the glove class to make them containers open only when not worn. ! Add two "after" rules to warn the player if there's something sharp ! to the touch, one for putting on the pair of gloves, one for putting on ! an individual glove.) ! ---------------------------------------------------------------------------- ! ---------------------------------------------------------------------------- ! >CO A traditional Inform example object: ! ---------------------------------------------------------------------------- Object -> cone "green cone" has edible, with name 'cone' 'marzipan', adjective 'green' 'emerald' 'misshapen', describe [; if (cone has moved) "^A misshapen cone of green marzipan sits here."; "^Nearby is an emerald green cone, one foot high."; ], description "The cone seems to be made of emerald-coloured marzipan.", respond [; Eat: if (random(100) <= 30) { deadflag = 1; "Unfortunately, you seem to be allergic to almonds."; } "You nibble at a corner of the cone."; ], respond_late [; Take: "Taken. (Your hands are smeared with marzipan.)"; Drop: cone.description = "The cone is a vague green mess."; "The cone drops to the floor and sags a little."; ]; ! ---------------------------------------------------------------------------- ! >HW It's the draught from this slightly-concealed window which propels the ! balloon: ! ---------------------------------------------------------------------------- Object -> "high window" has static concealed openable open, with name 'window', adjective 'high', description [; print "A narrow, high window "; if (self has open) "through which a draught blows."; "which is closed."; ], respond_late [; Open: give balloon activedaemon; Close: Achieved(close_window); give balloon ~activedaemon; ]; ! ---------------------------------------------------------------------------- ! >BC A typical locked container, containing a rather pathetic prize... ! ! Note that there is no lockable attribute. An object is assumed to be ! lockable if it provides the with_key property. ! ---------------------------------------------------------------------------- Object -> "bolted cupboard" has container openable locked static, with name "bolted" "cupboard", describe [; if (self hasnt open) "^A shut cupboard is bolted to one wall."; print "^Bolted up on one wall is an open cupboard."; return 2; ], with_key key; Object -> -> "boiled sweet" has edible, with name 'sweet', adjective 'boiled', respond_late [; Eat: Achieved(eat_sweet); "It takes an irritatingly long time to eat."; ]; ! ---------------------------------------------------------------------------- ! >GB This is really to demonstrate "transparent". Shutting up the glowing ! >SB ball in the glass box does not make the room go dark: shutting it up ! in the steel box does. Also, you can examine things in the glass box ! even when the glass box is shut. ! (Note also that the Dark Room is explicitly told not to have "light", ! which it would otherwise inherit from the "Toyroom" class.) ! ---------------------------------------------------------------------------- Toyroom DarkRoom "Dark Room" has ~light, with description "A featureless storage room, hardly worth illumination.", cant_go "The only exit is back south.", dirs sdir East_End; Object -> "glass box with a lid" has container openable transparent open, with name 'box', adjective 'glass' 'with' 'lid'; Object -> "steel box with a lid" has container openable open, with name 'box', adjective 'steel' 'with' 'lid'; Toyroom West_End "West End" with name 'end', adjective 'west', scenery 'soldiers' 'model' 'aircraft' 'shelves' 1 0, description "The western end of the toyshop is blue, and soldiers and model aircraft line the shelves. A small office lies to the south.", shared padded_floor, dirs edir Toyshop sdir Office; ! ---------------------------------------------------------------------------- ! >BL The class Block provides for stackable building blocks. ! ! Note that with the "describe" routine missing, the game would still ! correctly describe stacks of blocks: just a little less elegantly. ! ---------------------------------------------------------------------------- Class Block has supporter, with name 'block' 'cube' 'blocks//p' 'cubes//p', adjective 'building', description "Just a child's building block, four inches on a side.", describe [ c d e; d = child(self); while (d && d ofclass Block) { c++; e=d; d=child(d); } if (c == 0) rfalse; print "^There is a pile of building blocks here, "; while (c >= 0) { print (string) e.block_color; if (c > 0) print " on "; c--; e = parent(e); } "."; ], respond [ c; PutOn: if (second ofclass Block) { if (child(second)~=0 && child(second) ofclass Block) "There's no room on the top of one cube for two more, side by side."; } else print "(They're really intended to be piled on top of each other.)^"; c = second; while (c ofclass Block) c = parent(c); if (c ~= actor.location or mantelpiece) "Too unsteady a base."; ], respond_late [ c stack; PutOn: stack = noun; while (parent(stack) ofclass Block) { stack = parent(stack); c++; } if (c < 2) rfalse; if (c == 2) "The pile of three cubes is unsteady, but viable."; if (actor == Chris) { Achieved(build_tower); "^Expertly he keeps the pile of four cubes stable."; } stack = noun; while (parent(stack) ofclass Block) { c = stack; stack = parent(stack); MoveTo(c, actor.location); } "The pile of four cubes wobbles, wobbles, steadies... and suddenly collapses!"; Take: stack = child(noun); if (stack == 0) rfalse; while (stack) { c = stack; stack = child(stack); MoveTo(c, actor.location); } "Your pile of cubes is collapsed as a result."; ]; Block -> "green cube" with adjective 'green', block_color "green"; Block -> "red cube" with adjective 'red', block_color "red"; Block -> "yellow cube" with adjective 'yellow', block_color "yellow"; Block -> "blue cube" with adjective 'blue', block_color "blue"; ! ---------------------------------------------------------------------------- ! >CH A guest appearance by [Graham's] cousin Christopher, aged six (*), who ! plays with one thing at a time (easily forgetting which). Being ! "transparent" (no reflection on him!) means the parser allows the ! player to examine whatever he's playing with... but not to take it ! from him. ! ! Answer, Ask, and Consult set second to the specified object, which ! can be anything having the "known" attribute. If no such object is ! matched, second is 0, and consult_from and consult_words must be, er, ! consulted. ! ! We make a single, modest use of Christopher's perform property. Since ! we have just printed his name, we call SetNamePrinted() so that the ! library will start its action description with "He" rather than ! repeating it. ! ! (* In 1993, when this game was first written.) ! ---------------------------------------------------------------------------- Actors -> Chris "Christopher" has male proper transparent, with name 'chris' 'boy' 'chistopher' 'child', describe [; print "^A boy called Christopher sits here"; if (child(Chris)) print ", playing with ", (a) child(Chris); "."; ], respond [; Ask: if (second ofclass Block) "~Bet I can make a higher tower than you.~"; switch(second) { balloon: "Christopher yawns."; juggling_ball: "~That's mine!~"; toyshop_subject: "~Isn't it fabulous here?~"; default: "~Dunno.~"; } Answer: switch(second) { hello_subject: "~Hello,~ says Christopher cheerfully."; default: "Christopher seems preoccupied."; } Attack: remove self; "Christopher makes a run for it, effortlessly slipping past you!"; Kiss: "~That's soppy, that is.~"; ], respond_indirect [ x; Give: if (noun == balloon) "He's too bored by the balloon."; x = child(Chris); if (x) { move x to actor.location; print "He forgets about ", (the) x, " and "; } else print "He "; print "eagerly grabs ", (the) noun; move noun to Chris; "."; ], orders [; Drop: if (noun in Chris) "~Won't! It's mine!~"; Take: "Christopher can't be bothered."; Give: if (second == player) "~Get your own!~"; Go: "~But I like it here!~"; PutOn: if (noun notin Chris) "He is mightily confused."; if (~~(noun ofclass Block && second ofclass Block)) "He can't see the point of this."; print "Christopher leans over with great concentration. "; SetNamePrinted(self); self.perform(##PutOn, noun, second); rtrue; ], each_turn [; if (random(3) ~= 1) rtrue; "^Christopher ",(string) random("yawns","frowns","stretches", "hums tonelessly"),"."; ]; Object juggling_ball "fluorescent juggling ball" Chris has light, with name 'ball', adjective 'juggling' 'flourescent', describe [; if (self hasnt moved) "^On the floor is a flourescent juggling ball!"; ], description "It glows with soft light."; Object hello_subject "hello" has known, with name 'hello' 'hi' 'hallo'; Object toyshop_subject "Toyshop" has known, with name 'toyshop' 'toys'; ! ---------------------------------------------------------------------------- ! >OF A simple movement rule. ! ---------------------------------------------------------------------------- Toyroom Office "Office" with name 'office', description "A small, grey office, with a broad stone mantelpiece. In the east wall is a doorway marked ~Exit~, and the Toyshop, of course, lies north.", cant_go "The Toyshop floor lies north.", dirs [ d; if (d == ndir) return West_End; if (d ~= edir || finding_path) rfalse; if (score ~= maximum_score) "A gong sounds. ~You cannot leave the Toyshop until you have done six interesting things!~"; deadflag = 2; "A gong sounds. ~Congratulations! You may now leave the Toyshop and begin writing your own Inform game with Platypus!~"; ]; ! ---------------------------------------------------------------------------- ! >TB A somewhat acquisitive container... but it can be taught to behave. ! ---------------------------------------------------------------------------- Object -> "toothed bag" has container open, with name 'bag', adjective 'toothed', describe [; if (self hasnt moved) { print "^In one corner is a curious, toothed bag."; return 2; } ], description "A capacious bag with a toothed mouth.", respond_indirect [; Take: "The bag defiantly bites itself shut on your hand until you desist."; ], respond_late_indirect [; Insert: if (noun == cone) { self.respond_indirect = 0; self.respond_late_indirect = 0; "The bag wriggles interminably as it tries to eat the enormous mass of marzipan. That'll teach it."; } "The bag wriggles hideously as it swallows ", (the) noun, "."; ]; ! ---------------------------------------------------------------------------- ! >SL Which can be put on the mantelpiece: the first time this is done, the ! game randomly decides which end is higher, and sticks to this decision. ! ---------------------------------------------------------------------------- Object -> -> spirit_level "spirit level" with name 'level' 'wood' 'flask', adjective 'spirit', number 0, description [; print "A length of wood containing a flask of viscous green liquid, in which a bubble is trapped"; if (self in mantelpiece) { print " at the "; if (self.number == 1) print "northeast end"; else print "southeast end"; } "."; ], respond_late [; PutOn: if (second ~= mantelpiece) rfalse; if (spirit_level hasnt general) self.number = random(2); give spirit_level general; Achieved(test_mantelpiece); print "You put the spirit level on the mantelpiece, and the bubble slowly drifts towards the "; if (self.number == 1) "northeast."; "southwest."; ]; Object -> mantelpiece "mantelpiece" has static concealed supporter, with name 'mantel' 'mantle' 'mantelpiece' 'mantlepiece' 'piece'; Object -> -> key "iron key" with name 'key', adjective 'iron'; ! ---------------------------------------------------------------------------- ! >BB A blackboard which can be written on or wiped clear. ! ---------------------------------------------------------------------------- Object -> -> chalk "stick of chalk" with name 'stick' 'chalk', adjective 'of'; Array boardtext string 64; Object -> blackboard "blackboard" has static, with name 'board' 'blackboard', adjective 'black', describe [; <>; ], respond [ i f; Examine: for (i = 1:i <= boardtext->0:i++) if (boardtext->i~=' ' or 0) f=1; if (f == 0) { print "^The office blackboard is wiped clean.^"; if (self hasnt general) { give self general; "^[To write on it, try > write ~message...~]"; } rtrue; } print "^The office blackboard bears the message:^ "; for (i = 1:i <= boardtext->0:i++) { f = boardtext->i; if (f) print (char) f; } new_line; rtrue; Rub: for (i = 1:i <= boardtext->0:i++) boardtext->i = ' '; "You wipe the blackboard clean."; ]; Global from_char; Global to_char; [ QuotedText i j f; i = WordAddress(wn++); i=i-buffer; if (buffer->i=='"') { for (j=i+1:j<=(buffer->1)+1:j++) if (buffer->j=='"') f=j; if (f==0) return -1; from_char = i+1; to_char=f-1; if (from_char>to_char) return -1; while (buffer+f > WordAddress(wn)) wn++; wn++; return 1; } return -1; ]; [ WriteSub i j; if (chalk notin player) "You're holding nothing to write with."; if (blackboard notin player.location) "The blackboard is elsewhere."; for (i=from_char,j=1:i<=to_char && j0:i++,j++) boardtext->j = buffer->i; for (:j0:j++) boardtext->j=0; Achieved(write_blackboard); <>; ]; ! ---------------------------------------------------------------------------- ! End of object definitions. ! ---------------------------------------------------------------------------- ! ! Routines and Entry Points ! ! (Fuller examples of which can be found in the "Advent" example game.) ! ! Initialise() just sets up the initial state of the game. It is not ! required under Platypus; you could set the player's initial location ! in a startup property, or define a new player object with location ! already set. ! ! An actor's location property (including the player's) should not be ! set manually after startup. Use MoveTo() instead. ! ! The SetDefaultObjectPositions() does just what it says; it helps avert ! any problems due to our forgetting to set the upon, inside, and under ! attributes in our "has" lines, which would make those objects ! inaccessible. ! ---------------------------------------------------------------------------- [ Initialise; player.location = chair; SetDefaultObjectPositions(); print "^^^^^~What the heck is Platypus?~ is the last thing you remember saying to that furry, duck-billed alchemist. Big mistake...^^"; ]; [ PrintRank; print ", earning you the rank of duck-billed "; if (score >= 6) "Toyshop manager."; if (score >= 5) "management trainee."; if (score >= 4) "undergraduate."; if (score >= 3) "schoolchild."; if (score >= 2) "nursery-school child."; if (score >= 1) "toddler."; "newborn baby."; ]; ! ---------------------------------------------------------------------------- ! Now (as promised earlier) we provide the replacement for BurnSub, ! specially adapted to the rules of the Toyshop: ! ---------------------------------------------------------------------------- [ BurnSub; if (match hasnt light) "You have no source of flame."; if (noun has animate) <>; if (noun == padded_floor) { deadflag = 1; "A gong sounds, but before a sepulchral voice finishes clearing its throat, the whole padded floor goes up in an inferno."; } "A gong sounds, and a sepulchral, rather disappointed voice says: ~It is forbidden to play with fire in the Toyshop.~"; ]; ! ---------------------------------------------------------------------------- ! And we provide one new action, "Burst", which in fact just passes over to ! "Attack", plus one for writing on the board: ! ---------------------------------------------------------------------------- [ BurstSub; <>; ]; Include "Last"; Verb 'burst' 'pop' 'prick' 'stab' 'pierce' * noun -> Burst; Verb 'write' * QuotedText -> Write; ! ----------------------------------------------------------------------------