The TADS Alternate Library
Version 2.0

Floating Objects and Destinations

Copyright 2000 by Kevin Forchione.
This is part of the TADS Alternate Library Authors Manual.

Introduction and Table of Contents

Floating Class


Floating is a basic mix-in class that allows an object to assign its location relative to the actorís location. Floating class objects have only one location at any given moment, however their location is dependent upon two factors: the list returned by their foundIn property and the actorís location.


A Floating objectís foundIn property can either be a listor code that returns a list. The list must either be an empty list or a list of game objects in which the Floating object is to be found. This list is then compared with the actorís location, working outward recursively from the actorís location to the actorís locationís location, etc. This recursive search through an actorís nested locations is independent of sense.


In this way a Floating object will be placed in the closest location to the actor appearing in the foundIn list; otherwise it will be assigned a location of nil.



Alt Floating Objects appear as close to the actorís nested location as possible



Once a location has been determined the Floating object is moved into this location, which means that if the location is not nil then it appears in the contents list of the location.



Alt Floating Objects always appear in the contents lists of their locations




Floating object locations are determined by the moveFloating() function. This function makes its determination of all Floating object locations at least once per command execution cycle. To ensure that Floating objects are where they are expected to be Altís moveFloating() function is run during:


         preinit() to set up Floating objectís initial location

         validDoList() and validIoList()




An Example


Suppose our game defines a mist that appears in several locations. The mist is constant from one location to another, and simply provides an interesting smell.


mist: Floating, Decoration

††† foundIn = [forestClearing, stoneChamber]

††† noun = 'mist'

††† adjective = 'low-lying'

††† sDesc = "low-lying mist"

††† initial = "A low-lying mist hugs the ground about your feet."

††† smellDesc = "The mist smells of boiled cabbage."

††† doSmell(actor) = {self.smellDesc;}



Now whenever we enter the forestClearing or the stoneChamber the mist is there, waiting to be smelled.


Note that we can use initial to describe the mist because itís a Decoration and therefore canít be taken. Since the object is a decoration, however, we need to define doSmell() as well as smelldesc in order to be able to smell the mist. This is because Decorations use dobjGen() and iobjGen() to generate default messages for any actions not defined directly in the object by verification or action methods. The smelldesc property isnít an action method, itís merely called by doSmell(), so we need to define doSmell() in this object.


Destination Class


Altís Destination class serves functionally the same purpose as ADV.Tís obstacle class. Destination class provides a destination() method that determines what happens when an actor attempts to enter this object. This class generally serves as a bridge between two locations, with conditions that must be met in order to negotiate the transfer.


Destination class does not provide boarding methods, but does provide noExit handling. Most Destinations are accessed through travel directions properties, such as north, south, east, and west. Boarding can also be attempted for most Destination class objects through the <<enter obj>> command. Entering the object invokes its destination() method, which either transfers the actor to the location indicated by the leadsTo property or displays an appropriate message and prevents transfer.



When defining a Destination object it is important to override the classí leadsTo property,

which should be assigned a location to which the Destination leads.



Alt defines the following classes deriving from Destination



Venture contains a Passageway in the form of stoneSteps in the forestClearing leading down to a stoneChamber. The advantage to using a Destination, instead of simply connecting the forestClearing to the stoneChamber directly by travel direction properties is that we add depth to the passage from one location to another. In this case the stoneSteps carry information about the milieu we are in.


stoneSteps: Passageway

††† location = forestClearing

††† noun = 'steps'

††† adjective = 'stone'

††† isThem = true

††† sDesc = "stone steps"

††† lDesc = "Ancient steps extend down into shadows. Perhaps these steps

††††††† have have lain untrodden for a thousand years."

††† leadsTo = stoneChamber



The hasObstacle Method


Each instance of Destination class inherits a hasObstacle() method that determines the conditions under which the Destination can be successfully negotiated. This method should return true if passage through the destination is impeded in some way; otherwise it should return nil.



Use hasObstacle() to indicate whether the actor can successfully negotiate the Destination.

This method should return nil to indicate that progress is unimpeded; otherwise it should display

an appropriate message explaining why passage to the destination failed and return true.




The following is the hasObstructed() method for Doorways:


