Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[TADS3] TravelConnector Notes

16 views
Skip to first unread message

Bert Byfield

unread,
May 1, 2007, 4:53:01 PM5/1/07
to
Here is some stuff I got from the TADS3 documentation, in case someone
might find it useful in non-standard moving from room to room. I got a
mapping system working when I made these reference files. There are two
texts:

---------------------- one -------------------------------------

class TravelConnector: Thing

connectorTravelPreCond() { // get pre-conditions
local lst;
lst = []; // start with no conditions
/* if we have a staging location, require that we're in it */
if (connectorStagingLocation != nil)
lst = [new TravelerDirectlyInRoom(gActor, self,
connectorStagingLocation)];
/* If we're a physical Thing with a non-nil location, require
* that we be touchable. Only physical objects need to be
* touchable; connectors are sometimes abstract objects,
which
* obviously can't be touched.
*/
if (ofKind(Thing) && location != nil) {
/* require that the traveler can touch the connector */
local cond = new
TouchObjCondition(gActor.getTraveler(self));
lst += new ObjectPreCondition(self, cond);
}
return lst; // return the result
}
/* The "staging location" for travel through this connector. By
* default, if we have a location, that's our staging location;
if
* we don't have a location (in which case we probably an
outermost
* room), we don't have a staging location.
*/
connectorStagingLocation = (location)
/* Get the travel preconditions that this connector requires for
* travel by the given actor. In most cases, this won't depend on
* the actor, but it's provided as a parameter anyway; in most
cases,
* this will just apply the conditions that are relevant to
actors as
* travelers.
*
* By default, we require actors to be "travel ready" before
* traversing a connector. The exact meaning of "travel ready"
is
* provided by the actor's immediate location, but it usually
simply
* means that the actor is standing. This ensures that the actor
* isn't sitting in a chair or lying down or something like that.
* Some connectors might not require this, so this routine can be
* overridden per connector.
*
* Note that this will only be called when an actor is the
traveler.
* When a vehicle or other kind of traveler is doing the travel,
this
* will not be invoked.
*/

actorTravelPreCond(actor) {
/* create an object precondition ensuring that the actor is
* "travel ready"; the object of this precondition is the
* connector itself
*/
return [new ObjectPreCondition(self, actorTravelReady)];
}
/* Barrier or barriers to travel. This property can be set to a
* single TravelBarrier object or to a list of TravelBarrier
* objects. checkTravelBarriers() checks each barrier specified
* here.
*/
travelBarrier = []
/* Check barriers. The TravelVia check() routine must call this
to
* enforce barriers.
*/
checkTravelBarriers(dest) {
local traveler;
local lst;
traveler = gActor.getTraveler(self); // get the traveler
// ask the traveler what it thinks of travel through this
connector:
if (!traveler.canTravelVia(self, dest)) {
/* explain why the traveler can't pass */
traveler.explainNoTravelVia(self, dest);
exit; /* terminate the command */
}
/* check any travel conditions we apply directly */
if (!canTravelerPass(traveler)) {
/* explain why the traveler can't pass */
explainTravelBarrier(traveler);
exit; /* terminate the command */
}
lst = travelBarrier; /* get the barrier list */
/* if it's just a single object, make it a list of one element
*/
if (!lst.ofKind(Collection)) lst = [lst];

foreach (local cur in lst) { // check each item in barrier
list
/* if this barrier doesn't allow travel, we cannot travel
*/
if (!cur.canTravelerPass(traveler)) {
/* ask the barrier to explain why travel isn't
possible */
cur.explainTravelBarrier(traveler);
exit; /* terminate the command */
}
}
}


