§21   Starting, moving, changing and killing the player

Life's but a walking shadow, a poor player
That struts and frets his hour upon the stage
And then is heard no more; it is a tale
Told by an idiot, full of sound and fury,
Signifying nothing.
— William Shakespeare (1564–1616), Macbeth V v

To recap on §4, an “entry point routine” is one provided by your own source code which the library may call from time to time. There are about twenty of these, listed in §A5, and all of them are optional but one: Initialise. This routine is called before any text of the game is printed, and it can do many things: start timers and daemons, set the time of day, equip the player with possessions, make any random settings needed and so on. It usually prints out some welcoming text, though not the name and author of the game, because that appears soon after when the “game banner” is printed. The only thing it must do is to set the location variable to where the player begins.

This is usually a room, possibly in darkness, but might instead be an enterable object inside a room, such as a chair or a bed. Like medieval romance epics, interactive fiction games often start by waking the player from sleep, sometimes by way of a dream sequence. If your game begins with verbose instructions before the first opportunity for a player to type a command, you may want to offer the chance to restore a saved game at once:

print "Would you like to restore a game? >";
if (YesOrNo()) <Restore>;

To equip the player with possessions, simply move the relevant objects to player.

The return value from Initialise is ordinarily ignored, whether true or false, and the library goes on to print the game banner. If, however, you return 2, the game banner is suppressed for now. This feature is provided for games like ‘Sorcerer’ and ‘Seastalker’ which play out a short prelude first. If you do suppress the banner from Initialise, you should print it no more than a few turns later on by calling the library routine Banner. The banner is familiar to players, reassuringly traditional and useful when testing, because it identifies which version of a game is giving trouble. Like an imprint page with an ISBN, it is invaluable to bibliographers and collectors of story files.

· · · · ·

‘Ruins’ opens in classical fashion:

[ Initialise;
  TitlePage();
  location = Forest;
  move map to player;
  move sodium_lamp to player;
  move dictionary to player;
  thedark.description = "The darkness of ages presses in on you, and
      you feel claustrophobic.";
  "^^^Days of searching, days of thirsty hacking through the briars of
  the forest, but at last your patience was rewarded. A discovery!^";
];

For the source code of the ‘Ruins’ TitlePage routine, see the exercises in §42.

· · · · ·

The question “where is the player?” can be answered in three different ways. Looking at parent(player) tells you the object immediately containing the player, which can be a location but might instead be a chair or vehicle. So a condition such as:

if (player in Bridleway) ...

would be false if the player were riding a horse through the Bridleway. The safer alternative is:

if (location == Bridleway) ...

but even this would be false if the Bridleway were in darkness, because then location would be the special object thedark (see §19). The definitive location value is stored in real_location, so that:

if (real_location == Bridleway) ...

works in all cases. The condition for “is the player in a dark Bridleway?” is:

if (location == thedark && real_location == Bridleway) ...

Except for the one time in Initialise, you should not attempt to change either of these variables, nor to move the player-object by hand. One safe way to move the player in your own source code is to cause actions like

<Go n_obj>;

but for moments of teleportation it's easier to use the library routine PlayerTo. Calling PlayerTo(somewhere) makes the parent-object of the player somewhere and adjusts the location variables accordingly: it also runs through a fair number of standard game rules, for instance checking the light level and performing a Look action to print out the new room description. The value somewhere can be a room, or an enterable object such as a cage or a traction-engine, provided that the cardinal rule is always observed:

The parent of the player object must at all times be “location-like”. An object is “location-like” if either it is a location, or it has enterable and its parent is location-like.

In other words, you can't put the player in an enterable cardboard box if that box is itself shut up in a free-standing safe which isn't enterable. And you can't PlayerTo(nothing) or PlayerTo(thedark) because nothing is not an object and thedark is not location-like.

Calling PlayerTo(somewhere,1) moves the player without printing any room description. All other standard game rules are applied.

Calling PlayerTo(somewhere,2) is just like PlayerTo(somewhere) except that the room description is in the form the player would expect from typing “go east” rather than from typing “look”. The only difference is that in the former case the room is (normally) given an abbreviated description if it has been visited before, whereas in the latter case the description is always given in full.

· · · · ·

