Inform.t

Version 3.3

 

This file is part of the Inform.t Author’s Manual

Copyright © 1999 by Kevin Forchione. All rights reserved.

 

 

Message System

 

 

 

The Inform.t Message System

 

With inform.t release 3.3, the Message System has undergone major revisions, making it easier to understand and use. Some of the more significant changes include:

 

·         The scheduling maintenance methods from message class have been moved to the messagepump.

·         The message class has been replaced with an eventObj class, which is dynamically created when needed, and re-usable.

·         The eventList has been replaced with attributes used to store command variables, and providing the validate() and process() methods with this information in the standard ADV.T format.

·         The Message System now makes it possible for authors writing their own parser to use the system for all event handling: messages, daemons, fuses, and notifys.

·         Command-related messaging is now a reality. The inform_event.t file demonstrates simple ADV.T modifications that allow an author to tailor messages in any fashion they like.

 

 

As with its predecessor, the message system enables an author to generate an event which will process immediately from a method or function, or to place the event into one of three different processing queues based on the stage attribute set on the event object.

 

Three Process Queues

 

The first processing queue is invoked at the very beginning of the POSTACTION stage, the second occurs at the very beginning of the ENDCOMMAND stage, and the final queue occurs at the very end of the ENDCOMMAND stage. At each of these stages the messagepump is called using the invokeMessagepump() function. This function passes the queueStage to the messagepump.processQueue() method.

 

The Messaging System consists of three basic elements: event generation functions, the eventObj class, and the messagepump object.

 


event generation functions

 

From any point in the EXECUTION phase, before the final call to invokeMessagepump() in endCommand() a function or method can call one of the two inform.t event generation functions: commandEvent() and alertEvent(). Both of these take the same arguments:

 

     commandEvent( obj, &process, ... );

     alertEvent( obj, &process, ... );

 

The parameters should be entered in the following order, and have the following meaning:

 

obj                   This is the object whose process() method should execute when the event is processed by messagepump.

 

&process          A method pointer to the method to be processed

 

&validate          A method pointer to the method used for validation

 

stage                The queue stage at which the event is to process

 

nil:       process immediately, or in at the first queue stage in which this event passes validate

1:         process at the beginning of postAction()

2:         process at the beginning of endCommand

3:         process at the end of endCommand

 

retain               This indicates whether the event is to be retained on the messagepump schedule after it has been processed.  This is for the simulation of daemon / fuse behaviour.

 

true:     retain this event on the schedule after it has processed.

nil:        remove this event from the schedule after it has processed.

 

frequency:        Determines the frequency which the event will process and, in combination with retain, can be used to simulate daemon / fuse / notify behaviour. In general this behaves like a count-down based on turns, but is dependent upon the stage at which the event is set.

 

commArg:        Determines the number and types of arguments passed to &validate and &process.

 

true:     send the following values to &validate and &process: actor, verb, dobjList, prep, iobj, eventCnt, pendingReason.

nil:       send the following values to &validate an d&process: eventCnt and pendingReason.

 

actor                The actor object to be passed to &validate and &process when commArg is true.

 

verb:                The verb object to be passed to &validate and &process when commArg is true.

 

dobj:                The direct object to be passed to &validate and &process when commArg is true.

 

prep:                The prep object to be passed to &validate and &process when commArg is true.

 

iobj:                 The iobj object to be passed to &validate and &process when commArg is true.   

 

Only the obj and &process arguments are required by commandEvent() and alertEvent(). The other arguments default to the following values:

 

commandEvent( obj, &process, nil, 2, nil, 0, true, parserGetObj(PO_ACTOR), parserGetObj(PO_VERB), parserGetObj(PO_DOBJ), parserGetObj(PO_PREP), parserGetObj(PO_IOBJ))

 

&validate:         nil. No validate method.

 

stage:               2. Process at the beginning of endCommand.

 

retain:              nil. Remove from the schedule, once it processes.

 

frequency:        0. Each time the messagepump.processQueue is called.

 

commArg:        true. Pass actor, verb, dobjList, prep, iobj, eventCnt, and pendingReason to &validate and &process

 

actor:               parserGetObj(PO_ACTOR)

 

verb:                parserGetObj(PO_VERB)

 

dobj                 parserGetObj(PO_DOBJ)

 

prep:                parserGetObj(PO_PREP)

 

iobj:                 parserGetObj(PO_IOBJ)

 

alertEvent( obj, &process, nil, 2, nil, 0, true, parserGetObj(PO_ACTOR), parserGetObj(PO_VERB), parserGetObj(PO_DOBJ), parserGetObj(PO_PREP), parserGetObj(PO_IOBJ))

 

&validate:         nil. No validate method.

 

stage:                           nil. Process immediately, or at the first queue stage that this event passes validate.

 