/* Check to see if the Traveler object is allowed to travel through
* this connector. Returns true if travel is allowed, nil if
not.
*
* This is called from checkTravelBarriers() to check any
conditions
* coded directly into the TravelConnector. By default, we
simply
* return true; subclasses can override this to apply special
* conditions.
*
* If an override wants to disallow travel, it should return nil
* here, and then provide an override for explainTravelBarrier()
to
* provide a descriptive message explaining why the travel isn't
* allowed.
*
* Conditions here serve essentially the same purpose as barrier
* conditions. The purpose of providing this additional place
for
* the same type of conditions is simply to improve the
convenience
* of defining travel conditions for cases where barriers are
* unnecessary. The main benefit of using a barrier is that the
same
* barrier object can be re-used with multiple connectors, so if
the
* same set of travel conditions apply to several different
* connectors, barriers allow the logic to be defined once in a
* single barrier object and then re-used easily in each place
it's
* needed. However, when a particular condition is needed in only
* one place, creating a barrier to represent the condition is a
bit
* verbose; in such cases, the condition can be placed in this
method
* more conveniently.
*/
canTravelerPass(traveler) { return true; }

/* Explain why canTravelerPass() returned nil. This is called to
* display an explanation of why travel is not allowed by
* self.canTravelerPass().
*
* Since the default canTravelerPass() always allows travel, the
* default implementation of this method does nothing. Whenever
* canTravelerPass() is overridden to return nil, this should
also be
* overridden to provide an appropriate explanation.
*/
explainTravelBarrier(traveler) { }

/* Is this connector listed? This indicates whether or not the
exit
* is allowed to be displayed in lists of exits, such as in the
* status line or in "you can't go that way" messages. By
default,
* all exits are allowed to appear in listings.
*
* Note that this indicates if listing is ALLOWED - it doesn't
* guarantee that listing actually occurs. A connector can be
* listed only if this is true, AND the point-of-view actor for
the
* listing can perceive the exit (which means that
* isConnectorApparent must return true, and there must be
* sufficient light to see the exit).
*/
isConnectorListed = true

/* Get an unlisted proxy for this connector. This is normally
* called from the asExit() macro to set up one room exit
direction
* as an unlisted synonym for another.
*/
createUnlistedProxy() { return new UnlistedProxyConnector(self); }

/* Determine if the travel connection is apparent - as a travel
* connector - to the actor in the given origin location. This
* doesn't indicate whether or not travel is possible, or where
* travel goes, or that the actor can tell where the passage
goes;
* this merely indicates whether or not the actor should realize
* that the passage exists at all.
*
* A closed door, for example, would return true, because even a
* closed door makes it clear that travel is possible in the
* direction, even if it's not possible currently. A secret door,
* on the other hand, would return nil while closed, because it
* would not be apparent to the actor that the object is a door
at
* all.
*/
isConnectorApparent(origin, actor)
{
/* by default, passages are apparent */
return true;
}

/* Determine if the travel connection is passable by the given
* traveler in the current state. For example, a door would return
* true when open, nil when closed.
*
* This information is intended to help game code probing the
* structure of the map. This information is NOT used in actor
* travel; for actor travel, we rely on custom checks in the
* connector's TravelVia handler to enforce the conditions of
travel.
* Actor travel uses TravelVia customizations rather than this
method
* because that allows better specificity in reporting failures.
* This method lets game code get at the same information, but in
a
* more coarse-grained fashion.
*/
isConnectorPassable(origin, traveler) {
return true; /* by default, we're passable */
}