▲▲ It's perhaps worth taking a moment to say what the standard rules upon changing location are. The following rules are applied whenever a Look action or a call to PlayerTo take place.

  1. If PlayerTo has been called then the parent of the player, location and real_location are set.
  2. Any object providing found_in is checked. If it claims to be found_in the location, it is moved to that location. If not, or if it has absent, it is removed from the object tree. (See §8.)
  3. The availability of light is checked (see §19), and location is set to thedark if necessary.
  4. The “visibility ceiling” of the player is determined. For instance, the VC for a player in a closed wooden box is the box, but for a player in a closed glass box it's the location. To be more exact:
    1. The VC of a room is the value of location, i.e., either thedark or the room object.
    2. If the parent of an object is a room or is “see-through” (see §19 for this definition), the VC of the object is the VC of the parent.
    3. If not, the VC of the object is its parent.
  5. If the VC is thedark or (say) a box, skip this rule. Otherwise: if the VC has changed since the previous time that rule (3) produced a VC which wasn't an enterable object, then:
    1. The message location.initial() is sent, if the location provides an initial rule. If the library finds that the player has been moved in the course of running initial, it goes back to rule (3).
    2. The game's entry point routine NewRoom is called, if it provides one.
  6. The room description is printed out, unless these rules are being gone through by PlayerTo(somewhere,1). For exactly what happens in printing a room description, see §26.
  7. If the location doesn't have visited, give it this attribute and award the player ROOM_SCORE points if the location has scored. (See §22.) Note that this rule looks at location, not real_location, so no points unless the room is visible.

· · · · ·

In the course of this chapter, rules to interfere with actions have been attached to items, rooms and people, but not yet to the player. In §18 it was set out that an order like “austin, eat tuna” would result in the action Eat tuna being passed to austin.orders, and heavy hints were dropped that orders and actions are more or less the same thing. This is indeed so, and the player's own object has an orders routine. This normally does nothing and always returns false to mean “carry on as usual”, but you can install a rule of your own instead:

player.orders = MyNewRule;

where MyNewRule is a new orders rule. This rule is applied to every action or order issued by the player. The variable actor holds the person asked to do something, usually but not always player, and the variables action, noun and second are set up as usual. For instance:

Example command actor action noun second
“put tuna in dish” player Insert tuna dish
“austin, eat tuna” Austin Eat tuna nothing

For instance, if a cannon goes off right next to the player, a period of partial deafness might ensue:

[ MyNewRule;
  if (actor ~= player) rfalse;
  Listen: "Your hearing is still weak from all that cannon-fire.";
  default: rfalse;
];

The if statement needs to be there to prevent commands like “helena, listen” from being ruled out – after all, the player can still speak.

EXERCISE 51
Why not achieve the same effect by giving the player a react_before rule instead?

EXERCISE 52
(Cf. ‘Curses’.) Write an orders routine for the player so that wearing a gas mask will prevent speech.

· · · · ·

The player object can not only be altered but switched altogether, allowing the player to play from the perspective of someone or something else at any point in the game. The player who tampers with Dr Frankenstein's brain transference machine may suddenly become the Monster strapped to the table. A player who drinks too much wine could become a drunk player object to whom many different rules apply. The “snavig” spell of ‘Spellbreaker’, which transforms the player to an animal like the one cast upon, could be implemented thus. Similarly the protagonist of ‘Suspended’, who telepathically runs a weather-control station by acting through six sensory robots, Iris, Waldo, Sensa, Auda, Poet and Whiz. In a less original setting, a player might have a team of four adventurers exploring a labyrinth, and be able to switch the one being controlled by typing the name. In this case, an AfterLife routine (see below) may be needed to switch the focus back to a still-living member of the team after one has met a sticky end.

The library routine ChangePlayer(obj) transforms the player to obj. Any object can be used for this. There's no need to give it any name, as the parser always understands pronouns like “me” and “myself” to refer to the current player-object. You may want to set its description, as this is the text printed if the player types “examine myself”, or its capacity, the maximum number of items which this form of the player can carry. Finally, this player-object can have its own orders property and thus its own rules about what it can and can't do.

As ChangePlayer prints nothing, you may want to follow the call with a <<Look>>; action.

