ContAction

 

 

User’s Guide

 

Version 2.5

 

 

ContAction is a collection of interrelated modules that provide a mechanism for continuous actions, actions that consist of a series of actions that are continuously requeued until they have either satisfied a condition or are externally terminated.

 

Thanks to Michael J. Roberts for his many suggestions.

 

Copyright © 2001-2004 by Kevin Forchione. All rights reserved.


Contents

 

Getting Started.. 3

ContAction Overview... 4

The ContAction Mix-in Class.. 5

ContIAction, ContTAction, and ContTIAction Classes.. 8

ContActorState Class.. 9

Global Pending Command Info and the Modification to PendingCommandInfo Classes   10

Modifications to ContAction and ContIAction Classes.. 11

Modifications to Actor Class.. 12

Querying to Continue a Continuous Action.. 13

Continuous Action Events.. 14

ContActEventMixIn.. 14

ContActFuse. 14

SenseContActFuse. 14

ContActDaemon.. 15

SenseContActDaemon.. 15

 

 


Getting Started

Nothing could be easier. Simply add the files

 

 

to your project source files after those for the TADS 3 system and library files.

 

#include the following header file to your game source files:

 

 

Next we simply define continuous verbs. Three verb classes are supported:

 

ContIAction – a Continuous Intransitive Action

ContTAction – a Continuous Transitive Action

ContTIAction – a Continuous Transitive-with-indirect Action.

 

Macros are provided in contaction.h for defining continuous actions similarly to those in adv3.h.

 

Suppose we want to define a continuous intransitive action that will display “Foo!” five times.

 

#include "contaction.h"

 

DefineContIAction(Foo)

    execAction()

    {

        "Foo! ";

    }

 

    checkActionCompleted()

    {

        if (execActionCnt_ > 4)

            return true;

        else

            return nil;

    }

;

 

VerbRule(Foo)

    'foo'

    : FooAction

    verbPhrase = 'foo/fooing'

;

 

That’s all there is to it! Notice that the VerbRule is defined exactly as we would for any IAction. The action definition is also very similar to that of an ordinary IAction, except that in addition to providing the required execAction() method (which simply displays “Foo!”) we are  also required to define a checkActionCompleted() method that tells the action when it is to be considered completed.

ContAction Overview

The example above is trivial. Why not simply code a loop to display “Foo!” five times in the execAction of an IAction?

 

Continuous actions are actions that are requeued at the end of the afterAction phase of their execution. What happens is this: when an action is first parsed it is converted into a pending command info object (PendingCommandInfo) and stored in the appropriate actor’s pending command queue (pendingCommand). The command execution cycle then determines which actor is next on the schedule and processes its first pending command.

 

With normal commands the command is then removed from the pending command queue after execution and that’s the end of the story, at least as far as that command is concerned. But with a continuous command a new pending command info object will be inserted into the actor’s pending command queue after the action has executed. Since the pending command is placed at the head of the queue it will be the next that the actor executes. This process doesn’t stop until the action’s checkActionCompleted() method returns true.

 

So, while “Foo!” displays five times in our example above, it is actually occurring over five execution cycles. You can see that this is indeed the case if you examine the turn counter displayed in the game status line.

 

The effect is most noticeable for commands that are given to NPCs that have been set to issue commands synchronously. In this case the actor will proceed to execute the command over an extended series of interchanges.

 

The practical upsweep of this is that it enables things like time-oriented game play to be easily implemented. But continuous actions may have other applications, such as a command given to an actor to eat a loaf of bread that extends over a series of turns.

 


The ContAction Mix-in Class

The ContAction class is a mix-in class that handles the lifecycle of a continuous action. The class is combined with IAction, TAction, and TIAction classes to provide continuous action counterparts of these TADS actions.

 

The ContAction class defines the following methods:

 

afterActionMain() – This method first performs any inherited operations, then checks if the action has completed. If the action has completed it performs our action execution completed method; otherwise the action is requeued in the actor’s pending command queue.

 

afterContActionMain() – This method calls execActionCompleted(), then sets the current actor state to the nextState stored in the current actorState. If no nextState is available then the actorState persists.

 

beforeActionMain() – This method first performs any inherited operations, then gets the previously executed action (if this isn’t the first time the action has been performed), synchronizes the current action’s state with that of the previously executed action, issues a call to the initialization method, performs any action completion checking requested, and updates the action execution counter.

 

beforeContActionMain() – This method sets the current actor state to the actionState specified by this action, then calls execActionInitial().

 