/* Get the apparent destination of travel by the actor to the given
* origin. This returns the location to which the connector
* travels, AS FAR AS THE ACTOR KNOWS. If the actor does not
know
* and cannot tell where the connector leads, this should return
nil.
*
* Note that this method does NOT necessarily return the actual
* destination, because we obviously can't know the destination
for
* certain until we traverse the connection. Rather, the point
of
* this routine is to return as much information as the actor is
* supposed to have. This can be used for purposes like
* auto-mapping, where we'd want to show what the player
character
* knows of the map, and NPC goal-seeking, where an NPC tries to
* figure out how to get from one point to another based on the
* NPC's knowledge of the map. In these sorts of applications,
it's
* important to use only knowledge that the actor is supposed to
* have within the parameters of the simulation.
*
* Callers should always test isConnectorApparent() before
calling
* this routine. This routine does not check to ensure that the
* connector is apparent, so it could return misleading
information
* if used independently of isConnectorApparent(); for example,
if
* the connector *formerly* worked but has now disappeared, and
the
* actor has a memory of the former destination, we'll return the
* remembered destination.
*
* The actor can know the destination by a number of means:
*
* 1. The location is familiar to the character. For example,
if
* the setting is the character's own house, the character would
* obviously know the house well, so would know where you'd end
up
* going east from the living room or south from the
kitchen. We
* use the origin method actorKnowsDestination() to determine
this.
*
* 2. The destination is readily visible from the origin
location,
* or is clearly marked. For example, in an outdoor setting, it
* might be clear that going east from the field takes you to the
* hilltop. In an indoor setting, an open passage might make it
* clear that going east from the living room takes you to the
* dining room. We use the origin method actorKnowsDestination()
to
* determine this.
*
* 3. The actor has been through the connector already in the
course
* of the game, and so remembers the connection by virtue of
recent
* experience. If our travelMemory class property is set to a
* non-nil lookup table object, then we'll automatically use the
* lookup table to remember the destination each time an actor
* travels via a connector, and use this information by default
to
* provide apparent destination information.
*/
getApparentDestination(origin, actor) {
local dest;
/* Ask the origin if the actor knows the destination for the
* given connector. If so, and we can determine our
* destination, then return the destination.
*/
if (origin.actorKnowsDestination(actor, self)
&& (dest = getDestination(origin,
actor.getTraveler(self))) != nil)
return dest;

/* If we have a travelMemory table, look to see if the
traversal
* of this actor via this connector from this origin is
recorded
* in the table, and if so, assume that the destination is
the
* same as it was last time.
* Note that we ignore our memory of travel if we never saw
the
* destination of the travel (which would be the case if the
* destination was dark every time we've been there, so we've
* never seen any details about the location).
*/
if (travelMemory != nil
&& (dest = travelMemory[[actor, origin, self]]) != nil
&& actor.hasSeen(dest)) {
/* we know the destination from past experience */
return dest;
}
return nil; /* we don't know the destination */
}

/*
* Get our destination, given the traveler and the origin
location.
*
* This method is required to return the current destination for
the
* travel. If the connector doesn't go anywhere, this should
return
* nil. The results of this method must be stable for the extent
of
* a turn, up until the time travel actually occurs; in other
words,
* it must be possible to call this routine simply for
information
* purposes, to determine where the travel will end up.
*
* This method should not trigger any side effects, since it's
* necessary to be able to call this method more than once in the
* course of a given travel command. If it's necessary to trigger
* side effects when the connector is actually traversed, apply
the
* side effects in noteTraversal().
*
* For auto-mapping and the like, note that
getApparentDestination()
* is a better choice, since this method has internal information
* that might not be apparent to the characters in the game and
thus
* shouldn't be revealed through something like an auto-
map. This
* method is intended for internal use in the course of
processing a
* travel action, since it knows the true destination of the
travel.
*/
getDestination(origin, traveler) { return nil; }

/*
* Get the travel connector leading to the given destination from
the
* given origin and for the given travel. Return nil if we don't
* know a connector leading there.
*
* By default, we simply return 'self' if our destination is the
* given destination, or nil if not.
*
* Some subclasses might encapsulate one or more "secondary"
* connectors - that is, the main connector might choose among
* multiple other connectors. In these cases, the secondary
* connectors typically won't be linked to directions on their
own,
* so the room can't see them directly - it can only find them
* through us, since we're effectively a wrapper for the
secondary
* connectors. In these cases, we won't have any single
destination
* ourself, so getDestination() will have to return nil. But we
* *can* work backwards: given a destination, we can find the
* secondary connector that points to that destination. That's
what
* this routine is for.
*/

connectorGetConnectorTo(origin, traveler, dest) {
/* if we go there, return 'self', else return nil */
return (getDestination(origin, traveler) == dest ? self :
nil);
}

/*
* Note that the connector is being traversed. This is invoked
just
* before the traveler is moved; this notification is fired after
the
* other travel-related notifications (beforeTravel, actorTravel,
* travelerLeaving). This is a good place to display any special
* messages describing what happens during the travel, because
any
* messages displayed here will come after any messages related
to
* reactions from other objects.
*/
noteTraversal(traveler) {
/* do nothing by default */
}

