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’.