Contents
Back
Forward

22. Describing objects and rooms


And we were angry and poor and happy,
And proud of seeing our names in print.

...G. K. Chesterton (1874--1936), A Song of Defeat

Talking to the player about the state of the world is much easier than listening to his intentions for it. Despite this, the business of description takes up a fair part of Chapter V since the designer of a really complex game will eventually need to know almost every rule involved. (Whereas nobody would want to know everything about the parser.)

To begin, the simplest description is the "short name'' given to a single object. For instance

    print (a) brass_lamp;
may result in "an old brass lamp'' being printed. There are four such forms of print:
print (the) obj Print the object with its definite article
print (The) obj The same, but capitalised
print (a) obj Print the object with indefinite article
print (name) obj Print the object's short name alone

and these can be freely mixed into lists of things to print or print_ret, as for example:

    print_ret "The ogre declines to eat ", (the) noun, ".";

??EXERCISE 49:
(link to
the answer)
(By Gareth Rees.) When referring to animate objects, one usually needs to use pronouns such as "his''. Define new printing routines so that, say, print "You throw the book at ", (PronounAcc) obj, "!"; will insert the right accusative pronoun.

/\/\ There is also a special syntax print object for printing object names, but do not use it without good reason: it doesn't understand some of the features below and is not protected against crashing if you mistakenly try to print the name for an out of range object number.

Inform tries to work out the right indefinite article for any object automatically. In English-language games, it uses 'an' when the short name starts with a vowel and 'a' when it does not (unless the name is plural, when 'some' is used in either case). You can override this by setting article yourself. Here are some possibilities:

a / platinum bar, an / orange balloon, your / Aunt Jemima,
some bundles of / reeds, far too many / marbles, The / London Planetarium
If the object is given the attribute proper then its name is treated as a proper noun with no indefinite article, so the value of article is ignored.

/\ The article property can also hold a routine to print one.

Definite articles are always "the'' (except for proper nouns). Thus

the platinum bar, Benjamin Franklin, Elbereth
are all printed by print (the) ...; the latter two objects being proper.

/\ There's usually no need to worry about definite and indefinite articles for room objects, as Inform never has cause to print them.

A single object whose name is plural, such as "grapes'' or "marble pillars'', should be given the attribute pluralname. As a result the library might say, e.g., "You can't open those" instead of "You can't open that". It also affects the pronoun "them'' and makes the usual indefinite article "some''.

/\ You can give animate objects the attributes male, female or neuter to help the parser understand pronouns properly. animate objects are assumed to be male if you set neither alternative.

The short name of an object is normally the text given in double-quotes at the head of its definition. This is very inconvenient to change during play when, for example, "blue liquid'' becomes "purple liquid'' as a result of a chemical reaction. A more flexible way to specify an object's short name is with the short_name property. To print the name of such an object, Inform does the following:

1. -- If the short_name is a string, it's printed and that's all.

2. -- If it is a routine, then it is called. If it returns true, that's all.

3. -- The text given in the header of the object definition is printed.

For example, the dye might be given:

short_name
[;   switch(self.colour)
     {   1: print "blue ";
         2: print "purple ";
         3: print "horrid sludge"; rtrue;
     }
],
with "liquid" as the short name in its header. According to whether its colour property is 1, 2 or 3, the printed result is "blue liquid'', "purple liquid'' or "horrid sludge''.

/\ Alternatively, define the dye with short_name "blue liquid" and then simply execute dye.short_name = "purple liquid"; when the time comes.

/\ Rooms can also be given a short_name routine, which is useful to code, say, a grid of four hundred similar locations called "Area 1" up to "Area 400". (They can be represented by just one object in the program.)

For many objects the indefinite article and short name will most often be seen in inventory lists, such as

>i
You are carrying:
  a leaf of mint
  a peculiar book
  your satchel (which is open)
    a green cube
Some objects, though, ought to have fuller entries in an inventory: a wine bottle should say how much wine is left, for instance. The invent property is designed for this. The simplest way to use invent is as a string. For instance, declaring a peculiar book with
    invent "that harmless old book of Geoffrey's",
will make this the inventory line for the book. In the light of events, it could later be changed to
    geoffreys_book.invent = "that lethal old book of Geoffrey's";

/\ Note that this string becomes the whole inventory entry: if the object were an open container, its contents wouldn't be listed, which might be unfortunate. In such circumstances it's better to write an invent routine, and that's also the way to append text like "(half-empty)''.

/\ Each line of an inventory is produced in two stages. First, the basic line:

1a. -- The global variable inventory_stage is set to 1.

1b. -- The invent routine is called (if there is one). If it returns true, stop here.

1c. -- The object's indefinite article and short-name are printed.

Second, little informative messages like "(which is open)" are printed, and inventories are given for the contents of open containers:

2a. -- The global variable inventory_stage is set to 2.

2b. -- The invent routine is called (if there is one). If it returns true, stop here.

2c. -- A message such as "(closed, empty and providing light)'' is printed, as appropriate.

2d. -- If it is an open container, its contents are inventoried.

After each line is printed, linking text such as a new-line or a comma is printed, according to the current "list style''.

For example, here is the invent routine used by the matchbook in 'Toyshop':

invent
[ i; if (inventory_stage==2)
     {   i=self.number;
         if (i==0) print " (empty)";
         if (i==1) print " (1 match left)";
         if (i>1)  print " (",i," matches left)";
     }
],

