DM4 §26: Describing objects and rooms

## §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:

- (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 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:

- (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`, or a `supporter`, or is `transparent`, then 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 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:

- (1a) A new-line is printed. The short name of the visibility ceiling is printed, using emphasised type, which on most models of computer appears as bold face.
- (1b) If the player is on a `supporter`, then “ (on ‹something›)” is printed; if inside something (other than the visibility ceiling), 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)”. (See §21 for details of `ChangePlayer`.)
- (1d) A new-line is printed.

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.

- (2a) Starting with the visibility ceiling and working down through “levels” of `enterable` objects containing the player, a long description is printed, as follows:
  1. If the level is the current value of `location`, that is, the current room or else `thedark`, then: if `location` provides `describe` then the message `location.describe()` is sent. If not, then `location.description()` is sent. Every room is required to provide one or the other. (This is now redundant. In earlier Informs, `description` could only be a string, so `describe` was there in case a routine was needed.)
  2. If not, the level must be an enterable object `E`. If `E` provides it, the message `E.inside_description()` is sent.
- (2b) After the description of each visibility level, the objects contained in that level are “listed” (see below).

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

- (3) The entry point `LookRoutine` is called.

▲▲ 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).