signals.t

documentation
#charset "us-ascii"
#include "advlite.h"

/*--------------------------------------------------------*/
/*
 *   SIGNALS EXTENSION Still at an experimental stage
 *
 *   To use this extension, include the relations extensions before it.
 */

/* 
 *   A Signal is a kind of Relation that can be used to send a signal from a
 *   sender to all the objects related to that sender via this Signal Relation.
 *
 *   For a signal to be sent from a sender to a receiver, a relationship first
 *   needs to be set up between them with a statement like:
 *
 *   connect(sender, signal, receiver);
 *
 *   Where signal is either the programmatic name or the string name of the
 *   signal we want sent.
 *
 *   To break the link subsequently we can use:
 *
 *   unconnect(sender, signal, receiver);
 *
 *   [SIGNALS EXTENSION]
 */
Signal: Relation
    /* Signals can potentially relate many things to many other things. */
    relationType = manyToMany
    
    /* 
     *   Notify every object related to sender by us to handle us as a signal
     *   from sender.
     *
     *   If additional args are supplied, they can take one of two forms. Either
     *   values, which are then assigned in turn to the properties listed in our
     *   propList property, or two-element lists of the form [prop, val] where
     *   prop is a property pointer and val is the value to be assigned to this
     *   property. Note that these two forms cannot be mixed in the same call to
     *   this method, unless all the list form arguments come at the end.
	 *
	 *   [SIGNALS EXTENSION]
     */
    emit(sender, [args])   
    {
        local prop, val;
        
        /* 
         *   Clear out any property values left over from a previous call. We
         *   use null rather than nil as the 'cleared' value, since in some
         *   cases (e.g. in a moveSignal) nil could be a significant value.
         */
        propList.forEach({p: self.(p) = null });
        
        /* Assign additional arguments to properties. */
        for(local arg in args, local i=1;; i++)       
        {           
            /* 
             *   If each arg is a list, then the first item in the list is a
             *   property pointer, and the second is the value to assign to that
             *   property.
             */
            if(dataType(arg) == TypeList)
            {
               prop = arg[1];
               val = arg[2];
            }
            /*  
             *   Otherwise arg is just a value, which is assigned to the
             *   property found in the next element of propList.
             */
            else
            {
                val = arg;
                prop = propList[i];
            }
            self.(prop) = val;
        }
        
        relatedTo(sender).forEach({ obj: obj.dispatchSignal(sender, self) });
    }
    
    /* 
     *   A list of pointers to the properties to which additional arguments to
     *   our emit method should be assigned. [SIGNALS EXTENSION]
     */
    propList = []
    
	/*
	 *   A LookupTable liniking objects that might emit this signal (potential senders) to potential
	 *   receivers of this signal, so that notifications can be sent from the former to the latter.
	 *   Game code should not need to manipulate this table directly; it should instead be updated via
	 *   the supplied connect() and unconnect() functions.
	 *   
	 *   [SIGNALS EXTENSION]
	 */
    dispatchTab = nil
    
    addHandler(sender, receiver, handler)
    {
        if(dispatchTab == nil)
            dispatchTab = new LookupTable();
        
        dispatchTab[[sender, receiver]] = handler;
    }
    
    removeHandler(sender, receiver)
    {
        if(dispatchTab != nil)
        {
            dispatchTab.removeElement([sender, receiver]);
        }
    }
    
;



/* Signals to handle common state changes on Thing  [SIGNALS EXTENSION] */
DefSignal(lit, lit);
DefSignal(unlit, unlit);
DefSignal(discover, discovered);
DefSignal(undiscover, lost);
DefSignal(lock, locked);
DefSignal(unlock, unlocked);
DefSignal(on, turned on);
DefSignal(off, turned off);
DefSignal(worn, worn) wearer = nil propList = [&wearer];
DefSignal(doff, doffed);
DefSignal(move, moved) destination = nil propList= [&destination];
DefSignal(actmove, action moved) destination = nil propList= [&destination];
DefSignal(seen, seen) location = nil propList = [&location];
DefSignal(examine, examine) actor = nil propList = [&actor];
DefSignal(take, take) actor = nil propList = [&actor];
DefSignal(drop, drop) actor = nil propList = [&actor];
DefSignal(open, open);
DefSignal (close, closed);
DefSignal(push, push);
DefSignal(pull, pull);
DefSignal(feel, feel);


 /*
  * MODIFICATIONS TO TadsObject for SIGNALS EXTENSION
  *
  * Add handling for emiting, handling and dispatching signals. 
  */
modify TadsObject
    /* Emit a signal  [SIGNALS EXTENSION] */
    emit(signal, [args])
    {
        /* Simply call the signal's emit method with ourselves as the sender. */
        signal.emit(self, args...);
    }
    
    /* 
     *   Handle a signal from sender; game code will need to override particular
     *   instances. Note that this is a catch-all handler for signals we don't
     *   recognize or for which more specific handlers haven't been defined.
	 *   [SIGNALS EXTENSION]
     */
    handle(sender, signal)
    {
    }   
    
    /*
	 *   Dispatch a signal to the appropriate handler method on this object.
     *   We look up the property pointer to use on the signal's dispatchTab
	 *   LookupTable. If we find one and the property is defined on this object
	 *   then we use that property to handle the signal. Otherwise, we simply
	 *   use our catch-all generic handle(sender, signal) method.
	 *  
	 *   [SIGNALS EXTENSION] 
     */    
    dispatchSignal(sender, signal)
    {
        local prop;       
        
        if(signal.dispatchTab != nil && signal.dispatchTab[[sender, self]] != nil)
            prop = signal.dispatchTab[[sender, self]];
        
        else if(signal.propDefined(&handleProp) 
                && signal.propType(&handleProp) == TypeProp)
            prop = signal.handleProp;
        else
            prop = &handle;
        
        if(propDefined(prop))
            self.(prop)(sender, signal);
        else
            handle(sender, signal);
    }
