/* Copyright (c) 2000 by Kevin Forchione.  All Rights Reserved. */
/*
*  TADS ADV.T/STD.T LIBRARY EXTENSION
*  COMPASS.T
*  version 1.0
*
*          compass.t simulates the Inform compass. Directions are objects
*      and also do double duty as walls, floor, and ceiling. Like
*      the Inform compass this one can define WITHOUT_DIRECTIONS in
*      the game source, which will remove the usual directions from
*      the compass object.
*
*----------------------------------------------------------------------
*  REQUIREMENTS
*
*      + HTML TADS 2.4.0 or later
*      + Should be #included after ADV.T and STD.T
*
*----------------------------------------------------------------------
*  IMPORTANT LIBRARY INTERFACE AND MODIFICATION
*
*      + Replaces checkReach() function.
*      + Modifies deepverb validXoList() and validXo() methods.
*      + Modifies inspectVerb validDo() method.
*      + Replaces travelVerb definitions.
*      + Defines parseErrorParam() method.
*
*----------------------------------------------------------------------
*  COPYRIGHT NOTICE
*
*      You may modify and use this file in any way you want, provided that
*              if you redistribute modified copies of this file in source form, the
*      copies must include the original copyright notice (including this
*      paragraph), and must be clearly marked as modified from the original
*      version.
*
*------------------------------------------------------------------------------
*  REVISION HISTORY
*
*              20-Jun-00:      Creation.
*/

#ifndef __COMPASS_MODULE_
#define __COMPASS_MODULE_

#pragma C+

/*----------------------------------------------------------------------
*  THE COMPASS
*--------------------------------------------------------------------*/

class CompassDirection: decoration
   ldesc = "%You% see nothing special about <<self.thedesc>>."
   verDoGo(actor) = {}
   doGo(actor) = {actor.travelTo(self.travelDir(actor));}
;

class SpecialCompassDirection: CompassDirection
   dobjGen(a, v, i, p) = {
       if (v != goVerb) {
           "%You% can't see any such thing. ";
           exit;
       }
   }
   iobjGen(a, v, d, p) = {self.dobjGen(a, v, d, p);}
;

compass: object
   sdesc = "compass"
;

#ifndef WITHOUT_DIRECTIONS

nObj: CompassDirection
   location = compass
   sdesc = "north wall"
   noun = 'wall'
   adjective = 'n' 'north'
   travelDir(actor) = {return actor.location.north;}
;
sObj: CompassDirection
   location = compass
   sdesc = "south wall"
   adjective = 's' 'south'
   noun = 'wall'
   travelDir(actor) = {return actor.location.south;}
;
eObj: CompassDirection
   location = compass
   sdesc = "east wall"
   adjective = 'e' 'east'
   noun = 'wall'
   travelDir(actor) = {return actor.location.east;}
;
wObj: CompassDirection
   location = compass
   sdesc = "west wall"
   adjective = 'w' 'west'
   noun = 'wall'
   travelDir(actor) = {return actor.location.west;}
;
neObj: CompassDirection
   location = compass
   sdesc = "northeast wall"
   adjective = 'ne' 'northeast'
   noun = 'wall'
   travelDir(actor) = {return actor.location.ne;}
;
nwObj: CompassDirection
   location = compass
   sdesc = "northwest wall"
   adjective = 'nw' 'northwest'
   noun = 'wall'
   travelDir(actor) = {return actor.location.nw;}
;
seObj: CompassDirection
   location = compass
   sdesc = "southeast wall"
   adjective = 'se' 'southeast'
   noun = 'wall'
   travelDir(actor) = {return actor.location.se;}
;
swObj: CompassDirection
   location = compass
   sdesc = "southwest wall"
   adjective = 'sw' 'southwest'
   noun = 'wall'
   travelDir(actor) = {return actor.location.sw;}
;
uObj: CompassDirection
   location = compass
   sdesc = "ceiling"
   noun = 'u' 'up' 'ceiling'
   travelDir(actor) = {return actor.location.up;}
;
dObj: CompassDirection
   location = compass
   sdesc = "floor"
   noun = 'd' 'down'
   travelDir(actor) = {return actor.location.down;}
;

#endif /* WITHOUT_DIRECTIONS */

outObj: SpecialCompassDirection
   location = compass
   sdesc = "outside"
   noun = 'out' 'outside'
   travelDir(actor) = {return actor.location.out;}
;
inObj: SpecialCompassDirection
   location = compass
   sdesc = "inside"
   noun = 'in' 'inside'
   travelDir(actor) = {return actor.location.in;}
;

/*----------------------------------------------------------------------
*  CHECK REACH MODIFICATIONS
*
*  These modifications always add the compass contents to scope.
*--------------------------------------------------------------------*/
replace checkReach: function(loc, actor, v, obj)
{
   if (obj == numObj || obj == strObj || obj.isIn(compass))
       return;
   if (!(actor.isCarrying(obj) || obj.isIn(actor.location)))
   {
       if (find(loc.reachable, obj) != nil)
            return;
       "%You% can't reach "; obj.thedesc; " from "; loc.thedesc; ". ";
       exit;
   }
}