/*
* Service routine: add a memory of a successful traversal of a
* travel connector. If we have a travel memory table, we'll add
* the traversal to the table, so that we can find it later.
*
* This is called from Traveler.travelerTravelTo() on successful
* travel. We're called for each actor participating in the
travel.
*/
rememberTravel(origin, actor, dest) {
/*
* If we have a travelMemory table, add this traversal. Store
* the destination, keyed by the combination of the actor,
* origin, and connector object (i.e., self) - this will
allow
* us to remember the destination we reached last time if we
* want to know where the same route goes in the future.
*/
if (TravelConnector.travelMemory != nil)
TravelConnector.travelMemory[[actor, origin, self]] =
dest;
}

/*
* Our "travel memory" table. If this contains a non-nil lookup
* table object, we'll store a record of each successful
traversal
* of a travel connector here - we'll record the destination
keyed
* by the combination of actor, origin, and connector, so that we
* can later check to see if the actor has any memory of where a
* given connector goes from a given origin.
*
* We keep this information by default, which is why we
statically
* create the table here. Keeping this information does
involve
* some overhead, so some authors might want to get rid of this
* table (by setting the property to nil) if the game doesn't
make
* any use of the information. Note that this table is stored
just
* once, in the TravelConnector class itself - there's not a
* separate table per connector.
*/
travelMemory = static new LookupTable(256, 512)

/*
* Is this a "circular" passage? A circular passage is one that
* explicitly connects back to its origin, so that traveling
through
* the connector leaves us where we started. When a passage is
* marked as circular, we'll describe travel through the passage
* exactly as though we had actually gone somewhere. By
default, if
* traveling through a passage leaves us where we started, we
assume
* that nothing happened, so we don't describe any travel.
*
* Circular passages don't often occur in ordinary settings;
these
* are mostly useful in disorienting environments, such as twisty
* cave networks, where a passage between locations can change
* direction and even loop back on itself.
*/
isCircularPassage = nil

/*
* Should we remember a circular trip through this passage? By
* default, we remember the destination of a passage that takes
us
* back to our origin only if we're explicitly marked as a
circular
* passage; in other cases, we assume that the travel was blocked
* somehow instead.
*/
rememberCircularPassage = (isCircularPassage)

/*
* Describe an actor's departure through the connector from the
* given origin to the given destination. This description is
from
* the point of view of another actor in the origin location.
*/
describeDeparture(traveler, origin, dest) {
local dir;
/* See if we can find a direction linked to this connector
from
* the origin location. If so, describe the departure using
the
* direction; otherwise, describe it using the generic
departure
* message.
*
* Find the connector from the player character's
perspective,
* because the description we're generating is for the
player's
* benefit and thus should be from the PC's perspective.
*/
if ((dir = origin.directionForConnector(self, gPlayerChar)) !=
nil) {
/* We found a direction linked to the connector, so this
* must have been the way they traveled. Describe the
* departure as being in that direction.
*
* Note that it's possible that more than one direction
is
* linked to the same connector. In such cases, we'll
just
* take the first link we find, because it's equally
* accurate to say that the actor went in any of the
* directions linked to the same connector.
*/
traveler.sayDepartingDir(dir, self);
}
else {
/* We didn't find any direction out of the origin linking
to
* this connector, so we don't know how what direction
they
* went. Show the generic departure message.
*/
traveler.sayDeparting(self);
}
}

/* Describe an actor's arrival through the connector from the given
* origin into the given destination. This description is from the
* point of view of another actor in the destination.
*
* Note that this is called on the connector that reverses the
* travel, NOT on the connector the actor is actually traversing
-
* that is, 'self' is the backwards connector, leading from the
* destination back to the origin location. So, if we have two
* sides to a door, and the actor traverses the first side, this
* will be called on the second side - the one that links the
* destination back to the origin.
*/
describeArrival(traveler, origin, dest) {
local dir;
/* See if we can find a direction linked to this connector in
* the destination location. If so, describe the arrival
using
* the direction; otherwise, describe it using a generic
arrival
* message.
*
* Find the connector from the player character's
perspective,
* because the description we're generating is for the
player's
* benefit and thus should be from the PC's perspective.
*/
if ((dir = dest.directionForConnector(self, gPlayerChar)) !=
nil) {
/* we found a direction linked to this back connector, so
* describe the arrival as coming from the direction we
* found
*/
traveler.sayArrivingDir(dir, self);
}
else {
/* we didn't find any direction links, so use a generic
* arrival message
*/
traveler.sayArriving(self);
}
}