checkActionCompleted() – This method controls whether the continuous action is to be requeued or not. It must return either true, the action has completed and will not be requeued; or nil, the action has not completed and will be requeued. By default this method will return true, meaning the action will not be requeued.

 

doAction(issuingActor, targetActor, targetActorPhrase,

             countsAsIssuerTurn) – This method synchronizes the a current continuous action with the previous continuous action of a given series and initializes the current action.

 

execAction() – This method must be defined by concrete subclasses of ContAction. For ContIAction, the author must define this just as he would for any IAction. ContTAction and ContTIAction define this method.

 

execActionCompleted() – This method is called when checkActionCompleted() returns true, either during beforeActionMain() or afterActionMain() depending on the checkBeforeExec_ property. This method should do any work required by an author when an action has completed.

 

execActionInitial() – This method is called when our action execution counter (execActionCnt_) is zero, indicating that this is the first time this action is being executed. This method should do any initial work required by the action.

 

execActionInterrupted() – This method is called when gActor.issueContActionInterrupt() is issued successfully. This method should do any work required by the author when an action has been terminated before completion.

 

incrQueryActionCnt() – handles the incrementing of counters for queries for interruption of an actor’s continuous action for both the current action and the continuous action series.

 

incrQueryActionCurrCnt() – handles the incrementing of the counter for queries for interruption of an actor’s continuous action for the current action.

 

incrQueryActionSeriesCnt() – handles the incrementing of the counter for queries for interruption of an actor’s continuous action for the continuous action series.

 

incrQueryActionSeriesCnt() – increments the queryActionSeriesCnt.

 

incrQueryActionCurrCnt() – increments the queryActionCurrCnt.

 

initializeActionProps() – initializes the current continuous action.

 

interruptedContActionMain() – this method handles the termination of the continuous action series.

 

isEquivContAction(action) – Returns true if this action is equivalent to action. To be equivalent the two actions must be part of the same series of continuous actions. A series of continuous actions consists of an initial action followed by subsequent actions generated from the same command tokens or action as the initial one, until the series is completed or terminated.

 

removeActorPendingCommand() - Method will remove any requeued pending continuous command that is identical to the one being executed if the current command hasn't been requeued (i.e. it's a newly issued player command). This will prevent, if necessary, any nesting of pending continuous commands due to the same command being reissued by the player.

 

requeuePendingAction() – This method is called when the continuous action has been defined as pendingCommandRequeue == nil. When this variable is set to nil it indicates that we wish to requeue the player command action, and the objects that resulted from parsing. This method will requeue a clone of the command’s action, and the objects required by the specific type of action. (Concrete subclasses of ContAction must define this method). The method will then update the resulting pending command info object with information specific to the continuous action.

 

requeuePendingCommand() – This method is called when the continuous action has been defined as pendingCommandRequeue == true. When this variable is set to true it indicates that we wish to requeue the player command tokens, not the action and objects that resulted from parsing those tokens. This method will requeue the command’s original token list and update the resulting pending command info object with information specific to the continuous action.

 

setActionCompleted(val) – Sets the action’s isActionCompleted property to val.

 

setCurrActorState(actor, newState, nextState) – This method sets the current state of actor to an instance of newState, with the actor’s next state indicated by nextState.

 

setActorNextRunTime(actor) – allows the action to handle the actor’s next run time when the action has been terminated.

 

setNextActorState(actor) – This method sets the actor’s current state to the nextState indicated by its curState object. If no nextState is available then the actor’s current state is unchanged.

 

synchronizeActionProps(obj1, obj2) – synchronizes obj1’s state for the properties listed in updActPropList with those of obj2.

 

updateActionState(action) – Keeping track of certain data may be desirable from one execution of a continuous action to another. This method loops over the property pointers supplied in updActPropList and sets the currently executing action’s properties to those of the previously executed continuous action. This allows the current action to “know” what the previous one knew.

 

updatePendingCommandInfo() – This method will updated the newly queued pending command info object, indicating that it is a requeued action, and storing a pointer to the last continuous action processed.

 


ContIAction, ContTAction, and ContTIAction Classes

The library extension defines ContIAction, ContTAction and ContTIAction counterparts to the normal IAction, TAction and TIAction classes. These classes allow an author to define a continuous actions using macros similar to those found in the adv3.h header file.

 

 

These classes define:

 


ContActorState Class

The ContActorState class is a HermitActorState that is used by continuous actions to assign a continuous actor state throughout the execution of a continuous action. It can be used, for example, to provide an actor with a WaitingActorState during WaitTimeActions in TimeSys.

 

The class defines the following properties:

 

construct(actor, next) – This method passes the actor and nextState information to the construction of the new state.

 

execActionInitial(action) – by default we do nothing.

 

