TravelActor is a mix-in class
that enables an ordinary actor to traverse the travel graph of the game world
in an automated fashion. Travel is accomplished through a two-step process.
First a logical path from the actor’s
location to the desired destination is computed using Dijkstra’s shortest paths
algorithm; then a daemon generates a series of actor commands that attempt the
actor’s physical traversal along the
path. Course corrections are made when necessary when the physical traversal fails.
TravelActor utilizes the
actor’s knowledge of the game world,
specifically the travel graph, in order to compute a path to the destination,
and in choosing the appropriate direction to take to reach a given location.
When physical traversal from one location to another is blocked, or the chosen
direction does not lead to the location the actor thought it would, the
corresponding vertex and edge are noted in the actor’s travelEdgeMemory along
with the results of the attempted edge traversal.
At the end of each call to
the actor’s travelDaemon(), a call is made to the actor’s travelScript()
method, passing it a vector of the results of the calculations that occurred
during that call.
In this way, TravelActor
makes use of its knowledge both in where it has been previously and what
happened to get where it currently is; as well as where it is going, and how to
choose a route to get there.
It’s as simple as defining
any other actor. Below is the definition for Joe, our brave little explorer.
joe:
TravelActor, Person
{
'joe' 'Joe' @livingRoom
isProperName = true
isHim = true
obeyCommand(issuer) { return true; }
wantsFollowInfo(obj) { return true; }
}
This isn’t any different from
an ordinary actor’s definition might be, except that Joe inherits from the
TravelActor mix-in.
A TravelActor is driven by a
daemon, which should be set at the beginning of the game. The
initiateTravelActor() method let’s you do this, as well as setting up the
initial travel destination list. The method also lets an author call the
TravelActor’s runActor() method prior to the creation of the daemon, if
desired. If the actor is initiated before runGame() is called this has the
effect of starting the actor in motion when the actor’s commands are executed
on the first turn, rather than waiting for the second turn.
joe.initiateTravelActor(true, shed);
Now Joe will be setup with a
daemon to execute his runActor() method each turn, and a travel destination
list that contains the shed. In addition, the first argument, true, will cause the actor’s runActor() method to be
executed at this time, and a dijkstra path from the actor’s location to the
shed will be computed, a direction chosen, and the appropriate command placed
in the actor’s command queue to be executed that will attempt to move him to
the next location along his path.
By issuing the same command
with a nil preTurn argument we postpone the computation, selection,
and issuing of the command until the daemon triggers, which will mean our actor
won’t attempt to move to the next location until his command queue is executed
on the next turn.
It’s important to note this
distinction of the travel process:
Actor travel occurs when its command queue is
processed. Actor travel commands are
generated by the runActor() method, which is driven by a daemon.
Although the daemon should
normally run continuously throughout the duration of the game, the
terminateTravelActor() method will stop the actor and remove its daemon from
the eventManager.
joe.terminateTravelActor();
To restart Joe after
termination it will be necessary to call his initiateTravelActor(). Issuing
multiple initiateTravelActor() and terminateTravelActor() commands can lead to
stack overflow errors. To avoid this the TravelActor provides methods to
temporarily pause it while its daemon is active.
Once a TravelActor has been
initiated an author should use the startActor() and stopActor() methods to
temporarily pause and restart the actor.
Joe.startActor();
All this method will do is
set Joe’s status to active, so that it’s daemon will proceed to process its
travel destination list.
To temporarily pause a
TravelActor an author should call its stopActor() method. This will set the
actor’s status to inactive, and all processing of its travel destination list
will be halted. This will not stop the actor from attempting to process any
travel commands pending in its command queue, but will simply stop it from
issuing any further commands.
The runActor() method calls doTravelScript() right before it exits, if the actor is active. This allows the actor a chance to perform special actions before its command queue gets executed on the next turn.
A log of the runActor()
decision-making process is created in the form of a Vector of TravelActionInfo
objects. The log is built sequentially through runActor() processing and
provided to the actor’s doTravelScript() method. This gives the actor a chance
to know what the outcome of its previous travel command was, as well as
information regarding the next travel command to be executed.
A typical log might look like
this:
Travel Script
Value : TravelEdgeSuccess
travelDest: Tunnel
currTravelNode: Living Room
nextTravelNode: Den
travelEdge: east
location: Den
—————————————————-
Travel Script
Value : TravelCmdIssued
travelDest: Tunnel
currTravelNode: Den
nextTravelNode: Top of Stairs
travelEdge: north
location: Den
—————————————————-
What this indicates is that
travel was successful when the actor moved east from living room to the den.
Next a travel command was issued to the actor’s command queue to move north
from the den to what the actor believes will be the top of the stairs.
The following table gives the
meanings for the travel log values:
Value |
Meaning |
StartOfList |
The actor is at the start
of a new path |
EndOfList |
The actor has reached the
end of the travel destination list |
TravelCmdIssued |
A travel command has been
appended to the actor’s command queue |
TravelEdgeSuccess |
The actor has succeeded in
getting to its next location (without previous failure) |
TravelLinkSuccess |
The actor has succeeded in
getting to its next location (after having previously failed) |
TravelDestSuccess |
The actor has reached its
destination |
TravelEdgeBlocked |
The actor failed to reach
the location by the direction it has taken |
TravelLinkBlocked |
The actor is prevented from
going to its next location by any known direction |
TravelNodeBlocked |
The location the actor was
attempting to travel to (along its way to its destination) was blocked along
each avenue |
TravelDestBlocked |
The destination is blocked
along each avenue |
TravelEdgeFailure |
The actor didn’t reach the location
it thought it would when it traveled along this direction |
This file is part of the TADS 3
Proteus Library Extension
Copyright ©
2001-2004 Kevin Forchione. All rights reserved.