;  
    
   
    
    
    
 modify Thing  
    /*  
     *   Make various common state changes and actions emit the appropriate
     *   signals. [SIGNALS EXTENSION]
     */
	 
	/*
	 *  emit a litSignal or unlitSignal when this object is lit or unlit.
	 *  [SIGNALS EXTENSION]
	 */
    makeLit(stat)
    {
        inherited(stat);
        emit(stat ? litSignal : unlitSignal);
    }
    
	/*
	 *  emit a discoverSignal or undiscoverSignal when this object is discovered or undiscovered.
	 *  SIGNALS EXTENSION]
	 */
    discover(stat = true)
    {
        inherited(stat);
        emit(stat ? discoverSignal : undiscoverSignal);
    }
    
	/*
	 *  emit a lockSignal or unlockSignal when this object is locked or unlocked.
	 *  [SIGNALS EXTENSION]
	 */
    makeLocked(stat)
    {
        inherited(stat);
        emit(stat ? lockSignal : unlockSignal);       
    }
    
	/*
	 *  emit an onSignal or offSignal when this object is turned on or off
	 *  [SIGNALS EXTENSION]
	 */
    makeOn(stat)
    {
        inherited(stat);
        emit(stat ? onSignal: offSignal);
    }
    
	/*
	 *  emit a wornSignal or doffSignal when this object is worn or doffed (taken off).
	 *  [SIGNALS EXTENSION]
	 */
    makeWorn(stat)
    {
        inherited(stat);
        if(stat)
            emit(wornSignal, stat);
        else
            emit(doffSignal);
    }
    
	/*
	 *  emit a moveSignal when this object is moved.
	 *  [SIGNALS EXTENSION]
	 */
    moveInto(newCont)
    {
        inherited(newCont);
        
        emit(moveSignal, newCont);
    }
    
	/*
	 *  emit a actmoveSignal or unlitSignal when this object moved as part of action handling.
	 *  [SIGNALS EXTENSION]
	 */
    actionMoveInto(newCont)
    {
        inherited(newCont);
        
        emit(actmoveSignal, newCont);
    }
    
    /*
	 *  emit a seenSignal or unlitSignal when this object is seen.
	 *  [SIGNALS EXTENSION]
	 */
    noteSeen()
    {
        inherited();
        
        emit(seenSignal, location);
    }
        
    /*
	 *  emit an openSignal or closeSignal when this object is open or closed.
	 *  [SIGNALS EXTENSION]
	 */
    makeOpen(stat)
    {
        inherited(stat);
        emit(stat ? openSignal : closeSignal);
    }
;
    
 
/*
 *  Function to set up a signalling relation between sender and receiver via the signal Signal. 
 *  This first created a relation between sender and receiver [using the RELATIONS extension)
 *  And then, if the handler parameter is supplied, adds an appropriate entry to the signal's 
 *  dispatchTab table to register that this is the handler to use on the receiver when signal is
 *  sent to receiver from sender.
 *  [SIGNALS EXTENSION]
 */
connect(sender, signal, receiver, handler?)
{
    signal = relationTable.getRelation(signal)[1];
    
    relate(sender, signal, receiver);
    if(handler)
        signal.addHandler(sender, receiver, handler);
}


/*
 * Function to remove the signalling relationship between sender and receiver via the signal
 * Signal. [SIGNALS EXTENSION]
 */
unconnect(sender, signal, receiver)
{
    signal = relationTable.getRelation(signal)[1];
    unrelate(sender, signal, receiver);
    
    if(receiver.propDefined(&removeSenderHandler))
       signal.removeHandler(sender, receiver);
}

modify TAction
    /*
	 * The signal (if any) )o be emitted by the direct object of this action.
	 * [SIGNALS EXTENSION]
     */	
    signal = nil
    
	/*
	 * If this action defines an associated signal, then have the direct object emit the signal
	 * after carrrying out out inherited handling. [SIGNALS EXTENSION]
	 */
    doAction()
    {
        inherited();
        if(signal)
            curDobj.emit(signal);
    }
;

modify Take
   /* [SIGNALS EXTENSION] */  
    signal = takeSignal
;

modify Drop
/* [SIGNALS EXTENSION] */  
    signal = dropSignal
;

modify Examine
/* [SIGNALS EXTENSION] */  
    signal = examineSignal
;

modify Push
/* [SIGNALS EXTENSION] */  
    signal = pushSignal
;

modify Pull
/* [SIGNALS EXTENSION] */  
    signal = pullSignal
;

modify Feel
/* [SIGNALS EXTENSION] */  
    signal = feelSignal
;

Adv3Lite Library Reference Manual
Generated on 25/04/2024 from adv3Lite version 2.0