/* * Copyright (c) 2021 Ross Cunniff * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "libadv.oah" namespace stdadv { public pSeen, /* I've been here/seen this */ pOpens, /* This can be opened */ pLocks, /* This can be locked */ pOpened, /* This is opened */ pLocked, /* This is locked */ pTrans, /* This is transparent */ pLight, /* This gives off light */ pFlame, /* This is on fire */ pNoTake, /* Ignore this object for "take all" */ pAllLink, /* Link for objs used in "take" and "drop" */ pSaveSent; /* First variable in a sentence save area */ /* Strings used more than once */ const YouSeeNo = "You see no ", Huh = "Huh?\n", CR = "\n", EOL = ".\n", MeanMsg = "What do you mean by \"", ItConfused = "I can't seem to figure out what you mean by 'it'.\n", Dropped = "dropped"; /* Flags for Expect */ const NO_OBJ = 1, /* It's valid to have no objects */ ONE_OBJ = 2, /* It's valid to have one object */ MULT_OBJ = 4, /* It's valid to have multiple objects */ STR_OBJ = 8, /* It's valid to have string objects */ PLAIN_OBJ = 16; /* It's valid to have plain objects */ /* Global variables */ var First = true, /* Is the current adv::Dobj the first in the adv::Dobj list? */ AllSeen, /* Did the player type "all" in this sentence? */ MultList = {}, /* Array of multiple objects */ MyConj, /* Records where "but" has been seen */ NumSeen, /* Number of adv::Dobj's seen by "take" or "drop" so far */ adv::IobjSave, /* Save for the adv::Iobj (for TAKE and DROP) */ Skip, /* Should TorDACT skip this object? */ Scripting, /* Are we writing a script file? */ Conts, /* Have we already printed out "You can see:"? */ Indent, /* Indent outer object descriptions? */ Dark, /* Is it dark? */ MyLoc = nil, /* My last location */ adv::Verbose; /* Does the player want verbose output? */ /* Derived classes */ class StdLoc(adv::Location) { public var pSeen = false; } class LitRoom(StdLoc) { public var pLight = true; } class FixedThing(adv::Thing) { public var pNoTake = true; } /* Standard words from English */ adv::SepClass thenSep("then"); adv::ConjClass andConj("and"); adv::ConjClass butConj("but"); adv::ConjClass orConj("or"); adv::PrepClass withPrep("with"); adv::PrepClass toPrep("to"); adv::PrepClass inPrep("in", "into"); adv::PrepClass atPrep("at"); adv::PrepClass underPrep("under"); adv::PrepClass fromPrep("from"); adv::PrepClass offPrep("off"); adv::PrepClass onPrep("on"); adv::ArtClass theArticle("the"); adv::ArtClass aArticle("a", "an"); proc StdInit, /* StdInit(actor) Standard game with actor playing */ Reach, /* Reach(Obj,Where) True IFF I can reach Obj in Where */ See, /* See(Obj,Where) True IFF I can see Obj in Where */ Lit, /* LitP() True IFF something is lit or burning */ Describe, /* Describe(depth,obj,rout) Describe obj */ Avail, /* Avail(Obj) Is Obj available? */ CheckAvail, /* CheckAvail() check availability of adv::Dobj and adv::Iobj */ Expect, /* Expect(adv::DobjFlags,adv::IobjFlags) Check the form */ Preact, /* Standard verb preact */ Looker, /* Looking daemon */ Prompter, /* User prompt */ ActAction, /* Standard actor ACTION */ SaveSentence, /* SaveSentence() - save the value of the curr. sent. */ TakeAct, /* User defined take action */ DropAct, /* User defined drop action */ Dwimmer; /* Dwimmer(Obj) - is Obj the one I want? */ /* Standard objects */ adv::Thing all(nil); adv::Thing it(nil); /* adv::Verbs - NOTE: do not change the PREACT or ACTION of any of these * without carefully considering the consequences */ adv::VerbClass take; adv::VerbClass north(); adv::Synonym _n(north,"n"); adv::VerbClass south(); adv::Synonym _s(south,"s"); adv::VerbClass east(); adv::Synonym _e(east,"e"); adv::VerbClass west(); adv::Synonym _w(west,"w"); adv::VerbClass northeast(); adv::Synonym _ne(northeast, "ne"); adv::VerbClass southeast(); adv::Synonym _se(southeast, "se"); adv::VerbClass northwest(); adv::Synonym _nw(northwest, "nw"); adv::VerbClass southwest(); adv::Synonym _sw(southwest, "sw"); adv::VerbClass up(); adv::Synonym _up(up, "u"); adv::VerbClass down(); adv::Synonym _down(down, "d"); adv::VerbClass enter(); adv::VerbClass exit(); adv::VerbClass again(); adv::Synonym _again(again, "g"); /* StdInit(actor) - initializes the ACTION routine of actor, sets * up the prompter, and sets up the looking daemon. */ class StdActor(adv::Actor) { public var action; public var pNoTake; public var pSaveSent; public var pTrans; public var pOpened; public var pSeen; } proc StdInit(actor) { oadl::srandom(); actor.action = ActAction; actor.pNoTake = true; actor.pSaveSent = new Array(6); actor.activate(nil, true); adv::Prompt = Prompter; adv::Setdaemon(Looker); adv::dirVec = {north,south,east,west, northeast,southeast,northwest,southwest, up,down}; } /* RandInt(min,max) - return a random integer between min and max, inclusive */ proc RandInt(min, max) { return min + Int(0.5 + oadl::random()*(max-min)); } /* Percent(n) - returns 1 n % of the time */ proc Percent(n) { return RandInt(0,100) <= n; } /* FindIt(obj) - figure out what an 'it' in a player's sentence refers to */ proc FindIt() { var SavePlace, /* The value of adv::$ME.pSaveSent */ LastDobj, /* The last DIRECT OBJECT typed */ LastIobj, /* The last INDIRECT OBJECT typed */ LastNumd; /* The previous NUMBER OF DIRECT OBJECTS typed */ /* Retrieve the pertinent info from pSaveSent */ SavePlace = adv::$ME.pSaveSent; if( !SavePlace ) { say(ItConfused); adv::ExitPhase(adv::PHX_ACTOR); } LastNumd = SavePlace[1]; LastDobj = SavePlace[3]; LastIobj = SavePlace[5]; if( LastNumd > 1 ) { say(ItConfused); adv::ExitPhase(adv::PHX_ACTOR); } if( (LastDobj != nil) && (LastIobj == nil) ) { return LastDobj; } else if( (LastDobj == nil) && (LastIobj != nil) ) { return LastIobj; } else { say(ItConfused); adv::ExitPhase(adv::PHX_ACTOR); } } /* ActAction - the default Actor Action */ proc ActAction() { var SavePlace; if( adv::Verb == again ) { SavePlace = adv::$ME.pSaveSent; if( !SavePlace ) { "I can't do that.\n"; adv::ExitPhase(adv::PHX_ACTOR); } if( adv::Dobj || adv::Iobj ) { "You may not use objects with 'again'.\n"; adv::ExitPhase(adv::PHX_ACTOR); } if( SavePlace[1] > 1 ) { "You can't use 'again' with multiple direct objects.\n"; adv::ExitPhase(adv::PHX_ACTOR); } adv::Verb = SavePlace[0]; adv::Numd = SavePlace[1]; adv::Conj = SavePlace[2]; adv::Dobj = SavePlace[3]; adv::Prep = SavePlace[4]; adv::Iobj = SavePlace[5]; adv::ExitPhase(adv::PHX_CURRENT); } if( (adv::Dobj == it) && (adv::Iobj != it) ) { adv::Dobj = FindIt(); } else if( (adv::Iobj == it) && (adv::Dobj != it) ) { adv::Iobj = FindIt(); } else if( (adv::Dobj == it) && (adv::Iobj == it) ) { "You may only use the word 'it' once in a sentence.\n"; adv::ExitPhase(adv::PHX_ACTOR); } SaveSentence(); } proc Prompter() { say( "> " ); } /* CheckAvail() - checks to see whether the objects named by the player are indeed available */ proc CheckAvail() { if( adv::Dobj ) { Avail(adv::Dobj); } if( adv::Iobj ) { Avail(adv::Iobj); } } /* Expect(adv::DobjFlags, adv::IobjFlags) - Checks for a valid sentence */ proc Expect(DobjFlags, IobjFlags) { /* Check the number of direct objects */ if( adv::Numd == 0 ) { if( !(DobjFlags & NO_OBJ) ) { "You must tell me what to ", adv::Verb.name, EOL; adv::ExitPhase(adv::PHX_SENTENCE); } } else if( (adv::Numd == 1) & (adv::Dobj != all) ) { if( !(DobjFlags & MULT_OBJ) && !(DobjFlags & ONE_OBJ) ) { "You may not use a direct object with ", adv::Verb.name, EOL; adv::ExitPhase(adv::PHX_ACTOR); } } else { if( !(DobjFlags & MULT_OBJ) ) { "You may not use multiple direct objects with ", adv::Verb.name, EOL; adv::ExitPhase(adv::PHX_ACTOR); } } /* Check the number of Indirect objects */ if ((!adv::Iobj) && !(IobjFlags & NO_OBJ)) { "How would you like to do that?\n"; adv::ExitPhase(adv::PHX_SENTENCE); } else if (adv::Iobj && !(IobjFlags & ONE_OBJ)) { "You may not use an indirect object with ", adv::Verb.name, EOL; adv::ExitPhase(adv::PHX_ACTOR); } /* Check the type of the objects */ if ( ((typeof(adv::Dobj) == String) && !(DobjFlags & STR_OBJ)) || ((typeof(adv::Iobj) == String) && !(IobjFlags & STR_OBJ))) { "You may not use strings with ", adv::Verb.name, EOL; adv::ExitPhase(adv::PHX_ACTOR); } if ( (adv::Dobj && (typeof(adv::Dobj) != String) && !(DobjFlags & PLAIN_OBJ)) || (adv::Iobj && (typeof(adv::Iobj) != String) && !(IobjFlags & PLAIN_OBJ)) ) { "You must use a string with ", adv::Verb.name, EOL; adv::ExitPhase(adv::PHX_ACTOR); } } /* Preact - the default verb Preact */ proc Preact() { Expect(ONE_OBJ|PLAIN_OBJ, NO_OBJ|ONE_OBJ|PLAIN_OBJ); CheckAvail(); } /* Visible(List,Propno) - Returns 1 IFF an object is visible on List that has a nonzero prop Propno */ proc Visible(arr, Propno) { forall (arr[i]) { var o = arr[i]; if (o.(Propno)) { /* This is it! */ return true; } else if (o.pOpened || o.pTrans) { /* Look inside */ if (Visible(o.cont, Propno)) { return true; } } } return false; } /* Reach(Obj, Loc) - Returns 1 IFF Obj == Loc, or can (recursively) be reached via the Loc */ proc Reach(Obj, Loc) { var o; forall (Loc[i]) { o = Loc[i]; if (Obj == o) { /* This is the one! */ return true; } else if (o.pOpened) { /* Still explore inside */ if (Reach(Obj, o.cont)) { return true; } } } return false; } /* See(Obj,Loc) - Returns 1 IFF the Obj == Loc, or can be reached via the Loc (similar to Reach, above) */ proc See(Obj, Loc) { if (Dark) { /* Can't see in a dark room! */ return false; } forall (Loc[i]) { var o = Loc[i]; if (Obj == o) { /* This is the one! */ return true; } else if (o.pTrans || o.pOpened) { /* Still explore inside */ if (See(Obj, o.cont)) { return true; } } } return false; } /* Avail(Obj) - Returns 1 IFF I can see Obj or I can reach Obj, performs a (exit 1) otherwise */ proc Avail(Obj) { if (!Obj) { "The what?\n"; adv::ExitPhase(adv::PHX_ACTOR); } else if (!(See(Obj, adv::$ME.loc.cont) || See(Obj,adv::$ME.cont))) { "I can't see that item here.\n"; adv::ExitPhase(adv::PHX_ACTOR); } else if (!(Reach(Obj, adv::$ME.loc.cont) || Reach(Obj,adv::$ME.cont))) { "I can't get at that item.\n"; adv::ExitPhase(adv::PHX_ACTOR); } return true; } /* Lit(Room) - Returns true IFF Room is lit */ proc Lit(Room) { if (Room.pLight) { /* Intrinsically lit */ return true; } else if (Visible(Room.cont, pLight) || Visible(Room.cont, pFlame)) { return true; /* I can see a light */ } else if (Visible(adv::$ME.cont, pLight) || Visible(adv::$ME.cont, pFlame)) { return true; /* I have a light */ } else { return false; } } /* Blank(num) - Type 2*n blanks */ proc Blank(num) { var idx; if (!Indent) return; for (idx = 0; idx < num; idx++ ) { " "; } } /* Describe(Level,Obj,Rout) - Describes Obj using Rout (which is a public that indexes a ROUTINE that describes Obj, typically sdesc or ldesc), and also describes the contents of Obj */ proc Describe(Level, Obj, Rout) { if (!Obj) { /* Null list */ return 0; } else if (!Level) { /* Level 0 == This is a room. Check lighting */ Conts = false; if (Lit(Obj)) { Dark = false; /* Can't be dark in a lit room! */ Obj.(Rout)(); /* Talk about the room */ if (!Dark) { Describe(1, Obj.cont, Rout); /* Talk about its contents */ } } else { "It's mighty dark in here!\n"; Dark = true; } } else { /* Level > 0 == This is a list of objs */ forall (Obj[i]) { var o = Obj[i]; if (o.(Rout)) { /* Talk (only) about the visible */ if ((Rout == sdesc) && !Conts) { Blank(Level - 1); "You can see:\n"; } Conts = true; Blank(Level); /* Indent */ o.(Rout)(); /* Blurb the object */ if (o.cont.length()) { /* something inside it...*/ if (o.pOpened || o.pTrans) { if (Rout == ldesc) { Blank(Level); "It contains:\n"; } else { ", containing\n"; } o.pSeen = true; /*Short descs for conts*/ Describe(Level+1, o.cont, sdesc); } else if (Rout == sdesc) { say(CR); } } else if (Rout == sdesc) { say(CR); } } } } } /* SaveSentence() - save the value of the current sentence */ proc SaveSentence() { var SavePlace; SavePlace = adv::$ME.pSaveSent; if (!SavePlace) { return 0; } SavePlace[0] = adv::Verb; SavePlace[1] = adv::Numd; SavePlace[2] = adv::Conj; SavePlace[3] = adv::Dobj; SavePlace[4] = adv::Prep; SavePlace[5] = adv::Iobj; } /* Looker() - The standard Looking daemon. Usually only mentioned in START. */ proc Looker() { adv::$ME.pTrans = false; MyConj = false; First = true; adv::IobjSave = nil; AllSeen = false; if (MyLoc != adv::$ME.loc) { if (adv::$ME.loc.pSeen && !adv::Verbose) { Describe(0, adv::$ME.loc, sdesc); } else { adv::$ME.loc.sdesc(); Describe(0, adv::$ME.loc, ldesc); adv::$ME.loc.pSeen = true; } if (Dark) { adv::$ME.loc.pSeen = false; } MyLoc = adv::$ME.loc; } adv::$ME.pTrans = true; adv::$ME.pOpened = true; } /* The following are routines relating to sentence constructions such as "take all but rock and cow. drop all but sword." */ /* DelList(Obj) -- Deletes Obj from the list of multiple direct objects */ proc DelList(Obj) { var i, n; if (Obj == all) { /* The player typed something like "take all but all" */ "I don't understand that.\n"; adv::ExitPhase(adv::PHX_ACTOR); } // Find the object on the list n = MultList.length(); for (i = 0; i < n; i++) { if( MultList[i] == Obj ) { break; } } if( i < n ) { // Reconstitute the list without the object MultList = MultList[:i-1] ## MultList[i+1:]; } else { // Was not on the list. "", YouSeeNo, Obj.name, " here.\n"; adv::ExitPhase(adv::PHX_ACTOR); } } /* AddList(Obj) -- Adds Obj to the list of multiple direct objects */ proc AddList(Obj) { if (Obj == all) { /* The player typed something like "Take rock and all" */ "I don't understand that.\n"; adv::ExitPhase(adv::PHX_ACTOR); } MultList = MultList ## { Obj }; } /* InitList(Where) -- Adds each object contained in Where to MultList */ proc InitList(Where) { MultList = {}; AllSeen = true; forall (Where[i]) { var o = Where[i]; if (!o.pNoTake) { MultList = MultList ## o; } } } /* Mover(Where,String) - Moves each object on MultList to Where, printing String as it does so. */ proc Mover(Where, Str) { var i, n; n = MultList.length(); if (!n) { "There is nothing to ", adv::Verb.name, EOL; adv::ExitPhase(adv::PHX_ACTOR); } for (i = 0; i < n; i++) { adv::Dobj = MultList[i]; adv::Iobj = adv::IobjSave; Skip = false; adv::Dobj.action(); /* Call the ACTION routines */ if (!Skip) { adv::Iobj.action(); /* for the adv::Dobj and adv::Iobj */ } if (!Skip) { /* Call the ACTIONs for the verb */ if (adv::Verb == take) { TakeAct(); } else { /* adv::Verb == drop */ DropAct(); } } if (!Skip) { adv::Dobj.move(Where); /* Do the moving */ " ", adv::Dobj.name, " - ", Str, CR; } } MultList = {}; } /* CheckLoc(Obj,Where) - Checks whethere Obj can be seen on Where and can be reached on Where */ proc CheckLoc(Obj, Where, Loc) { if (!See(Obj, Where)) { if (Loc == adv::$ME) { "You have no ", Obj.name, EOL; } else { "", YouSeeNo, Obj.name, " here.\n"; } adv::ExitPhase(adv::PHX_ACTOR); } else if (!Reach(Obj, Where)) { "You can't reach the ", Obj.name, EOL; adv::ExitPhase(adv::PHX_ACTOR); } } /* TorDPRE(Where) -- Uses Where as the context for a multiple direct object (with "all" as a possible object) list. */ proc TorDPRE(Where, Loc) { if (!First) { // The MultList is initialized if (adv::Conj == butConj) { if (!AllSeen) { // The player typed something like "take a, b but c" "I don't understand that.\n"; adv::ExitPhase(adv::PHX_ACTOR); } MyConj = true; } if (MyConj) { // We have seen "but" in the sentence, so delete this object // from the list DelList(adv::Dobj); } else { // We have NOT seen "but" // See if the obj is in the right place CheckLoc(adv::Dobj, Where, Loc); // if so, add the object to the mult list AddList(adv::Dobj); } } else { // The MultList is NOT initialized, but there are objects in // the sentence if (adv::Dobj == all) { // The direct obj. is "all", so set the MultList to the cont of // the loc of adv::$ME InitList(Where); } else { // The dir obj. is NOT all so set MultList to be the direct object. CheckLoc(adv::Dobj, Where, Loc); MultList = MultList ## {adv::Dobj}; } First = false; MyConj = false; NumSeen = 1; } // We will call the ACTION routines later... adv::Dobj = nil; } /* (TorDACT Where String) -- Moves all objects on the multlist to Where (using Mover) if all of the objects have been seen; otherwise it waits. String is the past participle of verb. (e.g. "taken", "dropped" */ proc TorDACT(Where, Str) { if (adv::Numd <= NumSeen) { Mover(Where, Str); } else { NumSeen = NumSeen + 1; } } /* The following objects are for things like "go north" */ adv::NounClass DIR("DIR"); adv::Thing n_DIR {noun = DIR adjec = north} adv::Thing s_DIR {noun = DIR adjec = south} adv::Thing e_DIR {noun = DIR adjec = east} adv::Thing w_DIR {noun = DIR adjec = west} adv::Thing ne_DIR {noun = DIR adjec = northeast} adv::Thing se_DIR {noun = DIR adjec = southeast} adv::Thing nw_DIR {noun = DIR adjec = northwest} adv::Thing sw_DIR {noun = DIR adjec = southwest} adv::Thing u_DIR {noun = DIR adjec = up} adv::Thing d_DIR {noun = DIR adjec = down} /* We keep them in this array for PORTABLE referencing */ var DirArray = { n_DIR, s_DIR, e_DIR, w_DIR, ne_DIR, se_DIR, nw_DIR, sw_DIR, u_DIR, d_DIR }; adv::VerbClass go { preact = proc() { var i; Expect(ONE_OBJ|PLAIN_OBJ, NO_OBJ); /* Try to find the adv::Dobj in the list of Directions */ for (i = 0; i < 10; i++) { if (DirArray[i] == adv::Dobj) { /* We found it. Set the adv::Verb and adv::Dobj appropriately */ adv::Verb = adv::Dobj.adjec; adv::Dobj = nil; adv::Verb.preact(); return; } } /* if we get here, we didn't find the adv::Dobj */ "", Huh; adv::ExitPhase(adv::PHX_ACTOR); } } proc Silly() { "That's silly!\n"; adv::ExitPhase(adv::PHX_ACTOR); } adv::Thing adv::NONOUN { } adv::VerbClass adv::NOVERB { preact = proc() { if (adv::Iobj == adv::NONOUN) { // The user just typed a preposition if (adv::Prep == inPrep) { // Transform this sentence into "enter" adv::Verb = enter; return enter.preact(); } } if (typeof(adv::Dobj) == Object) { "What do you want to do with the ", adv::Dobj.name, "?\n"; adv::ExitPhase(adv::PHX_SENTENCE); } else if (typeof(adv::Dobj) == String) { "", MeanMsg, adv::Dobj, "\"?\n"; adv::ExitPhase(adv::PHX_SENTENCE); } else if (typeof(adv::Iobj) == Object) { "What to you want to do ", adv::Prep.name, " the ", adv::Iobj.name, "?\n"; adv::ExitPhase(adv::PHX_SENTENCE); } else if (typeof(adv::Iobj) == String) { "", MeanMsg, adv::Iobj, "\"?\n"; adv::ExitPhase(adv::PHX_SENTENCE); } else { "I beg your pardon?\n"; adv::ExitPhase(adv::PHX_ACTOR); } } } adv::VerbClass wait { preact = proc() { Expect(NO_OBJ, NO_OBJ); "Time passes...\n"; adv::ExitPhase(adv::PHX_ACTOR); } } adv::Synonym _z(wait, "z"); adv::VerbClass wear { preact = Preact action = Silly } adv::VerbClass remove { preact = Preact action = Silly } adv::VerbClass verbose { preact = proc() { Expect(NO_OBJ, NO_OBJ); } action = proc() { "Maximum verbosity.\n"; adv::Verbose = true; } } adv::VerbClass terse { preact = proc() { Expect(NO_OBJ, NO_OBJ); } action = proc() { "Minimum verbosity.\n"; adv::Verbose = false; } } adv::VerbClass take { preact = proc() { Expect(ONE_OBJ|MULT_OBJ|PLAIN_OBJ, NO_OBJ|ONE_OBJ|PLAIN_OBJ); if (adv::Iobj) { if (!adv::Prep) { /* The sentence was "take X Y" */ say(Huh); adv::ExitPhase(adv::PHX_ACTOR); } if (adv::Iobj.pOpened) { TorDPRE(adv::Iobj.cont, adv::Iobj); } else { "You can't reach into the ", adv::Iobj.name, CR; adv::ExitPhase(adv::PHX_ACTOR); } } else { adv::$ME.pOpened = false; adv::$ME.pTrans = false; TorDPRE(adv::$ME.loc.cont, adv::$ME.loc); adv::$ME.pOpened = true; adv::$ME.pTrans = true; } } action = proc() { TorDACT(adv::$ME, "taken"); } } adv::VerbClass drop { preact = proc() { Expect(ONE_OBJ|MULT_OBJ|PLAIN_OBJ, NO_OBJ|ONE_OBJ|PLAIN_OBJ); if (adv::Iobj) { if (!adv::Prep) { /* The sentence was "drop X Y" */ say(Huh); adv::ExitPhase(adv::PHX_ACTOR); } if (!adv::Iobj.pOpened) { "You can't put that into the ", adv::Iobj.name, EOL; adv::ExitPhase(adv::PHX_ACTOR); } adv::IobjSave = adv::Iobj; adv::Iobj = 0; } TorDPRE(adv::$ME.cont, adv::$ME); } action = proc() { if (adv::IobjSave) { TorDACT(adv::IobjSave, Dropped); } else { TorDACT(adv::$ME.loc, Dropped); } } } adv::Synonym put(drop); adv::Synonym get(take); adv::VerbClass open { preact = Preact action = proc() { if (!adv::Dobj.pOpens) { "I don't know how to open that!\n"; adv::ExitPhase(adv::PHX_ACTOR); } else if (adv::Dobj.pLocks && adv::Dobj.pLocked) { "I can't open it, it's locked!\n"; adv::ExitPhase(adv::PHX_ACTOR); } else if (adv::Dobj.pOpened) { "It's already open!\n"; adv::ExitPhase(adv::PHX_ACTOR); } else { adv::Dobj.pOpened = true; if (adv::Dobj.cont.length() && !adv::Dobj.pTrans) { "Opening the ", adv::Dobj.name, " reveals:\n"; Describe(1, adv::Dobj.cont, sdesc); } else { "Opened.\n"; } } } } adv::VerbClass close { preact = Preact action = proc() { if (!adv::Dobj.pOpens) { "I don't know how to close that!\n"; adv::ExitPhase(adv::PHX_ACTOR); } else if (!adv::Dobj.pOpened) { "It's already closed!\n"; adv::ExitPhase(adv::PHX_ACTOR); } else { adv::Dobj.pOpened = false; "Closed.\n"; } } } proc Lockact() { if (adv::Dobj.pLocks) { "Hmm, you don't seem to have the right key.\n"; } else { "I don't know how to lock or unlock such a thing.\n"; } } adv::VerbClass lock { preact = Preact action = Lockact } adv::VerbClass unlock { preact = Preact action = Lockact } adv::VerbClass move { preact = Preact action = proc() {"Nothing seems to happen.\n";} } adv::VerbClass V_break("break") { // "break" is a keyword preact = Preact action = proc() {"It seems to be unbreakable.\n";} } adv::VerbClass touch { preact = Preact action = proc() { "Touching the ", adv::Dobj.name, " doesn't seem too useful.\n"; } } adv::VerbClass rub { preact = Preact action = proc() { "Nothing happens when you rub the ", adv::Dobj.name, EOL; } } adv::VerbClass V_throw("throw") { // "throw" is a keyword preact = Preact action = proc() { adv::Dobj.move(adv::$ME.loc); "Thrown.\n"; } } adv::VerbClass turn { preact = Preact action = Silly } adv::VerbClass light { preact = Preact action = Silly } adv::VerbClass douse { preact = Preact action = Silly } adv::VerbClass V_read("read") { // "read" is a builtin preact = proc() { Expect(ONE_OBJ|PLAIN_OBJ, NO_OBJ|ONE_OBJ|PLAIN_OBJ); if (!(See(adv::Dobj, adv::$ME.cont) || See(adv::Dobj, adv::$ME.loc.cont))) { "You don't see that here.\n"; adv::ExitPhase(adv::PHX_ACTOR); } } action = proc() { "It doesn't have anything on it to read.\n"; } } adv::VerbClass burn { preact = Preact action = proc() { "That doesn't seem to work.\n"; } } adv::VerbClass examine { preact = Preact action = proc() { "You see nothing special about the ", adv::Dobj.name, EOL; } } adv::Synonym _x(examine,"x"); adv::VerbClass look { preact = proc() { Expect(NO_OBJ, NO_OBJ|ONE_OBJ|PLAIN_OBJ); CheckAvail(); } action = proc() { Describe(0, adv::$ME.loc, ldesc); } } adv::Synonym _l(look,"l"); adv::VerbClass inventory { preact = proc() { Expect(NO_OBJ, NO_OBJ); } action = proc() { if (!adv::$ME.cont.length()) { "You are empty-handed.\n"; adv::ExitPhase(adv::PHX_ACTOR); } adv::$ME.pSeen = true; "You are carrying:\n"; Conts = true; Describe(1, adv::$ME.cont, sdesc); } } adv::Synonym _i(inventory,"i"); proc yorn() { var str; while (true) { str = adv::Getstr(); if ((str == "y") || (str == "Y")) { return 1; } else if ((str == "n") || (str == "N")) { return 0; } else { "(Y or N) "; } } } adv::VerbClass quit { preact = proc() { Expect(NO_OBJ, NO_OBJ); } action = proc() { "Are you sure that you want to quit? "; if (yorn()) { adv::Quit(); } } } adv::Synonym _q(quit,"q"); adv::VerbClass save { preact = proc() { Expect(NO_OBJ, NO_OBJ); } action = proc() { var str, n; MyLoc = nil; adv::$ME.loc.pSeen = false; "Save to which file? "; str = adv::Getstr(); if (str.length()) { n = 1;//save(str); if (n < 0) { "Save failed.\n"; } else if (n == 0) { "Restored.\n"; } else { "Saved.\n"; } } adv::$ME.loc.pSeen = true; MyLoc = adv::$ME.loc; } } adv::VerbClass restore() { preact = proc() { Expect(NO_OBJ, NO_OBJ); } action = proc() { var str; "Restore from which file? "; str = adv::Getstr(); if (str.length()) { if (false/*restore(str) < 0*/) { "Restore failed.\n"; } } } } adv::VerbClass restart() { preact = proc() { Expect(NO_OBJ, NO_OBJ); } action = proc() { "Are you sure that you want to restart? "; if (yorn()) { adv::Restart(); } } } adv::VerbClass script(); //preact = Proc() { Expect(NO_OBJ, NO_OBJ); } //action = Proc() //{ // Var // str; // // if (Scripting) { // spec(SCRIPT, 0); // "Scripting turned off.\n"; // Scripting = false; // } // else { // "Script to which file? "; // str = Getstr(); // if (leng(str)) { // "Scripting turned on.\n"; // spec(SCRIPT, str); // Scripting = true; // } // } //} /* Dwimmer(Obj) - Returns 1 if the object is "possibly the one the user meant." Returns 0 otherwise. */ proc Dwimmer(Parser, Obj) { var Trans, Opened, CanSee, i; if (Parser.pVerb == go) { /* Try to find Obj in the list of Directions */ i = 0; while (i < 10) { if (DirArray[i] == Obj) { /* We found it! */ return true; } i = i + 1; } /* if we get here, we didn't find it. */ return 0; } else if (Parser.pVerb == take) { /* We don't want to look at stuff adv::$ME is already carrying */ Trans = adv::$ME.pTrans; Opened = adv::$ME.pOpened; adv::$ME.pTrans = false; adv::$ME.pOpened = false; CanSee = See(Obj, adv::$ME.loc.cont); adv::$ME.pTrans = Trans; adv::$ME.pOpened = Opened; return CanSee; } else if (Parser.pVerb == drop) { /* We need to be transparent */ Trans = adv::$ME.pTrans; CanSee = See(Obj, adv::$ME.cont); adv::$ME.pTrans = Trans; return CanSee; } else { /* This is the default case - it works pretty well */ return See(Obj, adv::$ME.cont) || See(Obj, adv::$ME.loc.cont); } } proc Die() { var Str; while (true) { "Do you want to RESTART, RESTORE, or QUIT? "; Str = adv::Getstr(); if ((Str == "restart") || (Str == "RESTART")) { restart.action(); } else if ((Str == "restore") || (Str == "RESTORE")) { /* Execute restore.ACTION */ restore.action(); } else if ((Str == "quit") || (Str == "QUIT")) { quit.action(); } } } adv::Synonym putOn({put,onPrep},wear); adv::Synonym takeOff({take,offPrep},remove); adv::Synonym turnOn({turn,onPrep},light); adv::Synonym turnOff({turn,offPrep},douse); adv::Synonym lookAt({look,atPrep},examine); } /**** EOF std.oad ****/