??/\/\EXERCISE 50:
(link to
the answer)
Suppose you want to change the whole inventory line for an ornate box but you can't use an invent string, or return true from stage 1, because you still want stage 2d to happen properly (so that its contents will be listed). How can you achieve this?

The largest and most complicated messages Inform ever prints on its own initiative are room descriptions, printed when the Look action is carried out (for instance, when the statement <Look>; triggers a room description). What happens is: the room's short name is printed (usually in bold-face) on a line of its own, then its description, followed by a list of the objects residing there which aren't concealed or scenery.

Chapter IV mentioned many different properties -- initial, when_on, when_off and so on -- giving descriptions of what an object looks like when in the same room as the player; some apply to doors, others to switchable objects and so on. All of them can be routines to print text, instead of being strings to print. The precise rules are given below.

But the whole system can be bypassed using the describe property. If an object gives a describe routine then this takes priority over everything: if it returns true, the library assumes that the object has already been described, and prints nothing further. For example,

    describe
    [;  "^The platinum pyramid catches the light beautifully.";
    ];
means that even when the pyramid has been moved (i.e. held by the player at some stage) it will always have its own line of room description.

/\ Note the initial ^ (new-line) character. The library doesn't print a skipped line itself before calling describe because it doesn't know yet whether the routine will want to say anything. A describe routine which prints nothing and returns true makes an object invisible, as if it were concealed.

/\/\ The Look action does three things: it 'notes arrival', prints the room description then 'scores arrival'. Only the printing rules are given here (see Section 20 for the others), but they're given in full. In what follows, the word 'location' means the room object if there's light to see by, and the special "Darkness'' object otherwise. First the top line:

1a. -- A new-line is printed. The location's short name is printed (in bold-face, if possible).

1b. -- If the player is on a supporter, then " (on <something>)'' is printed; if inside anything else, then " (in <something>)''.

1c. -- " (as <something>)'' is printed if this was requested by the game's most recent call to ChangePlayer (for instance, " (as a werewolf)'').

1d. -- A new-line is printed.

Now the 'long description'. This step is skipped if the player has just moved of his own will into a location already visited, unless the game is in "verbose" mode.

2. -- If the location has a describe property, then run it. If not, look at the location's description property: if it's a string, print it; if it's a routine, run it.

All rooms must provide either a describe property or a description of themselves. Now for items nearby:

3a. -- List any objects on the floor.

3b. -- If the player is in or on something, list the other objects in that.

The library has now finished, but your game gets a chance to add a postscript:

4. -- Call the entry point LookRoutine.

/\ The visited attribute is only given to a room after its description has been printed for the first time (it happens during 'scoring arrival'). This is convenient for making the description different after the first time.

/\ 'Listing objects' (as in 3a and 3b) is a complicated business. Some objects are given a line or paragraph to themselves, others are lumped together in a list at the end. The following objects are not mentioned at all: the player, what the player is in or on (if anything) and anything which is scenery or concealed. The remaining objects are looked through (eldest first) as follows:

1. -- If the object has a describe routine, run it. If it returns true, stop here and don't mention the object at all.

2. -- Work out the "description property'' for the object:

-- a. -- For a container, this is when_open or when_closed;

-- b. -- Otherwise, for a switchable object this is when_on or when_off;

-- c. -- Otherwise, for a door this is when_open or when_closed;

-- d. -- Otherwise, it's initial.

3. -- If either the object doesn't have this property or the object has been held by the player before (i.e., has moved) and the property isn't when_off or when_closed then then the object will be listed at the end.

4. -- Otherwise a new-line is printed and the property is printed (if it's a string) or run (if it's a routine).

/\ A supporter which is scenery won't be mentioned, but anything on top of it which is not concealed will be.

/\ Objects which have just been pushed into a new room are not listed in that room's description on the turn in question. This is not because of any rule about room descriptions, but because the pushed object is moved into the new room only after the room description is made. This means that when a wheelbarrow is pushed for a long distance, the player does not have to keep reading "You can see a wheelbarrow here.'' every move, as though that were a surprise.

/\ You can use a library routine called Locale to perform 'object listing'. See Appendix A7 for details: suffice to say here that the process above is equivalent to executing
    if (Locale(location, "You can see", "You can also see"))
        print " here.^";
Locale is useful for describing areas of a room which are sub-divided off, such as the stage of a theatre.

??/\/\EXERCISE 51:
(link to
the answer)
The library implements "superbrief'' and "verbose'' modes for room description (one always omits long room descriptions, the other never does). How can verbose mode automatically print room descriptions every turn? (Some of the later Infocom games did this.)

*REFERENCES:
'Balances' often uses short_name, especially for the white cubes (whose names change) and lottery tickets (whose numbers are chosen by the player). 'Adventureland' uses short_name in simpler ways: see the bear and the bottle, for instance.
The scroll class of 'Balances' uses invent.
See the ScottRoom class of 'Adventureland' for a radically different way to describe rooms (in pidgin English, like telegraphese).

Contents / Back / Forward
Chapter I / Chapter II / Chapter III / Chapter IV / Chapter V / Chapter VI / Appendix
Mechanically translated to HTML from third edition as revised 16 May 1997. Copyright © Graham Nelson 1993, 1994, 1995, 1996, 1997: all rights reserved.