////////////////////////////////////////////////////////////////////////
//
//  SimpleSense.t
//      Version 1.0
//
//      Provides a simplified method of sense-passing that is compatible
//      with ADV.T/STD.T. Simply #include this module after ADV.T/STD.T.
//      Next, connect locations using obstacle class objects. These objects
//      should be given a passesSense() method that returns either true or
//      nil indicating whether the obstacle passes sensing to its doordest.
//
//  Copyright (c) 2000 Kevin Forchione. All rights reserved.
//  Based on ADV.T (c) and STD.T (c) Michael Roberts.
//
//  This file is a library extension for ADV.T and
//  STD.T and requires TADS 2.2.6 or later.
//
////////////////////////////////////////////////////////////////////////

#ifndef _SIMPLE_SENSE_T_
#define _SIMPLE_SENSE_T_

#pragma C+

class SimpleSense: object
       /*
        *      canSenseObj( vantage, obj )
        *
        *      Returns true or nil depending upon whether the obj is found in
        *      the scope list.
        */
   canSenseObj( vantage, obj ) = {
       return ( find( self.scope( vantage ), obj ) != nil );
   }
   /*
    *  scope( vantage )
    *
    *  Builds a scope list using the scopeList() method for the
    *  vantage's location and each connected location. It then appends
    *  the floatingList.
    */
   scope( vantage ) = {
       local ret, objList, i, len;

       objList = ret = self.scopeList( vantage );

       len = length( objList );

       for (i = 1; i <= len; i++) {
               if ( isclass( objList[i], obstacle )
               && objList[i].passesSense( self ) )
               {
                       if ( objList[i].doordest ) {
                               local oth = objList[i].otherside;
                               if ( oth == nil )
                                       oth = [];
                               else oth = [ oth ];

                               /*
                                *      Add the scope list produced from the obstacle's
                                *      doordest, removing the obstacle's otherside!
                                */
                               ret += self.scopeList( objList[i].doordest ) - oth;
                       }
               }
       }

       /* Append the global.floatingList to the scope */
       return ret + global.floatingList;
   }
   /*
    *  scopeList( vantage )
    *
    *  This method is a variation of ADV.T's validDoList() and takes
    *  advantage of the ADV.T library's visibleList() function to
    *  recurse down the object tree.
    */
   scopeList( vantage ) = {
       local ret, loc;

       /*
        *      find the top level location (bubble-up) to begin the filter-
        *      down process.
        */
       loc = vantage;
       while ( loc.location )
           loc = loc.location;

       ret = visibleList( vantage, vantage )
               + visibleList( loc, vantage );

       return ret;
   }
;

visibleSense: SimpleSense
;

reachableSense: SimpleSense
   /*
    *  scopeList( vantage )
    *
    *  This method is a variation of ADV.T's validDoList() and takes
    *  advantage of the ADV.T library's reachableList() function to
    *  recurse down the object tree.
    */
   scopeList( vantage ) = {
       local ret, loc;

       /*
        *      find the top level location (bubble-up) to begin the filter-
        *      down process.
        */
       loc = vantage;
       while ( loc.location )
           loc = loc.location;

       ret = reachableList( vantage )
               + reachableList( loc );

       return ret;
   }
;

modify thing
       /*
        *      Replaced to use the visibleSense.canSenseObj()
        *      This method is required by the parser.
        */
       isVisible(vantage) = {
               return visibleSense.canSenseObj( vantage, self );
       }
       /*
        *      Replaced to use the reachableSense.canSenseObj()
        *      This method is not required by the parser, but provided for
        *      completeness.
        */
       isReachable( vantage ) = {
               return reachableSense.canSenseObj( vantage, self );
       }
       /*
        *      Replaced validActor to use reachableSense.canSenseObj() and
        *      allows the player object to communicate to actors in sense-
        *      connected locations.
        */
       sense = reachableSense
       validActor = {
               if ( self.sense.canSenseObj( parserGetMe(), self ) )
                       return true;
               pass validActor;
       }
;

/*
*      Provide obstacle classs with passesSense() method, which is used to
*      determine if this particular obstacle passes sight / touch to its
*      doordest.
*
*      Connections are made simply by placing obstacle class objects in
*      any room and providing them with a passesSense() method that
*      returns either true or nil. This can be conditional upon the
*      state of the obstacle as well as upon the particular SimpleSense
*      class object passed as an argument.
*
*      For example, doors and windows can allow sense-passing when open by
*      giving them a passesSense( sense ) = (self.isopen) attribute.
*/
modify obstacle
       passesSense( sense ) = { return nil; }
;

modify deepverb
       /*
        *      Replaced to use visibleSense.scope(). This method is called by
        *      the parser to provide a list of objects to intersect with the
        *      list produced by the dictionary match in order to limit the size
        *      of reasonable choices for object resolution.
        */
   validDoList(actor, prep, iobj) = {
       local ret = visibleSense.scope( actor );

       /*
        *      If the scope list is an empty list we return nil, telling
        *      the parser to use the dictionary match-list for
        *      disambiguation purposes.
        */
       if ( length( ret ) == 0 )
               return nil;
       else return ret;
   }
   /*
    *  Replaced to use reachableSense.canSenseObj() using reachability.
    *  This method is called by the parser in order to provide a model
    *  world validation hook for the library for the direct object.
    */
   validDo(actor, obj, seqno) = {
       return reachableSense.canSenseObj( actor, obj );
   }
   /*
    *  Replaced to use scope using reachability
    *  This method is called by the parser in order to provide a model
    *  world validation hook for the library for the indirect object.
    */
   validIo(actor, obj, seqno) = {
       return reachableSense.canSenseObj( actor, obj );
   }
;

#pragma C-

#endif /* SIMPLE_SENSE_T_ */