§15   Things to enter, travel in and push around

Vehicles were objects that became, in effect, mobile rooms… The code for the boat itself was not designed to function outside the river section, but nothing kept the player from carrying the deflated boat to the reservoir and trying to sail across…
— Tim Anderson, The History of Zork

Quite so. Even the case of an entirely static object which can be climbed into or onto poses problems of realism. Sitting on a garden roller, is one in the gardens, or not? Can one reasonably reach to pick up a leaf on the ground? The Inform library leaves most of these subtleties to the designer but has at least a general concept of “enterable object”. These have enterable and the Enter and Exit actions allow the player to get in (or on) and out (or off) of them.

Enterable items might include, say, an open-topped car, a psychiatrist's couch or even a set of manacles attached to a dungeon wall. In practice, though, manacles are an exceptional case, and one usually wants to make an enterable thing also a container, or – as in the case of the altar from ‘Ruins’ which appeared in the previous section – a supporter:

Object -> stone_table "slab altar"
  with name 'stone' 'table' 'slab' 'altar' 'great',
       initial "A great stone slab of a table, or altar, dominates the
           Shrine.",
  has  enterable supporter static;

A chair to sit on, or a bed to lie down on, should also be a supporter.

Sitting on furniture, one is hardly in a different location altogether. But suppose the player climbs into a container which is not transparent and then closes it from the inside? To all intents and purposes this has become another room. The interior may be dark, but if there's light to see by, the player will want to see some kind of room description. In any case, many enterable objects ought to look different from inside or on top. Inside a vehicle, a player might be able to see a steering wheel and a dashboard, for instance. On top of a cupboard, it might be possible to see through a skylight window.

For this purpose, any enterable object can provide a property called inside_description, which can hold a string of text or else a routine to print some text, as usual. If the exterior location is still visible, then the “inside description” is appended to the normal room description; if not, it replaces the room description altogether. As an extreme example, suppose that the player gets into a huge cupboard, closes the door and then gets into a plastic cabinet inside that. The resulting room description might read like so:

The huge cupboard (in the plastic cabinet)
It's a snug little cupboard in here, almost a room in itself.
In the huge cupboard you can see a pile of clothes.
The plastic walls of the cabinet distort the view.

The second line is the inside_description for the huge cupboard, and the fourth is that for the plastic cabinet.

EXERCISE 22
(Also from ‘Ruins’.) Implement a cage which can be opened, closed and entered.

All the classic games have vehicles (like boats, or fork lift trucks, or hot air balloons) which the player can journey in, and Inform makes this easy. Here is a simple case:

Object car "little red car" cave
  with name 'little' 'red' 'car',
       description "Large enough to sit inside. Among the controls is a
           prominent on/off switch. The numberplate is KAR 1.",
       when_on
           "The red car sits here, its engine still running.",
       when_off "A little red car is parked here.",
       before [;
           Go: if (car has on) "Brmm! Brmm!";
               print "(The ignition is off at the moment.)^";
       ],
  has  switchable enterable static container open;

Actually, this demonstrates a special rule. If a player is inside an enterable object and tries to move, say “north”, the before routine for the object is called with the action Go n_obj. It may then return:

0   to disallow the movement, printing a refusal;
1   to allow the movement, moving vehicle and player;
2   to disallow but print and do nothing; or
3   to allow but print and do nothing.

If you want to move the vehicle in your own code, return 3, not 2: otherwise the old location may be restored by subsequent workings. Notice that if you write no code, the default value false will always be returned, so enterable objects won't become vehicular unless you write them that way.

Because you might want to drive the car “out” of a garage, the “out” verb does not make the player get out of the car. Instead the player generally has to type something like “get out” or “exit” to make this happen.

EXERCISE 23
Alter the car so that it will only drive along roads, and not through all map connections.

Objects like the car or, say, an antiquated wireless on casters, are too heavy to pick up but the player should at least be able to push them from place to place. When the player tries to do this, an action like PushDir wireless is generated.

Now, if the before routine for the wireless returns false, the game will just say that the player can't move the wireless; and if it returns true, the game will do nothing at all, assuming that the before routine has already printed something more interesting. So how does one actually tell Inform that the push should be allowed? The answer is: first call the AllowPushDir routine (a library routine), and then return true. For example (‘Ruins’ again), here is a ball on a north-south corridor which slopes upward at the northern end:

Object -> huge_ball "huge pumice-stone ball"
  with name 'huge' 'pumice' 'pumice-stone' 'stone' 'ball',
       description
           "A good eight feet across, though fairly lightweight.",
       initial
           "A huge pumice-stone ball rests here, eight feet wide.",
       before [;
           PushDir:
               if (location == Junction && second == ne_obj)
                   "The Shrine entrance is far less than eight feet
                   wide.";
               AllowPushDir(); 
               rtrue;
           Pull, Push, Turn:
               "It wouldn't be so very hard to get rolling.";
           Take, Remove:
               "There's a lot of stone in an eight-foot sphere.";
       ],
       after [;
           PushDir:
               if (second == s_obj)
                   "The ball is hard to stop once underway.";
               if (second == n_obj)
                   "You strain to push the ball uphill.";
       ],
  has  static;

EXERCISE 24
The library does not normally allow pushing objects up or down. How can the pumice ball allow this?

REFERENCES
For an enterable supporter puzzle, see the magic carpet in ‘Balances’ (and several items in ‘Alice Through the Looking-Glass’).   When a vehicle has a sealed interior large enough to be a location, it is probably best handled as a location with changing map connections and not as a vehicle object moved from room to room. See for instance Martin Braun's "elevator.inf" example game, providing an elevator which serves eight floors of a building.