/* Describe a "local departure" via this connector. This is called
* when a traveler moves around entirely within the field of view
of
* the player character, and move *further away* from the PC -
that
* is, the traveler's destination is visible to the PC when we're
* leaving our origin, AND the origin's top-level location
contains
* the PC. We'll describe the travel not in terms of truly
* departing, but simply in terms of moving away.
*/
describeLocalDeparture(traveler, origin, dest) {
/* say that we're departing locally */
traveler.sayDepartingLocally(dest, self);
}

/* Describe a "local arrival" via this connector. This is called
* when the traveler moves around entirely within the field of
view
* of the player character, and comes *closer* to the PC - that
is,
* the traveler's origin is visible to the player character when
we
* arrive in our destination, AND the destination's top-level
* location contains the PC. We'll describe the travel not in
terms
* of truly arriving, since the traveler was already here to
start
* with, but rather as entering the destination, but just in
terms of
* moving closer.
*/
describeLocalArrival(traveler, origin, dest) {
/* say that we're arriving locally */
traveler.sayArrivingLocally(dest, self);
}

/* Describe "remote travel" via this connector. This is called when
* the traveler moves around entirely within the field of view of
the
* PC, but between two "remote" top-level locations - "remote"
means
* "does not contain the PC." In this case, the traveler isn't
* arriving or departing, exactly; it's just moving laterally
from
* one top-level location to another.
*/
describeRemoteTravel(traveler, origin, dest) {
/* say that we're traveling laterally */
traveler.sayTravelingRemotely(dest, self);
}

/* Find a connector in the destination location that connects back
as
* the source of travel from the given connector when traversed
from
* the source location. Returns nil if there is no such
connector.
* This must be called while the traveler is still in the source
* location; we'll attempt to find the connector back to the
* traveler's current location.
*
* The purpose of this routine is to identify the connector by
which
* the traveler arrives in the new location. This can be used,
for
* example, to generate a connector-specific message describing
the
* traveler's emergence from the connector (so we can say one
thing
* if the traveler arrives via a door, and another if the
traveler
* arrives by climing up a ladder).
*
* By default, we'll try to find a travel link in the destination
* that links us back to this same connector, in which case we'll
* return 'self' as the connector from which the traveler emerges
in
* the new location. Failing that, we'll look for a travel link
* whose apparent source is the origin location.
*
* This should be overridden for any connector with an explicit
* complementary connector. For example, it is common to
implement a
* door using a pair of objects, one representing each side of
the
* door; in such cases, each door object would simply return its
twin
* here. Note that a complementary connector doesn't actually
have
* to go anywhere, since it's still useful to have a connector
back
* simply for describing travelers arriving on the connector.
*
* This *must* be overridden when the destination location
doesn't
* have a simple connector whose apparent source is this
connector,
* because in such cases we won't be able to find the reverse
* connector with our direction search.
*/
connectorBack(traveler, dest) {
local origin;

/* if there's no destination, there's obviously no connector
*/
if (dest == nil) return nil;

/* get the origin location - this the traveler's current
* immediate container
*/
origin = traveler.location;

/* First, try to find a link back to this same connector -
this
* will handle simple symmetrical links with the same
connector
* object shared between two rooms.
*
* We try to find the actual connector before looking for a
* connector back to the origin - it's possible that there
are
* several ways back to the starting point, and we want to
make
* sure we pick the one that was actually traversed if
possible.
*/
foreach (local dir in Direction.allDirections) {
/* If this direction link from the destination is linked
back
* to this same connector, we have a symmetrical
connection,
* so we're the connector back. Note that we're
interested
* only in map structure here, so we don't pass an actor;
the
* actor isn't actually in the new location, so what the
* actor can see is irrelevant to us here.
*/
if (dest.getTravelConnector(dir, nil) == self) {
/* the same connector goes in both directions */
return self;
}
}

/* we didn't find a link back to the same connector, so try to
* find a link from the destination whose apparent source is
the
* origin
*/
foreach (local dir in Direction.allDirections) {
local conn;

/* if this link from the destination has an apparent
source
* of our origin, the traveler appears to be arriving
from
* this link
*/
if ((conn = dest.getTravelConnector(dir, nil)) != nil
&& conn.fixedSource(dest, traveler) == origin) {
/* this direction has an apparent source of the origin
* room - it's not necessarily the same link they
* traversed, but at least it appears to come from
the
* same place they came from, so it'll have to do
*/
return conn;
}
}

/* we couldn't find any link back to the origin */
return nil;
}


