§26   Describing objects and rooms

Talking about the state of the world is much easier than listening to the player's intentions for it. Despite this, the business of description takes up a fair part of this chapter 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.)

The simplest description of an object is its “short name”. 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:

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

EXERCISE 62
When referring to animate objects, you sometimes need to use pronouns such as “him”. Define new printing routines so that print "You throw the book at ", (PronounAcc) obj, "!"; will insert the right accusative pronouns.

▲▲ 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 object that doesn't exist.

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, either to some text or a routine to print some. Here are some possibilities, arranged as “article / name”:

“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 taking no article, so the value of article is ignored. Objects representing named people usually have proper, and so might a book like “Whitaker's Almanac”.

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.

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”. As mentioned above, the indefinite article becomes “some”, and the player can use the pronoun “them” to refer to the object, so for instance “take them” to pick up the grapes-object.

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.

There's usually no need to worry about definite and indefinite articles for room objects, as the standard Inform rules never print them.

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:

For example, the dye might be defined with:

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.

EXERCISE 63
Design a chessboard of sixty-four locations with a map corresponding to an eight-by-eight grid, so that White advances north towards Black, with pieces placed on the board according to a game position. Hint: using flexible routines for short_name, this can be done with just two objects, one representing all sixty-four squares, the other representing all thirty-two pieces.

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

>inventory
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 with a statement like:

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:

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

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 64
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 the Inform library 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 emphasised in bold-face, then the description, followed by a list of the objects residing there which aren't concealed or scenery.

Chapter III 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.";
],

Unlike an initial description, this is still seen even if the pyramid has moved, i.e., been held by the player at some stage.

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.

▲▲ Here is exactly how a room description is printed. Recall from §21 that location holds the player's location if there is light, and thedark if not, and see §21 for the definition of “visibility ceiling”, which roughly means the outermost thing the player can see: normally the location, but possibly a closed opaque container which the player is inside. First the top line:

Now the long description. This step is sometimes skipped, depending on which “look mode” the player has chosen: in the normal mode, it is skipped if the player has just moved by a Go action into a location already visited; in “superbrief” mode it is always skipped, while in “verbose” mode it is never skipped.

The library has now finished, but your game gets a chance to add a postscript by means of an entry point routine:

▲▲ Besides printing room descriptions, the Look action has side-effects: it can award the player some points, or mark a room with the attribute visited. For these rules in full, see §21.

▲▲ The visited attribute is only given to a room after its description has been printed for the first time. This is convenient for making the description different after the first time.

▲▲ When “listing objects” (as in 3a and 3b above) some objects are given a paragraph to themselves, while 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), because this has been taken care of in the short or long description already; and anything which has the attributes 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:
    1. For a container, this is when_open or when_closed;
    2. Otherwise, for a switchable object this is when_on or when_off;
    3. Otherwise, for a door this is when_open or when_closed;
    4. Otherwise, it's initial.
  3. If either the object doesn't provide this property or the object has moved and the property isn't when_off or when_closed then the object will be listed at the end, not given a paragraph of its own.
  4. Otherwise a new-line is printed and the property is printed (if it's a string) or run (if it's a routine). If it is a routine, it had better print something, as otherwise there will be a spurious blank line in the room description.

Note that although a supporter which is scenery won't be mentioned, anything on top of it may well be. If this is undesirable, set these objects on top to be concealed.

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 §A3 for details, but 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 while remaining part of the same location, such as the stage of a theatre.

▲▲ EXERCISE 65
As mentioned above, 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, owing to an extreme shortage of memory to store text – Scott Adams was obliged to write for machines with under 16K of free memory).