Constant Story "THE DREAMHOLD"; Constant Headline "^A tutorial adventure by Andrew Plotkin. Copyright 2003-4.^ First-time players should type ~about~.^"; Release 5; !Constant ZDEBUG; Constant WITHOUT_DIRECTIONS; Constant MANUAL_PRONOUNS; Constant NO_PLACES; Constant DEATH_MENTION_UNDO; Constant SKIP_MAGIC_ARTICLES; Constant INTERRUPT_MULTI_ACTION; Constant DIALECT_US; Constant AMERICAN_COMMAS; Constant USE_PARTINVENT; Constant BRACKET_COMMENTS; Replace DrawStatusLine; Replace NoteObjectAcquisitions; Replace Descriptors; Replace OffersLight; Replace CDefArt; Replace LookSub; Replace BurnSub; Replace LMode3Sub; Replace ScoreSub; Attribute helpflag; Attribute expendable; Global global_italic = false; Global ExpertMode = false; Global ImpossibleMode = false; Global Enlightened = false; Global ArtifNumGotten = 0; Constant DAYTIME = 0; Constant NIGHTTIME = 1; Constant DREAMTIME = 2; Global weather = DAYTIME; Constant DIRMOD_UNCERTAINPATH = $1; Constant DIRMOD_NEAR = $2; Constant DIRMOD_FAR = $4; Constant DIRMOD_ABOVE = $8; Constant DIRMOD_BELOW = $10; Constant DIRMOD_FOLLOWVERT = $20; Include "Parser"; Object LibraryMessages "lib_messages" with parse_name_clone 0, hinto 0, hint_name 0, hint_suppress 0, hint_threshold 0, coredir 0, coredirmod 0, before [; Prompt: GuideBeforePrompt(); if (glove has worn && glove notin player) print "^[BUG] worn glove gone missing^"; print "^>"; rtrue; Miscellany: switch (lm_n) { 4: print " The end "; rtrue; 5: GuideBeforePrompt(); rfalse; 10: ! the user just hit enter GuideContext.blank_line_count++; if (GuideContext.blank_line_count >= 4) { GuideContext.blank_line_count = 0; GuideEnqueue(GuideSeedMessage); } rtrue; 13: ! successful undo GuideContext.just_undid = true; rfalse; 12: "[You can't ~undo~ twice in succession. If you want to back up more than one move, use the ~save~ and ~restore~ commands.]"; 30: if (location && location ofclass DarknessRoom) "You can't see anything."; rfalse; 45, 46: GuideDisambiguationMessage.invoke(); rfalse; } VagueGo: GuideEnqueue(GuideVagueGoMessage); if (location ofclass DarknessRoom) "You'll have to say where to go."; "You'll have to say which compass direction to go in."; Go: switch (lm_n) { 1: if (noun == u_obj && (location == SittingRoom or MirrorRoom)) { GuideEnqueue(GuideUpStandUpMessage); } rfalse; } Look: switch (lm_n) { 4: if (lm_o == desk or easel or ledge or cavepithollow or labtable or leftscale or rightscale) rtrue; rfalse; 5, 6: if (lm_o == CisternEast && player in cisternplatform) { print "^You can"; if (lm_n==5) print " also"; print " see "; WriteListFrom(child(lm_o), ENGLISH_BIT + WORKFLAG_BIT + RECURSE_BIT + PARTINV_BIT + TERSE_BIT + CONCEAL_BIT); " resting on the floor."; } } Touch: switch (lm_n) { 2: if (glove has worn) "You feel nothing unexpected through the glove."; } Drink: print_ret (cthatorthose) lm_o, " ", (isorare) lm_o, "n't suitable to drink."; Blow: "Nothing happens."; Pray: "Praying in a wizard's house has complicated theological implications. Better not."; Strong, Mild: "Swearing in a wizard's house has complicated theological implications. Better not."; Wake: "You're not sure if that even makes sense."; Swim: "There's nowhere here to swim."; ]; Include "VerbLib"; [ Initialise; InformParser.parse_input = InformParser_parse_input; player = myselfobj; location = Cell; move quill to player; StairContext.invoke(0); #ifdef DEBUG; print "[BUG] DEBUG mode on.^^"; #endif; #ifdef ZDEBUG; print "[BUG] ZDEBUG mode on.^^"; #endif; inventory_style = FULLINV_BIT + ENGLISH_BIT + RECURSE_BIT; ! wide print "Time shifts and flattens, days and decades folding aside like pages in a book. You can see--^^"; new_line; Banner(); new_line; print "^You wrench your eyes open. Rough grey stone. Grey stone ", (emph) "ceiling.", " Your head hurts, and -- You're lying on the floor. You're staring at the ceiling, and it's rough and grey, and you don't recognize it.^^"; print "You roll slowly (smooth cold floor?) and try to sit up. It hurts. You crawl upright. The walls, rough stone also, scrape your aching fingers. You can't -- there was white agony, felt like raw light tearing you apart. You can't remember anything after that.^^"; print "You can't remember anything ", (emph) "before", " that. Gone. You clutch at memory, and there's nothing but empty air.^"; StartDaemon(Cell); GuideEnqueue(GuideSeedMessage); return 2; ]; Object myselfobj "(self object)" with short_name "yourself", description "You cannot remember what you look like.", capacity 100, number 0, react_before [; PutOn: if (second == self) <>; ], before [; Push: if (noun == self && verb_word == 'move') { <>; } Touch: "You seem to be all there."; WakeOther: <>; ], has concealed animate proper transparent; [ GamePostRoutine ix; Inv: if (Hall3 hasnt visited) { if (quill in player && (~~quill.helpmode)) { quill.helpmode = true; Cell.count = 1; GuideEnqueue(GuideFirstInvMessage); } } ix = children(player); if (warmberries in player) ix = ix+2; if (coolberries in player) ix = ix+2; if (ix > 7) GuideUnlimitedInventoryMessage.invoke(); rfalse; default: rfalse; ]; Class SittableClass; Class KeyClass; KeyClass falsekey with name 'false' 'key', description "[BUG] false key present"; [ ChangeWeather val; if (weather == val) "[BUG] Changing weather to itself."; weather = val; ! conveniently, the player can't change weather outdoors. safemove(gardenskyday, nothing); give gardenskyday absent; safemove(gardenskynight, nothing); give gardenskynight absent; safemove(gardenskydream, nothing); give gardenskydream absent; switch (weather) { DAYTIME: safemove(lighthousesmoke, nothing); safemove(lighthousefog, nothing); give gardenskyday ~absent; NIGHTTIME: safemove(lighthousesmoke, Lighthouse); safemove(lighthousefog, nothing); give gardenskynight ~absent; DREAMTIME: safemove(lighthousesmoke, nothing); safemove(lighthousefog, Lighthouse); give gardenskydream ~absent; } ]; Class MyCompassDirection class CompassDirection, with before [; Push: if (verb_word == 'move') <>; ]; MyCompassDirection n_obj "direction north" compass with name 'n//' 'north', name_str "north", door_dir n_to, count 0; MyCompassDirection s_obj "direction south" compass with name 's//' 'south', name_str "south", door_dir s_to, count 4; MyCompassDirection e_obj "direction east" compass with name 'e//' 'east', name_str "east", door_dir e_to, count 2; MyCompassDirection w_obj "direction west" compass with name 'w//' 'west', name_str "west", door_dir w_to, count 6; MyCompassDirection ne_obj "direction northeast" compass with name 'ne' 'northeast', name_str "northeast", door_dir ne_to, count 1; MyCompassDirection nw_obj "direction northwest" compass with name 'nw' 'northwest', name_str "northwest", door_dir nw_to, count 7; MyCompassDirection se_obj "direction southeast" compass with name 'se' 'southeast', name_str "southeast", door_dir se_to, count 3; MyCompassDirection sw_obj "direction southwest" compass with name 'sw' 'southwest', name_str "southwest", door_dir sw_to, count 5; MyCompassDirection u_obj "above" compass with name 'u//' 'up' 'above', name_str "up", articles "What's" "what's" "what's", door_dir u_to, before [ obj; obj = find_ceiling(); Examine: if (obj) <<(action) obj>>; rfalse; Touch, Push: if (verb_word == 'move') <>; if (obj) <<(action) obj>>; "The ceiling is out of reach."; Climb: <>; ]; MyCompassDirection d_obj "below" compass with name 'd//' 'down' 'below', name_str "down", articles "What's" "what's" "what's", door_dir d_to, before [ obj; obj = find_floor(); Examine: if (obj) <<(action) obj>>; rfalse; Touch, Push: if (verb_word == 'move') <>; if (obj) <<(action) obj>>; rfalse; Climb: <>; ]; Class CeilingObject with name 'roof' 'ceiling', short_name "ceiling", before [; Touch, Push: print_ret (The) self, " is out of reach."; ], has scenery; Class FloorObject with name 'floor' 'ground', short_name "floor", before [; Receive: <>; Enter: if (verb_word == 'lie') "That's no place to lie down."; if (verb_word == 'sit') "That's no place to sit down."; ], has scenery; Class WallObject with name 'wall' 'walls', short_name "wall", has scenery; Class SceneryObject with name 'room', short_name "room", before [; default: GuideEnqueue(GuideRoomSceneryObject); "You don't need to refer to that."; ], has scenery; [ find_ceiling ix; if (location == nothing) return nothing; objectloop (ix in location) { if (ix ofclass CeilingObject) return ix; } return nothing; ]; [ find_floor ix; if (location == nothing) return nothing; if (location ofclass CisternCatwalkClass) return cisterncatwalkcatwalk; objectloop (ix in location) { if (ix ofclass FloorObject) return ix; } return nothing; ]; [ ultimate_parent obj val; val = parent(obj); while (val) { obj = val; val = parent(obj); } return obj; ]; [ ParseNameClone cloneobj wd num; cloneobj = self.parse_name_clone; wd = NextWord(); while (WordInProperty(wd, cloneobj, name)) { num++; wd = NextWord(); } return num; ]; [ ParseNameClonePlus cloneobj wd num; cloneobj = self.parse_name_clone; wd = NextWord(); while (WordInProperty(wd, cloneobj, name) || WordInProperty(wd, self, name)) { num++; wd = NextWord(); } return num; ]; [ sweep_movables src dest obj next; obj = child(src); while (obj) { next = sibling(obj); if (obj hasnt static && obj hasnt scenery && obj ~= player) { !print "[DEBUG] sweeping ", (name) obj, " to ", (name) dest, ".^"; move obj to dest; } obj = next; } ]; [ safemove obj dest; if (dest == nothing) { if (parent(obj)) remove obj; } else { if (parent(obj) ~= dest) move obj to dest; } ]; [ TransportEffect; print "^^^"; ]; [ emph str; if (~~global_italic) { style underline; print (string) str; style roman; } else { style roman; print (string) str; style underline; } ]; [ helpcmd str; print "~"; if (~~global_italic) { style bold; if (metaclass(str)==Object) print (name) str; else print (string) str; style roman; } else { style bold; if (metaclass(str)==Object) print (name) str; else print (string) str; style roman; style underline; } print "~"; ]; [ helptopic str; print "~"; if (~~global_italic) { style bold; print "help "; print (string) str; style roman; } else { style bold; print "help "; print (string) str; style roman; style underline; } print "~"; ]; [ helpcmdstring str opt; print "~"; if (~~global_italic) { style bold; print (string) str; style roman; print " "; style underline; print (string) opt; style roman; } else { style bold; print (string) str; style roman; print " "; print (string) opt; style underline; } print "~"; ]; [ helpcmdobj str; helpcmdstring(str, "thing"); ]; [ helpcmdwd str; helpcmdstring(str, "command"); ]; Constant HelpFormatLen 4; Array HelpFormatArray --> HelpFormatLen; [ helpformat w0 w1 w2 w3 ix val; HelpFormatArray-->0 = w0; HelpFormatArray-->1 = w1; HelpFormatArray-->2 = w2; HelpFormatArray-->3 = w3; print "~"; for (ix=0 : ixix; if (val == 0) break; if (ix > 0) print " "; if (val > 0 && val < 10) { switch (val) { 2: val = "this"; 3: val = "that"; 4: val = "person"; 5: val = "topic"; 6: val = "word"; default: val = "thing"; } if (global_italic) { print (string) val; } else { style underline; print (string) val; style roman; } } else { if (~~global_italic) { style bold; print (string) val; style roman; } else { style underline; style bold; print (string) val; style roman; } } } if (global_italic) style underline; print "~"; ]; Include "mask.inf"; Include "artif.inf"; Include "darkrm.inf"; Include "corerm.inf"; Include "homerm.inf"; Include "hallrm.inf"; Include "astrorm.inf"; Include "orrerm.inf"; Include "gardenrm.inf"; Include "scoperm.inf"; Include "peakrm.inf"; Include "caverm.inf"; Include "cistrm.inf"; Include "labrm.inf"; Include "endrm.inf"; Include "remin.inf"; Include "guide.inf"; Include "help.inf"; Include "hint.inf"; [ DrawStatusLine width obj pos; @split_window 1; @set_window 1; @set_cursor 1 1; style reverse; width = 0->33; spaces width; @set_cursor 1 2; print (name) location; obj = parent(player); if (obj ~= location && width >= 50) { if (obj has container) print " (in "; else print " (on "; print (the) obj, ")"; } ! "3 of 7, +2" if (ImpossibleMode) { pos = width-10; @set_cursor 1 pos; print "(no way)"; } else if (ExpertMode) { pos = width-10; @set_cursor 1 pos; print "(expert)"; } else { if (MaskNumGotten || (Hall3 has visited)) { pos = width-12; @set_cursor 1 pos; print MaskNumGotten, " of 7"; if (ArtifNumGotten) { print ", +"; print ArtifNumGotten; } } } @set_cursor 1 1; style roman; @set_window 0; ]; [ LargeObject obj; if (obj has scenery || obj has static) rtrue; if (obj == desertpainting or mountainpainting or palette) rtrue; if (obj == cloak) rtrue; if (obj == glassshard) rtrue; rfalse; ]; [ BeforeParsing len buf cx count ix jx wd numwd; len = buffer->1; buf = buffer+2; count = 0; #ifdef BRACKET_COMMENTS; for (cx=0 : cxcx ~= ' ') break; } if (cx < len && buf->cx == '[') { print "[", (char) '#', (char) '#', (char) '#', " Report noted.]^"; parse-->1 = ',noop'; parse->1 = 1; return; } #endif; for (cx=0 : cxcx == '"') { count++; buf->cx = ' '; } } if (count == 0) jump phase2; GuidePrint("Don't include the quote marks when entering commands.", true); new_line; Tokenise__(buffer,parse); .phase2; count = 0; numwd = parse->1; for (ix=0 : ix(ix*2 + 1); if (wd == 'please') { count++; buf = WordAddress(ix+1); len = WordLength(ix+1); for (jx=0 : jxjx = ' '; } } if (count == 0) jump phase99; GuidePrint("You don't need to say ~please~ when entering a command. Politeness is a grace, but most IF games won't recognize the word.", true); new_line; Tokenise__(buffer,parse); .phase99; return; ]; [ NoteObjectAcquisitions obj total; total = 0; objectloop (obj in player) { give obj moved; if (obj ofclass Artifact) { if (~~obj.acquired) { AcquireArtifact(obj); } } if (obj ofclass MaskClass) { total++; if (~~obj.acquired) { AcquireMask(obj); } if (~~obj.witnessed) { WitnessMask(obj); } } } if (total == 7 && maskvoices hasnt general) { maskvoices.invoke(); } ]; [ ChooseObjects obj fl ix; if (fl == 0 or 1) { ! Scenery objects never count in "all". if (obj has scenery) return 2; rfalse; } if (action_to_be == ##Enter) { if (obj ofclass SittableClass) return 5; if (obj has scenery || obj has static) return 4; return 2; } if (action_to_be == ##DrawOn or ##DrawFigureOn) { return 4; } if (action_to_be == ##DrawWith or ##DrawFigureWith) { if (obj == quill) return 5; if (obj has scenery || obj has static) return 4; return 2; } if (action_to_be == ##PutOn && obj == player && parameters > 0) { ix = inputobjs-->2; if (ix ofclass MaskClass || ix has clothing) { return 5; } } if (~~indef_mode) { if (obj ofclass DistantMaskClass && obj.mask_word_used) { return 5; } if (obj ofclass MaskClass && obj hasnt moved && obj.mask_word_used) { return 5; } } if (obj has scenery) { return 2; } if (obj == labtable) { return 2; } return 4; ]; [ Descriptors allow_multiple o x flag cto type; ResetDescriptors(); if (wn > num_words) return 0; for (flag=true:flag:) { o=NextWordStopped(); flag=false; for (x=1:x<=LanguageDescriptors-->0:x=x+4) if (o == LanguageDescriptors-->x) { flag = true; type = LanguageDescriptors-->(x+2); if (type ~= DEFART_PK) indef_mode = true; indef_possambig = true; indef_cases = indef_cases & (LanguageDescriptors-->(x+1)); if (type == POSSESS_PK) { cto = LanguageDescriptors-->(x+3); switch(cto) { 0: indef_type = indef_type | MY_BIT; 1: indef_type = indef_type | THAT_BIT; default: indef_owner = PronounValue(cto); if (indef_owner == NULL) indef_owner = InformParser; } } if (type == light) indef_type = indef_type | LIT_BIT; if (type == -light) indef_type = indef_type | UNLIT_BIT; } if (o==OTHER1__WD or OTHER2__WD or OTHER3__WD) { indef_mode=1; flag=1; indef_type = indef_type | OTHER_BIT; } if (o==ALL1__WD or ALL2__WD or ALL3__WD or ALL4__WD or ALL5__WD) { indef_mode=1; flag=1; indef_wanted=100; if (take_all_rule == 1) take_all_rule = 2; indef_type = indef_type | PLURAL_BIT; } if (flag==1 && NextWordStopped() ~= OF1__WD or OF2__WD or OF3__WD or OF4__WD) wn--; ! Skip 'of' after these } wn--; if ((indef_wanted > 0) && (~~allow_multiple)) return MULTI_PE; return 0; ]; ! Simple light function which says everything is lit. [ OffersLight i; if (i == 0) rfalse; rtrue; ]; [ CDefart o i; i = indef_mode; indef_mode = false; if (o == player) { print "Your person"; indef_mode = i; return; } if (o has proper) { indef_mode = NULL; print (PSN__) o; indef_mode = i; return; } PrefaceByArticle(o, 0); indef_mode = i; ]; [ PrintVerb wd; switch (wd) { 'help': print "learn about"; rtrue; } rfalse; ]; [ UnknownVerb verb_wd; verb_wd = 0; ! squash compiler warning GuideContext.unknown_verb_count++; if ((~~GuideContext.unknown_verb_ever) || GuideContext.unknown_verb_count >= 3 || BasementHall hasnt general) { GuideContext.unknown_verb_ever = true; GuideContext.unknown_verb_count = 0; GuideEnqueue(GuideSeedMessage); return false; } rfalse; ]; [ LookSub allow_abbrev visibility_levels i j k; if (parent(player)==0) return RunTimeError(10); .MovedByInitial; if (location == thedark) { visibility_ceiling = thedark; NoteArrival(); } else { visibility_levels = FindVisibilityLevels(); if (visibility_ceiling == location) { NoteArrival(); if (visibility_ceiling ~= location) jump MovedByInitial; } } ! Printing the top line: e.g. ! Octagonal Room (on the table) (as Frodo) new_line; style bold; if (visibility_levels == 0) print (name) thedark; else { if (visibility_ceiling ~= location) print (The) visibility_ceiling; else print (name) visibility_ceiling; } style roman; for (j=1, i=parent(player):j 0) GuideContext.brief_look_count--; if (location.describe~=NULL) RunRoutines(location,describe); else { if (location.description==0) RunTimeError(11,location); else PrintOrRun(location,description); } } else { if (GuideVerboseMessage hasnt general) { GuideContext.brief_look_count++; if (GuideContext.brief_look_count >= 3 && GuideAnyQueued() == 0) { GuideEnqueue(GuideVerboseMessage); } } } } if (visibility_levels == 0) Locale(thedark); else { for (i=player, j=visibility_levels: j>0: j--, i=parent(i)) give i workflag; for (j=visibility_levels: j>0: j--) { for (i=player, k=0: k>; ]; [ ExamineDownSub; <>; ]; [ LookWithSub; "That won't reveal anything."; ]; [ LookBehindSub; L__M(##LookUnder,2); ]; [ ClimbUpSub; <>; ]; [ ClimbDownSub; <>; ]; [ PutOverSub; "It's not clear how to do that."; ]; [ PlaySub; "You can't play ", (thatorthose) noun, "."; ]; [ UntieSub; "You can't see how."; ]; [ TouchToSub; if (noun in player) <>; if (second in player) <>; "You're not holding ", (the) noun, "."; ]; [ TouchWithSub; if ((second == warmberries or coolberries or warmcluster or coolcluster or warmbush or coolbush) && (noun ~= warmberries or coolberries or warmcluster or coolcluster or warmbush or coolbush)) <>; if (second == mirror) <>; if (noun == second) "Topologically implausible."; "Nothing happens."; ]; ![ BendBarsSub; ! "Not in this game."; !]; [ BurnSub; if (noun == player) "That might be fatal."; if (noun == torch && torch has light) "The torch is already burning."; if (torch in player && torch has light) <>; if (warmberries in player) <>; if (location == GardenWarm) <>; if (location == Lighthouse && weather ~= DAYTIME) <>; if (location == SittingRoom) <>; if (location == Study) <>; if (noun == bonfire && weather == DAYTIME) OfferHint(HintoBonfire); "You don't have any handy way to set ", (thatorthose) noun, " alight."; ]; [ BurnWithSub; if (noun == player) "That might be fatal."; if (second == torch) { if (torch hasnt light) "The torch isn't lit."; if (torch notin player) "You're not holding the torch."; if (noun == torch) "The torch is already burning."; <>; } if (second == warmberries) { if (warmberries in player) <>; } if (location == GardenWarm) { if (second == warmcluster or warmbush) <>; } if (location == Lighthouse && weather ~= DAYTIME) { if (second == bonfire) <>; } if (location == SittingRoom) { if (second == basket or fireplace or sphereheap) <>; } if (location == Study) { if (second == studycandles) <>; } if (second == hallcandles) <>; print_ret (The) second, " won't set ", (thatorthose) noun, " alight."; ]; [ FreezeSub; if (noun == player) "That might be fatal."; if (coolberries in player) <>; if (location == GardenCool) <>; if (location == Lighthouse && weather == DREAMTIME) <>; "You don't have any handy way to chill ", (thatorthose) noun, "."; ]; [ FreezeWithSub; if (noun == player) "That might be fatal."; if (second == coolberries) { if (coolberries in player) <>; } if (location == GardenCool) { if (second == coolcluster or coolbush) <>; } if (location == Lighthouse && weather == DREAMTIME) { if (second == bonfire) <>; } print_ret (The) second, " won't chill ", (thatorthose) noun, "."; ]; [ BerryBurnSub; if (noun == player) "That might be fatal."; print (string) (random("You flick", "You toss")); print " an orange berry. It spatters on ", (the) noun, ", spraying juice"; if (location == Subterrane) "... but instead of sparks and embers, you perceive only smudges of colored darkness, like stains of blood in ink."; print " in a shower of sizzling embers. In less than a moment, the berry has burned itself away, leaving no trace"; if (location ofclass DarknessRoom) print ".^^The sparks were too brief to see anything but dim curves of stone. Now only the afterimages burn and shift against the darkness"; "."; ]; [ BerryFreezeSub; if (noun == player) "That might be fatal."; print (string) (random("You flick", "You toss")); " a white berry. It spatters on ", (the) noun, ", spraying juice that crackles instantly into frost. Within seconds, the frozen splinters of the berry have sublimed away."; ]; [ DrawFigureSub; if (quill notin player) "You're not holding your quill pen."; if (quill.number == 0) "You cannot draw with a dry pen."; if (location ~= Cell) "There is no desirable drawing surface here."; if (noun ~= minddiagram) { print_ret (The) noun, " is not what you must inscribe here."; } floordiagram.invoke(); ]; [ DrawFigureWithSub; if (second ~= quill) print_ret (The) second, " isn't a drawing tool."; <>; ]; [ DrawFigureOnSub; if (second ~= cellfloor) { if (second == player) "Your body is not a desirable drawing surface."; if (quill notin player || (~~FlaskIsInk())) print "Even if you had pen and ink, ", (the) second, " would not be"; else print (The) second, " is not"; " a desirable drawing surface."; } <>; ]; [ DrawWithSub; if (~~Enlightened) "You're not sure what to draw."; <>; ]; [ DrawOnSub; if (~~Enlightened) "You're not sure what to draw."; <>; ]; [ NoOpSub; rtrue; ]; [ AboutSub; print (string) Story, " is a gentle introduction to the world of IF. It's a small game, and not too difficult. More importantly, ", (string) Story, " features the Tutorial Voice -- a helpful guide that will lead you through the basics of playing a text adventure.^"; GuidePrint("When you see a message like this, it's the Tutorial Voice speaking!"); print "^Type ", (helpcmd) "help", " to learn how to play Interactive Fiction.^^"; !If you're looking for a hint about the specific problem you're stuck on, ! type ", (helpcmd) "hint", ". print "(If you want to play the game without the Tutorial Voice holding your hand, type ", (helpcmd) "tutorial off", ". And for a challenge, type ", (helpcmd) "expert", "! Certain puzzles will be somewhat harder in Expert mode.)^"; print "^", (string) Story, " is copyright 2003-4 by Andrew Plotkin. I created it with Inform, a free text-adventure development language created by Graham Nelson. My thanks for the beta-testing efforts of many people; notably Emily Short, Dan Efran, Julia Tenney, Karen Fabrizius, and Aleecia McDonald; and also the generous players and commentors of rec.games.int-fiction. If you are interested in playing more IF, you can find my other games at "; font off; print ""; font on; print ". The great Archive of all free text adventures is "; font off; print ""; font on; print "; you can find games there to suit any taste. You may wish to use Baf's Guide, "; font off; print ""; font on; print ", to help you find and choose games from the Archive.^"; ]; [ DeathMessage; print "You have come to an ending"; ]; [ PostNonEndingBanner; print "This is an ending of ", (string) Story, ". But it is not the only ending. Many IF games encompass variations, and it is often worth going back to see if you missed a more satisfying outcome. If you want to back up and try a different way, type ", (helpcmd) "undo", "."; ]; [ PostEndingBanner; print "Thank you for playing. You've reached the end of ", (string) Story, "; but that doesn't mean there isn't more hidden in the game"; if (ArtifNumGotten == 0) { print ". There may be other discoveries to make beyond the riddle of the masks"; } else { if (ArtifNumGotten == 1) print ". You made one additional discovery"; else print ". You made ", (EnglishNumber) ArtifNumGotten, " additional discoveries"; print " beyond the riddle of the masks; there may be others"; } print ".^^ And there are many other games to discover beyond ", (string) Story, ". If this game was your first experience of interactive fiction, and if you enjoyed it, then you should play more. You are now familiar enough with the IF interface to try any well-designed game. (I won't promise that you won't have trouble! Some games are meant to be tricky. But you'll have as fair a shot as any IF player.)^^ IF comes in a huge range of forms and styles. ", (string) Story, " is a fairly serious, surrealist fantasy exploration. But there are also silly games, detective stories, science fiction scenarios, romances, and nightmares. Some games are puzzle-fests; others focus on character, dialogue, or branching story variants. All these can be found at the IF Archive: "; font off; print ""; font on; print "^^So many games are collected there that it's hard to navigate them. Baf's Guide is an excellent categorized index: "; font off; print ""; font on; print "^^Baf's Guide lets you search for IF games by author, title, genre, rating, or origin. It also contains capsule reviews, to help you choose the game you want to play.^^ I hope you've gotten a glimpse of what text adventure gaming can be. Have fun. ^^ -- Andrew Plotkin, "; font off; print ""; font on; print "^"; ]; [ ScoreSub obj ix; if (deadflag) { if (ImpossibleMode) "For completing the game in Impossible mode, you are hereby awarded the Persistent Adventurer's Medal of Honor. Go play something harder now.^"; if (deadflag == 3) { GuidePrint(PostNonEndingBanner, true); rtrue; } if (deadflag == 2) { PostEndingBanner(); rtrue; } rtrue; } if (ImpossibleMode) "The score feature of ", (string) Story, " is not available in Impossible mode."; if (ExpertMode) "The score feature of ", (string) Story, " is not available in Expert mode."; if (~~(MaskNumGotten || (Hall3 has visited))) { "You are still at the beginning of ", (string) Story, "."; } if (Enlightened) { if (FlaskIsInk()) print "The end of ", (string) Story, " is within your grasp"; else print "You are approaching the end of ", (string) Story; } else if (MaskNumGotten == 0) { print "You have not begun achieving the seven main goals of the game"; } else { print "You have found ", (EnglishNumber) MaskNumGotten, " out of seven masks"; if (MaskNumGotten == 7) print ", but you do not yet know what to do with them"; } print ".^"; if (ArtifNumGotten) { print "^You have made ", (EnglishNumber) ArtifNumGotten, " additional "; if (ArtifNumGotten == 1) print "discovery"; else print "discoveries"; print ":^"; for (ix=0 : ixix; print " - ", (the) obj, "^"; } } !print_ret (string) Story, " does not measure your progress in points."; ]; [ TutorOnSub; if (ImpossibleMode) "The Tutorial Voice is not available in Impossible mode!"; if (ExpertMode) "The Tutorial Voice is not available in Expert mode!"; if (GuideActive) "Tutorial mode is already on."; GuideActive = true; print_ret (string) Story, " is now in ~tutorial~ mode. The Tutorial Voice will provide comments to help new players become accustomed to the world of IF."; ]; [ TutorOffSub; if (~~GuideActive) "Tutorial mode is already off."; GuideActive = false; print_ret (string) Story, " is no longer in ~tutorial~ mode. The Tutorial Voice will stop providing helpful comments. (The ", (helpcmd) "help", !" and ", (helpcmd) "hint", " commands are " command is still available if you want it.) If you want to turn the tutorial comments back on, type ", (helpcmd) "tutorial on", "."; ]; [ TutorToggleSub; if (GuideActive) <>; else <>; ]; [ ImpossibleSub; if (ImpossibleMode) "You are in Impossible mode. You cannot return to standard mode while in the middle of the game.^^ (If you type ", (helpcmd) "restart", ", the game will start over, and you will no longer be in Impossible mode.)"; if (location ~= Cell) { "You cannot switch to Impossible mode while in the middle of the game. If you want to try it, type ", (helpcmd) "restart", ". Then, after the game starts over, type ", (helpcmd) "impossible", "."; } print "Are you sure you want to enter Impossible mode? "; if (YesOrNo() == 0) "^No? That is wise."; ImpossibleMode = true; GuideActive = false; remove cellgap; print_ret "^Okay, ", (string) Story, " is now in ~impossible~ mode.^^ (To return to the standard game, type ", (helpcmd) "restart", ".)"; ]; [ ExpertSub val; if (ExpertMode || ImpossibleMode) { if (ImpossibleMode) val = "Impossible"; else val = "Expert"; "You are in ", (string) val, " mode. You cannot return to standard mode while in the middle of the game.^^ (If you type ", (helpcmd) "restart", ", the game will start over, and you will no longer be in ", (string) val, " mode.)"; } if (BasementHall has visited) { "You cannot switch to Expert mode while in the middle of the game. If you want to try it, type ", (helpcmd) "restart", ". Then, after the game starts over, type ", (helpcmd) "expert", "."; } ExpertMode = true; GuideActive = false; move labkey to Arbor; sail.number = 2; ! statue behaves differently remove orreryfarmaskeasy; move orreryfarmaskhard to Orrery; move orreryfarmaskhard2 to OrreryOnSilver; move orrerymaskobj to OrreryOnBlue; move mountainpainting to Atelier; move brownmask to ArtDesert; move whiteletter to ArtMountain; move distantscopemask to desertpainting; move redmask to CisternCatwalkSouth; move weightcase to labtable; move rightscale to Laboratory; move leftscale to Laboratory; move labscale to Laboratory; print_ret (string) Story, " is now in ~expert~ mode. You will face more challenging puzzles in this mode -- and there will be no Tutorial Voice!^^ (To return to the standard game, and restore the Tutorial Voice, type ", (helpcmd) "restart", ".)"; ]; [ IWantSub; GuidePrint(GuideIWantAmMessage, true); ]; [ IAmSub; GuidePrint(GuideIWantAmMessage, true); ]; [ IGiveUpSub; GuidePrint(GuideIGiveUpMessage, true); ]; [ QuestionsSub; GuidePrint(GuideQuestionsMessage, true); ]; [ LMode3Sub; L__M(##Miscellany, 38); ]; [ UseSub; GuideEnqueue(GuideUseMessage); L__M(##Miscellany, 38); ]; #ifdef ZDEBUG; [ ZapSub; lookmode=2; give HTHints general; switch (noun) { sittingdoor: give studytrunk general; give studytrunk open; move hallkey to player; give sittingdoor ~locked; give sittingdoor open; "[ZAP] ", (The) sittingdoor, " pops open."; desertpainting: print "[ZAP] night; to dome.^"; ChangeWeather(NIGHTTIME); give studytrunk general; give studytrunk open; move hallkey to player; give sittingdoor ~locked; give sittingdoor open; give Hall3 visited; give GuideUnlimitedInventoryMessage general; PlayerTo(StellariumNorth); fireplace: print "[ZAP] torch; to passage.^"; give studytrunk general; give studytrunk open; move hallkey to player; give sittingdoor ~locked; give sittingdoor open; move torch to player; give torch moved; give torch light; move warmberries to player; move coolberries to player; give Hall3 visited; give GuideUnlimitedInventoryMessage general; PlayerTo(CavePassage); tanglobe, onbluetanglobe: PlayerTo(OrreryOnSilver, 1); "[ZAP] to tan globe ring."; blueglobe, onsilverblueglobe: PlayerTo(OrreryOnBlue, 1); "[ZAP] to blue globe."; greenglobe, onsilvergreenglobe, onbluegreenglobe: PlayerTo(OrreryOnGreen, 1); "[ZAP] to green globe."; torch: if (torch has light) { give torch ~light; "[ZAP] Torch unlit."; } else { give torch light; "[ZAP] Torch lit."; } cisterndoor: if (cisterndoor hasnt locked) { give cisterndoor locked; "[ZAP] locked."; } else { give cisterndoor ~locked; "[ZAP] unlocked."; } cisterncolumn: switch (cisterncolumn.number) { e_obj: cisterncolumn.number = w_obj; w_obj: cisterncolumn.number = n_obj; n_obj: cisterncolumn.number = e_obj; } "[ZAP] column.number = ", (name) cisterncolumn.number, "."; drainvalve: give drainvalve general; give flowvalve general; give cisternpipetop general; goop.invoke(false); "[ZAP] drain and flow open."; catwalkweakcracks: CisternCatwalkSouthwest.count = 1; CisternCatwalkSoutheast.count = 2; "[ZAP] the cracks sinter."; mirrorchair: move blackmask to player; move bluemask to player; move greenmask to player; move brownmask to player; move redmask to player; move goldmask to player; move whitemask to player; give Hall3 visited; give GuideUnlimitedInventoryMessage general; "[ZAP] got masks."; mirror: Enlightened = true; move labkey to player; remove blackmask; remove bluemask; remove greenmask; remove brownmask; remove redmask; remove goldmask; remove whitemask; give Hall3 visited; "[ZAP] Enlightened!"; studydoor: Enlightened = true; move warmberries to player; move coolberries to player; remove blackmask; remove bluemask; remove greenmask; remove brownmask; remove redmask; remove goldmask; remove whitemask; give Hall3 visited; give studydoor ~locked open; give labhallspell general; "[ZAP] Enlightened and opened!"; cellfloor: Enlightened = true; give BasementHall general; move flask to player; move ink to flask; quill.number = true; remove blackmask; remove bluemask; remove greenmask; remove brownmask; remove redmask; remove goldmask; remove whitemask; give Hall3 visited; give studydoor ~locked open; give labhallspell general; "[ZAP] Enlightened and ready!"; dust: remove dust; "[ZAP] Dust gone."; default: "You can't zap ", (the) noun, "."; } ]; [ ZapDaySub; print "[ZAP] It's daytime.^"; ChangeWeather(DAYTIME); ]; [ ZapNightSub; print "[ZAP] It's nighttime.^"; ChangeWeather(NIGHTTIME); ]; [ ZapDreamSub; print "[ZAP] It's dreamtime.^"; ChangeWeather(DREAMTIME); ]; [ ZapWeighSub; if (~~(noun provides scaleweight)) "[ZAP] ", (The) noun, " has no weight."; else "[ZAP] ", (The) noun, " weighs ", noun.scaleweight, "."; ]; #endif; [ HelpScope obj; switch (scope_stage) { 1: rfalse; ! no multiple objects 2: ScopeWithin(compass); objectloop (obj ofclass HelpClass) { PlaceInScope(obj); } rtrue; 3: give HTBare general; "There is no help information on that subject. Type ", (helpcmd) "help", " for subjects you can learn about."; } ]; [ DrawingScope; switch (scope_stage) { 1: rfalse; ! no multiple objects 2: if (Enlightened) PlaceInScope(minddiagram); if ((~~Enlightened) && location == Study) PlaceInScope(diagram); rtrue; 3: "You cannot envision that clearly enough to draw it."; } ]; Include "Grammar"; Extend 'look' replace ! 'l//' * -> Look * 'u//'/'up'/'above' -> ExamineUp * 'd//'/'down'/'below' -> ExamineDown * 'at' noun -> Examine * 'at' noun 'with'/'through'/'in' noun -> LookWith reverse * 'inside'/'in'/'into'/'through'/'out'/'outside' noun -> Search * 'through' noun 'at' noun -> LookWith * 'behind' noun -> LookBehind * 'under' noun -> LookUnder; Extend 'examine' replace ! 'x//' 'watch' 'describe' 'check' * noun -> Examine * noun 'with'/'through'/'in' noun -> LookWith reverse; Extend only 'i//' replace * -> Inv * 'give' 'up' -> IGiveUp * 'want'/'need' -> IWant * 'want'/'need' topic -> IWant * 'am' -> IAm * 'am' topic -> IAm; Extend 'put' replace * multiexcept 'in'/'inside'/'into' noun -> Insert ! * held 'on' -> Wear * multiexcept 'on'/'onto' noun -> PutOn * noun 'over'/'above' noun -> PutOver * 'on' held -> Wear * 'down' multiheld -> Drop * multiheld 'down' -> Drop; Verb 'dip' * multiexcept 'in'/'inside'/'into' noun -> Insert; Extend 'get' replace * 'out'/'off'/'up' -> Exit * multi -> Take * 'in'/'into'/'inside'/'on'/'onto' noun -> Enter * 'out'/'off'/'up' 'of'/'from' noun -> GetOff * 'off' noun -> GetOff * multiinside 'from' noun -> Remove; Verb 'grab' 'snatch' * multi -> Take * multiinside 'from' noun -> Remove * multiinside 'off' noun -> Remove; Verb 'release' * noun -> Drop; Verb 'let' * 'go' 'of' noun -> Drop * 'go' noun -> Drop; Extend 'pull' replace ! and 'drag' * noun -> Pull * noun 'to' noun -> Transfer; Verb 'tug' * noun -> Pull * noun 'to' noun -> Transfer; Verb 'step' * 'out'/'off' -> Exit * 'in'/'into'/'inside'/'on'/'onto' noun -> Enter * 'out'/'off' 'of'/'from' noun -> GetOff * 'off' noun -> GetOff; Extend 'jump' replace ! and 'skip' 'hop' * -> Jump * 'over' noun -> JumpOver * 'on'/'onto'/'in'/'into' noun -> Enter * 'off'/'out' noun -> GetOff * 'off'/'out' 'of'/'from' noun -> GetOff; Extend 'go' last ! and 'walk' 'run' * 'to'/'toward'/'towards' noun -> Enter * 'from' noun -> Exit * 'away' 'from' noun -> Exit * 'back' -> VagueGo; Extend only 'move' last * 'toward'/'into'/'to'/'towards'/'through' noun -> Enter * 'from' noun -> Exit * 'away' 'from' noun -> Exit; Verb 'follow' * noun -> Enter; Extend only 'climb' replace * noun -> Climb * 'over' noun -> Climb * 'up' noun -> ClimbUp * 'down' noun -> ClimbDown * 'on'/'onto'/'in'/'into'/'inside' noun -> Enter * 'off'/'out' 'of' noun -> GetOff * 'off'/'out' noun -> GetOff; Extend only 'touch' replace * noun -> Touch * noun 'with' held -> TouchWith reverse * noun 'to' noun -> TouchTo; Extend only 'hold' replace * multi -> Take * 'on' 'to' noun -> Take * 'on'/'onto' noun -> Take; Verb 'hang' * noun 'on'/'onto' noun -> PutOn * noun 'over'/'above' noun -> PutOver; Extend 'squeeze' replace ! and 'squash' * noun -> Squeeze * noun 'on'/'to'/'onto' noun -> TouchTo * held 'in'/'into' noun -> Insert; Verb 'crush' * noun -> Squeeze * noun 'on'/'to'/'onto' noun -> TouchTo * held 'in'/'into' noun -> Insert; Extend 'burn' replace ! and 'light' * noun -> Burn * noun 'with'/'in' noun -> BurnWith; Verb 'ignite' * noun -> Burn * noun 'with'/'in' noun -> BurnWith; Verb 'freeze' 'chill' 'cool' * noun -> Freeze * noun 'with'/'in' noun -> FreezeWith; Verb 'draw' 'write' 'sketch' 'inscribe' 'copy' * scope=DrawingScope -> DrawFigure * scope=DrawingScope 'with' noun -> DrawFigureWith * scope=DrawingScope 'on' noun -> DrawFigureOn * 'with' noun -> DrawWith * 'on' noun -> DrawOn; Verb 'pour' * 'out' noun 'into'/'in'/'to'/'on'/'onto' noun -> EmptyT * noun 'into'/'in'/'to'/'on'/'onto' noun -> EmptyT; Extend 'dig' replace * 'in'/'into' noun -> Dig * 'in'/'into' noun 'with' held -> Dig * noun -> Dig * noun 'with' held -> Dig; Extend 'fill' replace * noun 'with'/'from' noun -> EmptyT reverse; Verb 'untie' 'detach' 'unfasten' 'loosen' * noun -> Untie; Verb 'breathe' 'inhale' * -> Smell * 'on' noun -> Blow * noun -> Smell; Verb 'knock' * 'on'/'at' noun -> Attack * 'over' noun -> Push; Verb 'lean' * 'against'/'on' noun -> Push; Verb 'shove' * noun -> Push * noun noun -> PushDir * noun 'to' noun -> Transfer; Verb 'i^m' * -> IAm * topic -> IAm; Verb 'who' 'where' 'what' 'why' 'who^s' 'what^s' 'where^s' * -> Questions * topic -> Questions; Extend only 'give' first * 'up' -> IGiveUp; Verb 'crap' 'curse' 'swear' * -> Strong * topic -> Strong; Extend 'pray' replace * -> Pray * 'to'/'for' topic -> Pray; Extend 'blow' replace * 'at'/'on'/'out'/'off' noun -> Blow * noun -> Blow * noun 'out' -> Blow; Verb 'play' 'strum' 'pluck' * noun -> Play; Verb 'lick' * noun -> Taste; Verb meta 'use' * -> Use * topic -> Use; !Verb meta 'bend' ! * 'bars' -> BendBars; Verb ',burnberry' * noun -> BerryBurn; Verb ',freezeberry' * noun -> BerryFreeze; Verb meta 'help' 'hint' 'hints' * -> HelpBare * scope=HelpScope -> Help * noun -> HelpConcrete; !Verb meta 'hint' 'hints' ! * -> Hint; Verb meta 'about' * -> About * 'game' -> About; Verb meta 'expert' * -> Expert * 'mode'/'game'/'on'/'off' -> Expert; Verb meta 'impossible' * -> Impossible * 'mode'/'game'/'on'/'off' -> Impossible; Verb meta 'tutorial' 'tutor' * -> TutorToggle * 'on' -> TutorOn * 'off' -> TutorOff; Verb meta ',noop' * -> NoOp * topic -> NoOp; #ifdef ZDEBUG; Verb 'zap' * 'day'/'daytime' -> ZapDay * 'night'/'nighttime' -> ZapNight * 'dream'/'dreamtime' -> ZapDream * 'weigh'/'weight' noun -> ZapWeigh * noun -> Zap; #endif;