< Previous page    Contents    Next page >

The batteries are in the radio: How objects relate to each other

How does Inform know that one room contains certain objects, another room contains others, and that the player is carrying yet others? Through the concept of the "object tree." Actually, there are several trees in an Inform game, so you might think of the game as an "object forest."

The object tree, like most trees in programming, is upside-down (like a family tree). Its root is at the top and its branches extend downward. Usually the root of an object tree is a room, but it is possible that some objects may be removed from all rooms and therefore become roots themselves.

When an object is located in (or possessed by) another object, the possessing object is called a parent. The objects being possessed are called children, but if you ask a parent what its child is, it will only reply with one object: the object that it most recently acquired. While this may make it seem like you would have no way of determining all the objects that a given object possesses, rest assured that you can. There are 4 functions which are used to determine the relationship of objects to each other:

parent(SomeObject)You provide the object for which you wish to determine the parent, and this function returns a reference to that object.
child(SomeObject)You provide the object for which you wish to determine the current child, and this function returns a reference to that object.
sibling(SomeObject)This function takes a given object and returns a reference to its sibling, that is, another object which shares the same parent.
children(SomeObject)This function returns the number of immediate children an object has. If those child objects themselves have children, their children are not counted.

Therefore, the children of an object could be determined by first calling child(ParentObj) and then calling sibling(ChildObj) first for the object returned by child() and then once for every object returned by sibling(). Fortunately, there is an easier way to do this: the in operator. We'll use this in an example later when we enter a really warm room.

Remember that if an object has multiple children, each child returns a reference to the same object when used in the parent() function (they all have the same parent), but the parent object only returns a reference to one object when used in the child() function.

When an object has no parent, child, or sibling, the respective functions will return the special value nothing. The sibling() function will return nothing when called with the last object a parent posesses.

Let's add an object to the Boring Room. (Yikes, it might not be so boring anymore!) Add this code to your file, after the room itself:

Object   RedButton "red button" BoringRoom
   with  name "red" "button",
         describe "A red button protrudes from one of the walls."
   has   static;
Change the description of the room to this:
         description "What a terribly boring room. The wood panelling is
         boring, the baseboard is boring, everything's boring."
Compile and play your super-enhanced game! It's still pretty dull, isn't it? You can't even push the button! (To do that requires intervening when the object is told it is being pushed, which requires a routine, which we'll cover in the next chapter.)

The object tree for the Boring Room now looks like this:

Tree diagram 1

Doesn't really look like a tree, does it? Once the game starts and the player is placed in the Boring Room, the tree looks like this:

Tree diagram 2

Notice how the player object is now the direct child of BoringRoom. This is because player was the last thing to be placed in the room. RedButton was put there during compilation, but player did not enter until the Initialise() routine executed. The RedButton object's parent is still BoringRoom, as the dotted arrow shows. parent(RedButton) would return BoringRoom. child(BoringRoom) would return player. sibling(player) would return RedButton. sibling(RedButton) would return nothing.

In the following diagrams I will omit the labels "parent, " "child," and "sibling," and also the "parent" arrows.

Let's take a look into the future and see the object tree of the game after we add three more rooms:

Tree diagram 3

It's looking a little more like a tree now. I show you this because this sample game is going to include a small puzzle: The player is trying to get to the kitchen to have some bread and butter with the chocolate for dessert. However, he must pass through the Warm Room first, and if the butter and/or chocolate are not protected, they will melt. When this happens, they will be taken out of play by issuing the statements

remove butter;
remove chocolate;
Tree diagram 4

The remove statement causes an object to have no parent, or more specifically, causes the object's parent to be nothing. You must use the remove statement to accomplish this, however; "move <object> to nothing" will not work. Since these objects have no parent, they will become trees. They will no longer be located in any room, and will effectively disappear. It is important to note that they are not destroyed, and can be brought back into play with a simple move statement.

Oops! I haven't covered the move statement, have I? Let's fix that right now. move puts an object into another object. This means that move changes the parent of an object. All subobjects (children) of the moved object go along with it. The syntax of move is as follows:

move <object> to <NewParent>;
Let's say I want the table to vanish from the kitchen and materialize in the room the player is in. I simply do this:
move table to location;
The above code is not perfect, because I should really test whether the player is in a dark room or not. I'll demonstrate that in two chapters when I talk about if. In the meantime, you get the idea how move works. Let's give the player his two foodstuffs. We'll declare a new attribute which will come into play later. Put the following line above the definition of BoringRoom:
Attribute soft;
It's not absolutely necessary to place attribute definitions near the beginning of the file, but since they are available to all objects (they're global), it's good programming practice to declare them early. Now add these object definitions after RedButton:
Object   chocolate "chocolate bar"
   with  name "chocolate" "bar",
         description "It looks delicious. You're tempted to eat it right now."
   has   edible soft;

Object   butter "stick of butter"
   with  name "stick" "of" "butter"
   has   soft;
Finally, add these lines to the Initialise() routine (in my file I put it after the assignment of location):
   move chocolate to player;
   move butter to player;
Compile and run your game. Eat the chocolate. Don't worry; it has no calories. Try to eat the butter. You shouldn't be able to. That's because only the chocolate was given the edible attribute. That's all you need to do to allow the player to eat something. In fact, the player can eat anything with the edible attribute as long as it can be taken, so if FryingPan has edible, you can easily get your daily recommended allowance of iron.

< Previous page    Contents    Next page >


This page hosted by Get your own Free Home Page

And yes, folks, it's really free. I'm too cheap to pay for this. 1