execAction(action) – by default we do nothing.

 

execActionCompleted(action) – by default we do nothing.

 

execActionInterrupted(issuingActor, action) – by default we do nothing.

 

checkActionCompleted(action) – by default we return true.

 

 

 

 

 

 

 

 

 

 

 

 


Global Pending Command Info and the Modification to PendingCommandInfo Classes

The pending command info class serves to store command tokens or actions that are to be queued on the actor’s pending command queue for command execution. The continuous action mechanism sets the following properties on a pending command info object once a continuous action has been requeued.

 

 

The PendingCommandToks and PendingCommandAction classes modify the following method:

 

executePending() – This method stores the pending command info object as a global variable gPendingCommaindInfo, valid during the duration of its execution.

 


Modifications to ContAction and ContIAction Classes

The cont_actor.t module modifies the ContAction class to redirect the following methods to the gActor:

 

 

The ContIAction class redirects the following methods to the gActor:

 

 

 



 

 


Modifications to Actor Class

While ContTAction and ContTIAction handle actions through the usual dobjFor() and iobjFor() methods, it would seem desirable to redirect the extra continuous methods to the actor as well.

 

In addition, the following properties have been added or modified on the Actor class:

 

allowsContActionInterrupt(issuingActor, action,) – Returns true if the actor allows the action to be interrupted; otherwise returns nil. If the actor is the player character then issues a query asking the player whether they wish to stop the continuous action.

 

contActionExpiredFor(actionClass) – This method returns true if the actor’s most recent action is an expired continuous action of class actionClass; otherwise it returns nil.

 

contActionPendingFor(actionClass) – This method returns true if the first pending command info object in the actor’s pending command queue is of class actionClass; otherwise it returns nil.

 

getExpContActionFor(actionClass) – Returns the expired action for this actor for this action class. If the most recent action isn’t ofKind() actionClass or is not completed then the method returns nil.

 

getPendContActionFor(actionClass) – Builds a list of actions for this actor for this action class. The list consists of the most recent action, first pending action, and query action.

 

issueCommandsSynchronously – By default we set this to nil, meaning that actors will perform a series of player command line orders over a series of turns, rather than all at once. It may seem confusing, but this setting works best for continuous actions.

 

issueContActionInterrupt(issuingActor, actionClass, queryActor) – This method handles all the details of issuing an interrupt of a continuous action for this actor. The actionClass should be a continuous action subclass. A queryActor value of true will issue a query to the actor’s allowsContActionInterrupt() method, while a value of nil will attempt to issue an interrupt without asking the actor whether they will allow one.

 

 


Querying to Continue a Continuous Action

The contActionYesOrNo(action) issues a yes/no query for indicating whether to terminate a continuous action or not. The function takes one argument, the action to be terminated. It returns true if the player wishes to continue with the continuous action; otherwise it returns nil.

 


Continuous Action Events

These classes work essentially the same as the normal TADS 3 library fuses and daemons, with the extra feature of attempting to issue a request for a continuous action interrupt to the player character after the fuse or daemon has fired and sent its message to the target object.

 

ContActEventMixIn

This mix-in facilitates the attempted interrupt of continuous actions for the player character.

 

ContActFuse

This fuse construct argument values are:

 

obj: same as for Fuse

prop: same as for Fuse

turns: same as for Fuse

actor: the actor to be notified for a continuous action interrupt

action: the continuous action to be interrupted

queryActor: indicate whether or not the actor should be queried to see if it will allow the interrupt.

 

SenseContActFuse

This fuse construct argument values are:

 

obj: same as for SenseFuse

prop: same as for SenseFuse

turns: same as for SenseFuse

actor: the actor to be notified for a continuous action interrupt

action: the continuous action to be interrupted

queryActor: indicate whether or not the actor should be queried to see if it will allow the interrupt.

source: same as for SenseFuse

sense: same as for SenseFuse

 


ContActDaemon

This daemon construct argument values are:

 

obj: same as for Daemon

prop: same as for Daemon

interval: same as for Daemon

actor: the actor to be notified for a continuous action interrupt

action: the continuous action to be interrupted

queryActor: indicate whether or not the actor should be queried to see if it will allow the interrupt.

SenseContActDaemon

This daemon construct argument values are:

 

obj: same as for SenseDaemon

prop: same as for SenseDaemon

interval: same as for SenseDaemon

actor: the actor to be notified for a continuous action interrupt

action: the continuous action to be interrupted

queryActor: indicate whether or not the actor should be queried to see if it will allow the interrupt.

source: same as for SenseDaemon

sense: same as for SenseDaemon