DM4 §6: Actions and reactions

## §6 Actions and reactions

> Only the actions of the just
> Smell sweet and blossom in their dust.
> — James Shirley (1594–1666),
> — The Contention of Ajax and Ulysses

> [Greek is] a language obsessed with action, and with the joy of seeing action multiply from action, action marching relentlessly ahead and with yet more actions filing in from either side to fall into neat step at the rear, in a long straight rank of cause and effect, to what will be inevitable, the only possible end.
> — Donna Tartt, The Secret History

Inform is a language obsessed with actions. An ‘action’ is an attempt to perform one simple task: for instance,

    Inv    Take sword    Insert gold_coin cloth_bag

are all examples. Here the actual actions are `Inv` (inventory), `Take` and `Insert`. An action has none, one or two objects supplied with it (or, in a few special cases, some numerical information rather than objects). It also has an “actor”, the person who is to perform the action, usually the player. Most actions are triggered off by the game's parser, whose job can be summed up as reducing the player's keyboard commands to actions: “take my hat off”, “remove bowler” or “togli il cappello” (if in an Italian game) might all cause the same action. Some keyboard commands, like “drop all”, cause the parser to fire off whole sequences of actions: others, like “empty the sack into the umbrella stand”, cause only a single action but one which may trigger off an avalanche of other actions as it takes place.

An action is only an attempt to do something: it may not succeed. Firstly, a `before` rule might interfere, as we have seen already. Secondly, the action might not even be very sensible. The parser will happily generate the action `Eat iron_girder` if the player asked to do so in good English. In this case, even if no `before` rule interferes, the normal game rules will ensure that the girder is not consumed.

Actions can also be generated by your own code, and this perfectly simulates the effect of a player typing something. For example, generating a `Look` action makes the game produce a room description as if the player had typed “look”. More subtly, suppose the air in the Pepper Room causes the player to sneeze each turn and drop something at random. This could be programmed directly, with objects being moved onto the floor by explicit move statements. But then suppose the game also contains a toffee apple, which sticks to the player's hands. Suddenly the toffee apple problem has an unintended solution. So rather than moving the objects directly to the floor, the game should generate `Drop` actions, allowing the game's rules to be applied. The result might read:

You sneeze convulsively, and lose your grip on the toffee apple…
The toffee apple sticks to your hand!

which is at least consistent.

As an example of causing actions, an odorous `low_mist` will soon settle over ‘Ruins’. It will have the description “The mist carries an aroma reminisicent of tortilla.” The alert player who reads this will immediately type “smell mist”, and we want to provide a better response than the game's stock reply “You smell nothing unexpected.” An economical way of doing this is to somehow deflect the action `Smell low_mist` into the action `Examine low_mist` instead, so that the “aroma of tortilla” message is printed in this case too. Here is a suitable `before` rule to do that:

    Smell: <Examine self>; rtrue;

The statement <Examine self> causes the action `Examine low_mist` to be triggered off immediately, after which whatever was going on at the time resumes. In this case, the action `Smell low_mist` resumes, but since we immediately return `true` the action is stopped dead.

Causing an action and then returning `true` is so useful that it has an abbreviation, putting the action in double angle-brackets. For example, the following could be added to ‘Ruins’ if the designer wanted to make the stone-cut steps more enticing:

    before [;
        Search: <<Enter self>>;
    ],

If a player types “search steps”, the parser will produce the action `Search steps` and this rule will come into play: it will generate the action `Enter steps` instead, and return `true` to stop the original `Search` action from going any further. The net effect is that one action has been diverted into another.

· · · · ·

At any given time, just one action is under way, though others may be waiting to resume when the current one has finished. The current action is always stored in the four variables

    actor    action    noun    second

