DM4 §5: Introducing messages and classes

## §5 Introducing messages and classes

> On a round ball
> A workman that hath copies by, can lay
> An Europe, Afrique and an Asia,
> And quickly make that, which was nothing, All.
> — John Donne (1571?–1631), Valediction: Of Weeping

Though §4 was a little vague in saying “the library asks the mushroom if it would like to react”, something basic was happening in Inform terms: the object `InformLibrary` was sending the message `before` to the object `mushroom`. Much more on how actions take place in §6, but here is roughly what the library does if the player types “eat mushroom”:

    if (mushroom.before() == false) {
        remove mushroom;
        if (mushroom.after() == false)
            print "You eat the mushroom. Not bad.^";
    }

The library sends the message `before` to ask the `mushroom` if it minds being eaten; then, if not, it consumes the mushroom; then it sends the message `after` to ask if the mushroom wishes to react in some way; then, if not, it prints the usual eating-something text. In response to the messages `before` and `after`, the mushroom is expected to reply either `true`, meaning “I'll take over from here”, or `false`, meaning “carry on”.

Most of the other properties in §4 are also receiving messages. For example, the message

    mushroom.description();

is sent when the player tries to examine the mushroom: if the reply is `false` then the library prints “You see nothing special about the speckled mushroom.” Now the mushroom was set up with

    description
        "The mushroom is capped with blotches, and you aren't at all
        sure it's not a toadstool.",

which doesn't look like a rule for receiving a message, but it is one all the same: it means “print this text out, print a new-line and reply `true`”. A more complicated rule could have been given instead, as in the following elaboration of the stone-cut steps in ‘Ruins’:

    description [;
        print "The cracked and worn steps descend into a dim chamber.
               Yours might ";
        if (Square_Chamber hasnt visited)
            print "be the first feet to tread";
        else print "have been the first feet to have trodden";
        " them for five hundred years. On the top step is inscribed
        the glyph Q1.";
    ],

`visited` is an attribute which is currently held only by rooms which the player has been to. The glyphs will come into the game later on.

The library can send out about 40 different kinds of message, `before`and `description` being two of these. The more interesting an object is, the more ingeniously it will respond to these messages. An object which ignores all incoming messages will be lifeless and inert in play, like a small stone.

▲ Some properties are just properties, and don't receive messages. Nobody ever sends a `name` message, for instance: the `name` property is just what it seems to be, a list of words.

· · · · ·

So the library is sending out messages to your objects all the time during play. Your objects can also send each other messages, including “new” ones that the library would never send. It's sometimes convenient to use these to trigger off happenings in the game. For example, one way to provide hints in ‘Ruins’ might be to include a macaw which squawks from time to time, for a variety of reasons:

    Object -> macaw "red-tailed macaw"
      with name 'red' 'tailed' 'red-tailed' 'macaw' 'bird',
           initial "A red-tailed macaw eyes you from an upper branch.",
           description "Beautiful plumage.",
           before [;
               Take: "The macaw flutters effortlessly out of reach.";
           ],
           squawk [ utterance;
               if (self in location)
                   print "The macaw squawks, ~", (string) utterance,
                         "! ", (string) utterance, "!~^^";
           ],
      has  animate;

(For the final version of ‘Ruins’ the designer thought better of the macaw and removed it, but it still makes a good example.) We might then, for instance, change the `after` rule for dropping the mushroom to read:

    Drop: macaw.squawk("Drop the mushroom");
          "The mushroom drops to the ground, battered slightly.";

so that the maddening creature would squawk “Drop the mushroom! Drop the mushroom!” each time this was done. At present it would be an error to send a `squawk` message to any object other than the macaw, since only the macaw has been given a rule telling it what to do if it receives one.

· · · · ·

In most games there are groups of objects with certain rules in common, which it would be tiresome to have to write out many times. For making such a group, a class definition is simpler and more elegant. These closely resemble object definitions, but since they define prototypes rather than actual things, they have no initial location. (An individual tree may be somewhere, but the concept of being a tree has no particular place.) So the ‘header’ part of the definition is simpler.