You can call ChangePlayer as part of a game's Initialise routine, but if so then you should do this before setting location.

Calling ChangePlayer(obj,1); does the same except that it makes the game print “(as Whoever)” during subsequent room descriptions.

The body dispossessed remains where it was, in play, unless you move it away or otherwise dispose of it. The player-object which the player begins with is a library-defined object called selfobj, and is described in room descriptions as “your former self”.

EXERCISE 53
In Central American legend, a sorceror can transform himself into a nagual, a familiar such as a spider-monkey; indeed, each individual has an animal self or wayhel, living in a volcanic land over which the king, as a jaguar, rules. Turn the player into wayhel form.

EXERCISE 54
Alter the Wormcast of ‘Ruins’ (previously defined in §9) so that when in wayhel form, the player can pass through into a hidden burial shaft.

EXERCISE 55
To complete the design of this sequence from ‘Ruins’, place a visible iron cage above the hidden burial shaft. The cage contains skeletons and a warning written in glyphs, but the player who enters it despite these (and they all will) passes into wayhel life. (The transformed body is unable to move the sodium lamp, but has nocturnal vision, so doesn't need to.) Unfortunately the player is now outside a cage which has closed around the human self which must be returned to, while the wayhel lacks the dexterity to open the cage. The solution is to use the Wormcast to reach the Burial Chamber, then bring its earthen roof down, opening a connection between the chamber below and the cage above. Recovering human form, the player can take the grave goods, climb up into the cage, open it from the inside and escape. Lara Croft would be proud.

· · · · ·

▲▲ The situation becomes a little complicated if the same orders routine has to do service in two situations: once while its owner is a character met in the course of play, and then a second time when the player has changed into it. This could be done simply by changing the value of orders when the transformation takes place, but an alternative is to arrange code for a single orders routine like so:

orders [;
    if (player == self) {
        if (actor == self) {
            ! I give myself an action
        }
        else {
            ! I give someone else an order
        }
    }
    else {
        ! Someone else gives me an order
    }
],

▲▲ EXERCISE 56
Write an orders routine for a Giant with a conscience, who will refuse to attack even a mouse, but so that a player who becomes the Giant can be wantonly cruel.

· · · · ·

“There are only three events in a man's life; birth, life and death; he is not conscious of being born, he dies in pain and he forgets to live.” (Jean de la Bruyère again.) Death is indeed the usual conclusion of an adventure game, and occurs when the source code sets the library variable deadflag to true: in normal play deadflag is always false. The “standard Inform rules” never lead to the player's death, so this is something the designer must explicitly do.

Unlike life, however, interactive fiction offers another way out: the player can win. This happens if and when the variable deadflag is set to 2.

Any higher values of deadflag are considered to be more exotic ways the game can end, requiring text beyond “You have died” or “You have won”. The Inform library doesn't know what this text should be, so it calls the DeathMessage entry point routine, which is expected to look at deadflag and can then print something suitable. For instance, ‘Ruins’ has a chasm subject to the following before rule:

before [;
    Enter: deadflag = 3;
        "You plummet through the silent void of darkness, cracking
        your skull against an outcrop of rock. Amid the pain and
        redness, you dimly make out the God with the
        Owl-Headdress...";
    JumpOver: "It is far too wide.";
],

and this means that it needs a DeathMessage routine like so:

[ DeathMessage;
      if (deadflag == 3) 
          print "You have been captured";
];

Capture was about the worst fate that could befall you in the unspeakably inhumane world of Maya strife.

‘Ruins’ doesn't, but many games allow reincarnation or, as David M. Baggett points out, in fact resurrection. You too can allow this, by providing an AfterLife entry point routine. This gets the chance to do as it pleases before any “death message” is printed, and it can even reset deadflag to false, causing the game to resume as though nothing had happened. Such AfterLife routines can be tricky to write, though, because the game often has to be altered to reflect what has happened.

REFERENCES
The magic words “xyzzy” and “plugh” in ‘Advent’ employ PlayerTo.   ‘Advent’ has an amusing AfterLife routine: for instance, try collapsing the bridge by leading the bear across, then returning to the scene after resurrection. ‘Balances’ has one which only slightly penalises death.