retain:              nil. Remove from the schedule, once it processes.

 

frequency:        0. Each time the messagepump.processQueue is called.

 

commArg:        nil. Pass only eventCnt, and pendingReason to &validate and &process

 

actor:               nil.

 

verb:                nil.

 

dobj                 nil.

 

prep:                nil.

 

iobj:                 nil.

 

 

Although these parameters may seem complicated, they give the author great flexibility and control over the message system. Much of the time, however, only the object, &process, and &validate need to be supplied, letting the function defaults handle the rest.

 

Suppose you want the following display in your game:

 

>Take the coins

Three coins taken.

 

>Take the apple and the grapes

An apple and four grapes taken.

 

You would first replace the code in the doTake() method of thing to generate an event to queue the display your “Taken.” Message at a stage when all the direct objects have processed.

 

Modify thing

    doTake(actor) =

    {

        local totbulk, totweight;

 

        totbulk = addbulk(actor.contents) + self.bulk;

        totweight = addweight(actor.contents);

        if (! actor.isCarrying(self))

totweight = totweight + self.weight + addweight(self.contents);

 

        if (totweight > actor.maxweight)

            "%Your% load is too heavy. ";

        else if (totbulk > actor.maxbulk)

        {

            if ( self.moveToSackItem( actor ) )

            {

                  self.moveInto( actor );

                  commandEvent(takeVerb, &mpDoTake);

            }

            else

                  "%You've% already got %your% hands full. ";

        }

        else

        {

            self.moveInto(actor);

            commandEvent(takeVerb, &mpDoTake); // “Taken.” Replaced.

        }

    }

;

 

Notice that we have only replaced the “Taken.” Message from the very last line of the method with the following command:

 

      commandEvent(takeVerb, &mpDoTake);

 

This function is called each time we doTak(). In the case of our coins it is called three times. The first time it is called an event is scheduled on the messagepump. Each subsequent doTake() updates this scheduled event, specifically it adds the doTake() object to the event’s dobjListPtr and increments its eventCnt.

 

At the beginning of endCommand() the messagepump is called using  invokeMessagepump( 2  ). Our scheduled event is passed to the messagepump.checkQueue() method, which checks to see if the event has a validate method. Since our event doesn’t have a validate method it calls takeVerb.mpDoTake(actor, verb, dobjList, prep, iobj, eventCnt, pendingReason).

 

modify takeVerb

    mpDoTake( actor, verb, dobjList, prep, iobj, eCnt, pReason ) =

    {

        "\n";

        if (actor != parserGetMe())

        {

            "<<actor.thedesc>> takes ";

            if (length(dobjList) == 1)

            {

                local dobj = car(dobjList);

                dobj.thedesc;

            }

            else

                listcont(dobjList);

            ". ";

        }

        else

        {

            caps();

            if (length(dobjList) > 1)

            {

                listcont(dobjList); " ";

            }

            "taken. ";

        }

    }

;

 

Our accumulated dobjList (from each generate of our event) is then passed to listcont() and the “taken.” appended to its result.*

 

&validate

 

This is an author-defined method that allows constraints to be put on the conditions under which the message is to process. This method should return nil if the message is to process; otherwise it should return a non-nil value if the message should remain in the messagepump schedule.

 

Some basic return codes have been defined in Inform.t:

 

            MP_PURGE:               Message should be purged from the schedule

            MP_WAITING              Message fails due to player waiting

            MP_LOCATION          Message fails due to player location

 

The system is flexible enough to accommodate author-defined return codes (any non-nil return value will fail &validate).

 

The non-nil return value will be kept in eventObj.pendingReason and can be used to tailor the processEvent. For instance, if the player’s waiting invalidates the processing of the message then returning a value, such as MP_WAITING can be used by &process.

 

&process

 

This is an author-defined method that handles the processing of the event. The method can make use of information provided by actor, verb, dobjList, prep, iobj, eventCnt, and pendingReason to make refinements to its processing.

 

Note that this method need not produce any display. It can instead be used to perform scheduled state-changes or generate new events.


eventObj class objects

 

eventObj class

==========

isscheduled

objPtr

processPtr

validatePtr

stage

retain

frequency

frequencyCnt

commArg

actorPtr

verbPtr

dobjListPtr

prepPtr

iobjPtr

eventCnt

pendingReason

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


This class of object is created dynamically as needed, and then re-initialised for reuse during the game. It consists of a collection of attributes that carry the essential information of the event, specifically:

 

isscheduled:                Indicates whether the eventObj is currently on the messagepump schedule.

 

objPtr:                          The object whose methods the &validate and &process

 

processPtr:                   Holds the method pointer of the object method which is called when the event processes.

 

validatePtr:                   Holds the method pointer of the object method which is called when the event is validated.

 