`actor`, `noun` and `second` hold the objects involved, or the special value `nothing` if they aren't involved at all. (There's always an `actor`, and for the time being it will always be equal to `player`.) `action` holds the kind of action. Its possible values can be referred to in the program using the `##` notation: for example

    if (action == ##Look) ...

tests to see if the current `action` is a `Look`.

▲ Why have `##` at all, why not just write `Look`? Partly because this way the reader of the source code can see at a glance that an action type is being referred to, but also because the name might be used for something else. For instance there's a variable called `score` (holding the current game score), quite different from the action type `##Score`.

▲▲ For a few actions, the ‘noun’ (or the ‘second noun’) is actually a number (for instance, “set timer to 20” would probably end up with `noun` being `timer` and `second` being 20). Occasionally one needs to be sure of the difference, e.g., to tell if `second` is holding a number or an object. It's then useful to know that there are two more primitive variables, `inp1` and `inp2`, parallel to `noun` and `second` and usually equal to them – but equal to 1 to indicate “some numerical value, not an object”.

· · · · ·

The library supports about 120 different actions and most large games will add some more of their own. The full list, given in Table 6, is initially daunting, but for any given object most of the actions are irrelevant. For instance, if you only want to prevent an object from entering the player's possession, you need only block the `Take` action, unless the object is initially in something or on something, in which case you need to block `Remove` as well. In the author's game ‘Curses’, one exceptional object (Austin, the cat) contains rules concerning 15 different actions, but the average is more like two or three action-rules per object.

The list of actions is divided into three groups, called Group 1, Group 2 and Group 3:

1. Group 1 contains ‘meta’ actions for controlling the game, like `Score` and `Save`, which are treated quite differently from other actions as they do not happen in the “model world”.
2. Actions in group 2 normally do something to change the state of the model world, or else to print important information about it. `Take` (“pick up”) and `Inv` (“inventory”) are examples of each. Such actions will affect any object which doesn't block them with a `before` rule.
3. Finally, group 3 actions are the ones which normally do nothing but print a polite refusal, like `Pull` (“it is fixed in place”), or a bland response, like `Listen` (“you hear nothing unexpected”). Such actions will never affect any object which doesn't positively react with a `before` rule.

▲ Some of the group 2 actions can be ignored by the programmer because they are really only keyboard shorthands for the player. For example, `<Empty rucksack table>` means “empty the contents of the rucksack onto the table” and is automatically broken down into a stream of actions like `<Remove fish rucksack>` and `<PutOn fish table>`. You needn't write rules concerning `Empty`, only `Remove` and `PutOn`.

▲▲ Most of the library's group 2 actions are able to “run silently”. This means that if the variable `keep_silent` is set to `true`, then the actions print nothing in the event of success. The group 2 actions which can't run silently are exactly those ones whose successful operation does nothing but print: `Wait`, `Inv`, `Look`, `Examine`, `Search`.

•▲ EXERCISE 3
“The door-handle of my room… was different from all other door-handles in the world, inasmuch as it seemed to open of its own accord and without my having to turn it, so unconscious had its manipulation become…” (Marcel Proust). Use silent-running actions to make an unconsciously manipulated door: if the player tries to pass through when it's closed, print “(first opening the door)” and do so. (You need to know some of §13, the section on doors, to answer this.)

•▲▲ EXERCISE 4
Now add “(first unlocking the door with…)”, automatically trying to unlock it using either a key already known to work, or failing that, any key carried by the player which hasn't been tried in the lock before.

· · · · ·

▲ Some actions happen even though they don't arise directly from anything the player has typed. For instance, an action called `ThrownAt` is listed under group 3 in Table 6. It's a side-effect of the ordinary `ThrowAt` action: if the player types “throw rock at dalek”, the parser generates the action `ThrowAt rock dalek`. As usual the rock is sent a `before` message asking if it objects to being thrown at a Dalek. Since the Dalek may also have an opinion on the matter, another `before` message is sent to the Dalek, but this time with the action `ThrownAt`. A dartboard can thus distinguish between being thrown, and having things thrown at it:

    before [;
        ThrowAt: "Haven't you got that the wrong way round?";
        ThrownAt:
            if (noun==dart) {
                move dart to self;
                if (random(31)==1)
                    print (string) random("Outer bull", "Bullseye");
                else {
                    print (string) random("Single", "Double", "Triple");
                    print " ", (number) random(20);
                }
                "!";
            }
            move noun to location;
            print_ret (The) noun, " bounces back off the board.";
    ],

Such an imaginary action – usually, as in this case, a perfectly sensible action seen from the point of view of the second object involved, rather than the first – is sometimes called a “fake action”. Two things about it are fake: there's no grammar that produces `ThrownAt`, and there's no routine called `ThrownAtSub`. The important fake actions are `ThrownAt`, `Receive` and `LetGo`, the latter two being used for containers: see §12.

▲ If you really need to, you can declare a new fake action with the directive `Fake_action` ‹Action-name›`;`. You can then cause this action with `<` and `>` as usual.

•▲▲ EXERCISE 5
`ThrownAt` would be unnecessary if Inform had an idea of `before` and `after` routines which an object could provide if it were the second noun of an action. How might this be implemented?

▲▲ Very occasionally, in the darker recesses of §18 for instance, you want “fake fake actions”, actions which are only halfway faked in that they still have action routines. Actually, these are perfectly genuine actions, but with the parser's grammar jinxed so that they can never be produced whatever the player types.

· · · · ·

The standard stock of actions is easily added to. Two things are necessary to create a new action: first one must provide a routine to make it happen. For instance:

    [ BlorpleSub;
      "You speak the magic word ~Blorple~. Nothing happens.";
    ];

Every action has to have a “subroutine” like this, the name of which is always the name of the action with `Sub` appended. Secondly, one must add grammar so that `Blorple` can actually be called for. Far more about grammar in Chapter IV: for now we add the simplest of all grammar lines, a directive

    Verb 'blorple' * -> Blorple;

placed after the inclusion of the `Grammar` file. The word “blorple” can now be used as a verb. It can't take any nouns, so the parser will complain if the player types “blorple daisy”.

`Blorple` is now a typical Group 3 action. `before` rules can be written for it, and it can be triggered off by a statement like

    <Blorple>;

The unusual action in ‘Ruins’, `Photograph`, needs to be a Group 2 action, since it actually does something, and objects need to be able to react with `after` rules. (Indeed, the definition of the `Treasure` class in the previous section contains just such an `after` rule.) A photographer needs a camera:

    Object -> -> camera "wet-plate camera"
      with name 'wet-plate' 'plate' 'wet' 'camera',
           description
              "A cumbersome, sturdy, stubborn wooden-framed wet plate
              model: like all archaeologists, you have a love-hate
              relationship with your camera.";

(This is going to be inside a packing case which is inside the Forest, hence the two arrows `->`.) And now the action subroutine. The sodium lamp referred to will be constructed in §14.

    [ PhotographSub;
      if (camera notin player) "Not without the use of your camera.";
      if (noun == player) "Best not. You haven't shaved since Mexico.";
      if (children(player) > 1)
         "Photography is a cumbersome business, needing the use of both
          hands. You'll have to put everything else down.";
      if (location == Forest) "In this rain-soaked forest, best not.";
      if (location == thedark) "It is far too dark.";
      if (AfterRoutines()) return;
     "You set up the elephantine, large-format, wet-plate camera, adjust
      the sodium lamp and make a patient exposure of ", (the) noun, ".";
    ];

What makes this a Group 2 action is that, if the action successfully takes place, then the library routine `AfterRoutines` is called. This routine takes care of all the standard rules to do with `after` (see below), and returns `true` if any object involved has dealt with the action and printed something already. (Failing that, the message “You set up…” will be printed.) Finally, some grammar for the parser:

    Verb 'photograph' * noun -> Photograph;

This matches input like “photograph statuette”, because the grammar token `noun` tells the parser to expect the name of a visible object. See §30 and §31 for much more on grammar.

▲ To make a Group 1 action, define the verb as `meta` (see §30).

· · · · ·

Actions are processed in a simple way, but one which involves many little stages. There are three main stages:

1. ‘Before’, for group 2 and 3 actions. An opportunity for your code to interfere with or block altogether what might soon happen.
2. ‘During’, for all actions. The library takes control and decides if the action makes sense according to its normal world model: for example, only an `edible` object may be eaten; only an object in the player's possession can be thrown at somebody, and so on. If the action is impossible, a complaint is printed and that's all. Otherwise the action is now carried out.
3. ‘After’, for group 2 actions. An opportunity for your code to react to what has happened, after it has happened but before any text announcing it has been printed. If it chooses, your code can print and cause an entirely different outcome. If your code doesn't interfere, the library reports back to the player (with such choice phrases as “Dropped.”).

▲ Group 1 actions, like `Score`, have no ‘Before’ or ‘After’ stages: you can't (easily) stop them from taking place. They aren't happening in the game's world, but in the player's.

▲ The ‘Before’ stage consults your code in five ways, and occasionally it's useful to know in what order:

- (1a) The `GamePreRoutine` is called, if you have written one. If it returns `true`, nothing else happens and the action is stopped.
- (1b) The `orders` property of the player is called on the same terms. For more details, see §18.
- (1c) And the `react_before` of every object in scope, which roughly means ‘in the vicinity’. For more details, see §32.
- (1d) And the `before` of the current room.
- (1e) If the action has a first noun, its `before` is called on the same terms.

▲ The library processes the ‘During’ stage by calling the action's subroutine: for instance, by calling `TakeSub`.

▲ The ‘After’ stage only applies to Group 2 actions, as all Group 3 actions have been wound up with a complaint or a bland response at the ‘During’ stage. During ‘After’ the sequence is as follows: (3a) `react_after` rules for every object in scope (including the player object); (3b) the room's `after`; (3c) the first noun's `after` and (3d) finally `GamePostRoutine`.

▲▲ To some extent you can even meddle with the ‘During’ stage, and thus even interfere with Group 1 actions, by unscrupulous use of the `LibraryMessages` system. See §25.

· · · · ·

As mentioned above, the parser can generate decidedly odd actions, such as `Insert camel eye_of_needle`. The parser's policy is to allow any action which the player has clearly asked for at the keyboard, and it never uses knowledge about the current game position except to resolve ambiguities. For instance, “take house” in the presence of the Sydney Opera House and also a souvenir model of the same will be resolved in favour of the model. But if there is no model to cloud the issue, the parser will cheerfully generate `Take Sydney_Opera_House`.

Actions are only checked for sensibleness after the `before` stage. In many ways this is a good thing, because in adventure games the very unlikely is sometimes correct. But sometimes it needs to be remembered when writing `before` rules. Suppose a `before` rule intercepts the action of putting the mushroom in the crate, and exciting things happen as a result. Now even if the mushroom is, say, sealed up inside a glass jar, the parser will still generate the action `Insert mushroom crate`, and the `before` rule will still cut in, because the impossibility of the action hasn't yet been realised.

The upshot of this is that the exciting happening should be written not as a `before` but as an `after` rule, when it's known that the attempt to put the mushroom in the crate has already succeeded.

▲ That's fine if it's a Group 2 action you're working with. But consider the following scenario: a siren has a cord which needs to be pulled to sound the alarm. But the siren can be behind glass, and is on the other side of a barred cage in which the player is imprisoned. You need to write a rule for `Pull cord`, but you can't place this among the cord's `after` rules because `Pull` is a group 3 action and there isn't any “after”: so it has to be a `before` rule. Probably it's best to write your own code by hand to check that the cord is reachable. But an alternative is to call the library's routine:

    ObjectIsUntouchable(item, silent_flag, take_flag)

This determines whether or not the player can touch `item`, returning `true` if there is some obstruction. If `silent_flag` is `true`, or if there's no obstruction anyway, nothing will be printed. Otherwise a suitable message will be printed up, such as “The barred cage isn't open.” So a safe way to write the cord's `before` rule would be:

    before [;
        Pull: if (ObjectIsUntouchable(self)) rtrue;
              "~Vwoorp! Vwoorp!~";
    ],

`ObjectIsUntouchable` can also be a convenience when writing action subroutines for new actions of your own.

▲▲ If you set `take_flag`, then a further restriction will be imposed: the `item` must not belong to something or someone already: specifically, it must not be in the possession of an `animate` or a `transparent` object that isn't a `container` or `supporter`. For instance, the off button on a television set can certainly be touched, but if `take_flag` is `true`, then `ObjectIsUntouchable` will print up “That seems to be a part of the television set.” and return `true` to report an obstacle.

• REFERENCES
In a game compiled with the `-D` for “Debugging” switch set, the “actions” verb will result in trace information being printed each time any action is generated. Try putting many things into a rucksack and asking to “empty” it for an extravagant list. •Diverted actions (using `<<` and `>>`) are commonplace. They're used in about 20 places in ‘Advent’: a good example is the way “take water” is translated into a `Fill bottle` action. •L. Ross Raszewski's library extension `"yesno.h"` makes an interesting use of `react_before` to handle semi-rhetorical questions. For instance, suppose the player types “eat whale”, an absurd command to which the game replies “You can fit a blue whale in your mouth?” Should the player take this as a literal question and type “yes”, the designer might want to be able to reply “Oh. I should never have let you go through all those doors.” How might this be done? The trick is that, when the game's first reply is made, an invisible object is moved into play which does nothing except to react to a `Yes` action by making the second reply.