| ! ---------------------------------------------------------------------------- | |
| ! 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:i<len && i<7:i++) cube_text_buffer->i = 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 (k<j-1) print ", "; | |
| } | |
| if (j==1) print " spell is"; else print " spells are"; | |
| print " yours forever. Other than that, y"; | |
| } | |
| else print "Y"; | |
| print "ou have "; | |
| j=0; k=0; | |
| objectloop (i in self) if (i.number<100) j++; | |
| if (j>0) | |
| { 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 (k<j-1) print ", "; | |
| } | |
| } | |
| else print "no spells"; | |
| " memorised."; | |
| ], | |
| learn_spell | |
| [ sp; | |
| if (sp.number==100) "You always know that spell."; | |
| print "Using your best study habits, you commit the "; | |
| sp.word_name(); | |
| print " spell to memory"; | |
| if (sp notin self) sp.number=0; | |
| move sp to self; | |
| self.number_known++; | |
| sp.number++; | |
| if (sp.number==1) print "."; | |
| if (sp.number==2) print " once again."; | |
| if (sp.number==3) print " a third time."; | |
| if (sp.number>3) 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:i<self.capacity && (p-->i)~=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:i<self.capacity && (p-->i)~=0:i++) | |
| { j=p-->i; <Examine j>; | |
| } | |
| 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:k<i.capacity && (i.&array_of_spells)-->k~=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:k<i.capacity && (i.&array_of_spells)-->k~=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; <Cast the_spell_was noun>; ]; | |
| [ 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) <<Search second>>; 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 self>>; | |
| 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 self>>; | |
| 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; <<Look>>; | |
| 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.~"; | |
| <<Push self>>; | |
| 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; | |
| ! ---------------------------------------------------------------------------- | |
Xet Storage Details
- Size:
- 75.5 kB
- Xet hash:
- 40574a84a03e5f51e13c1aab30fd7affcc1e6c3a53b50687a07d79e85b756196
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.