This method should return nil, if the event passes validation; otherwise it should return a non-nil value. An author may add values of his own. Some of the standard values are:

 

MP_PURGE:   Message should be purged from the schedule

MP_WAITING: Message fails due to player waiting

MP_LOCATION: Message fails due to player location

 

 

stage:                           Holds the value of the stage at which this event is to process (see stage above).

 

retain:                          Indicates whether this event is to be kept on the messagepump schedule after processing.

 

frequency:                    Indicates the frequency of validation / processing for this event.

 

frequencyCnt:               A counter used as a count-down to processing.

 

commArg:                    Indicates the number and types of arguments to be passed to &validate and &process (see above)

 

actorPtr:                       The actor object for this event

 

verbPtr:                        The verb object for this event

 

dobjListPtr:                  A list of direct objects for this event

 

prepPtr:                        The prep object for this event

 

iobjPtr:                         The indirect object for this event.

 

eventCnt:                      A count of how many generateEvent() requests were made for this event up to the point it processed.

 

pendingReason:                       The non-nil return value from the &validate method.

 


message pump object

 

messagepump

==========

schedule

----------------

generateEvent

scheduleEvent

getEvent

processQueue

checkQueue

checkFrequency

deletePending

unscheduleEvent

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


This object maintains a schedule of events (messages to be processed). It is called each time invokeMessagepump() is invoked, looping through its scheduled list of events and processing each event for that stage whose frequencyCnt has reached 0 and that has passed its validate method.

 

 

generateEvent( o, p, v, s, r, f, c, actor, verb, dobj, prep, iobj )

 

This method calls both scheduleEvent and checkQueue. The event is first scheduled on the messagepump, then checked to see if it passes validate; otherwise, depending upon its attributes, it may be queued or purged.

 

scheduleEvent( o, p, v, s, r, f, c, actor, verb, dobj, prep, iobj)

 

This method is used to schedule an event on the messagepump schedule, increment the messageCnt, add any passed direct object to the dobjList.

 

Authors should use the commandEvent() or alertEvent() methods, which issue generateEvent() rather than scheduleEvent() as the generateEvent() method also checks the queue status of the event.

 

getEvent( o, p, v, s, r, f )

 

This method searches the schedule for an event matching the object, &process, &validate, stage, retain, and frequency parameters passed. If there is a match the schedule event is returned; otherwise the method returns nil.

 

processQueue( queueStage )

 

This method is called from the invokeMessagepump function at the beginning of the POSTACTION and ENDCOMMAND stages, as well as at the end of the ENDCOMMAND stage.

 

It calls checkQueue( queueStage ) for each object listed in schedule, processing them in the order that they were added to the schedule.

 

checkQueue( event, queueStage )

 

This method handles validation, processing, and cleanup of a scheduled event. It is called initially from generateEvent to determine if the event should process immediately (eventObj.stage = nil). Subsequent calls to this method are made each time the messagepump is invoked.

 

checkFrequency( event )

 

Called from checkQueue() before validation. If the event frequencyCnt is not 0 then the event is not yet ready to process. This method decrements the count in that case and returns MP_FUSE; otherwise this method returns nil. If the eventObj.retain = true then this method resets the eventObj.frequencyCnt = eventObj.frequency when the frequencyCnt reaches 0.

 

deletePending( o, p, v, s, r, f )

 

This method should be used for explicit removal of events from the schedule by author code. This method uses the getEvent() to identify a method on the schedule from its unique attributes.

 

UnscheduleEvent( event )

 

This method is called by checkQueue(). It performs the removal of the event from messagepump.schedule and sets the eventObj.isscheduled to nil.
Overview of the Message System

 

The following shows diagrammatically the message pump process. As the EXECUTION Phase runs its course object methods and functions generate events by calling the commandEvent() and alertEvent() functions.

 

These events are scheduled by the messagepump and then checkQueue() determines whether the event is to be processed immediately, or kept in the schedule queue.

 

At the beginning of postAction() the invokeMessagepump() is executed for queue stage 1. These are potentially all the messages queued during the ACTION stage of execution, but may contain messages with stage nil that are now valid to process.

 

At the beginning of endCommand() the invokeMessagepump() is executed for queue stage 2. These are potentially all the messages queued during the ACTION, POSTACTION and DAEMON/FUSES stages of execution, but may contain messages with stage nil that are now valid to process.

 

At the end o endCommand() the invokeMessagepump() is executed for queue stage 3.  These are potentially all the messages queued during ACTION, POSTACTION, DAEMON/FUSES, and ENDCOMMAND stages of execution, but may contain messages with stage nil that are now valid to process.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 



* You may be wondering what happened to the object.sdesc; “:”; messages that print automatically through the parser. They were suppressed by inform.t between the call of object.multisdesc and verb.verbAction().