/*
* 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 ****/