/* Get the "fixed" source for travelers emerging from this
connector,
* if possible. This can return nil if the connector does not
have a
* fixed relationship with another connector.
*
* The purpose of this routine is to find complementary
connectors
* for simple static map connections. This is especially useful
for
* direct room-to-room connections.
*
* When a connector relationship other than a simple static
mapping
* exists, the connectors must generally override
connectorBack(), in
* which case this routine will not be needed (at least, this
routine
* won't be needed as long as the overridden connectorBack()
doesn't
* call it). Whenever it is not clear how to implement this
routine,
* don't - implement connectorBack() instead.
*/
fixedSource(dest, traveler) {
/* by default, return nothing */
return nil;
}

/* Can the given actor see this connector in the dark, looking from
* the given origin? Returns true if so, nil if not.
*
* This is used to determine if the actor can travel from the
given
* origin via this connector when the actor (in the origin
location)
* is in darkness.
*
* By default, we implement the usual convention, which is that
* travel from a dark room is possible only when the destination
is
* lit. If we can't determine our destination, we will assume that
* the connector is not visible.
*/
isConnectorVisibleInDark(origin, actor) {
local dest;
/* Get my destination - if we can't determine our destination,
* then assume we're not visible.
*/
if ((dest = getDestination(origin, actor.getTraveler(self)))
== nil)
return nil;

/* Check the ambient illumination level in the
destination. If
* it's 2 or higher, then it's lit; otherwise, it's
dark. If
* the destination is lit, consider the connector to be
visible,
* on the theory that the connector lets a little bit of the
* light from the destination leak into the origin room -
just
* enough to make the connection itself visible without
making
* anything else in the origin room visible.
*/
return (dest.wouldBeLitFor(actor));
}

/* Handle travel in the dark. Specifically, this is called when an
* actor attempts travel from one dark location to another dark
* location. (We don't invoke this in any other case:
* light-to-light, light-to-dark, and dark-to-light travel are
all
* allowed without any special checks.)
*
* By default, we will prohibit dark-to-dark travel by calling
the
* location's darkTravel handler. Individual connectors can
* override this to allow such travel or apply different
handling.
*/
darkTravel(actor, dest) {
/* by default, simply call the actor's location's darkTravel
* handler
*/
actor.location.roomDarkTravel(actor);
}

