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