[Main]
[Previous]   [Next]

Other Responses to Actions

So far we have concentrated on how you can customise the responses to actions on objects directly involved in those actions as direct or indirect object, and that will probably be the most common type of action customisation you'll perform. But there are other types of response we should look at for the sake of completeness. (NOTE: This discussion assumes that gameMain.beforeRunsBeforeCheck is nil, otherwise stopping an action in check() will not prevent beforeAction() and roomBeforeAction() from being called on other objects, although everything else will be the same).


If you want an object not directly involved in a command to respond to it, you can use beforeAction() or afterAction(). As their names suggest, the first of these responds to the action just before it's performed (i.e. just before the appropriate action routine is invoked) while afterAction() is called just after an action is performed. These two routines are called on every object that's in the actor's scope when the action is performed, but only if the command reaches the action stage (i.e. it hasn't already been ruled out by verify(), check(), or preCond). Thus, if you want another object to respond to an action that fails, you must make it fail in action(), rather than before, e.g.
 
wickedWitch: Person 'wicked ugly witch' 'wicked witch'
  "Boy is she ugly! "
  isHer = true
  dobjFor(Kiss)
  {
     verify() { }
     action()
     {
         reportFailure('You move your lips towards hers, but your
           nerve fails you at the last moment. ');
     }
  }
;
 
bob: Person ' fine young man /bob'  'Bob'
   "He looks a fine young man. "
   isHim = true
   isProperName = true
   beforeAction()
   {
       if(gActionIs(Kiss) && gDobj == wickedWitch)
       {
           "<q>Hey, what do you  think you\'re doing!</q> cries Bob,
            grabbing you by the arm and pulling you back, <q>Don\'t you
  ;          know that kissing her will turn you into a lump of vile green
           blancmange?</q> ";      
           exit;
       }
   }
;
 
If the PC tries to kiss the wicked witch while Bob is present we'll get:
 
>kiss witch
"Hey, what do you think you're doing!" cries Bob, grabbing you by the arm and pulling you back, "Don't you know that kissing her will turn you into a lump of vile green blancmange?"
 
Whereas if the PC tries to kiss her when Bob is elsewhere we'll get:
 
>kiss witch
You move your lips towards hers, but your nerve fails you at the last moment.
 
Note the use of the exit macro in Bob's beforeAction() routine to veto the action before it takes place. We could alternatively have given Bob an afterAction() routine to give his reaction after the event:
 
  afterAction()
   {
       if(gActionIs(Kiss) && gDobj == wickedWitch)
       {
           "<q>Wise decision</q> Bob approves, <q>I suppose you realize
            that if you had gone ahead and kissed her you\'d have been
            turned into a lump of vile green blancmange!</q> ";      
       }
   }
 
You can also allow the actor's location (Room or NestedRoom) to respond to actions in a similar way, but in that case you need to use roomBeforeAction() or roomAfterAction, e.g.:
 
topOfTree : OutdoorRoom 'At the top of the tree'
   "You cling precariously to the trunk, next to a firm, narrow branch."
    down = clearing     
    enteringRoom(traveler) 
    {       
      if(!traveler.hasSeen(self) && traveler == gPlayerChar)   
          addToScore(1, 'reaching the top of the tree. ');              
    }
   &n bsp;roomBeforeAction()
    {
      if(gActionIs(Jump))
         failCheck('Not here -- you might fall to the ground and
            hurt yourself. ');  
    }
    roomAfterAction()
    {
       if(gActionIs(Yell))
         "Your shout is lost on the breeze. ";          
    }
;
 
Finally, you can also use the actorAction() method on the actor performing the action to interfere with or otherwise repond to an action the actor is about to perform. For example, suppose at some point in your game your player character is tied up, and while he's tied up he can't perform any actions other that system actions (like quit, save and undo) and look, inventory or examine; you might achieve this by adding an isTiedUp property to your Player Character object (normally me), and then adding the following actorAction() routine:

actorAction()
{
    if(isTiedUp && !gAction.ofKind(SystemAction)
        && !gActionIn(Look, Inventory, Examine)
     {
           "You can't do that while you're tied up. ";
            exit;
     } 
}

Finally, note that we've introduced a few more of those things beginning with g in the last page or so. Remember that gAction means the current action; gActionIs(Whatever) tests whether gAction is Whatever and returns true or nil accordingly; gActionIn(Foo, Bar, Whatsit) tests whether gAction is either Foo or Bar or Whatsit and returns true if it is or nil otherwise. The other one, gMessageParams(obj), is a bit different; it's used to allow obj to be used in message parameter strings (like '{the obj/him}') where obj is the name of an existing local variable. This allows us to write:

cannotPutComponentMsg(obj)
{
    gMessageParams(obj);
    return 'You can\'t do that, because it\'s part of {the obj/him}. ';
}

Instead of:

cannotPutComponentMsg(obj)
{
    return 'You can\'t do that, 
because it\'s part of ' 
       + obj.theName + '. ';
}

Getting Started in TADS 3
[Main]
[Previous]   [Next]