For example, the scoring system in ‘Ruins’ works as follows: the player, an archaeologist of the old school, gets a certain number of points for each ‘treasure’ (i.e., cultural artifact) he can filch and put away into his packing case. Treasures clearly have rules in common, and the following class defines them:

    Class Treasure
      with cultural_value 5, photographed_in_situ false,
           before [;
               Take, Remove:
                   if (self in packing_case)
                       "Unpacking such a priceless artifact had best wait
                       until the Carnegie Institution can do it.";
                   if (self.photographed_in_situ == false)
                       "This is the 1930s, not the bad old days. Taking an
                       artifact without recording its context is simply
                       looting.";
               Photograph:
                   if (self has moved)
                       "What, and fake the archaeological record?";
                   if (self.photographed_in_situ)
                       "Not again.";
           ],
           after [;
               Insert:
                   if (second == packing_case)
                   {   score = score + self.cultural_value;
                       "Safely packed away.";
                   }
               Photograph: self.photographed_in_situ = true;
           ];

(The packing case won't be defined until §12, which is about containers.) Note that `self` is a variable, which always means “whatever object I am”. If we used it in the definition of the mushroom it would mean the mushroom: used here, it means whatever treasure happens to be being dealt with. Explanations about `Insert` and `Remove` will come later (in §12). The action `Photograph` is not one of the standard actions built in to the library, and will be added to ‘Ruins’ in the next section.

An object of the class `Treasure` automatically inherits the properties and attributes given in the class definition. Here for instance is an artifact which will eventually be found in the Stooped Corridor of ‘Ruins’:

    Treasure -> statuette "pygmy statuette"
      with name 'snake' 'mayan' 'pygmy' 'spirit' 'precious' 'statuette',
           description
              "A menacing, almost cartoon-like statuette of a pygmy spirit
               with a snake around its neck.",
           initial "A precious Mayan statuette rests here!";

From `Treasure`, this statuette inherits a `cultural_value` score of 5 and the rules about taking and dropping treasures. If it had itself set `cultural_value` to 15, say, then the value would be 15, because the object's actual definition always takes priority over anything the class might have specified. Another of the five ‘Ruins’ treasures, which will be found in the Burial Shaft, has a subtlety in its definition:

    Treasure -> honeycomb "ancient honeycomb"
      with article "an",
           name 'ancient' 'old' 'honey' 'honeycomb',
           description "Perhaps some kind of funerary votive offering.",
           initial
              "An exquisitely preserved, ancient honeycomb rests here!",
           after [;
               Eat: "Perhaps the most expensive meal of your life.
                   The honey tastes odd, perhaps because it was used to
                   store the entrails of the Lord buried here, but still
                   like honey.";
           ],
      has  edible;

The subtlety is that the honeycomb now has two `after` rules: a new one of its own, plus the existing one that all treasures have. Both apply, but the new one happens first.

▲▲ So comparing `cultural_value` and `after`, there seems to be an inconsistency. In the case of `cultural_value`, an object's own given value wiped out the value from the class, but in the case of `after`, the two values were joined up into a list. Why? The reason is that some of the library's properties are “additive”, so that their values accumulate into a list when class inheritance takes place. Three useful examples are `before`, `after` and `name`.

▲▲ Non-library properties you invent (like `squawk` or `cultural_value`) will never be additive, unless you declare them so with a directive like

    Property additive squawk;

before `squawk` is otherwise mentioned. (Or you could imitate similar kinds of inheritance using the superclass operator.)

• REFERENCES
See ‘Balances’ for an extensive use of message-sending. The game defines several complicated classes, among them the white cube, spell and scroll classes. •‘Advent’ has a treasure-class similar to this one, and uses class definitions for the many similar maze and dead-end rooms, as well as the sides of the fissure. •‘Toyshop’ contains one easy class (the wax candles) and one unusually hard one (the building blocks). •Class definitions can be worthwhile even when as few as two objects use them, as can be seen from the two kittens in ‘Alice Through the Looking-Glass’.