/*----------------------------------------------------------------------
*  DEEP VERB MODIFICATIONS
*
*  These modifications always add the compass contents to scope.
*--------------------------------------------------------------------*/

modify deepverb                // A deep-structure verb.
   validDo(actor, obj, seqno) =
   {
       if (obj.isIn(compass)) return true;
       return obj.isReachable(actor);
   }
   validDoList(actor, prep, iobj) =
   {
       local ret;
       local loc;

       loc = actor.location;
       while (loc.location)
           loc = loc.location;
       ret = visibleList(actor, actor) + visibleList(loc, actor)
              + global.floatingList + compass.contents;;
       return ret;
   }
   validIo(actor, obj, seqno) =
   {
       if (obj.isIn(compass)) return true;
       return obj.isReachable(actor);
   }
;
modify inspectVerb
   validDo(actor, obj, seqno) =
   {
       if (obj.isIn(compass)) return true;
       return obj.isVisible(actor);
   }
;

/*----------------------------------------------------------------------
*  TRAVEL VERB MODIFICATIONS
*
*  (a) goVerb defines doAction = 'Go' for verb templates verDoGo() and
*      doGo() defined by the compass direction objects.
*  (b) Replace travelVerbs so that they redirect travel to the goVerb.
*--------------------------------------------------------------------*/

goVerb: travelVerb
   verb = 'go'
   doAction = 'Go'
   /*
    *  Allowing multiple objects can cause erroneous sdescs
    *  (e.g. nObj.sdesc) to get printed.
    */
   rejectMultiDobj(prep) = {
       "You can't use multiple objects with this verb.";
       return true;
   }
   /*
    *  Beside returning the compass contents as default objects this
    *  method sets the important global.parseErrDirections flag used
    *  by parseErrorParam().
    */
   doDefault(actor, prep, io) = {
       global.parseErrDirections = true;
       return compass.contents;
   }
   sdesc = "go"
;

replace eVerb: travelVerb
   verb = 'e' 'east'
   sdesc = "go east"
   action(actor) = {parserReplaceCommand('go east');}
;
replace sVerb: travelVerb
   verb = 's' 'south'
   sdesc = "go south"
   action(actor) = {parserReplaceCommand('go south');}
;
replace nVerb: travelVerb
   verb = 'n' 'north'
   sdesc = "go north"
   action(actor) = {parserReplaceCommand('go north');}
;
replace wVerb: travelVerb
   verb = 'w' 'west'
   sdesc = "go west"
   action(actor) = {parserReplaceCommand('go west');}
;
replace neVerb: travelVerb
   verb = 'ne' 'northeast'
   sdesc = "go northeast"
   action(actor) = {parserReplaceCommand('go ne');}
;
replace nwVerb: travelVerb
   verb = 'nw' 'northwest'
   sdesc = "go northwest"
   action(actor) = {parserReplaceCommand('go nw');}
;
replace seVerb: travelVerb
   verb = 'se' 'southeast'
   sdesc = "go southeast"
   action(actor) = {parserReplaceCommand('go se');}
;
replace swVerb: travelVerb
   verb = 'sw' 'southwest'
   sdesc = "go southwest"
   action(actor) = {parserReplaceCommand('go sw');}
;
replace inVerb: travelVerb
   verb = 'in' 'enter' 'go to' 'go into'
   sdesc = "enter"
   doAction = 'Enter'
   ioAction(onPrep) = 'EnterOn'
   ioAction(inPrep) = 'EnterIn'
   ioAction(withPrep) = 'EnterWith'
   action(actor) = {parserReplaceCommand('go in');}
;
replace outVerb: travelVerb
   sdesc = "go out"
   action(actor) = { actor.travelTo(self.travelDir(actor)); }
   verb = 'out' 'go out' 'exit' 'leave'
   travelDir(actor) = { return actor.location.out; }
;
replace dVerb: travelVerb
   verb = 'd' 'down'
   sdesc = "go down"
   action(actor) = {parserReplaceCommand('go down');}
;
replace uVerb: travelVerb
   verb = 'u' 'up'
   sdesc = "go up"
   action(actor) = {parserReplaceCommand('go up');}
;

/*----------------------------------------------------------------------
*  ERROR MESSAGE HANDLING FOR <<GO>>
*--------------------------------------------------------------------*/

parseErrorParam: function(errnum, str, ...) {
   if (errnum == 140 && global.parseErrDirections) {
       global.parseErrDirections = nil;
       return 'Where do you want to ';
   }
   else return nil;
}

#pragma C-

#endif /* __COMPASS_MODULE_ */