Inform.t

Version 3.2

 

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

Copyright © 1999 by Kevin Forchione. All rights reserved.

 

 

Object Reactions

 

Inform Reactions

 

Third-party reactions occur when the action between the actor, and possibly direct and indirect objects indirectly effect another object. A good example is the garage opener in Mike Robert's The Plant. Taking the garage opener out of the glovebox when Mr. Teeterwaller is present elicits a response. This kind of interaction goes a long way toward making your game feel realistic and three-dimensional.

 

With the advent of TADS version 2.5 there are many different ways to code third-party reactions. Inform 3.0 simplified the coding of the reactions and moved the after reaction logic to postAction, while moving the eachTurn logic to endCommand.

 

Inform.t version 3.1 has made some further enhancements and changed the naming of the reaction methods to be more "intuitively obvious" and

 

The inform.t Execution Sequence

 

(A)   preCommand()

(B)  verbAction()

(1)   actor.actorPreAction()

(2)    actor.location.roomPreAction()    // location is scopeCeiling

(3)   obj.scopePreAction()    // obj is within actor's scope for the verb

(4)   iobj.ioPreAction()

(5)   dobj.doPreAction()

(C)  actor.actorAction

(D)  actor.location.roomAction()

(E)  iobjCheck - ioAction / dobjCheck - doAction

(F)   postAction()

(1)   obj.scopePostAction()    // obj is within actor's scope for the verb

(2)   actor.location.roomPostAction()    // location is scopeCeiling

(3)   iobj.ioPostAction()

(4)   dobj.doPostAction()

(G)  Run daemons / fuses

(H)  endCommand()

(1)   turncount()                    // turn count advance

(2)   timesys.advance()     // time-clock advance

(3)   actor.location.roomEndCommand()    // location is scopeCeiling

(4)   obj.scopeEndCommand()    // obj is within actor's scope for the verb

(5)    timesys.events        // time-driven events

(6)   scoreStatus()

 

Because inform.t is TADS version of reaction behaviour the above execution sequence parallels that of the inform language to a high degree, while also capitalising on several of the advantages provided by TADS. This execution sequence maximizes object-interactions by providing opportunities for object behaviour both before and after the action methods have executed. Of course, it also retains the core TADS execution sequence, which means that if you don't code for reactions then your game will behave like any other TADS game.

 

Return Values

 

These reaction methods can execute the TADS built-in functions exitobj, exit, and abort which will terminate the reaction process, as well as having the same behaviour as they would when executed from the corresponding action method (preAction processing, because it has no corresponding preAction function in TADS, is called from verbAction and so passes control to postAction, unlike preCommand, which passes control to endCommand).

 

Additionally, reaction methods can choose to return values equivalent to the above mentioned built-in functions. Passing back EC_SUCCESS, EC_EXITOBJ, EC_EXIT, or EC_ABORT will perform exactly as though you had issued return, exitobj, exit, or abort.

 

actorPreAction

 

This method performs a similar function to actorAction(), but allows the author to terminate processing before roomPreAction has been executed, or to tailor the ordering of display messages.

 

roomPreAction / roomPostAction

 

Because inform.t uses an alternative scoping mechanism, it doesn't generally work with top-level locations, but determines a scopeCeiling for the actor based on accessibility rules. While the TADS built-in parser will call actor.location.roomAction() this might not be accurate for an actor inside an enterable class or similar object.

 

The actor.location.roomPreAction() and actor.location.roomAction() methods may at first appear to be redundant, but allows for a more accurate and tighter check on the actor's location.

 

scopePreAction and scopePostAction

 

These methods are called for each object within the actor's scope for the given verb and scopeCeiling, excluding the actor, scopeCeiling_location, direct object, and indirect object. These methods allow for a bearded psychiatrist to make observations on the actor's efforts at object manipulation or allow teeterwaller to comment on our garage opener or map. 

 

postAction Status

 

Because postAction() receive the status of the execution sequence it's possible to code for both successful and unsuccessful execution of the action method (You may still have to check game-state). This allows for the following style of interactions:

 

Wonderful World of Containers
     This is Room 11, east of the foyer. You notice a typical piece of scenery which

turns out to be a surface: a mantelpiece.
     You see a green ball, a red cone, a blue pyramid, a plain shopping bag (which

can only hold 2 things) , a glass box with a lid, a steel box with a lid, a toothed bag,

a bolted cupboard, a bolted key, and a television here. The macrame bag seems

to contain a music box.

 

 A beardded psychiatrist has you under observation.


>take ball
“Subject feels lack of the green ball. Suppressed Oedipal complex? Mmm.”

 

Taken.

 

>put ball in steel box
Done.

 

“Subject puts a green ball in the steel box with a lid. Interesting.”

 

>close steel box
Closed.

 

>put cone in steel box
The steel box with a lid is closed.

 

“Subject fails to put a red cone in the steel box with a lid. Most distressing.”

 

ioPreAction / doPreAction / ioPostAction doPostAction

 

These methods resemble xobjCheck() methods in functionality and are included into the inform.t schema for completeness. They allow an object to have a say before the execution of the command, and after the execution. Of particular usefulness are the postAction methods, which carry the status of the commands action method with them. Using these methods the following scenario is possible.

 

>GIVE THE DOG A BONE

You reach into your pocket, groping about frantically.    // actorPreAction generated message

You don't have a bone!    // default verification message

 

The dog, perceiving your movements         // doPostAction generated message

as a threatening gesture, lunges at you

menacingly.

 

endCommand Processing

 

You will notice that endCommand handles the increment of turncount and the advancement of time. This is a reversal in the normal TADS / Inform processing, which update the turn counters and advance the time before running daemons and fuses.

 

Differences between the two processes will only be apparent in games which reference the global.turnsofar or timesys object directly. In this case the will be one unit behind normal TADS processing. However, if the daemon or fuse does not address the global.turnsofar or timesys object directly then this change has no affect on the execution of the daemon or fuse.

 

From a philosophical perspective this makes the daemon or fuse the last part of the current "turn" and not the beginning of the following "turn", but again, this will not be noticeable unless the daemon addresses the global.turnsofar or timesys object from within its code. In this case it the counter values would need to be incremented by one in order to keep the behaviour in line with the normal TADS library.

 

This change in processing order has some advantages. It frees the time-oriented waiting process (>Wait for 5 minutes) from the daemons/fuses processing and allows for the advancement of daemons / fuses to be independent of turns / time. While under normal processing a daemon / fuse is advanced once per "turn", inform.t allows these processes to be decoupled so that daemon / fuse execution can occur either once per timerate or once per turn. This allows the author to keep daemon / fuse execution consistent during waiting and non-waiting intervals.

 

roomEndCommand and scopeEndCommand

 

After the increment of turns and time, as well as the processing of any timesys.events (such as room lighting) have occurred the actor.location.roomEndCommand process is called, which becomes the first reaction of the new "turn". The location is based upon the determination of the scopeCeiling for the actor.

 

Next, the scopeEndCommand process executes for each object within the actor's scope. This includes the direct and indirect objects of a command, but excludes the actor and scopeCeiling

 

timesys.events

Lastly, endCommand() executes a user-defined method, timesys.events. This allows the author to affect time-related events such as room lighting, anouncement of the hour by clocks, changing weather patterns, etc.