! ---------------------------------------------------------------------------- ! Balances 961216 One of the standard Inform 6 example games ! ! created: 25.9.94 ! updated: 6.10.94 ! modernised: 11.12.95 ! translated to Inform 6: 8.5.96 ! minor bugs fixed: 16.12.96 ! ! This short story was written to demonstrate large-scale programming of ! the parser, and features multiple objects, complicated plurals, variable ! verbs, objects named by the player and questions. The spell-casting ! system is written in a "safe" way so that it could easily be transplanted. ! ! Needs Inform 6, library 6/1 or later to compile. ! ---------------------------------------------------------------------------- Release 5; Serial "961216"; Switches d; Constant Story "BALANCES"; Constant Headline "^An Interactive Short Story ^Copyright (c) 1994, 1995, 1996 by Graham Nelson.^"; Constant OBJECT_SCORE 5; Constant MAX_SCORE 51; Include "Parser"; Include "VerbLib"; ! ---------------------------------------------------------------------------- ! The white featureless cubes from "Spellbreaker", which can be identified ! by being written on with the magic burin, so that their names are given ! by the player in the course of play ! ! A particularly witty thing to do is to give several of them the same name, ! or to frotz some of them to distinguish them from the others... ! And the game will have no problem with this. ! ---------------------------------------------------------------------------- Array cube_text_buffer -> 8; Global the_named_word = 0; Global from_char; Global to_char; Class FeaturelessCube with number 0 0 0 0, ! There's room for 8 bytes of text in these 4 entries description "A perfect white cube, four inches on a side.", parse_name [ i j flag; if (parser_action==##TheSame) { for (i=0:i<8:i++) if ((parser_one.&number)->i ~= (parser_two.&number)->i) return -2; return -1; } for (::i++) { j=NextWord(); flag=0; if (j=='cube' or 'white' || (j=='featureless' or 'blank' && ((self.&number)->0) == 0)) flag=1; if (j=='cubes') { flag=1; parser_action=##PluralFound; } if (flag==0 && ((self.&number)->0) ~= 0) { wn--; if (TextReader(0)==0) return i; for (j=0: j<8: j++) if ((self.&number)->j ~= cube_text_buffer->j) return i; flag=1; } if (flag==0) return i; } ], article "a", short_name [ i; if (((self.&number)->0) == 0) print "featureless white cube"; else { print "~"; while (((self.&number)->i) ~= 0) print (char) (self.&number)->i++; print "~ cube"; } rtrue; ], plural [; self.short_name(); print "s"; ], baptise [ i; wn = the_named_word; if (TextReader(1)==0) return i; for (i=0: i<8: i++) (self.&number)->i = cube_text_buffer->i; self.article="the"; print_ret "It is now called ", (the) self, "."; ], has scored; ! Copies word "wn" from what the player most recently typed, putting it as ! plain text into cube_text_buffer, returning false if no such word is there [ TextReader flag point i j len; if (flag==1 && from_char~=to_char) { for (i=from_char, j=0:i<=to_char && j<7:i++) { cube_text_buffer->j = buffer->i; if (buffer->i ~= ' ' or ',' or '.') j++; } for (:j<8:j++) cube_text_buffer->j = 0; from_char=0; to_char=0; rtrue; } for (i=0:i<8:i++) cube_text_buffer->i = 0; if (wn > parse->1) { wn++; rfalse; } i=wn*4+1; j=parse->i; point=j+buffer; len=parse->(i-1); for (i=0:ii = point->i; wn++; rtrue; ]; Object burin "magic burin" with name "magic" "magical" "burin" "pen", description "This is a magical burin, used for inscribing objects with words or runes of magical import. Such a burin also gives you the ability to write spell scrolls.", before [; WriteOn: if (second ofclass FeaturelessCube) { if (second notin player) "Writing on a cube is such a fiddly process that you need to be holding it in your hand first."; if (burin notin player) "You would need some powerful implement for that."; second.baptise(); rtrue; } if (second ofclass SpellBook) "If a burin could write in a spell book, you wouldn't need the gnusto spell!"; if (second ofclass Scroll) "You cannot write just anything on the magic parchment of a scroll: you can only ~copy~ a spell to it."; ]; [ WriteOnSub; "Graffiti is banned."; ]; [ CopyToSub; if (burin notin player) "You need to be holding the burin to copy a spell."; if (second ofclass SpellBook) "If a burin could write in a spell book, you wouldn't need the gnusto spell!"; if (~~(second ofclass Scroll)) "You can only copy spells to scrolls."; if (child(second)~=0) "The scroll is already full of incantation."; "The scroll is not blank, only illegible."; ]; ! ---------------------------------------------------------------------------- ! Now the whole spell-casting system ! ---------------------------------------------------------------------------- Attribute known_about; ! Player has seen this spell somewhere Attribute reversed; ! Effect of this known spell reversed Attribute is_spell; Class Spell with name "spell" "spells", article "the", number 0, word_name [; print (address) (self.&name)-->0; ], short_name [; self.word_name(); print " spell"; give self known_about; rtrue; ], specification [; self.short_name(); print ": ", (string) self.purpose; ], before [; Examine: self.specification(); "."; ], has is_spell; Object memory with capacity 5, number_known 1, describe_contents [ i j k; objectloop (i in self) if (i.number==100) j++; if (j>0) { print "The "; objectloop (i in self) if (i.number==100) { k++; i.word_name(); if (k==j-1) print " and "; if (k0) { print "the "; objectloop (i in self) if (i.number<100) { k++; print (name) i; if (i.number==2) print " (twice)"; if (i.number==3) print " (thrice)"; if (i.number==4) print " (four times)"; if (i.number>=5) print " (many times)"; if (k==j-1) print " and "; if (k3) print " yet another time."; if (self.number_known <= self.capacity) { new_line; rtrue; } self.forget_spell(sibling(child(self))); " You have so much buzzing around in your head, though, that it's likely something may have been forgotten in the shuffle."; ], forget_spell [ sp; if (sp notin self || sp.number==100) rtrue; self.number_known--; sp.number--; if (sp.number==0) remove sp; rtrue; ]; Spell -> gnusto_spell with name "gnusto", purpose "copy a scroll into your spell book", number 100, magic [ i a_book; if (second ofclass SpellBook) "Unlike scrolls, spell books are magically guarded against the 'theft' of their lore."; if (second==0 || ~~(second ofclass Scroll)) "Your spell fizzles vaguely out."; if (second notin player) "A gnusto spell would require close scrutiny of the scroll it is to copy: which you do not seem to be holding."; objectloop (i in player) if (i ofclass SpellBook) a_book=i; if (a_book==0) "Your spell fails, as you have no spell book."; i=child(second); if (i==0 || ~~(i ofclass Spell)) { print_ret "Your spell fails, as ", (the) second, " is illegible."; } a_book.learn_spell(i); remove second; print_ret "Your spell book begins to glow softly. Slowly, ornately, the words of ", (the) i, " are inscribed, glowing even more brightly then the book itself. The book's brightness fades, but the spell remains! However, the scroll on which it was written vanishes as the last word is copied."; ]; Class SpellBook with array_of_spells 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0, capacity 16, learn_spell [ sp p i; p = self.&array_of_spells; for (i=0:ii)~=0:i++) ; if (i==self.capacity) rtrue; p-->i = sp; ], before [; Open, Close: print_ret (The) self, " is always open to the right place, but it is also always closed. This eliminates tedious leafing and hunting for spells. Many lives have been saved by this magical innovation."; Attack: print_ret "When you are done, ", (the) self, " remains unmarred."; ], after [ p i j; Examine: p = self.&array_of_spells; for (i=0:ii)~=0:i++) { j=p-->i; ; } rtrue; ]; Class Scroll with parse_name [ i j k; j=-1; if (self has general) { if (child(self)~=0 && child(self) ofclass Spell) j=(child(self).&name)-->0; else j='illegible'; } for (::) { k=NextWord(); if (k=='scrolls') parser_action=##PluralFound; if ((k=='scrolls' or 'scroll' or j) || k==(self.&name)-->0) i++; else return i; } ], before [ i; Examine: i=child(self); give self general; if (i==0 || ~~(i ofclass Spell)) "The scroll has faded, and you cannot read it."; print "The scroll reads ~"; i.specification(); "~."; ], invent [; if (inventory_stage==2 && self has general) { if (child(self)==0 || ~~(child(self) ofclass Spell)) print " (which is illegible)"; else { print " (of ", (the) child(self), ")"; } } ]; [ ReadableSpell i j k; if (scope_stage==1) { if (action_to_be==##Examine) rfalse; rtrue; } if (scope_stage==2) { objectloop (i in player) if (i ofclass SpellBook) { for (k=0:kk~=0:k++) { j=(i.&array_of_spells)-->k; PlaceInScope(j); } } rtrue; } ! No need for scope_stage 3 (the error stage), because our ! ParserError routine handles that case instead ]; [ CopyableSpell i j k; if (scope_stage==1) return 1; if (scope_stage==2) { objectloop (i in player) if (i ofclass SpellBook) { for (k=0:kk~=0:k++) { j=(i.&array_of_spells)-->k; PlaceInScope(j); } } rfalse; } ! No need for scope_stage 3 (the error stage), because our ! ParserError routine handles that case instead ]; [ SpellsSub; memory.describe_contents(); ]; [ LearnSub; if (location==thedark) print "(The magic writing of the spells casts enough light that you can read them.)^"; memory.learn_spell(noun); ]; Global the_spell_was = gnusto_spell; [ CastOneSub; ; ]; [ CastSub; the_spell_was = noun; memory.forget_spell(noun); if (noun has reversed) { give noun ~reversed; if (noun.unmagic() ~= 0) return; "Nothing happens."; } if (second ~= 0) { ResetVagueWords(second); ! Set "it", "him", "her" if (second provides before && second.before() ~= 0) return; ! Run before routine(s) } if (noun.magic() ~= 0) return; "Nothing happens."; ]; [ InScope i; if (verb_word=='c,cast' or 'cast') objectloop (i in memory) PlaceInScope(i); rfalse; ]; [ ParserError x i flag vb; if (etype==VERB_PE or ASKSCOPE_PE) { if (etype==ASKSCOPE_PE) { if (verb_word=='cast') vb=1; if (verb_word=='learn' or 'memorise' or 'memorize') vb=2; if (verb_word=='copy') vb=3; if (vb==0) { etype=CANTSEE_PE; rfalse; } } wn=verb_wordnum; if (vb~=0) wn++; x=NextWordStopped(); for (i=player+1:i<=top_object:i++) if (i ofclass Spell && Refers(i,x)==1 && i has known_about) flag=1; if (flag==1) { if (vb==0 or 1) "You haven't got that spell committed to memory. [Type ~spells~ to see what you do remember.]"; if (vb==2) "Your training is such that you can only memorise such a spell with the aid of a spell book containing it."; if (vb==3) "You have no text of that spell to copy."; } if (vb==1) "You haven't learned that spell, if indeed it is a spell."; if (vb==2 or 3) "You haven't access to that spell, if indeed it is a spell."; } rfalse; ]; [ ChooseObjects obj code; if (code<2) rfalse; if (action_to_be==##WriteOn && obj in player) return 9; return 0; ]; [ UnknownVerb word i; objectloop (i in memory) if (word==(i.&name)-->0) { the_spell_was = i; return 'c,cast'; } rfalse; ]; [ PrintVerb v; if (v=='c,cast') { print "cast a spell at"; rtrue; } rfalse; ]; ! ---------------------------------------------------------------------------- ! And now, on with the story. First, some global variables: ! ---------------------------------------------------------------------------- Global prepared_flag = false; ! Prepared for resurrection? Global hearing_good = false; ! Sharp hearing? Global number_filled = 0; ! Sockets in the temple filled ! ---------------------------------------------------------------------------- ! A "questions" verb. Thus, ! "who is my friend helistar" ! "what was the great change" ! and so on are recognised. ! ---------------------------------------------------------------------------- [ QuerySub; noun.description(); ]; [ Topic i; if (scope_stage==1) return 0; if (scope_stage==2) { objectloop (i ofclass Question) PlaceInScope(i); rtrue; } "At the moment, even the simplest questions confuse you."; ]; Class Question; Question with name "helistar" "my" "friend" "colleague", description "Helistar is your colleague, an Enchanter like you who has been much on your mind lately. She has been investigating some very dark magic indeed, and seems not to be around any more. You feel rather vague about the details."; Question with name "magical" "magic" "burin", description "A burin is an engraving and writing tool."; Question with name "change" "great", description "Something you had a lot to do with, but what exactly? No, it's gone."; Question with name "cyclops", description "A one-eyed giant, usually hostile. (Don't they teach anything at adventurer school these days?)"; Question with name "grue", description "The grue is a sinister, lurking presence in the dark places of the earth. Its favorite diet is adventurers, but its insatiable appetite is tempered by its fear of light. No grue has ever been seen by the light of day, and few have survived its fearsome jaws to tell the tale."; Question with name "grimoire", description "According to Chambers English Dictionary, a grimoire is ~a magician's book for calling up spirits~."; Question with name "spells" "work", description "Your memory is still dream-hazed, but it's coming back. As a trained Enchanter, you have the ability to cast spells like ~frotz~, provided you have learned them in advance. Some of these spells can be cast at something; others can be cast alone. ^^Spells are very complicated. Each time you cast one, you forget it (though you can get around this by learning it several times, so as to have several uses up your sleeve). The only way to hang on to a spell is to have it written down, on a scroll or in a spell book. Scrolls are not ideal for this, and you can only learn a spell from your spell book. (But you can add spells to your book.) ^^[Type ~learn frotz~ and then ~frotz coin~ for an example. You can also type ~spells~ to see what you currently have memorised.]"; ! ---------------------------------------------------------------------------- ! Some multiple objects, coins in fact, coded in deluxe fashion: ! ---------------------------------------------------------------------------- Attribute is_coin; Class Coin with name "coin", description "A round unstamped disc, presumably part of the local currency.", parse_name [ i j w; if (parser_action==##TheSame) { if ((parser_one.&name)-->0 == (parser_two.&name)-->0) return -1; return -2; } w=(self.&name)-->0; for (::i++) { j=NextWord(); if (j=='coins') parser_action=##PluralFound; else if (j~='coin' or w) return i; } ], has is_coin; Class GoldCoin class Coin, with name "gold", short_name "gold coin", plural "gold coins"; Class SilverCoin class Coin, with name "silver", short_name "silver coin", plural "silver coins"; Class BronzeCoin class Coin, with name "bronze", short_name "bronze coin", plural "bronze coins"; SilverCoin players_coin; [ TossCoinSub; if (noun notin player) "You need to be holding the coin first."; move noun to parent(player); if (location==thedark) "You throw it away into the darkness."; if (random(20)==1) "You toss the coin, and it lands... on its edge, amazingly."; "You toss the coin, and it comes up... blank, since neither side is marked."; ]; ! ---------------------------------------------------------------------------- ! The player's spell book, and three initial spells (to go with gnusto): ! ---------------------------------------------------------------------------- SpellBook players_book "spell book" with name "spell" "book" "my" "spellbook", description "My Spell Book^"; Spell frotz_spell with name "frotz", purpose "cause an object to give off light", magic [; if (second==0) "There is a brief, blinding flash of light."; if (second has animate) "The spell, not designed for living creatures, goes sour."; if (second in compass) "The spell dissipates vaguely."; give second light; print_ret "There is an almost blinding flash of light as ", (the) second, " begins to glow! It slowly fades to a less painful level, but ", (the) second, " is now quite usable as a light source."; ], unmagic [; if (second==0) "There is a brief moment of deep darkness."; if (second has animate) "The spell, not designed for living creatures, goes sour."; if (second in compass) "The spell dissipates vaguely."; if (second hasnt light) print_ret (The) second, " isn't producing light as it is."; give second ~light; print_ret "A pool of darkness coagulates around ", (the) second, " but slowly fades back to normality. Still, ", (the) second, " is no longer any kind of light source."; ]; Spell rezrov_spell with name "rezrov", purpose "open even locked or enchanted objects", magic [; if (second==0) "The world is open already."; if (second has animate) "It might be a boon to surgeons if it worked, but it doesn't."; if (second has open || second hasnt openable) "It doesn't need opening."; if (second hasnt locked) { give second open; print_ret (The) second, " opens obediently. Like swatting a fly with a sledge hammer, if you ask me."; } give second open ~locked; print "Silently, ", (the) second, " swings open. "; if (second has container) <>; new_line; rtrue; ], unmagic [; if (second==0) "The world is closed already."; if (second has animate) "Happily, that is unnecessary."; if (second has locked || second hasnt lockable) "It doesn't need locking."; give second ~open locked; "Silently, ", (the) second, " swings shut and locks."; ]; Spell yomin_spell with name "yomin", purpose "mind probe", magic [; if (second==0 || second hasnt animate) "That must be either vegetable or mineral."; if (second==player) "You give yourself a mild headache."; print_ret "You look into the rather ordinary thoughts of ", (the) second, "."; ], unmagic [; if (second==0 || second hasnt animate) "That must be either vegetable or mineral."; if (second==player) "You give yourself a mild headache."; print_ret (The) second, " is rather shocked, for some reason."; ]; ! ---------------------------------------------------------------------------- ! The first scene: the Hut and its (rather easy) secret ! ---------------------------------------------------------------------------- Class Place has light; Place Hut "Ramshackle Hut" with description "Until quite recently, someone lived here, you feel sure. Now the furniture is matchwood and the windows are glassless. Outside, it is a warm, sunny day, and grasslands extend to the low hills on the horizon.", out_to Grasslands, w_to Grasslands, cant_go "There's only the one room: better go ~out~.", name "windows" "grasslands" "grass" "hills"; Object -> furniture "wooden furniture" with name "furniture" "broken" "wood" "wooden", before [; Examine, Search, LookUnder: self.before=0; score=score+5; move h_box to player; "Searching through the furniture, which is good for nothing but firewood now, you come across an old cedarwood box, which you pick up for a closer look."; ], has scenery; Object h_box "cedarwood box" with name "cedar" "cedarwood" "wooden" "box", description "The box bears the calligraphed initial H." has container openable lockable locked; SpellBook -> helistars_book "Helistar's grimoire" with name "grimoire" "helistar" "helistars", description "This must be the grimoire of dangerous spells kept by your irresponsible friend Helistar. Many pages are missing, but a few spells remain:^", has proper; ! ---------------------------------------------------------------------------- ! Grasslands and the valley ! ---------------------------------------------------------------------------- Place Grasslands "Grasslands, near Hut" with name "grasslands" "grass" "hut" "path", description "The grasslands sway over low hills in all directions: it is a peaceful wilderness, broken only by this hut and a faint path to the north.", in_to Hut, e_to Hut, n_to Valley, cant_go "You wander around for a while but end up back at the hut."; Place Valley "Pocket Valley" with name "valley" "trail", description "A pleasant pocket valley in the grassy hills, through which a trail runs north-to-south.", n_to "The trail runs out to nothing, and you retreat for fear of getting so lost you couldn't find the hut again by nightfall.", cant_go "You wander around the pleasant valley, but are afraid to lose sight of the trail.", s_to Grasslands; [ RideSub; print_ret "You can hardly ride ", (a) noun, "."; ]; Object -> horse "horse" with short_name [; if (self has general) print "winged horse"; else print "chestnut horse"; rtrue; ], parse_name [ i j; if (self has general) j='winged'; else j=-1; while (NextWord()==j or 'horse' or 'chestnut') i++; return i; ], describe [; print_ret "There is ", (a) self, " here, munching on a pile of oats."; ], before [; Cast: if (the_spell_was == bozbar_spell) { give self general; "A pair of handsome brown wings suddenly appears on the horse's powerful shoulders. The horse turns in a complete circle, a look of puzzlement on his face."; } if (the_spell_was == yomin_spell) "He is mainly thinking about oats. Partly who you are and what you're up to, but mainly oats."; Enter: <>; Ride: if (horse hasnt general) "You ride around for a while, exercising the horse, but soon enough he tires of this and pointedly brings you back to the oats. Obligingly you dismount and he begins grazing again."; print "You begin to ride north. Then, slowly at first but with increasing sureness, the horse begins beating its powerful wings. You rise majestically through the air, sailing gracefully across a chasm where the hills fall away. The horse lands gently on the far side and deposits you, taking to the skies again.^"; PlayerTo(Edge); rtrue; ], has animate; Object -> oats "pile of oats" with name "oats" "pile" "of", before [; Examine, Search, LookUnder: self.before=NULL; move shiny_scroll to player; score=score+5; itobj=shiny_scroll; "Sifting through the oats, you find a shiny scroll! Lucky you got to it before the horse did. As you turn it over in your hands, it seems undamaged."; Take: "What would you want with all those oats?"; ], has scenery; Scroll shiny_scroll "shiny scroll" with name "shiny"; Spell -> bozbar_spell with name "bozbar", purpose "cause an animal to sprout wings", magic [; if (second==0 || second hasnt animate) "The spell dies away in vain."; if (second==player) "Your elbows twitch, but there is no other effect."; print_ret "For a moment, ", (the) second, " looks highly discomforted, but the moment passes."; ], unmagic [; if (second==0 || second hasnt animate) "The spell dies away in vain."; if (second==player) "What wings?"; if (second==horse && horse has general) { give horse ~general; "The Enchanter giveth, and the Enchanter taketh away. The horse looks disconsolate but returns to the oats."; } print_ret (The) second, " has no wings to lose."; ]; ! ---------------------------------------------------------------------------- ! The Chasm and the snake ! ---------------------------------------------------------------------------- Place Edge "Edge of Chasm" with name "wide" "chasm" "road" "daffodils" "clump", description "The road ends suddenly at a wide chasm. The road leads upward to the north, and you can see it continuing on the southern side of the chasm.", u_to Up_Road, n_to Up_Road, cant_go "The chasm is too perilous to approach. The only safe way is up and to the north.", before [; Jump: deadflag = true; "You jump bravely into the chasm, and plunge... gracefully through the air. (It gets a bit less noble and airy after that.)"; ]; Object -> snake "hissing snake" with name "hissing" "snake", initial "Lying in a tight coil at the edge of the chasm is a hissing snake.", description "It has some V-markings, some scaly parts, colours from grey to reddish-brown. Is that any help?", life [; "The snake hisses angrily!"; ], before [; Cast: switch(the_spell_was) { urbzig_spell: remove self; snakes_cube.initial = "Beside a clump of daffodils is a featureless white cube."; "The snake is replaced by a clump of daffodils."; bozbar_spell: deadflag = true; remove self; snakes_cube.initial = "A featureless cube rests where the snake took off from."; "The snake is transformed into a huge, winged serpent, a dragon which bellows and leaps out into the chasm, backwinging furiously... and knocking you over the edge quite by accident."; yomin_spell: "Horrid reptilian thoughts insinuate their way into you."; } Take, Remove: "The slipperiness of its skin is only one of many reasons why this is ill-advised."; ], has animate; FeaturelessCube -> snakes_cube "cube" with initial "The snake appears to be curled around a featureless white cube.", before [; if (snake notin nothing) "The snake won't let you near that cube!"; ]; ! ---------------------------------------------------------------------------- ! The crest of the hill; Icarus the tortoise; the chewed scroll ! ---------------------------------------------------------------------------- Place Up_Road "Crest of Hill" with description "The road crosses the top of a ridge here, sloping downwards to the south and the northwest. A track diverges to east.", nw_to Cave_Mouth, s_to Edge, d_to Edge, e_to Track; Object -> tortoise "tortoise" with name "tortoise" "turtle", initial "A tortoise ambles along the road, extremely slowly.", life [; "The tortoise (slowly) turns its neck to look at you (stupidly)."; ], before [; Cast: switch(the_spell_was) { urbzig_spell: "Just how safe do you want your surroundings to be?"; bozbar_spell: move chewed_scroll to parent(self); remove self; StartDaemon(self); score=score+5; "The tortoise seems to be incapable of expressing surprise, but is now soaring away high in the sky. Something rather grubby is left behind."; yomin_spell: "For a moment you think there is nothing there, as you chew absentmindedly on a leaf. But somewhere inside the tortoise is a sense of wonder at the amazing blue canopy of the sky."; } Take, Remove: "Your parents always warned you not to pick up casual acquaintances met on the road."; ], daemon [ i; if (location ~= Up_Road or Track || random(6)~=1) rfalse; if (random(4)==1 && self hasnt general) { move feather to location; give self general; "^A tortoise-feather flutters to the ground before you!"; } i=random(3); switch(i) { 1: print "^High in the sky,"; 2: print "^Far above you,"; 3: print "^Tiny in the blue sky,"; } " a tortoise flaps across the sun."; ], has animate; Scroll torn_scroll "torn scroll" with name "torn"; Spell -> lobal_spell with name "lobal", purpose "sharpen hearing", magic [; if (second==0 || second hasnt animate) "There is a loud bang in your ear, but no other effect."; if (second==player) { if (hearing_good) "There is no further effect."; hearing_good=1; StartTimer(self, 5); "Nothing happens, possibly because those butterflies on the other side of the hill keep distracting you."; } print_ret (The) second, " is no doubt grateful for the gift of sharper hearing."; ], unmagic [; if (second==0 || second hasnt animate) "There is a brief silence, but no other effect."; if (second==player) { StopTimer(self); hearing_good=0; "Pardon?"; } print_ret (The) second, " is no doubt grateful not to have to listen to you."; ], time_left 0, time_out [; if (hearing_good) { hearing_good = false; "^Those wretched butterflies finally shut up."; } ]; Scroll chewed_scroll "chewed scroll" with initial "It looks as if the tortoise was eating something - once it might have been a scroll, but now it lies there, chewed up like a lettuce leaf.", before [; Cast: if (the_spell_was == caskly_spell) { move torn_scroll to parent(self); remove self; score=score+5; "Before your eyes, the scroll begins to repair itself, failing only at the very last tear. Not quite perfect perhaps, but certainly a readable, if torn scroll."; } Eat: "~Eating your words~ is notoriously dangerous for a wizard. Rearranged in the stomach, a spell might do anything!"; ], with name "chewed"; Object feather "tortoise feather" with name "tortoise" "feather", description "Possibly your rarest, and also least valuable, possession."; ! ---------------------------------------------------------------------------- ! The cave mouth and the perfect sapphire ! ---------------------------------------------------------------------------- Place Cave_Mouth "Cave Mouth" with name "gorse" "footpath" "cave" "mouth", description "This is a cave mouth, at one end of a road which winds southeast over rising ground. The entrance west to the caves is a dark tunnel, and only a footpath runs further north, into gorse.", u_to Up_Road, se_to Up_Road, in_to Iron_Door, w_to Iron_Door, n_to Footpath; Object -> Iron_Door "iron door" with name "iron" "door" "heavy", description "It just looks like an ordinary heavy iron door.", door_dir [; if (location==Cave_Mouth) return w_to; return e_to; ], door_to [; if (location==Cave_Mouth) return In_Cave; return Cave_Mouth; ], describe [; if (self has open) "^The iron door stands open."; if (self hasnt locked) "^The iron door is unlocked but shut."; "A heavy iron door bars the cave mouth."; ], found_in In_Cave Cave_Mouth has static door openable locked lockable; ! Cf. T. S. Eliot, "Burnt Norton" II: ! (but see also Mallarme's sonnet from which Eliot borrowed the image) Object -> sapphire "perfect sapphire" with name "perfect" "sapphire" "gemstone" "gem", initial "Clotted in the mud beside the door is a perfect sapphire.", before [; Examine: remove self; move caskly_spell to memory; players_book.learn_spell(caskly_spell); caskly_spell.number=100; "As you gaze into the perfect blue of the sapphire, you feel your mind begin to reel. Unable to bear the naked sight of perfection, you look away, ashamed. As you do so, the sapphire cracks and wastes away to thin hot dust. But something remains, something in your mind..."; ]; Spell caskly_spell with name "caskly", purpose "cause perfection", magic [; if (second==0) "Trying to make everything perfect was a little too ambitious."; if (second==player) "Oh, don't be too hard on yourself."; if (second==helistars_book) "Your spell is not powerful enough to restore the lost pages."; print_ret (The) second, " looks pretty perfect as is."; ]; ! ---------------------------------------------------------------------------- ! Inside the Cave, the powerful urbzig spell and its consequences ! ---------------------------------------------------------------------------- Place In_Cave "Inside Cave" with description "A wide but shallow cave not far inside the hill. There is no obvious exit, except for the way you came in.", out_to [; if (CoinsIn(left_pan)+CoinsIn(right_pan) < 6) "Something bars your way, and you hear the scales jangling militantly. You were trying to steal its coins!"; if (scales.number~=0) "Something bars your way, and you hear the scales jangle slightly with energy."; return Iron_Door; ], e_to [; return self.out_to(); ], cant_go "The only way is back ~out~ through the iron door.", after [; Take: if (parent(noun)==left_pan or right_pan) print_ret "Taken from ", (the) parent(noun), "."; ], has ~light; FeaturelessCube -> cave_cube "cube" with initial "Balanced on a rock formation is a featureless white cube."; Object -> scales "pair of scales" with name "pair" "of" "scales" "pans", number 0, describe [; print "^A fair-sized pair of scales hangs from a bracket in the cave wall. "; if (self.number==0) "The scales are balanced."; if (self.number==1) "The left-hand side is higher."; "The right-hand side is higher."; ], before [; "There are left and right hand pans, which you should refer to individually."; ], has static supporter; Class ScalePan with name "pan" "side" "tray", before [; Receive: if (noun ofclass Scroll or Coin) rfalse; if (noun==feather) rfalse; "The pans gleam with what almost seems greed, and somehow they contrive to nudge your hand past them with your worthless and boring item."; ], after [ i j d w1 w2; Receive, LetGo: i=scales.number; objectloop (j in left_pan) w1=w1 + WeightOf(j); objectloop (j in right_pan) w2=w2 + WeightOf(j); if (w1==w2) scales.number=0; if (w1 > w2) scales.number=-1; if (w1 < w2) scales.number=1; j=scales.number; d=(w2-w1)*(scales.number); if (j==i) rfalse; if (j==0) "The scales come into balance."; if (j==1) print "The left pan "; else print "The right pan "; if (d==1) "very slowly rises up."; "rises up."; ], has supporter scenery; [ WeightOf obj; if (obj==bronze_coin) return 2; if (obj ofclass Scroll || obj==feather) return 1; return 3; ]; [ CoinsIn obj i c; objectloop (i in obj) if (i ofclass Coin) c++; return c; ]; ScalePan -> right_pan "right pan" with name "right"; GoldCoin -> ->; GoldCoin -> ->; GoldCoin -> ->; ScalePan -> left_pan "left pan" with name "left"; BronzeCoin -> -> bronze_coin; GoldCoin -> ->; GoldCoin -> ->; Scroll -> -> crumpled_scroll "crumpled scroll" with name "crumpled"; Spell -> -> -> urbzig_spell with name "urbzig", purpose "turn a dangerous object into a harmless one", magic [; if (second==0) "The spell fizzles away."; if (second==player) "It's a matter of opinion, isn't it?"; if (second==helistars_book or mace || second ofclass FeaturelessCube) { CDefArt(second); remove second; if (second==mace && cyclops in location) { remove cyclops; move eye_cube to location; " turns into a featureless white cube just as the cyclops was about to hit you with it. Mightily embarrassed by this, he drops the cube and runs off!"; } print " turns into a moth and flutters away.^"; rtrue; } print_ret "Nothing obvious happens. Perhaps ", (the) second, " isn't so very dangerous after all."; ], unmagic [; if (second==0) "The spell fizzles away."; if (second==player) "It's a matter of opinion, isn't it?"; if (second has static || second has scenery) { print_ret "Your spell is too weak for something quite as monumentally harmless as ", (the) second, "."; } if (second==helistars_book or snake or cyclops or mace || second ofclass FeaturelessCube) "Nothing obvious happens."; if (second in player) { remove second; deadflag = true; "Suddenly, a tarantula races up your arm to your throat! Perhaps it was unwise to gizbru something you were actually holding."; } if (cyclops has general) "Nothing happens. Perhaps that's just as well, after the last time."; move cyclops to location; remove second; give cyclops general; StartTimer(cyclops, 5); print_ret (The) second, " is replaced by a buck-toothed cyclops wielding a mace!"; ]; Object cyclops "buck-toothed cyclops" with name "buck" "toothed" "buck-toothed" "cyclops", initial "A huge buck-toothed cyclops menaces you, armed with a heavy mace!", before [; Cast: if (the_spell_was == bozbar_spell) "Does the term ~death wish~ mean anything to you?"; if (the_spell_was == urbzig_spell) "The cyclops bellows with glee as your spell has no effect. (After all, he wouldn't be ~dangerous~ if an urbzig spell worked on him, would he?)"; ], life [; "He roars incoherently, swinging the mace!"; ], time_left 0, time_out [; if (self notin location) { remove self; rtrue; } deadflag = true; remove mace; remove cyclops; "Feeling that he's given you quite long enough to explain why you made such a mess of his life, he swings the great mace maniacally down on you!"; ], each_turn [ i; i=random(4); if (i==1) "^The cyclops leaps and bellows!"; if (i==2) "^Whirling the mace, the cyclops jabbers at you incoherently."; if (i==3) "^The cyclops is losing patience (the appropriate cyclops word is untranslatable into English, but approximately means ~forbearance in not smashing all nearby skulls~)."; "^The cyclops jabs you with the mace, almost breaking your rib."; ], has animate transparent; Object -> mace "mace" with name "heavy" "mace" "axe", description "It looks much too heavy for you to even lift."; FeaturelessCube -> eye_cube "cube" with initial "A featureless white cube lies where the cyclops dropped it."; ! ---------------------------------------------------------------------------- ! The Footpath and the carpet ! ---------------------------------------------------------------------------- Place Footpath "Gorse Bushes" with description "The footpath from the cave mouth runs into dense, impenetrable gorse bushes. Perhaps it wasn't so much a footpath as a rill in the earth where roots wouldn't take; anyway, there's no way but back south.", s_to Cave_Mouth; Object -> carpet "beautiful red carpet" with name "beautiful" "magic" "red" "carpet", initial "Slung over one of the gorse bushes is a beautiful red carpet.", description "This is a carpet of unusual design. It is red, beautifully woven and bears a pattern of cubes.", before [ i; Receive: if (self notin location || self hasnt moved) "Not until the carpet's on the ground, you can't."; Ride: <>; Enter: if (self notin location || self hasnt moved) "Not until the carpet's on the ground, you can't."; if (location==Balance_Room) "Mysteriously, the carpet rucks and pulls until you're thrown off. It settles back on the white floor with a contented sigh."; if (location==In_Cave) "The carpet rises suddenly, crashing into the roof of the cave and throwing you back off again. Painfully."; if (location==Bazaar) i=Up_Road; else i=Bazaar; print "The carpet rises suddenly into the fluffy white clouds, and after a headlong journey deposits you...^"; move self to i; PlayerTo(i,1); move player to self; <>; Take: if (player in self) "Not while you're on it!"; for (i=child(self):i~=0:i=child(self)) { move i to location; print "(Dislodging ", (the) i, ")^"; } ], has supporter enterable; ! ---------------------------------------------------------------------------- ! A Bazaar Lottery ! ---------------------------------------------------------------------------- Global last_called = 1; Global explicit_flag = 0; Global tickets_taken = 0; Class Ticket(6) with number -1, name "ticket", description [; if (self.number==2306) "It is labelled ~First Prize~!"; if (self.number==5802) "It is labelled ~Nineteenth Prize~."; "~You lose,~ says the ticket, with a smily face. ~Try again!~"; ], short_name [; if (self.number==-1) rfalse; print "lottery ticket ", self.number; rtrue; ], parse_name [ i j w; i=0; if (NextWord()=='lottery') i++; else wn--; if (NextWord()=='tickets') { parser_action=##PluralFound; return i+1; } else wn--; if (NextWord()~='ticket') return 0; i++; w=TryNumber(wn); if (w==-1000) { explicit_flag = false; return i; } if (w==0) return 0; if (self.number==-1) { objectloop(j ofclass Ticket) if (w == j.number) return 0; } else { if (self.number~=w) return 0; } i++; last_called = w; explicit_flag = true; return i; ], before [; Examine: if (self in board) "It would be cheating to see what's written on the curled up tickets still in the board."; Cast: "~Get outta here, bub!~, the barker says, disgusted."; ]; Place Bazaar "Crowded Bazaar" with description "This is a crowded, noisy bazaar. Directly in front of you is a lottery! But the contemptuous-looking barker is doing a very poor trade: hardly anyone wants his first prize, the big cuddly toy elephant, or even his nineteenth prize, a featureless white cube.", each_turn [; switch(random(4)) { 1: "^~Roll up! Roll up! One silver piece for three goes!~"; 2: "^~Come on, then! Just a silver coin gets you three!~"; 3: "^~Think what you could win, all for one silver coin!~"; 4: "^~This could be your lucky day!~"; } ], before [; Learn: "~None of that!~ snaps the barker angrily, putting you off your study habits. He mutters about ~Enchanter cheats~, but under the circumstances you decide to let the insult pass."; ], cant_go "Everywhere, the crowds of jabbering natives block your way to all the good stalls. In fact, the only one you can get at is this dismal lottery."; Object -> board "lottery board" with credit 0, name "board" "lottery" "holes", description "There are a hundred holes each way, making, um, let's see, yes, ten thousand tickets in all. Still, there are nineteen prizes, so your odds must be, oh, well, not too awful anyway.", before [ i; LetGo: if (self.credit == 0) "The barker stabs you in the chest with his finger. ~That's a silver coin to you, bub!~"; if (explicit_flag) { objectloop (i ofclass Ticket) if (last_called == i.number) "That ticket's already taken."; } else { .RandomChoice; last_called = random(10000); objectloop (i ofclass Ticket) if (last_called == i.number) jump RandomChoice; } tickets_taken++; self.credit--; i = Ticket.create(); if (i == 0) "The barker looks metaphysically embarrassed. ~Um, Inform's object creation system seems not to have worked.~"; i.number = last_called; itobj = i; move i to player; give i moved proper; if (explicit_flag==0) print "Randomly picking from the ", 10001-tickets_taken, " numbered holes with tickets in, you "; else print "You "; print_ret "take ", (the) i, " out of the board."; Examine: ; Receive: if (noun ofclass Ticket) "~No changes of mind, that's your ticket now! Give it to me if you want to play it.~"; <>; default: "The barker is burly, and won't let you tamper with the board."; ], initial "Behind the barker is a huge drilled board, and inside each little numbered hole is a rolled-up lottery ticket." has static container open; Ticket -> -> ticket_in_board "rolled-up ticket from the board" with article "a"; Object -> barker "barker" with name "barker" "burly" "man", number 0, description "A boxer gone to seed who failed as a magician all down the coast, that'd be your guess.", life [; Attack, Kiss: "No way. He must weigh twice what you do."; Ask: switch(noun) { 'prize', 'prizes': "~Just one silver coin and a prize could be yours!~"; 'white', 'featureless', 'cube': "He blows the dust off it. ~Genuine antique, that.~"; 'elephant', 'toy', 'cuddly': "~Good quality merchandise,~ he says, in a way that suggests he can only spell one of those three words."; 'ticket', 'tickets', 'lottery': "~Three tickets for one silver coin!~"; default: "~Just play the game, bub.~"; } Order, Answer: "The barker glowers at you."; Give: if (noun ofclass Ticket) { remove noun; if (noun.number==2306) { move elephant to player; give elephant moved; remove pelephant; Bazaar.description = "This is a crowded, noisy bazaar. Directly in front of you is the lottery!"; "With very bad grace, the barker shoves the cuddly toy elephant into your arms."; } if (noun.number==5802) { move barker_cube to player; give barker_cube moved; remove pcube; Bazaar.description = "This is a crowded, noisy bazaar. Directly in front of you is the lottery!"; score=score+5; "With concealed relief, the barker shoves the featureless white cube into your hands."; } "~Bad luck! You lose!~"; } if (self.number==2) "~You've had enough goes already!~ he growls. No wonder trade is bad."; if (~~(noun ofclass Coin)) "~What do you call that? One silver coin to play!~"; if ((noun.&name)-->0 == 'bronze') "~Bronze! Not a chance, sunshine.~"; remove noun; board.credit = board.credit + 3; self.number++; if ((noun.&name)-->0 == 'gold') "Gleefully the barker snatches the gold coin. ~Sorry bub, no change. Business is slack today!~"; "Grudgingly the barker takes the silver coin and stands back to let you at the board, arms folded."; ], before [; Cast: switch(the_spell_was) { bozbar_spell: "He's not that much of an animal."; lobal_spell: "His problem is listening, not hearing."; caskly_spell: "For a moment his hair seems to comb itself. Irritated, he ruffles it again, and the spell dies an ignominious death."; yomin_spell: if (elephant has moved || barker_cube has moved) "The barker's mind is a heap of grumbles about lost prizes and scrawny Enchanters."; if (self hasnt general) { give self general; "~Hope that scrawny Enchanter doesn't pick 2306!~ thinks the barker (slowly)."; } "~If that mark does win, hope it's only worthless old 5802,~ ponders the barker."; } ], has animate scenery; Object -> prizes "prizes" with name "prize" "prizes", before [; "~Hands off those prizes!~"; ], has scenery; Object -> pelephant "prize elephant" with name "prize" "elephant" "cuddly" "toy", description "Pink, cuddly, toy, elephant. Says it all, really.", before [; Examine: ; default: "~Hands off those prizes!~"; ], has scenery; Object -> pcube "prize cube" with name "prize" "featureless" "white" "cube", description "Wouldn't you like to win it?", before [; Examine: ; default: "~Hands off those prizes!~"; ], has scenery; Object elephant "cuddly toy elephant" with name "cuddly" "toy" "elephant", description "Pink, cuddly, toy, elephant. Says it all, really.", before [; Cast: if (the_spell_was == bozbar_spell) "Let me get this straight. You, the enchanter who defeated Krill, the head of the Borphee Guild himself... are attempting to grow wings on a pink cuddly elephant?"; if (the_spell_was == yomin_spell) "Woolly."; ]; FeaturelessCube barker_cube "cube"; ! ---------------------------------------------------------------------------- ! The spells in Helistar's grimoire ! ---------------------------------------------------------------------------- Spell lleps_spell with name "lleps", purpose "reverse effect of memorised spell", magic [; if (second==0 || second notin memory) "The spell backfires, painfully."; if (second.number==100) "You know that spell too well for your mind to be able to accept the change."; if (second has reversed) give second ~reversed; else give second reversed; if (second==lleps_spell) { memory.forget_spell(second); "Your mind wrenches as the two lleps spells cancel each other out, leaving only a sensation quite like a hangover."; } print_ret "Your mind wrenches as ", (the) second, " reverses itself."; ], unmagic [; return self.magic(); ! The reverse of "lleps" is "lleps" ]; Spell mortin_spell with name "mortin", purpose "cause immediate death of caster", magic [; deadflag = true; "You really can't fault Helistar on this one. Death is absolutely immediate, like a sudden blackout curtain..."; ], unmagic [; prepared_flag = true; "Nothing quite happens... and yet you feel enormously more confident as you go about this dangerous world."; ]; ! ---------------------------------------------------------------------------- ! Death and the Boneyard ! ---------------------------------------------------------------------------- [ AfterLife; if (~~prepared_flag) rfalse; if (player in Balance_Room) "^^Your foresight in preparing a resurrection was wasted. The tangled magic of the Balance Room coiled around your puny enchantment like a constricting serpent."; prepared_flag = false; deadflag = false; hearing_good = false; if (memory.capacity >= 2) memory.capacity--; while (child(player)~=0) move child(player) to parent(player); move players_book to player; print "^^With great foresight you prepared yourself for resurrection... Your mind feels a little weaker, but at least you're alive.^"; PlayerTo(Boneyard); ]; Place Boneyard "Boneyard" with name "bones" "blades" "shoulder" "skulls", description "This is a room of bones. Shoulder blades make up the floor, skulls the walls and leg-bones the door frames. The west exit leads into darkness, but the doorway to the north opens onto a seemingly normal scene.", n_to [; if (scales.number ~= 0) return In_Cave; return Grasslands; ], w_to "Some magical force blocks your way, as though that doorway led into adventures from your past which you cannot rejoin now.", before [; Examine, Search: if (noun==w_obj) "You can make out nothing to the west."; ]; Scroll -> worthless_scroll "worthless scroll" with initial "You are almost treading on a worthless scroll.", name "worthless"; Spell -> -> filfre_spell with name "filfre", purpose "produce gratuitous fireworks", magic [; if (self hasnt scored) { score++; give self scored; } "A brief shower of gratuitous fireworks spells out: ^^The masterly Enchanter trilogy was written by Marc Blank, Dave Lebling and Steve Meretzky."; ], unmagic [; "A lengthy shower of artistically justified fireworks spells out: ^^The masterly Enchanter trilogy was written by Jane Austen, Emily Bronte and Edgar Allen Poe."; ]; ! ---------------------------------------------------------------------------- ! The Cubical Temple ! ---------------------------------------------------------------------------- Place Track "Track, outside Temple" with description "This is the end of a long track winding through desolate hills, which runs back west up to the ridge.", before [; Listen: if (~~hearing_good) "The chanting is too quiet to make out."; "The endlessly repeating threnody of the monks tells of the legend of one who will some day enlighten their order, and so be taken up to a higher plane. He (or she, presumably) is known as The Four-Cubed One."; ], w_to Up_Road, u_to Up_Road; Object -> Temple "cubical Temple" with name "temple" "cubical" "cube" "enormous", before [ i j; Enter: "The Temple is featureless and unbroken. Perhaps the top is open, because the sound must come from somewhere... but you wouldn't bet on it."; Cast: switch(the_spell_was) { rezrov_spell: "The huge temple remains impassive at your relatively puny enchantment."; frotz_spell: objectloop (i in player) if (i ofclass FeaturelessCube) j++; if (j==0) "The temple shakes, but then is still again."; if (j<4) "The temple shakes! White light plays over your hands and possessions, but then all is still again."; print "The temple shakes and white light bathes you. Smoothly it unfolds itself in a four-dimensional way your senses can barely comprehend. All you know is that when it is over, you find yourself in...^"; hearing_good = false; score=score+5; PlayerTo(Balance_Room); rtrue; } ], describe [; print "^You stand outside an enormous temple in the shape of a perfect, featureless white cube, four hundred feet on a side. From somewhere within you hear the "; if (hearing_good) print "bellowing noise"; else print "tiny sound"; " of the monks chanting."; ], description "It's much like every other gigantic temple in the shape of a featureless white cube you've ever seen. No obvious way in.", has static; ! ---------------------------------------------------------------------------- ! Inside the Temple ! ---------------------------------------------------------------------------- Place Balance_Room "Balance Room" with description "This seems to be the inside of a featureless white cube, forty feet on a side. The air is stale and there is no exit."; Object -> balance_meter "image of the scales" with name "image" "scales" "of" "pair", article "the", initial "The image of a pair of scales hangs high in the air. One pan is much lower than the other.", before [; "It's only an image."; ], has static; Object -> dusty_podium "dusty podium" with name "podium" "dusty" "cobwebs" "cobwebbed", initial "Far below the scales, in the centre of the ~floor~, is a predictably-shaped podium, but it is so dusty and cobwebbed that you can't see what it once was.", before [; Cast: if (the_spell_was == caskly_spell) "Nice try, but it is protected from enchantment."; "However dusty it is, the podium is still protected from casual enchantment."; Rub: remove self; move balance_key to Balance_Room; itobj = balance_key; "No substitute for old-fashioned hard work, sometimes, and after much patient (sneezy) scrubbing, the podium appears in its true white glory. Set into it are four sockets, arranged in a two by two square."; ], has static; Object balance_key "podium" with name "podium" "pedestal" "platform" "cubical", description "As predicted, it is cubical.", initial "Far below the scales, in the centre of the ~floor~, is a predictably-shaped podium. Set into it are four sockets, arranged in a two by two square.", has static supporter; Object -> sockets "two by two square" with name "square" "two" "by" "two", before [ i; if (action~=##Examine || number_filled==0) "You'll have to say which socket you mean. (Let's call them ~top left~, ~bottom right~ and so on.)"; objectloop (i in self) { print (The) i; if (child(i)==0) print " is empty.^"; else { print " contains ", (a) child(i), ".^"; } } rtrue; ], has static; Class Socket with name "socket", article "the", before [; Cast: "The sockets are proof against magic."; Examine: print (The) self, ", cubical and slightly more than four inches on a side, is decorated with ", (string) self.description; if (child(self) == nothing) "."; print_ret ", and contains ", (a) child(self), "."; Receive: if (~~(noun ofclass FeaturelessCube)) "The socket rejects that."; if (child(self) ~= nothing) "There is already a cube in that socket."; ], after [; LetGo: number_filled--; "With much struggle, you manage to pull the cube away."; Receive: number_filled++; if (number_filled==4) { if (snakes_cube in bl_socket && barker_cube in ul_socket && cave_cube in br_socket && eye_cube in ur_socket) { deadflag=2; score=score+5; "As you place the final cube into the sockets, you feel imbued with celestial wisdom (more so than usually). You find yourself growing to the height of the cube, so that you pull the balances back level by hand, and then you grow still further, out of the temple until it is but a cube in your hand, and you are a giant towering over the land. ^^Then, of course, you wake up, glumly realising it's time to go to your job at the new Borphee Laboratories and all those Wheatstone bridge experiments. But at least you can dream about the old days."; } "The sockets are all full now, but that doesn't mean anything's happened."; } "The cube is a predictably perfect fit in the socket."; ], has static container open; Socket -> bl_socket "bottom left socket" with name "bottom" "left" "serpent", description "a serpent"; Socket -> ul_socket "top left socket" with name "top" "left" "bazaar", description "a scene in a bazaar"; Socket -> br_socket "bottom right socket" with name "bottom" "right" "cave", description "an engraving of a rocky cave"; Socket -> ur_socket "top right socket" with name "top" "right" "eye", description "an eye"; ! ---------------------------------------------------------------------------- ! That's all of the object definitions: just a little code and grammar left ! ---------------------------------------------------------------------------- [ Initialise; location = Hut; move burin to player; move players_coin to player; move players_book to player; thedark.description = "It is pitch black. You are likely to be eaten by a grue."; ! (In fact you are stone-cold certain not to be, but never mind.) players_book.learn_spell(gnusto_spell); players_book.learn_spell(frotz_spell); players_book.learn_spell(yomin_spell); players_book.learn_spell(rezrov_spell); helistars_book.learn_spell(frotz_spell); helistars_book.learn_spell(lleps_spell); helistars_book.learn_spell(mortin_spell); give gnusto_spell known_about; "^^^^^[Welcome to a short story called ~Balances~, one of the example games for the Inform design system. Some people may recognise the setting, but others might like to type ~how do spells work~ - the game responds to a few such questions.] ^^You feel a little confused as to how you got here. Something to do with Helistar! That's right, and how the world is so far off balance nowadays, after the Great Change.^^"; ]; [ PrintRank; print ", earning you the rank of "; if (score >= 50) "Scientist."; if (score >= 40) "Spellbreaker."; if (score >= 30) "Sorcerer."; if (score >= 20) "Enchanter."; if (score >= 10) "novice Enchanter."; "lost dreamer."; ]; [ DiagnoseSub; switch(memory.capacity) { 5: "You feel fine, and your memory is unimpaired."; 4: "You feel shaky after your brush with death, but your mental faculties seem sound."; 3: "For someone who has died twice, you're in reasonable shape."; } "How many times have you died now? Your memory isn't what it was."; ]; ! ---------------------------------------------------------------------------- ! Grammar extensions needed by the spell-casting and cube-writing rules: ! ---------------------------------------------------------------------------- Include "Grammar"; [ AnyWord; from_char=0; to_char=0; the_named_word=wn++; return burin; ]; [ 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 burin; } return -1; ]; Verb "write" "scribe" * AnyWord "on" held -> WriteOn * QuotedText "on" held -> WriteOn; Verb "copy" * scope=CopyableSpell "to" noun -> CopyTo; Verb "who" "what" "how" * "do" scope=Topic -> Query * "is" scope=Topic -> Query * "was" scope=Topic -> Query; Verb "spells" "memory" * -> Spells; Verb "learn" "memorise" "memorize" * scope=ReadableSpell -> Learn; Extend "examine" first * scope=ReadableSpell -> Examine; Verb "c,cast" * -> CastOne * noun -> CastOne; Verb "cast" * is_spell -> Cast * is_spell "at" noun -> Cast * is_spell "on" noun -> Cast; Verb "diagnose" "health" * -> Diagnose; ! ---------------------------------------------------------------------------- ! And one for the game itself. ! ---------------------------------------------------------------------------- Verb "ride" "mount" "straddle" * creature -> Ride * noun -> Enter; Verb "flip" "toss" * is_coin -> TossCoin; ! ----------------------------------------------------------------------------