††† hasObstacle = {

††††††† if (self.isOpen)

††††††††††† return nil;

††††††† else if (!self.isLocked && !self.noAutoOpen) {

††††††††††† self.setIsOpen(true);

††††††††††† "(Opening << self.theDesc >>)\n";

††††††††††† return nil;

††††††† } else {

††††††††††† "%You%'ll have to open << self.theDesc >> first. ";

††††††††††† setit(self);

††††††††††† return true;

††††††† }

††† }


Passageways offer no obstacle to passage, while Doorways must be open, or automatically openable. Gateways, too, must be raised or automatically raisable. If these conditions arenít met then hasObstacle displays a message explaining why passage is denied and returns true to indicate that the passage is being obstructed.


Paired Doorways


The stoneSteps define location as forestClearing and leadsTo as stoneChamber. This makes them one-direction only. To join and synchronise two Destination class objects you need to code their otherSide properties to point to each other. For example, the following two Doorways are synchronised with each other, behaving like a single door.


hallDoor: Doorway

††† location = hallway

††† noun = 'door'

††† adjective = 'hall'

††† sDesc = "hall door"

††† leadsTo = kitchen

††† otherSide = kitchenDoor



kitchenDoor: Doorway

††† location = kitchen

††† noun = 'door'

††† adjective = 'kitchen'

††† sDesc = "kitchen door"

††† leadsTo = hallway

††† otherSide = hallDoor



Each Doorway has a location property explicitly coded, each has a leadsTo property assigned the location to which the Doorway leads and each Doorway has an otherSide pointing to the opposite Doorway. This strategy works very well when you want to define doors that behave differently on each side, for instance, one side being lockable, the other not.



Each member of a paired set of Doorways must define an otherSide attribute that points to the opposite Doorway.



FloatingDestination Class


Like a Floating object, a FloatingDestination object occupies only one location at any given time, and determines its location based on the actorís nested location and its own foundIn property. It uses information provided by its foundIn property and its leadsTo property to determine the destination of the object for any given location it currently occupies.


FloatingDestination class provides a superclass for Passage, Door, Gate, and Connector classes. These objects behave much like their Destination counterparts, except that they ďfloatĒ with the actor, moving to their locations according to the rules for Floating objects.


This class allows an author to define a Door, an object that simulates the behaviour of paired Doorway objects. For example, the Doorways above could be more compactly defined using a single Door object:


hallDoor: Door

††† foundIn = [ hallway, kitchen ]

††† sDesc = "hall door"

††† noun = 'door'

††† adjective = 'hall'



With FloatingDestination class we donít need to code an otherSide. The object automatically keeps its other side(s) in synch using the foundIn and leadsTo properties. Coding leadsTo is also unnecessary in our example. When the Door is found in the hallway, it leads to the kitchen; when found in the kitchen, it leads to the hallway. Whenever an object returns only two locations in its foundIn property and these locations lead to each other then the leadsTo property doesnít need to be coded.



FloatingDestination objects are Floating objects that determine

their destinations using their foundIn and leadsTo properties



If, however, our Door was found in both the hallway and the kitchen, but its kitchen location lead to the entryway then we would need to code the leadsTo property, like this:



* When the actor is is the hallway the door leads to the kitchen,

* but from the kitchen the door leads to the entryway!


hallDoor: Door

††† foundIn = [ hallway, kitchen ]

††† leadsTo = [ kitchen, entryway ]

††† sDesc = "hall door"

††† noun = 'door'

††† adjective = 'hall'



Also, using this technique the Door object could be defined for multiple locations:


multiDoor: Door

††† foundIn = [ entryway, hallway, kitchen ]

††† leadsTo = [ hallway, kitchen, entryway ]

††† sDesc = "multi door"

††† noun = 'door'

††† adjective = 'multi'



This door appears in the entryway, hallway, and kitchen when the actor occupies each of these Rooms. From the entryway it leads to the hallway; from the hallway it leads to the kitchen; and from the kitchen it leads to the entryway.


The next step, of course, is to code up the Room directions to point to the multiDoor object. Notice that we cannot assign the multiDoor to go from the hallway into either the entryway or the kitchen depending upon the travel direction properties of the Rooms. This leads to an important rule:



A FloatingDestination provides only one destination for any given location




Hence you will need to have one door object for each separate destination from any given location.