/* Action handler for the internal "TravelVia" action. This is
not a
* real action, but is instead a pseudo-action that we implement
* generically for travel via the connector. Subclasses that
want to
* handle real actions by traveling via the connector can use
* remapTo(TravelVia) to implement the real action
handlers. Note
* that remapTo should be used (rather than, say, asDobjFor),
since
* this will ensure that every type of travel through the
connector
* actually looks like a TravelVia action, which is useful for
* intercepting travel actions generically in other code.
*/
dobjFor(TravelVia) {
preCond() {
/* For our preconditions, use the traveler's
preconditions,
* plus the location's preconditions, plus any special
* connector-specific preconditions we supply.
*/
return gActor.getTraveler(self).travelerPreCond(self)
+ gActor.location.roomTravelPreCond()
+ connectorTravelPreCond();
}
verify() {
/* Verify travel for the current command's actor through
this
* connector. This performs normal action verify
processing.
*
* The main purpose of this routine is to allow the
connector
* to flag obviously dangerous travel to allow a caller
to
* avoid such travel as an implicit or scripted
action. In
* most cases, there's no need to make travel illogical
* because there's generally no potential ambiguity
involved
* in analyzing a travel verb.
*
* Note that this routine must check with the actor to
* determine if the actor or a vehicle will actually be
* performing the travel, by calling
gActor.getTraveler(), if
* the routine cares about the difference.
*/
}
check() {
local t = gActor.getTraveler(self);
local dest;
/* Check the travel.
* This routine should take into account the light levels
at
* the source and destination locations, if travel
between
* dark rooms is to be disallowed.
*/
dest = getDestination(t.location, t); // get destination

gActor.checkDarkTravel(dest, self); // check dark-to-
dark travel

checkTravelBarriers(dest); /* enforce barriers */
}

action() {
local t = gActor.getTraveler(self);
local dest;
/* Execute the travel, moving the command's actor through
the
* travel connection: we carry out any side effects of
the
* travel and deliver the actor (if appropriate) to the
* destination of the connector.
*
* Note that this routine must check with the actor to
* determine if the actor or a vehicle will actually be
* performing the travel, by calling
gActor.getTraveler(), if
* the routine cares about the difference. In most cases,
* the routine won't care: most implementations of this
* routine will (if they effect any travel at all)
eventually
* call gActor.travelTo() to carry out the travel, and
that
* routine will always route the actual movement to the
* vehicle if necessary.
*/
dest = getDestination(t.location, t); // get my
destination

/* travel to my destination */
gActor.travelTo(dest, self, connectorBack(t, dest));
}
}
;

--------------- and 2 -----------------------------------------------


rec.arts.int-fiction Subject: Re: TADS 3: TravelConnector Question

>>> Second, how does a two-way room connector identify the starting
>>> location and ending location of the traveler who is using the
>>> connector? I spent some time reading through travel.t, and
>>> didn't spot any property that seemed to hold this information. I
>>> think I need to know that so that the disappearance of the
>>> bridge will be triggered properly.

>> The two locations RoomConnector connects are held in its room1
>> and room2 properties. The method getDestination() determines the
>> destination of someone traveling via the connector.

> To use getDestination, I need to send it the origin. But if I knew
that,
> I wouldn't need to use getDestination. What I'm trying to do is
> figure out which way the player is traveling across the bridge
> **without knowing it ahead of time.**

Doesn't gActor.getOutermostRoom (or gPlayerChar.getOutermostRoom, if
the PC is the only actor who's ever going to cross the bridge) give you
the starting location?

That's only true BEFORE the move is executed. I'm trying to find out
where the player came from AFTER she/he arrives in the new room.

if (gAction.originalAction.getDirection == northDirection)
This is equivalent to Inform's "if (noun == n_obj)". You can test this
in the new room to find out which direction the player arrived from.

> If that's you want, use travelerArriving(traveler, origin, connector,
> backConnector) instead of enteringRoom(), since the traveler's
starting
> point is indicated by the origin parameter passed to the method.

It looks to me as if, in order to use travelerArriving, I need to
already know the origin. The origin is what I'm trying to find out!
travelerArriving sets the posture for the arriving actor, runs
enteringRoom(traveler), and then describes the arrival by calling the
describeArrival method on the traveler. It has no return value, so it
can't (and shouldn't!) be used to test the value of any variable.Or am
I misunderstanding something that you're hinting at?

travelerArriving(traveler, origin, connector, backConnector)
/* your stuff here, which can look at the value of origin that's
been passed to this routine to see where the traveler's
come from.
*/
inherited((traveler, origin, connector, backConnector);
;


Newsgroups: rec.arts.int-fiction
Subject: Re: TADS 3: Detecting Travel

The direct object of TravelVia is the connector being traversed (not a
wall).
If the player is going north from kitchen, then the connector being
traversed will be the connector held by kitchen.north. That means you
should be able simply to write:

leavingRoom(traveler)
{
if (gDobj==north) "Going north now...";
if (gDobj==south) "Going south now...";
}

That should work if you actually have different connectors for the
different directions.

If that's not suitable, you can use this:
if (gAction.originalAction.getDirection == northDirection) "Going
north now..."; // (same place as shown above)


---------------- end notes ---------------------------

0 new messages