Inventory This is the complete source code of the example game Balances.inf.
Back to List
Complete
Browsing Balances.inf
0001 ! ----------------------------------------------------------------------------
0002 ! Balances 961216 One of the standard Inform 6 example games
0003 !
0004 ! created: 25.9.94
0005 ! updated: 6.10.94
0006 ! modernised: 11.12.95
0007 ! translated to Inform 6: 8.5.96
0008 ! minor bugs fixed: 16.12.96
0009 !
0010 ! This short story was written to demonstrate large-scale programming of
0011 ! the parser, and features multiple objects, complicated plurals, variable
0012 ! verbs, objects named by the player and questions. The spell-casting
0013 ! system is written in a "safe" way so that it could easily be transplanted.
0014 !
0015 ! Needs Inform 6, library 6/1 or later to compile.
0016 ! ----------------------------------------------------------------------------
0017
0018 Release 5;
0019 Serial "961216";
0020 Switches d;
0021
0022 Constant Story "BALANCES";
0023 Constant Headline "^An Interactive Short Story
0024 ^Copyright (c) 1994, 1995, 1996 by Graham Nelson.^";
0025
0026 Constant OBJECT_SCORE 5;
0027 Constant MAX_SCORE 51;
0028
0029 Include "Parser";
0030 Include "VerbLib";
0031
0032 ! ----------------------------------------------------------------------------
0033 ! The white featureless cubes from "Spellbreaker", which can be identified
0034 ! by being written on with the magic burin, so that their names are given
0035 ! by the player in the course of play
0036 !
0037 ! A particularly witty thing to do is to give several of them the same name,
0038 ! or to frotz some of them to distinguish them from the others...
0039 ! And the game will have no problem with this.
0040 ! ----------------------------------------------------------------------------
0041
0042 Array cube_text_buffer -> 8;
0043 Global the_named_word = 0;
0044 Global from_char; Global to_char;
0045
0046 Class FeaturelessCube
0047 with number 0 0 0 0, ! There's room for 8 bytes of text in these 4 entries
0048 description "A perfect white cube, four inches on a side.",
0049 parse_name
0050 [ i j flag;
0051 if (parser_action==##TheSame)
0052 { for (i=0:i<8:i++)
0053 if ((parser_one.&number)->i
0054 ~= (parser_two.&number)->i) return -2;
0055 return -1;
0056 }
0057 for (::i++)
0058 { j=NextWord(); flag=0;
0059 if (j=='cube' or 'white' ||
0060 (j=='featureless' or 'blank' &&
0061 ((self.&number)->0) == 0)) flag=1;
0062 if (j=='cubes')
0063 { flag=1; parser_action=##PluralFound; }
0064 if (flag==0 && ((self.&number)->0) ~= 0)
0065 { wn--;
0066 if (TextReader(0)==0) return i;
0067 for (j=0: j<8: j++)
0068 if ((self.&number)->j ~= cube_text_buffer->j)
0069 return i;
0070 flag=1;
0071 }
0072 if (flag==0) return i;
0073 }
0074 ],
0075 article "a",
0076 short_name
0077 [ i; if (((self.&number)->0) == 0) print "featureless white cube";
0078 else
0079 { print "~";
0080 while (((self.&number)->i) ~= 0)
0081 print (char) (self.&number)->i++;
0082 print "~ cube";
0083 }
0084 rtrue;
0085 ],
0086 plural
0087 [; self.short_name(); print "s";
0088 ],
0089 baptise
0090 [ i; wn = the_named_word;
0091 if (TextReader(1)==0) return i;
0092 for (i=0: i<8: i++)
0093 (self.&number)->i = cube_text_buffer->i;
0094 self.article="the";
0095 print_ret "It is now called ", (the) self, ".";
0096 ],
0097 has scored;
0098
0099 ! Copies word "wn" from what the player most recently typed, putting it as
0100 ! plain text into cube_text_buffer, returning false if no such word is there
0101
0102 [ TextReader flag point i j len;
0103
0104 if (flag==1 && from_char~=to_char)
0105 { for (i=from_char, j=0:i<=to_char && j<7:i++)
0106 { cube_text_buffer->j = buffer->i;
0107 if (buffer->i ~= ' ' or ',' or '.') j++;
0108 }
0109 for (:j<8:j++) cube_text_buffer->j = 0;
0110 from_char=0; to_char=0;
0111 rtrue;
0112 }
0113
0114 for (i=0:i<8:i++) cube_text_buffer->i = 0;
0115 if (wn > parse->1) { wn++; rfalse; }
0116 i=wn*4+1; j=parse->i; point=j+buffer; len=parse->(i-1);
0117
0118 for (i=0:i<len && i<7:i++) cube_text_buffer->i = point->i;
0119
0120 wn++; rtrue;
0121 ];
0122
0123 Object burin "magic burin"
0124 with name "magic" "magical" "burin" "pen",
0125 description
0126 "This is a magical burin, used for inscribing objects with words
0127 or runes of magical import. Such a burin also gives you the
0128 ability to write spell scrolls.",
0129 before
0130 [; WriteOn:
0131 if (second ofclass FeaturelessCube)
0132 { if (second notin player)
0133 "Writing on a cube is such a fiddly process that you
0134 need to be holding it in your hand first.";
0135 if (burin notin player)
0136 "You would need some powerful implement for that.";
0137 second.baptise();
0138 rtrue;
0139 }
0140 if (second ofclass SpellBook)
0141 "If a burin could write in a spell book, you wouldn't need
0142 the gnusto spell!";
0143 if (second ofclass Scroll)
0144 "You cannot write just anything on the magic parchment of
0145 a scroll: you can only ~copy~ a spell to it.";
0146 ];
0147
0148 [ WriteOnSub; "Graffiti is banned."; ];
0149
0150 [ CopyToSub;
0151 if (burin notin player) "You need to be holding the burin to copy a spell.";
0152 if (second ofclass SpellBook)
0153 "If a burin could write in a spell book, you wouldn't need
0154 the gnusto spell!";
0155 if (~~(second ofclass Scroll)) "You can only copy spells to scrolls.";
0156 if (child(second)~=0)
0157 "The scroll is already full of incantation.";
0158 "The scroll is not blank, only illegible.";
0159 ];
0160
0161 ! ----------------------------------------------------------------------------
0162 ! Now the whole spell-casting system
0163 ! ----------------------------------------------------------------------------
0164
0165 Attribute known_about; ! Player has seen this spell somewhere
0166 Attribute reversed; ! Effect of this known spell reversed
0167
0168 Attribute is_spell;
0169 Class Spell
0170 with name "spell" "spells", article "the",
0171 number 0,
0172 word_name
0173 [; print (address) (self.&name)-->0;
0174 ],
0175 short_name
0176 [; self.word_name(); print " spell"; give self known_about; rtrue;
0177 ],
0178 specification
0179 [; self.short_name();
0180 print ": ", (string) self.purpose;
0181 ],
0182 before
0183 [; Examine: self.specification(); ".";
0184 ],
0185 has is_spell;
0186
0187 Object memory
0188 with capacity 5,
0189 number_known 1,
0190 describe_contents
0191 [ i j k;
0192 objectloop (i in self) if (i.number==100) j++;
0193 if (j>0)
0194 { print "The ";
0195 objectloop (i in self)
0196 if (i.number==100)
0197 { k++; i.word_name();
0198 if (k==j-1) print " and ";
0199 if (k<j-1) print ", ";
0200 }
0201 if (j==1) print " spell is"; else print " spells are";
0202 print " yours forever. Other than that, y";
0203 }
0204 else print "Y";
0205 print "ou have ";
0206 j=0; k=0;
0207 objectloop (i in self) if (i.number<100) j++;
0208 if (j>0)
0209 { print "the ";
0210 objectloop (i in self)
0211 if (i.number<100)
0212 { k++;
0213 print (name) i;
0214 if (i.number==2) print " (twice)";
0215 if (i.number==3) print " (thrice)";
0216 if (i.number==4) print " (four times)";
0217 if (i.number>=5) print " (many times)";
0218 if (k==j-1) print " and ";
0219 if (k<j-1) print ", ";
0220 }
0221 }
0222 else print "no spells";
0223 " memorised.";
0224 ],
0225 learn_spell
0226 [ sp;
0227 if (sp.number==100) "You always know that spell.";
0228 print "Using your best study habits, you commit the ";
0229 sp.word_name();
0230 print " spell to memory";
0231 if (sp notin self) sp.number=0;
0232 move sp to self;
0233 self.number_known++;
0234 sp.number++;
0235 if (sp.number==1) print ".";
0236 if (sp.number==2) print " once again.";
0237 if (sp.number==3) print " a third time.";
0238 if (sp.number>3) print " yet another time.";
0239 if (self.number_known <= self.capacity) { new_line; rtrue; }
0240 self.forget_spell(sibling(child(self)));
0241 " You have so much buzzing around in your head, though,
0242 that it's likely something may have been forgotten
0243 in the shuffle.";
0244 ],
0245 forget_spell
0246 [ sp;
0247 if (sp notin self || sp.number==100) rtrue;
0248 self.number_known--;
0249 sp.number--;
0250 if (sp.number==0) remove sp;
0251 rtrue;
0252 ];
0253
0254 Spell -> gnusto_spell
0255 with name "gnusto",
0256 purpose "copy a scroll into your spell book",
0257 number 100,
0258 magic
0259 [ i a_book;
0260 if (second ofclass SpellBook)
0261 "Unlike scrolls, spell books are magically guarded against
0262 the 'theft' of their lore.";
0263 if (second==0 || ~~(second ofclass Scroll))
0264 "Your spell fizzles vaguely out.";
0265 if (second notin player)
0266 "A gnusto spell would require close scrutiny of the scroll
0267 it is to copy: which you do not seem to be holding.";
0268 objectloop (i in player)
0269 if (i ofclass SpellBook) a_book=i;
0270 if (a_book==0)
0271 "Your spell fails, as you have no spell book.";
0272 i=child(second);
0273 if (i==0 || ~~(i ofclass Spell))
0274 { print_ret "Your spell fails, as ", (the) second,
0275 " is illegible.";
0276 }
0277 a_book.learn_spell(i); remove second;
0278 print_ret
0279 "Your spell book begins to glow softly. Slowly, ornately,
0280 the words of ", (the) i, " are inscribed,
0281 glowing even more brightly then the book itself.
0282 The book's brightness fades, but the spell remains!
0283 However, the scroll on which it was written vanishes as
0284 the last word is copied.";
0285 ];
0286
0287 Class SpellBook
0288 with array_of_spells 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,
0289 capacity 16,
0290 learn_spell
0291 [ sp p i;
0292 p = self.&array_of_spells;
0293 for (i=0:i<self.capacity && (p-->i)~=0:i++) ;
0294 if (i==self.capacity) rtrue;
0295 p-->i = sp;
0296 ],
0297 before
0298 [; Open, Close:
0299 print_ret
0300 (The) self, " is always open to the right place, but it
0301 is also always closed. This eliminates tedious leafing and
0302 hunting for spells. Many lives have been saved by this
0303 magical innovation.";
0304 Attack:
0305 print_ret "When you are done, ", (the) self, " remains unmarred.";
0306 ],
0307 after
0308 [ p i j; Examine:
0309 p = self.&array_of_spells;
0310 for (i=0:i<self.capacity && (p-->i)~=0:i++)
0311 { j=p-->i; <Examine j>;
0312 }
0313 rtrue;
0314 ];
0315
0316 Class Scroll
0317 with parse_name
0318 [ i j k; j=-1;
0319 if (self has general)
0320 { if (child(self)~=0 && child(self) ofclass Spell)
0321 j=(child(self).&name)-->0; else j='illegible';
0322 }
0323 for (::)
0324 { k=NextWord();
0325 if (k=='scrolls') parser_action=##PluralFound;
0326 if ((k=='scrolls' or 'scroll' or j) || k==(self.&name)-->0)
0327 i++;
0328 else return i;
0329 }
0330 ],
0331 before
0332 [ i; Examine:
0333 i=child(self);
0334 give self general;
0335 if (i==0 || ~~(i ofclass Spell))
0336 "The scroll has faded, and you cannot read it.";
0337 print "The scroll reads ~"; i.specification(); "~.";
0338 ],
0339 invent
0340 [; if (inventory_stage==2 && self has general)
0341 { if (child(self)==0 || ~~(child(self) ofclass Spell))
0342 print " (which is illegible)";
0343 else
0344 { print " (of ", (the) child(self), ")"; }
0345 }
0346 ];
0347
0348 [ ReadableSpell i j k;
0349 if (scope_stage==1)
0350 { if (action_to_be==##Examine) rfalse;
0351 rtrue;
0352 }
0353 if (scope_stage==2)
0354 { objectloop (i in player)
0355 if (i ofclass SpellBook)
0356 { for (k=0:k<i.capacity && (i.&array_of_spells)-->k~=0:k++)
0357 { j=(i.&array_of_spells)-->k; PlaceInScope(j);
0358 }
0359 }
0360 rtrue;
0361 }
0362 ! No need for scope_stage 3 (the error stage), because our
0363 ! ParserError routine handles that case instead
0364 ];
0365
0366 [ CopyableSpell i j k;
0367 if (scope_stage==1) return 1;
0368 if (scope_stage==2)
0369 { objectloop (i in player)
0370 if (i ofclass SpellBook)
0371 { for (k=0:k<i.capacity && (i.&array_of_spells)-->k~=0:k++)
0372 { j=(i.&array_of_spells)-->k; PlaceInScope(j);
0373 }
0374 }
0375 rfalse;
0376 }
0377 ! No need for scope_stage 3 (the error stage), because our
0378 ! ParserError routine handles that case instead
0379 ];
0380
0381 [ SpellsSub; memory.describe_contents(); ];
0382
0383 [ LearnSub; if (location==thedark)
0384 print "(The magic writing of the spells casts enough light
0385 that you can read them.)^";
0386 memory.learn_spell(noun);
0387 ];
0388
0389 Global the_spell_was = gnusto_spell;
0390
0391 [ CastOneSub; <Cast the_spell_was noun>; ];
0392
0393 [ CastSub;
0394 the_spell_was = noun; memory.forget_spell(noun);
0395
0396 if (noun has reversed)
0397 { give noun ~reversed;
0398 if (noun.unmagic() ~= 0) return;
0399 "Nothing happens.";
0400 }
0401
0402 if (second ~= 0)
0403 { ResetVagueWords(second); ! Set "it", "him", "her"
0404 if (second provides before
0405 && second.before() ~= 0) return; ! Run before routine(s)
0406 }
0407 if (noun.magic() ~= 0) return;
0408 "Nothing happens.";
0409 ];
0410
0411 [ InScope i;
0412 if (verb_word=='c,cast' or 'cast')
0413 objectloop (i in memory) PlaceInScope(i);
0414 rfalse;
0415 ];
0416
0417 [ ParserError x i flag vb;
0418 if (etype==VERB_PE or ASKSCOPE_PE)
0419 { if (etype==ASKSCOPE_PE)
0420 { if (verb_word=='cast') vb=1;
0421 if (verb_word=='learn' or 'memorise' or 'memorize') vb=2;
0422 if (verb_word=='copy') vb=3;
0423 if (vb==0) { etype=CANTSEE_PE; rfalse; }
0424 }
0425 wn=verb_wordnum; if (vb~=0) wn++;
0426 x=NextWordStopped();
0427 for (i=player+1:i<=top_object:i++)
0428 if (i ofclass Spell && Refers(i,x)==1
0429 && i has known_about) flag=1;
0430 if (flag==1)
0431 { if (vb==0 or 1)
0432 "You haven't got that spell committed to memory. [Type ~spells~
0433 to see what you do remember.]";
0434 if (vb==2)
0435 "Your training is such that you can only memorise such a spell
0436 with the aid of a spell book containing it.";
0437 if (vb==3)
0438 "You have no text of that spell to copy.";
0439 }
0440 if (vb==1)
0441 "You haven't learned that spell, if indeed it is a spell.";
0442 if (vb==2 or 3)
0443 "You haven't access to that spell, if indeed it is a spell.";
0444 }
0445 rfalse;
0446 ];
0447
0448 [ ChooseObjects obj code;
0449 if (code<2) rfalse;
0450 if (action_to_be==##WriteOn && obj in player) return 9;
0451 return 0;
0452 ];
0453
0454 [ UnknownVerb word i;
0455 objectloop (i in memory)
0456 if (word==(i.&name)-->0) { the_spell_was = i; return 'c,cast'; }
0457 rfalse;
0458 ];
0459
0460 [ PrintVerb v;
0461 if (v=='c,cast') { print "cast a spell at"; rtrue; }
0462 rfalse;
0463 ];
0464
0465 ! ----------------------------------------------------------------------------
0466 ! And now, on with the story. First, some global variables:
0467 ! ----------------------------------------------------------------------------
0468
0469 Global prepared_flag = false; ! Prepared for resurrection?
0470 Global hearing_good = false; ! Sharp hearing?
0471 Global number_filled = 0; ! Sockets in the temple filled
0472
0473 ! ----------------------------------------------------------------------------
0474 ! A "questions" verb. Thus,
0475 ! "who is my friend helistar"
0476 ! "what was the great change"
0477 ! and so on are recognised.
0478 ! ----------------------------------------------------------------------------
0479
0480 [ QuerySub;
0481 noun.description();
0482 ];
0483 [ Topic i;
0484 if (scope_stage==1) return 0;
0485 if (scope_stage==2)
0486 { objectloop (i ofclass Question) PlaceInScope(i);
0487 rtrue;
0488 }
0489 "At the moment, even the simplest questions confuse you.";
0490 ];
0491
0492 Class Question;
0493 Question
0494 with name "helistar" "my" "friend" "colleague",
0495 description
0496 "Helistar is your colleague, an Enchanter like you who has been much
0497 on your mind lately. She has been investigating some very dark
0498 magic indeed, and seems not to be around any more. You feel rather
0499 vague about the details.";
0500 Question
0501 with name "magical" "magic" "burin",
0502 description "A burin is an engraving and writing tool.";
0503 Question
0504 with name "change" "great",
0505 description
0506 "Something you had a lot to do with, but what exactly? No, it's gone.";
0507 Question
0508 with name "cyclops",
0509 description
0510 "A one-eyed giant, usually hostile. (Don't they teach anything at
0511 adventurer school these days?)";
0512 Question
0513 with name "grue",
0514 description
0515 "The grue is a sinister, lurking presence in the dark places of the
0516 earth. Its favorite diet is adventurers, but its insatiable appetite
0517 is tempered by its fear of light. No grue has ever been seen by the
0518 light of day, and few have survived its fearsome jaws to
0519 tell the tale.";
0520 Question
0521 with name "grimoire",
0522 description
0523 "According to Chambers English Dictionary, a grimoire is ~a magician's
0524 book for calling up spirits~.";
0525 Question
0526 with name "spells" "work",
0527 description
0528 "Your memory is still dream-hazed, but it's coming back. As a trained
0529 Enchanter, you have the ability to cast spells like ~frotz~, provided
0530 you have learned them in advance. Some of these spells can be cast
0531 at something; others can be cast alone.
0532 ^^Spells are very complicated. Each time you cast one, you forget it
0533 (though you can get around this by learning it several times, so as
0534 to have several uses up your sleeve). The only way to hang on to
0535 a spell is to have it written down, on a scroll or in a spell book.
0536 Scrolls are not ideal for this, and you can only learn a spell from
0537 your spell book. (But you can add spells to your book.)
0538 ^^[Type ~learn frotz~ and then ~frotz coin~ for an example. You can
0539 also type ~spells~ to see what you currently have memorised.]";
0540
0541 ! ----------------------------------------------------------------------------
0542 ! Some multiple objects, coins in fact, coded in deluxe fashion:
0543 ! ----------------------------------------------------------------------------
0544
0545 Attribute is_coin;
0546 Class Coin
0547 with name "coin",
0548 description "A round unstamped disc, presumably part of the local
0549 currency.",
0550 parse_name
0551 [ i j w;
0552 if (parser_action==##TheSame)
0553 { if ((parser_one.&name)-->0 == (parser_two.&name)-->0) return -1;
0554 return -2;
0555 }
0556 w=(self.&name)-->0;
0557 for (::i++)
0558 { j=NextWord();
0559 if (j=='coins') parser_action=##PluralFound;
0560 else if (j~='coin' or w) return i;
0561 }
0562 ],
0563 has is_coin;
0564
0565 Class GoldCoin
0566 class Coin,
0567 with name "gold",
0568 short_name "gold coin",
0569 plural "gold coins";
0570 Class SilverCoin
0571 class Coin,
0572 with name "silver",
0573 short_name "silver coin",
0574 plural "silver coins";
0575 Class BronzeCoin
0576 class Coin,
0577 with name "bronze",
0578 short_name "bronze coin",
0579 plural "bronze coins";
0580
0581 SilverCoin players_coin;
0582
0583 [ TossCoinSub; if (noun notin player) "You need to be holding the coin first.";
0584 move noun to parent(player);
0585 if (location==thedark) "You throw it away into the darkness.";
0586 if (random(20)==1)
0587 "You toss the coin, and it lands... on its edge, amazingly.";
0588 "You toss the coin, and it comes up... blank, since neither side is
0589 marked.";
0590 ];
0591
0592 ! ----------------------------------------------------------------------------
0593 ! The player's spell book, and three initial spells (to go with gnusto):
0594 ! ----------------------------------------------------------------------------
0595
0596 SpellBook players_book "spell book"
0597 with name "spell" "book" "my" "spellbook",
0598 description "My Spell Book^";
0599
0600 Spell frotz_spell
0601 with name "frotz",
0602 purpose "cause an object to give off light",
0603 magic
0604 [; if (second==0) "There is a brief, blinding flash of light.";
0605 if (second has animate)
0606 "The spell, not designed for living creatures, goes sour.";
0607 if (second in compass)
0608 "The spell dissipates vaguely.";
0609 give second light;
0610 print_ret
0611 "There is an almost blinding flash of light as ", (the) second,
0612 " begins to glow! It slowly fades to a less painful level, but ",
0613 (the) second, " is now quite usable as a light source.";
0614 ],
0615 unmagic
0616 [; if (second==0) "There is a brief moment of deep darkness.";
0617 if (second has animate)
0618 "The spell, not designed for living creatures, goes sour.";
0619 if (second in compass)
0620 "The spell dissipates vaguely.";
0621 if (second hasnt light)
0622 print_ret (The) second, " isn't producing light as it is.";
0623 give second ~light;
0624 print_ret "A pool of darkness coagulates around ", (the) second,
0625 " but slowly fades back to normality. Still, ",
0626 (the) second, " is no longer any kind of light source.";
0627 ];
0628
0629 Spell rezrov_spell
0630 with name "rezrov",
0631 purpose "open even locked or enchanted objects",
0632 magic
0633 [; if (second==0) "The world is open already.";
0634 if (second has animate)
0635 "It might be a boon to surgeons if it worked, but it doesn't.";
0636 if (second has open || second hasnt openable)
0637 "It doesn't need opening.";
0638 if (second hasnt locked)
0639 { give second open;
0640 print_ret (The) second, " opens obediently.
0641 Like swatting a fly with a sledge hammer, if you ask me.";
0642 }
0643 give second open ~locked;
0644 print "Silently, ", (the) second, " swings open. ";
0645 if (second has container) <<Search second>>; new_line; rtrue;
0646 ],
0647 unmagic
0648 [; if (second==0) "The world is closed already.";
0649 if (second has animate)
0650 "Happily, that is unnecessary.";
0651 if (second has locked || second hasnt lockable)
0652 "It doesn't need locking.";
0653 give second ~open locked;
0654 "Silently, ", (the) second, " swings shut and locks.";
0655 ];
0656
0657 Spell yomin_spell
0658 with name "yomin",
0659 purpose "mind probe",
0660 magic
0661 [; if (second==0 || second hasnt animate)
0662 "That must be either vegetable or mineral.";
0663 if (second==player) "You give yourself a mild headache.";
0664 print_ret "You look into the rather ordinary thoughts of ",
0665 (the) second, ".";
0666 ],
0667 unmagic
0668 [; if (second==0 || second hasnt animate)
0669 "That must be either vegetable or mineral.";
0670 if (second==player) "You give yourself a mild headache.";
0671 print_ret (The) second, " is rather shocked, for some reason.";
0672 ];
0673
0674 ! ----------------------------------------------------------------------------
0675 ! The first scene: the Hut and its (rather easy) secret
0676 ! ----------------------------------------------------------------------------
0677
0678 Class Place
0679 has light;
0680
0681 Place Hut "Ramshackle Hut"
0682 with description
0683 "Until quite recently, someone lived here, you feel sure.
0684 Now the furniture is matchwood and
0685 the windows are glassless. Outside, it is a warm, sunny day,
0686 and grasslands extend to the low hills on the horizon.",
0687 out_to Grasslands, w_to Grasslands,
0688 cant_go "There's only the one room: better go ~out~.",
0689 name "windows" "grasslands" "grass" "hills";
0690
0691 Object -> furniture "wooden furniture"
0692 with name "furniture" "broken" "wood" "wooden",
0693 before
0694 [; Examine, Search, LookUnder:
0695 self.before=0; score=score+5;
0696 move h_box to player;
0697 "Searching through the furniture, which is good for nothing
0698 but firewood now, you come across an old cedarwood box,
0699 which you pick up for a closer look.";
0700 ],
0701 has scenery;
0702
0703 Object h_box "cedarwood box"
0704 with name "cedar" "cedarwood" "wooden" "box",
0705 description "The box bears the calligraphed initial H."
0706 has container openable lockable locked;
0707
0708 SpellBook -> helistars_book "Helistar's grimoire"
0709 with name "grimoire" "helistar" "helistars",
0710 description "This must be the grimoire of dangerous spells kept by
0711 your irresponsible friend Helistar. Many pages are
0712 missing, but a few spells remain:^",
0713 has proper;
0714
0715 ! ----------------------------------------------------------------------------
0716 ! Grasslands and the valley
0717 ! ----------------------------------------------------------------------------
0718
0719 Place Grasslands "Grasslands, near Hut"
0720 with name "grasslands" "grass" "hut" "path",
0721 description
0722 "The grasslands sway over low hills in all directions: it is a
0723 peaceful wilderness, broken only by this hut and a faint path
0724 to the north.",
0725 in_to Hut, e_to Hut,
0726 n_to Valley,
0727 cant_go "You wander around for a while but end up back at the hut.";
0728
0729 Place Valley "Pocket Valley"
0730 with name "valley" "trail",
0731 description
0732 "A pleasant pocket valley in the grassy hills, through which a
0733 trail runs north-to-south.",
0734 n_to "The trail runs out to nothing, and you retreat for fear of
0735 getting so lost you couldn't find the hut again by nightfall.",
0736 cant_go "You wander around the pleasant valley, but are afraid to
0737 lose sight of the trail.",
0738 s_to Grasslands;
0739
0740 [ RideSub; print_ret "You can hardly ride ", (a) noun, "."; ];
0741
0742 Object -> horse "horse"
0743 with short_name
0744 [; if (self has general) print "winged horse";
0745 else print "chestnut horse";
0746 rtrue;
0747 ],
0748 parse_name
0749 [ i j; if (self has general) j='winged'; else j=-1;
0750 while (NextWord()==j or 'horse' or 'chestnut') i++;
0751 return i;
0752 ],
0753 describe
0754 [; print_ret
0755 "There is ", (a) self, " here, munching on a pile of oats.";
0756 ],
0757 before
0758 [; Cast: if (the_spell_was == bozbar_spell)
0759 { give self general;
0760 "A pair of handsome brown wings suddenly appears on
0761 the horse's powerful shoulders. The horse turns in a
0762 complete circle, a look of puzzlement on his face.";
0763 }
0764 if (the_spell_was == yomin_spell)
0765 "He is mainly thinking about oats. Partly who you are
0766 and what you're up to, but mainly oats.";
0767 Enter: <<Ride self>>;
0768 Ride: if (horse hasnt general)
0769 "You ride around for a while, exercising the horse, but
0770 soon enough he tires of this and pointedly brings you
0771 back to the oats. Obligingly you dismount and he
0772 begins grazing again.";
0773
0774 print "You begin to ride north. Then, slowly at first but with
0775 increasing sureness, the horse begins beating its powerful
0776 wings. You rise majestically through the air, sailing
0777 gracefully across a chasm where the hills fall away.
0778 The horse lands gently on the far side and deposits you,
0779 taking to the skies again.^";
0780 PlayerTo(Edge); rtrue;
0781 ],
0782 has animate;
0783
0784 Object -> oats "pile of oats"
0785 with name "oats" "pile" "of",
0786 before
0787 [; Examine, Search, LookUnder:
0788 self.before=NULL;
0789 move shiny_scroll to player; score=score+5;
0790 itobj=shiny_scroll;
0791 "Sifting through the oats, you find a shiny scroll! Lucky
0792 you got to it before the horse did. As you turn it over
0793 in your hands, it seems undamaged.";
0794 Take: "What would you want with all those oats?";
0795 ],
0796 has scenery;
0797
0798 Scroll shiny_scroll "shiny scroll"
0799 with name "shiny";
0800
0801 Spell -> bozbar_spell
0802 with name "bozbar",
0803 purpose "cause an animal to sprout wings",
0804 magic
0805 [; if (second==0 || second hasnt animate)
0806 "The spell dies away in vain.";
0807 if (second==player)
0808 "Your elbows twitch, but there is no other effect.";
0809 print_ret "For a moment, ", (the) second,
0810 " looks highly discomforted, but the moment passes.";
0811 ],
0812 unmagic
0813 [; if (second==0 || second hasnt animate)
0814 "The spell dies away in vain.";
0815 if (second==player) "What wings?";
0816 if (second==horse && horse has general)
0817 { give horse ~general;
0818 "The Enchanter giveth, and the Enchanter taketh away.
0819 The horse looks disconsolate but returns to the oats.";
0820 }
0821 print_ret (The) second, " has no wings to lose.";
0822 ];
0823
0824 ! ----------------------------------------------------------------------------
0825 ! The Chasm and the snake
0826 ! ----------------------------------------------------------------------------
0827
0828 Place Edge "Edge of Chasm"
0829 with name "wide" "chasm" "road" "daffodils" "clump",
0830 description
0831 "The road ends suddenly at a wide chasm. The road leads upward
0832 to the north, and you can see it continuing on the southern side
0833 of the chasm.",
0834 u_to Up_Road, n_to Up_Road,
0835 cant_go "The chasm is too perilous to approach. The only safe way is
0836 up and to the north.",
0837 before
0838 [; Jump: deadflag = true;
0839 "You jump bravely into the chasm, and plunge...
0840 gracefully through the air. (It gets a bit less noble and
0841 airy after that.)";
0842 ];
0843
0844 Object -> snake "hissing snake"
0845 with name "hissing" "snake",
0846 initial
0847 "Lying in a tight coil at the edge of the chasm is a hissing snake.",
0848 description
0849 "It has some V-markings, some scaly parts, colours from grey to
0850 reddish-brown. Is that any help?",
0851 life
0852 [; "The snake hisses angrily!"; ],
0853 before
0854 [; Cast:
0855 switch(the_spell_was)
0856 { urbzig_spell:
0857 remove self;
0858 snakes_cube.initial =
0859 "Beside a clump of daffodils is a featureless white cube.";
0860 "The snake is replaced by a clump of daffodils.";
0861 bozbar_spell:
0862 deadflag = true; remove self;
0863 snakes_cube.initial =
0864 "A featureless cube rests where the snake took off from.";
0865 "The snake is transformed into a huge, winged serpent,
0866 a dragon which bellows and leaps out into the chasm,
0867 backwinging furiously... and knocking you over the
0868 edge quite by accident.";
0869 yomin_spell:
0870 "Horrid reptilian thoughts insinuate their way into you.";
0871 }
0872 Take, Remove:
0873 "The slipperiness of its skin is only one of many reasons
0874 why this is ill-advised.";
0875 ],
0876 has animate;
0877
0878 FeaturelessCube -> snakes_cube "cube"
0879 with initial
0880 "The snake appears to be curled around a featureless white cube.",
0881 before
0882 [; if (snake notin nothing) "The snake won't let you near that cube!";
0883 ];
0884
0885 ! ----------------------------------------------------------------------------
0886 ! The crest of the hill; Icarus the tortoise; the chewed scroll
0887 ! ----------------------------------------------------------------------------
0888
0889 Place Up_Road "Crest of Hill"
0890 with description
0891 "The road crosses the top of a ridge here, sloping downwards to
0892 the south and the northwest. A track diverges to east.",
0893 nw_to Cave_Mouth, s_to Edge, d_to Edge, e_to Track;
0894
0895 Object -> tortoise "tortoise"
0896 with name "tortoise" "turtle",
0897 initial "A tortoise ambles along the road, extremely slowly.",
0898 life
0899 [; "The tortoise (slowly) turns its neck to look at you (stupidly).";
0900 ],
0901 before
0902 [; Cast: switch(the_spell_was)
0903 { urbzig_spell:
0904 "Just how safe do you want your surroundings to be?";
0905 bozbar_spell:
0906 move chewed_scroll to parent(self); remove self;
0907 StartDaemon(self); score=score+5;
0908 "The tortoise seems to be incapable of expressing
0909 surprise, but is now soaring away high in the sky.
0910 Something rather grubby is left behind.";
0911 yomin_spell:
0912 "For a moment you think there is nothing there, as you
0913 chew absentmindedly on a leaf. But somewhere inside
0914 the tortoise is a sense of wonder at the amazing blue
0915 canopy of the sky.";
0916 }
0917 Take, Remove:
0918 "Your parents always warned you not to pick up casual
0919 acquaintances met on the road.";
0920 ],
0921 daemon
0922 [ i; if (location ~= Up_Road or Track || random(6)~=1) rfalse;
0923 if (random(4)==1 && self hasnt general)
0924 { move feather to location; give self general;
0925 "^A tortoise-feather flutters to the ground before you!";
0926 }
0927 i=random(3);
0928 switch(i)
0929 { 1: print "^High in the sky,";
0930 2: print "^Far above you,";
0931 3: print "^Tiny in the blue sky,";
0932 }
0933 " a tortoise flaps across the sun.";
0934 ],
0935 has animate;
0936
0937 Scroll torn_scroll "torn scroll"
0938 with name "torn";
0939
0940 Spell -> lobal_spell
0941 with name "lobal",
0942 purpose "sharpen hearing",
0943 magic
0944 [; if (second==0 || second hasnt animate)
0945 "There is a loud bang in your ear, but no other effect.";
0946 if (second==player)
0947 { if (hearing_good) "There is no further effect.";
0948 hearing_good=1; StartTimer(self, 5);
0949 "Nothing happens, possibly because those butterflies on the
0950 other side of the hill keep distracting you.";
0951 }
0952 print_ret (The) second,
0953 " is no doubt grateful for the gift of sharper hearing.";
0954 ],
0955 unmagic
0956 [; if (second==0 || second hasnt animate)
0957 "There is a brief silence, but no other effect.";
0958 if (second==player) { StopTimer(self); hearing_good=0; "Pardon?"; }
0959 print_ret (The) second,
0960 " is no doubt grateful not to have to listen to you.";
0961 ],
0962 time_left 0,
0963 time_out
0964 [; if (hearing_good)
0965 { hearing_good = false;
0966 "^Those wretched butterflies finally shut up.";
0967 }
0968 ];
0969
0970 Scroll chewed_scroll "chewed scroll"
0971 with initial "It looks as if the tortoise was eating something - once
0972 it might have been a scroll, but now it lies there,
0973 chewed up like a lettuce leaf.",
0974 before
0975 [; Cast: if (the_spell_was == caskly_spell)
0976 { move torn_scroll to parent(self);
0977 remove self; score=score+5;
0978 "Before your eyes, the scroll begins to repair itself,
0979 failing only at the very last tear. Not quite perfect
0980 perhaps, but certainly a readable, if torn scroll.";
0981 }
0982 Eat: "~Eating your words~ is notoriously dangerous for a wizard.
0983 Rearranged in the stomach, a spell might do anything!";
0984 ],
0985 with name "chewed";
0986
0987 Object feather "tortoise feather"
0988 with name "tortoise" "feather",
0989 description
0990 "Possibly your rarest, and also least valuable, possession.";
0991
0992 ! ----------------------------------------------------------------------------
0993 ! The cave mouth and the perfect sapphire
0994 ! ----------------------------------------------------------------------------
0995
0996 Place Cave_Mouth "Cave Mouth"
0997 with name "gorse" "footpath" "cave" "mouth",
0998 description
0999 "This is a cave mouth, at one end of a road which winds southeast
1000 over rising ground. The entrance west to the caves is a dark
1001 tunnel, and only a footpath runs further north, into gorse.",
1002 u_to Up_Road, se_to Up_Road, in_to Iron_Door, w_to Iron_Door,
1003 n_to Footpath;
1004
1005 Object -> Iron_Door "iron door"
1006 with name "iron" "door" "heavy",
1007 description "It just looks like an ordinary heavy iron door.",
1008 door_dir
1009 [; if (location==Cave_Mouth) return w_to; return e_to;
1010 ],
1011 door_to
1012 [; if (location==Cave_Mouth) return In_Cave;
1013 return Cave_Mouth;
1014 ],
1015 describe
1016 [; if (self has open) "^The iron door stands open.";
1017 if (self hasnt locked) "^The iron door is unlocked but shut.";
1018 "A heavy iron door bars the cave mouth.";
1019 ],
1020 found_in In_Cave Cave_Mouth
1021 has static door openable locked lockable;
1022
1023 ! Cf. T. S. Eliot, "Burnt Norton" II:
1024 ! (but see also Mallarme's sonnet from which Eliot borrowed the image)
1025
1026 Object -> sapphire "perfect sapphire"
1027 with name "perfect" "sapphire" "gemstone" "gem",
1028 initial "Clotted in the mud beside the door is a perfect sapphire.",
1029 before
1030 [; Examine: remove self; move caskly_spell to memory;
1031 players_book.learn_spell(caskly_spell);
1032 caskly_spell.number=100;
1033 "As you gaze into the perfect blue of the sapphire,
1034 you feel your mind begin to reel. Unable to bear
1035 the naked sight of perfection, you look away, ashamed.
1036 As you do so, the sapphire cracks and wastes away to
1037 thin hot dust. But something remains, something in your
1038 mind...";
1039 ];
1040
1041 Spell caskly_spell
1042 with name "caskly",
1043 purpose "cause perfection",
1044 magic
1045 [; if (second==0) "Trying to make everything perfect was a little
1046 too ambitious.";
1047 if (second==player) "Oh, don't be too hard on yourself.";
1048 if (second==helistars_book)
1049 "Your spell is not powerful enough to restore the lost pages.";
1050 print_ret (The) second, " looks pretty perfect as is.";
1051 ];
1052
1053 ! ----------------------------------------------------------------------------
1054 ! Inside the Cave, the powerful urbzig spell and its consequences
1055 ! ----------------------------------------------------------------------------
1056
1057 Place In_Cave "Inside Cave"
1058 with description
1059 "A wide but shallow cave not far inside the hill. There is no
1060 obvious exit, except for the way you came in.",
1061 out_to
1062 [; if (CoinsIn(left_pan)+CoinsIn(right_pan) < 6)
1063 "Something bars your way, and you hear
1064 the scales jangling militantly. You were trying to
1065 steal its coins!";
1066 if (scales.number~=0) "Something bars your way, and you hear
1067 the scales jangle slightly with energy.";
1068 return Iron_Door;
1069 ],
1070 e_to
1071 [; return self.out_to();
1072 ],
1073 cant_go "The only way is back ~out~ through the iron door.",
1074 after
1075 [; Take: if (parent(noun)==left_pan or right_pan)
1076 print_ret "Taken from ", (the) parent(noun), ".";
1077 ],
1078 has ~light;
1079
1080 FeaturelessCube -> cave_cube "cube"
1081 with initial "Balanced on a rock formation is a featureless white cube.";
1082
1083 Object -> scales "pair of scales"
1084 with name "pair" "of" "scales" "pans", number 0,
1085 describe
1086 [; print "^A fair-sized pair of scales hangs from a bracket in the
1087 cave wall. ";
1088 if (self.number==0) "The scales are balanced.";
1089 if (self.number==1) "The left-hand side is higher.";
1090 "The right-hand side is higher.";
1091 ],
1092 before
1093 [; "There are left and right hand pans, which you should refer to
1094 individually.";
1095 ],
1096 has static supporter;
1097
1098 Class ScalePan
1099 with name "pan" "side" "tray",
1100 before
1101 [; Receive:
1102 if (noun ofclass Scroll or Coin) rfalse;
1103 if (noun==feather) rfalse;
1104 "The pans gleam with what almost seems greed, and somehow they
1105 contrive to nudge your hand past them with your worthless and
1106 boring item.";
1107 ],
1108 after
1109 [ i j d w1 w2; Receive, LetGo: i=scales.number;
1110 objectloop (j in left_pan) w1=w1 + WeightOf(j);
1111 objectloop (j in right_pan) w2=w2 + WeightOf(j);
1112 if (w1==w2) scales.number=0;
1113 if (w1 > w2) scales.number=-1;
1114 if (w1 < w2) scales.number=1;
1115 j=scales.number; d=(w2-w1)*(scales.number);
1116 if (j==i) rfalse;
1117 if (j==0) "The scales come into balance.";
1118 if (j==1) print "The left pan "; else print "The right pan ";
1119 if (d==1) "very slowly rises up.";
1120 "rises up.";
1121 ],
1122 has supporter scenery;
1123
1124 [ WeightOf obj;
1125 if (obj==bronze_coin) return 2;
1126 if (obj ofclass Scroll || obj==feather) return 1;
1127 return 3;
1128 ];
1129
1130 [ CoinsIn obj i c;
1131 objectloop (i in obj) if (i ofclass Coin) c++;
1132 return c;
1133 ];
1134
1135 ScalePan -> right_pan "right pan" with name "right";
1136 GoldCoin -> ->;
1137 GoldCoin -> ->;
1138 GoldCoin -> ->;
1139
1140 ScalePan -> left_pan "left pan" with name "left";
1141 BronzeCoin -> -> bronze_coin;
1142 GoldCoin -> ->;
1143 GoldCoin -> ->;
1144
1145 Scroll -> -> crumpled_scroll "crumpled scroll"
1146 with name "crumpled";
1147 Spell -> -> -> urbzig_spell
1148 with name "urbzig",
1149 purpose "turn a dangerous object into a harmless one",
1150 magic
1151 [; if (second==0) "The spell fizzles away.";
1152 if (second==player) "It's a matter of opinion, isn't it?";
1153 if (second==helistars_book or mace || second ofclass FeaturelessCube)
1154 { CDefArt(second); remove second;
1155 if (second==mace && cyclops in location)
1156 { remove cyclops; move eye_cube to location;
1157 " turns into a featureless white cube just as the cyclops
1158 was about to hit you with it. Mightily embarrassed
1159 by this, he drops the cube and runs off!";
1160 }
1161 print " turns into a moth and flutters away.^";
1162 rtrue;
1163 }
1164 print_ret "Nothing obvious happens. Perhaps ", (the) second,
1165 " isn't so very dangerous after all.";
1166 ],
1167 unmagic
1168 [; if (second==0) "The spell fizzles away.";
1169 if (second==player) "It's a matter of opinion, isn't it?";
1170 if (second has static || second has scenery)
1171 { print_ret "Your spell is too weak for something quite as
1172 monumentally harmless as ", (the) second, ".";
1173 }
1174 if (second==helistars_book or snake or cyclops or mace
1175 || second ofclass FeaturelessCube)
1176 "Nothing obvious happens.";
1177 if (second in player)
1178 { remove second; deadflag = true;
1179 "Suddenly, a tarantula races up your arm to your throat!
1180 Perhaps it was unwise to gizbru something you were
1181 actually holding.";
1182 }
1183 if (cyclops has general)
1184 "Nothing happens. Perhaps that's just as well,
1185 after the last time.";
1186 move cyclops to location;
1187 remove second; give cyclops general; StartTimer(cyclops, 5);
1188 print_ret (The) second, " is replaced by a buck-toothed cyclops
1189 wielding a mace!";
1190 ];
1191
1192 Object cyclops "buck-toothed cyclops"
1193 with name "buck" "toothed" "buck-toothed" "cyclops",
1194 initial "A huge buck-toothed cyclops menaces you, armed with a
1195 heavy mace!",
1196 before
1197 [; Cast: if (the_spell_was == bozbar_spell)
1198 "Does the term ~death wish~ mean anything to you?";
1199 if (the_spell_was == urbzig_spell)
1200 "The cyclops bellows with glee as your spell has
1201 no effect. (After all, he wouldn't be ~dangerous~ if
1202 an urbzig spell worked on him, would he?)";
1203 ],
1204 life [; "He roars incoherently, swinging the mace!"; ],
1205 time_left 0,
1206 time_out
1207 [; if (self notin location)
1208 { remove self; rtrue;
1209 }
1210 deadflag = true; remove mace; remove cyclops;
1211 "Feeling that he's given you quite long enough to explain why
1212 you made such a mess of his life, he swings the great mace
1213 maniacally down on you!";
1214 ],
1215 each_turn
1216 [ i; i=random(4); if (i==1) "^The cyclops leaps and bellows!";
1217 if (i==2)
1218 "^Whirling the mace, the cyclops jabbers at you incoherently.";
1219 if (i==3)
1220 "^The cyclops is losing patience (the appropriate cyclops
1221 word is untranslatable into English, but approximately means
1222 ~forbearance in not smashing all nearby skulls~).";
1223 "^The cyclops jabs you with the mace, almost breaking your rib.";
1224 ],
1225 has animate transparent;
1226
1227 Object -> mace "mace"
1228 with name "heavy" "mace" "axe",
1229 description "It looks much too heavy for you to even lift.";
1230
1231 FeaturelessCube -> eye_cube "cube"
1232 with initial
1233 "A featureless white cube lies where the cyclops dropped it.";
1234
1235 ! ----------------------------------------------------------------------------
1236 ! The Footpath and the carpet
1237 ! ----------------------------------------------------------------------------
1238
1239 Place Footpath "Gorse Bushes"
1240 with description
1241 "The footpath from the cave mouth runs into dense, impenetrable
1242 gorse bushes. Perhaps it wasn't so much a footpath as a rill
1243 in the earth where roots wouldn't take; anyway, there's no way
1244 but back south.",
1245 s_to Cave_Mouth;
1246
1247 Object -> carpet "beautiful red carpet"
1248 with name "beautiful" "magic" "red" "carpet",
1249 initial
1250 "Slung over one of the gorse bushes is a beautiful red carpet.",
1251 description
1252 "This is a carpet of unusual design. It is red, beautifully woven
1253 and bears a pattern of cubes.",
1254 before
1255 [ i; Receive:
1256 if (self notin location || self hasnt moved)
1257 "Not until the carpet's on the ground, you can't.";
1258 Ride: <<Enter self>>;
1259 Enter:
1260 if (self notin location || self hasnt moved)
1261 "Not until the carpet's on the ground, you can't.";
1262 if (location==Balance_Room)
1263 "Mysteriously, the carpet rucks and pulls until you're
1264 thrown off. It settles back on the white floor with a
1265 contented sigh.";
1266 if (location==In_Cave)
1267 "The carpet rises suddenly, crashing into the roof of
1268 the cave and throwing you back off again. Painfully.";
1269 if (location==Bazaar) i=Up_Road; else i=Bazaar;
1270 print "The carpet rises suddenly into the fluffy white
1271 clouds, and after a headlong journey deposits you...^";
1272 move self to i;
1273 PlayerTo(i,1); move player to self; <<Look>>;
1274 Take: if (player in self) "Not while you're on it!";
1275 for (i=child(self):i~=0:i=child(self))
1276 { move i to location;
1277 print "(Dislodging ", (the) i, ")^";
1278 }
1279 ],
1280 has supporter enterable;
1281
1282 ! ----------------------------------------------------------------------------
1283 ! A Bazaar Lottery
1284 ! ----------------------------------------------------------------------------
1285
1286 Global last_called = 1;
1287 Global explicit_flag = 0;
1288 Global tickets_taken = 0;
1289
1290 Class Ticket(6)
1291 with number -1, name "ticket",
1292 description
1293 [; if (self.number==2306) "It is labelled ~First Prize~!";
1294 if (self.number==5802) "It is labelled ~Nineteenth Prize~.";
1295 "~You lose,~ says the ticket, with a smily face. ~Try again!~";
1296 ],
1297 short_name
1298 [; if (self.number==-1) rfalse;
1299 print "lottery ticket ", self.number; rtrue;
1300 ],
1301 parse_name
1302 [ i j w;
1303 i=0;
1304 if (NextWord()=='lottery') i++; else wn--;
1305 if (NextWord()=='tickets')
1306 { parser_action=##PluralFound; return i+1; } else wn--;
1307 if (NextWord()~='ticket') return 0;
1308 i++;
1309 w=TryNumber(wn);
1310 if (w==-1000) { explicit_flag = false; return i; }
1311 if (w==0) return 0;
1312 if (self.number==-1)
1313 { objectloop(j ofclass Ticket)
1314 if (w == j.number) return 0;
1315 }
1316 else
1317 { if (self.number~=w) return 0;
1318 }
1319 i++; last_called = w; explicit_flag = true; return i;
1320 ],
1321 before
1322 [; Examine:
1323 if (self in board)
1324 "It would be cheating to see what's written on the curled up
1325 tickets still in the board.";
1326 Cast: "~Get outta here, bub!~, the barker says, disgusted.";
1327 ];
1328
1329 Place Bazaar "Crowded Bazaar"
1330 with description
1331 "This is a crowded, noisy bazaar. Directly in front of you is
1332 a lottery! But the contemptuous-looking barker is doing a
1333 very poor trade: hardly anyone wants his first prize, the
1334 big cuddly toy elephant, or even his nineteenth prize, a
1335 featureless white cube.",
1336 each_turn
1337 [; switch(random(4))
1338 { 1: "^~Roll up! Roll up! One silver piece for three goes!~";
1339 2: "^~Come on, then! Just a silver coin gets you three!~";
1340 3: "^~Think what you could win, all for one silver coin!~";
1341 4: "^~This could be your lucky day!~";
1342 }
1343 ],
1344 before
1345 [; Learn:
1346 "~None of that!~ snaps the barker angrily, putting you off
1347 your study habits. He mutters about ~Enchanter cheats~,
1348 but under the circumstances you decide to let the insult
1349 pass.";
1350 ],
1351 cant_go "Everywhere, the crowds of jabbering natives block your way
1352 to all the good stalls. In fact, the only one you can get at is
1353 this dismal lottery.";
1354
1355 Object -> board "lottery board"
1356 with credit 0,
1357 name "board" "lottery" "holes",
1358 description
1359 "There are a hundred holes each way, making, um, let's see, yes,
1360 ten thousand tickets in all. Still, there are nineteen prizes,
1361 so your odds must be, oh, well, not too awful anyway.",
1362 before
1363 [ i; LetGo:
1364 if (self.credit == 0)
1365 "The barker stabs you in the chest with
1366 his finger. ~That's a silver coin to you, bub!~";
1367
1368 if (explicit_flag)
1369 { objectloop (i ofclass Ticket)
1370 if (last_called == i.number)
1371 "That ticket's already taken.";
1372 }
1373 else
1374 { .RandomChoice;
1375 last_called = random(10000);
1376 objectloop (i ofclass Ticket)
1377 if (last_called == i.number)
1378 jump RandomChoice;
1379 }
1380
1381 tickets_taken++;
1382 self.credit--;
1383
1384 i = Ticket.create();
1385 if (i == 0)
1386 "The barker looks metaphysically embarrassed. ~Um,
1387 Inform's object creation system seems not to have worked.~";
1388
1389 i.number = last_called; itobj = i;
1390
1391 move i to player; give i moved proper;
1392 if (explicit_flag==0)
1393 print "Randomly picking from the ", 10001-tickets_taken,
1394 " numbered holes with tickets in, you ";
1395 else print "You ";
1396 print_ret "take ", (the) i, " out of the board.";
1397
1398 Examine: ;
1399 Receive:
1400 if (noun ofclass Ticket)
1401 "~No changes of mind, that's your ticket now! Give it to
1402 me if you want to play it.~";
1403 <<Push self>>;
1404 default:
1405 "The barker is burly, and won't let you
1406 tamper with the board.";
1407 ],
1408 initial
1409 "Behind the barker is a huge drilled board, and inside each little
1410 numbered hole is a rolled-up lottery ticket."
1411 has static container open;
1412
1413 Ticket -> -> ticket_in_board "rolled-up ticket from the board"
1414 with article "a";
1415
1416 Object -> barker "barker"
1417 with name "barker" "burly" "man",
1418 number 0,
1419 description
1420 "A boxer gone to seed who failed as a magician all down the
1421 coast, that'd be your guess.",
1422 life
1423 [; Attack, Kiss: "No way. He must weigh twice what you do.";
1424 Ask: switch(noun)
1425 { 'prize', 'prizes':
1426 "~Just one silver coin and a prize could be yours!~";
1427 'white', 'featureless', 'cube':
1428 "He blows the dust off it. ~Genuine antique, that.~";
1429 'elephant', 'toy', 'cuddly':
1430 "~Good quality merchandise,~ he says, in a way that
1431 suggests he can only spell one of those three words.";
1432 'ticket', 'tickets', 'lottery':
1433 "~Three tickets for one silver coin!~";
1434 default: "~Just play the game, bub.~";
1435 }
1436 Order, Answer: "The barker glowers at you.";
1437 Give: if (noun ofclass Ticket)
1438 { remove noun;
1439 if (noun.number==2306)
1440 { move elephant to player; give elephant moved;
1441 remove pelephant;
1442 Bazaar.description =
1443 "This is a crowded, noisy bazaar. Directly in front of you is
1444 the lottery!";
1445 "With very bad grace, the barker shoves the
1446 cuddly toy elephant into your arms.";
1447 }
1448 if (noun.number==5802)
1449 { move barker_cube to player; give barker_cube moved;
1450 remove pcube;
1451 Bazaar.description =
1452 "This is a crowded, noisy bazaar. Directly in front of you is
1453 the lottery!";
1454 score=score+5;
1455 "With concealed relief, the barker shoves the
1456 featureless white cube into your hands.";
1457 }
1458 "~Bad luck! You lose!~";
1459 }
1460 if (self.number==2) "~You've had enough goes already!~ he
1461 growls. No wonder trade is bad.";
1462 if (~~(noun ofclass Coin))
1463 "~What do you call that? One silver coin to play!~";
1464 if ((noun.&name)-->0 == 'bronze')
1465 "~Bronze! Not a chance, sunshine.~";
1466 remove noun;
1467 board.credit = board.credit + 3;
1468 self.number++;
1469 if ((noun.&name)-->0 == 'gold')
1470 "Gleefully the barker snatches the gold coin. ~Sorry
1471 bub, no change. Business is slack today!~";
1472 "Grudgingly the barker takes the silver coin and stands
1473 back to let you at the board, arms folded.";
1474 ],
1475 before
1476 [; Cast: switch(the_spell_was)
1477 { bozbar_spell:
1478 "He's not that much of an animal.";
1479 lobal_spell:
1480 "His problem is listening, not hearing.";
1481 caskly_spell:
1482 "For a moment his hair seems to comb itself.
1483 Irritated, he ruffles it again, and the spell dies
1484 an ignominious death.";
1485 yomin_spell:
1486 if (elephant has moved || barker_cube has moved)
1487 "The barker's mind is a heap of grumbles about lost
1488 prizes and scrawny Enchanters.";
1489 if (self hasnt general)
1490 { give self general;
1491 "~Hope that scrawny Enchanter doesn't pick 2306!~
1492 thinks the barker (slowly).";
1493 }
1494 "~If that mark does win, hope it's only worthless
1495 old 5802,~ ponders the barker.";
1496 }
1497 ],
1498 has animate scenery;
1499
1500 Object -> prizes "prizes"
1501 with name "prize" "prizes",
1502 before [; "~Hands off those prizes!~"; ],
1503 has scenery;
1504
1505 Object -> pelephant "prize elephant"
1506 with name "prize" "elephant" "cuddly" "toy",
1507 description "Pink, cuddly, toy, elephant. Says it all, really.",
1508 before [; Examine: ; default: "~Hands off those prizes!~"; ],
1509 has scenery;
1510
1511 Object -> pcube "prize cube"
1512 with name "prize" "featureless" "white" "cube",
1513 description "Wouldn't you like to win it?",
1514 before [; Examine: ; default: "~Hands off those prizes!~"; ],
1515 has scenery;
1516
1517 Object elephant "cuddly toy elephant"
1518 with name "cuddly" "toy" "elephant",
1519 description "Pink, cuddly, toy, elephant. Says it all, really.",
1520 before
1521 [; Cast: if (the_spell_was == bozbar_spell)
1522 "Let me get this straight. You, the enchanter who
1523 defeated Krill, the head of the Borphee Guild
1524 himself... are attempting to grow wings on a pink
1525 cuddly elephant?";
1526 if (the_spell_was == yomin_spell) "Woolly.";
1527 ];
1528
1529 FeaturelessCube barker_cube "cube";
1530
1531 ! ----------------------------------------------------------------------------
1532 ! The spells in Helistar's grimoire
1533 ! ----------------------------------------------------------------------------
1534
1535 Spell lleps_spell
1536 with name "lleps",
1537 purpose "reverse effect of memorised spell",
1538 magic
1539 [; if (second==0 || second notin memory)
1540 "The spell backfires, painfully.";
1541 if (second.number==100)
1542 "You know that spell too well for your mind to be able
1543 to accept the change.";
1544 if (second has reversed) give second ~reversed;
1545 else give second reversed;
1546 if (second==lleps_spell)
1547 { memory.forget_spell(second);
1548 "Your mind wrenches as the two lleps spells
1549 cancel each other out, leaving only a sensation
1550 quite like a hangover.";
1551 }
1552 print_ret "Your mind wrenches as ", (the) second,
1553 " reverses itself.";
1554 ],
1555 unmagic
1556 [; return self.magic(); ! The reverse of "lleps" is "lleps"
1557 ];
1558
1559 Spell mortin_spell
1560 with name "mortin",
1561 purpose "cause immediate death of caster",
1562 magic
1563 [; deadflag = true;
1564 "You really can't fault Helistar on this one. Death is
1565 absolutely immediate, like a sudden blackout curtain...";
1566 ],
1567 unmagic
1568 [; prepared_flag = true;
1569 "Nothing quite happens... and yet you feel enormously more
1570 confident as you go about this dangerous world.";
1571 ];
1572
1573 ! ----------------------------------------------------------------------------
1574 ! Death and the Boneyard
1575 ! ----------------------------------------------------------------------------
1576
1577 [ AfterLife;
1578 if (~~prepared_flag) rfalse;
1579
1580 if (player in Balance_Room)
1581 "^^Your foresight in preparing a resurrection was wasted. The
1582 tangled magic of the Balance Room coiled around your puny
1583 enchantment like a constricting serpent.";
1584
1585 prepared_flag = false; deadflag = false; hearing_good = false;
1586
1587 if (memory.capacity >= 2) memory.capacity--;
1588
1589 while (child(player)~=0) move child(player) to parent(player);
1590 move players_book to player;
1591
1592 print "^^With great foresight you prepared yourself for resurrection...
1593 Your mind feels a little weaker, but at least you're alive.^";
1594 PlayerTo(Boneyard);
1595 ];
1596
1597 Place Boneyard "Boneyard"
1598 with name "bones" "blades" "shoulder" "skulls",
1599 description
1600 "This is a room of bones. Shoulder blades make up the floor,
1601 skulls the walls and leg-bones the door frames. The west exit
1602 leads into darkness, but the doorway to the north opens onto a
1603 seemingly normal scene.",
1604 n_to
1605 [; if (scales.number ~= 0) return In_Cave;
1606 return Grasslands;
1607 ],
1608 w_to "Some magical force blocks your way, as though that doorway
1609 led into adventures from your past which you cannot rejoin now.",
1610 before
1611 [; Examine, Search:
1612 if (noun==w_obj) "You can make out nothing to the west.";
1613 ];
1614
1615 Scroll -> worthless_scroll "worthless scroll"
1616 with initial "You are almost treading on a worthless scroll.",
1617 name "worthless";
1618
1619 Spell -> -> filfre_spell
1620 with name "filfre",
1621 purpose "produce gratuitous fireworks",
1622 magic
1623 [; if (self hasnt scored) { score++; give self scored; }
1624 "A brief shower of gratuitous fireworks spells out:
1625 ^^The masterly Enchanter trilogy was written by Marc Blank,
1626 Dave Lebling and Steve Meretzky.";
1627 ],
1628 unmagic
1629 [; "A lengthy shower of artistically justified fireworks spells out:
1630 ^^The masterly Enchanter trilogy was written by Jane Austen,
1631 Emily Bronte and Edgar Allen Poe.";
1632 ];
1633
1634 ! ----------------------------------------------------------------------------
1635 ! The Cubical Temple
1636 ! ----------------------------------------------------------------------------
1637
1638 Place Track "Track, outside Temple"
1639 with description
1640 "This is the end of a long track winding through desolate hills,
1641 which runs back west up to the ridge.",
1642 before
1643 [; Listen:
1644 if (~~hearing_good) "The chanting is too quiet to make out.";
1645 "The endlessly repeating threnody of the monks tells of
1646 the legend of one who will some day enlighten their order,
1647 and so be taken up to a higher plane. He (or she,
1648 presumably) is known as The Four-Cubed One.";
1649 ],
1650 w_to Up_Road, u_to Up_Road;
1651
1652 Object -> Temple "cubical Temple"
1653 with name "temple" "cubical" "cube" "enormous",
1654 before
1655 [ i j;
1656 Enter: "The Temple is featureless and unbroken. Perhaps the top
1657 is open, because the sound must come from somewhere...
1658 but you wouldn't bet on it.";
1659 Cast: switch(the_spell_was)
1660 { rezrov_spell:
1661 "The huge temple remains impassive at your relatively
1662 puny enchantment.";
1663 frotz_spell:
1664 objectloop (i in player)
1665 if (i ofclass FeaturelessCube) j++;
1666 if (j==0)
1667 "The temple shakes, but then is still again.";
1668 if (j<4) "The temple shakes! White light plays
1669 over your hands and possessions, but then all is
1670 still again.";
1671 print "The temple shakes and white light bathes you.
1672 Smoothly it unfolds itself in a four-dimensional
1673 way your senses can barely comprehend. All you
1674 know is that when it is over,
1675 you find yourself in...^";
1676 hearing_good = false; score=score+5;
1677 PlayerTo(Balance_Room); rtrue;
1678 }
1679 ],
1680 describe
1681 [; print "^You stand outside an enormous temple in the shape of a
1682 perfect, featureless white cube, four hundred feet on a
1683 side. From somewhere within you hear the ";
1684 if (hearing_good) print "bellowing noise";
1685 else print "tiny sound";
1686 " of the monks chanting.";
1687 ],
1688 description
1689 "It's much like every other gigantic temple in the shape of a
1690 featureless white cube you've ever seen. No obvious way in.",
1691 has static;
1692
1693 ! ----------------------------------------------------------------------------
1694 ! Inside the Temple
1695 ! ----------------------------------------------------------------------------
1696
1697 Place Balance_Room "Balance Room"
1698 with description
1699 "This seems to be the inside of a featureless white cube, forty
1700 feet on a side. The air is stale and there is no exit.";
1701
1702 Object -> balance_meter "image of the scales"
1703 with name "image" "scales" "of" "pair", article "the",
1704 initial "The image of a pair of scales hangs high in the air. One
1705 pan is much lower than the other.",
1706 before
1707 [; "It's only an image.";
1708 ],
1709 has static;
1710
1711 Object -> dusty_podium "dusty podium"
1712 with name "podium" "dusty" "cobwebs" "cobwebbed",
1713 initial "Far below the scales, in the centre of the ~floor~, is a
1714 predictably-shaped podium, but it is so dusty and
1715 cobwebbed that you can't see what it once was.",
1716 before
1717 [; Cast: if (the_spell_was == caskly_spell)
1718 "Nice try, but it is protected from enchantment.";
1719 "However dusty it is, the podium is still protected from
1720 casual enchantment.";
1721 Rub: remove self; move balance_key to Balance_Room;
1722 itobj = balance_key;
1723 "No substitute for old-fashioned hard work, sometimes,
1724 and after much patient (sneezy) scrubbing, the podium
1725 appears in its true white glory. Set into it are four
1726 sockets, arranged in a two by two square.";
1727 ],
1728 has static;
1729
1730 Object balance_key "podium"
1731 with name "podium" "pedestal" "platform" "cubical",
1732 description "As predicted, it is cubical.",
1733 initial "Far below the scales, in the centre of the ~floor~, is a
1734 predictably-shaped podium. Set into it are four sockets,
1735 arranged in a two by two square.",
1736 has static supporter;
1737
1738 Object -> sockets "two by two square"
1739 with name "square" "two" "by" "two",
1740 before
1741 [ i; if (action~=##Examine || number_filled==0)
1742 "You'll have to say which socket you mean.
1743 (Let's call them ~top left~, ~bottom right~ and so on.)";
1744 objectloop (i in self)
1745 { print (The) i;
1746 if (child(i)==0) print " is empty.^";
1747 else { print " contains ", (a) child(i), ".^"; }
1748 }
1749 rtrue;
1750 ],
1751 has static;
1752
1753 Class Socket
1754 with name "socket", article "the",
1755 before
1756 [; Cast: "The sockets are proof against magic.";
1757 Examine: print (The) self, ", cubical and slightly more
1758 than four inches on a side, is decorated with ",
1759 (string) self.description;
1760 if (child(self) == nothing) ".";
1761 print_ret ", and contains ", (a) child(self), ".";
1762 Receive: if (~~(noun ofclass FeaturelessCube))
1763 "The socket rejects that.";
1764 if (child(self) ~= nothing)
1765 "There is already a cube in that socket.";
1766 ],
1767 after
1768 [; LetGo: number_filled--;
1769 "With much struggle, you manage to pull the cube away.";
1770 Receive: number_filled++;
1771 if (number_filled==4)
1772 { if (snakes_cube in bl_socket
1773 && barker_cube in ul_socket
1774 && cave_cube in br_socket
1775 && eye_cube in ur_socket)
1776 { deadflag=2; score=score+5;
1777 "As you place the final cube into the sockets, you feel
1778 imbued with celestial wisdom (more so than usually).
1779 You find yourself growing to the height of the cube, so
1780 that you pull the balances back level by hand, and then
1781 you grow still further, out of the temple until it is but
1782 a cube in your hand, and you are a giant towering over
1783 the land.
1784 ^^Then, of course, you wake up, glumly realising it's time
1785 to go to your job at the new Borphee Laboratories and
1786 all those Wheatstone bridge experiments. But at least
1787 you can dream about the old days.";
1788 }
1789 "The sockets are all full now, but that doesn't mean
1790 anything's happened.";
1791 }
1792 "The cube is a predictably perfect fit in the socket.";
1793 ],
1794 has static container open;
1795
1796 Socket -> bl_socket "bottom left socket"
1797 with name "bottom" "left" "serpent",
1798 description "a serpent";
1799
1800 Socket -> ul_socket "top left socket"
1801 with name "top" "left" "bazaar",
1802 description "a scene in a bazaar";
1803
1804 Socket -> br_socket "bottom right socket"
1805 with name "bottom" "right" "cave",
1806 description "an engraving of a rocky cave";
1807
1808 Socket -> ur_socket "top right socket"
1809 with name "top" "right" "eye",
1810 description "an eye";
1811
1812 ! ----------------------------------------------------------------------------
1813 ! That's all of the object definitions: just a little code and grammar left
1814 ! ----------------------------------------------------------------------------
1815
1816 [ Initialise;
1817
1818 location = Hut;
1819 move burin to player;
1820 move players_coin to player;
1821 move players_book to player;
1822
1823 thedark.description =
1824 "It is pitch black. You are likely to be eaten by a grue.";
1825 ! (In fact you are stone-cold certain not to be, but never mind.)
1826
1827 players_book.learn_spell(gnusto_spell);
1828 players_book.learn_spell(frotz_spell);
1829 players_book.learn_spell(yomin_spell);
1830 players_book.learn_spell(rezrov_spell);
1831
1832 helistars_book.learn_spell(frotz_spell);
1833 helistars_book.learn_spell(lleps_spell);
1834 helistars_book.learn_spell(mortin_spell);
1835
1836 give gnusto_spell known_about;
1837
1838 "^^^^^[Welcome to a short story called ~Balances~, one of the example
1839 games for the Inform design system. Some people may recognise the
1840 setting, but others might like to type ~how do spells work~ -
1841 the game responds to a few such questions.]
1842 ^^You feel a little confused as to how you got here. Something
1843 to do with Helistar! That's right, and how the world is so far
1844 off balance nowadays, after the Great Change.^^";
1845 ];
1846
1847 [ PrintRank;
1848 print ", earning you the rank of ";
1849 if (score >= 50) "Scientist.";
1850 if (score >= 40) "Spellbreaker.";
1851 if (score >= 30) "Sorcerer.";
1852 if (score >= 20) "Enchanter.";
1853 if (score >= 10) "novice Enchanter.";
1854 "lost dreamer.";
1855 ];
1856
1857 [ DiagnoseSub;
1858 switch(memory.capacity)
1859 { 5: "You feel fine, and your memory is unimpaired.";
1860 4: "You feel shaky after your brush with death, but your mental
1861 faculties seem sound.";
1862 3: "For someone who has died twice, you're in reasonable shape.";
1863 }
1864 "How many times have you died now? Your memory isn't what it was.";
1865 ];
1866
1867 ! ----------------------------------------------------------------------------
1868 ! Grammar extensions needed by the spell-casting and cube-writing rules:
1869 ! ----------------------------------------------------------------------------
1870
1871 Include "Grammar";
1872
1873 [ AnyWord; from_char=0; to_char=0; the_named_word=wn++; return burin; ];
1874
1875 [ QuotedText i j f;
1876 i = WordAddress(wn++); i=i-buffer;
1877 if (buffer->i=='"')
1878 { for (j=i+1:j<=(buffer->1)+1:j++)
1879 if (buffer->j=='"') f=j;
1880 if (f==0) return -1;
1881 from_char = i+1; to_char=f-1;
1882 if (from_char>to_char) return -1;
1883 while (buffer+f > WordAddress(wn)) wn++; wn++;
1884 return burin;
1885 }
1886 return -1;
1887 ];
1888
1889 Verb "write" "scribe"
1890 * AnyWord "on" held -> WriteOn
1891 * QuotedText "on" held -> WriteOn;
1892 Verb "copy" * scope=CopyableSpell "to" noun -> CopyTo;
1893 Verb "who" "what" "how"
1894 * "do" scope=Topic -> Query
1895 * "is" scope=Topic -> Query
1896 * "was" scope=Topic -> Query;
1897 Verb "spells" "memory"
1898 * -> Spells;
1899 Verb "learn" "memorise" "memorize"
1900 * scope=ReadableSpell -> Learn;
1901 Extend "examine" first
1902 * scope=ReadableSpell -> Examine;
1903 Verb "c,cast"
1904 * -> CastOne
1905 * noun -> CastOne;
1906 Verb "cast"
1907 * is_spell -> Cast
1908 * is_spell "at" noun -> Cast
1909 * is_spell "on" noun -> Cast;
1910 Verb "diagnose" "health"
1911 * -> Diagnose;
1912
1913 ! ----------------------------------------------------------------------------
1914 ! And one for the game itself.
1915 ! ----------------------------------------------------------------------------
1916
1917 Verb "ride" "mount" "straddle"
1918 * creature -> Ride
1919 * noun -> Enter;
1920 Verb "flip" "toss" * is_coin -> TossCoin;
1921 ! ----------------------------------------------------------------------------
Last updated 23 June 2004.
This site is no longer supported; information may be out of date.
Maintained as a historical archive by the Interactive Fiction Technology Foundation.
Copyright 1993-2018 IFTF, CC-BY-SA unless otherwise noted.
This page was originally managed by Graham Nelson (graham@gnelson.demon.co.uk) assisted by C Knight.