Section 19: Starting, moving, changing and killing the player

Contents Back Forward | ### 19. Starting, moving, changing and killing the player
| 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 (1645--1696) 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 The only compulsory task for a game's `Initialise` routine is to set the `location` variable to the place where the player should begin. This is usually a room (and is permitted to be one that's in darkness) but could instead be an object inside a room, such as a chair or a bed. If you would like to give the player some items to begin with, `Initialise` should also `move` them to `player`. Games with a long opening sequence might want to start by offering the player a chance to restore a saved game at once. They can do so by writing the following in their `Initialise` routines:
        print "Would you like to restore a game?  >";
        if (YesOrNo()) <Restore>;
(If you want to make the status line invisible during an opening sequence, see Section 33.) `Initialise` normally returns 0 or 1 (it doesn't matter which), but if it returns 2 then no game banner will be printed at once. (This is for games which, like 'Sorcerer', delay their banners until after the prologue.) 'Ruins', however, opens in classical fashion:
    [ Initialise;
      TitlePage();
      location = Forest;
      move food_ration 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!^";
    ];
(The `TitlePage` routine will be an exercise in Section 33: 'Ruins' is really too small a game to warrant one, but never mind.) The `location` variable needs some explanation. It holds either the current room, if there's light to see by, or the special value `thedark` (the "Darkness'' object) if there isn't. In the latter case (but only in the latter case) the actual current room is held in the variable `real_location`, should you need to know it. Neither of these is necessarily the same as the parent of the `player` object. For instance, if the player sits in a jeep parked in a dark garage, then `location` is `thedark`, `real_location` is `Garage` and `parent(player)` is `jeep`. Because of this, one shouldn't simply `move` the player object by hand. Instead, to move the player about (for teleportation of some kind), use the routine `PlayerTo(place);` (which automatically takes care of printing the new room's description if there's enough light there to see by).
| `PlayerTo` can also be used to move the player to a `place` inside a room (e.g., a cage, or a traction engine).
| Calling `PlayerTo(place, 1);` moves the player but prints nothing (in particular, prints no room description).
| Calling `PlayerTo(place, 2);` will `Look` as if the player had arrived in the room by walking in as usual, so only a short description appears if the room is one that has been seen before.
| In a process called 'scoring arrival', a room which the player has entered for the first time is given the `visited` attribute. If it was listed as `scored`, points are awarded. (See Section 14.)
| When a `Look` action takes place, or a call to `PlayerTo(place,1)`, the library 'notes arrival' as well as 'scores arrival'. 'Noting arrival' consists of checking to see if the room has changed since last time (darkness counting as a different room for this purpose). If so, the following happens: 1. -- If the new location has an `initial` property, this is printed if it's a string, or run if it's a routine. 2. -- The entry point `NewRoom` is called (if it exists). 3. -- Any 'floating objects', such as drifting mist, which are `found_in` many places at once, are moved into the room.
| The player's whole persona can easily be changed, because the player object can itself have an `orders` routine, just as the object for any non-player character can. To replace the `orders` routine for the standard `player` object, set
    player.orders = MyNewRule;
where `MyNewRule` is a new `orders` rule. Note that this is applied to every action or order issued by the player. The variable `actor` holds the person being told to do something, which may well be the player himself, and the variables `action`, `noun` and `second` are set up as usual. 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.";
    ];
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 42: (link to the answer)
| Why not achieve the same effect by giving the player a `react_before` rule instead?
| EXERCISE 43: (link to the answer)
| (Cf. 'Curses'.) Write an `orders` routine for the player so that wearing the gas mask will prevent him from talking.
| In fact a much more powerful trick is available: the `player` can actually become a different character in the game, allowing the real player at the keyboard to act through someone else. Calling `ChangePlayer(obj)` will transform the player to `obj`. There's no need for `obj` to have names like "me'' or "myself''; the parser understands these words automatically to refer to the currently-inhabited `player` object. However, it must provide a `number` property (which the library will use for workspace). The maximum number of items the player can carry as that object will be its `capacity`. Finally, since `ChangePlayer` prints nothing, you may want to conclude with a `<<Look>>;`
| `ChangePlayer` has many possible applications. 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. More ambitiously, a game could have a stock of half a dozen main characters, and the focus of play can switch between them. A player might have a team of four adventurers to explore a dungeon, 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.
| Calling `ChangePlayer(object,1);` will do the same but make the game print "(as Whoever)'' during room descriptions.
| When the person to be changed into has an `orders` routine, things start to get complicated. It may be useful to arrange such a routine as follows:
          orders
          [;  if (player==self)
              {   ! I am the player object...
                  if (actor==self)
                  {   ! ...giving myself an order, i.e., trying an action.
                  }
                  else
                  {   ! ...giving someone else, the "actor", an order.
                  }
              }
              else
              {   ! The player is the "actor" and is giving me an order.
              }
          ],
| EXERCISE 44: (link to the answer)
| 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 his wayhel.
| EXERCISE 45: (link to the answer)
| Write an `orders` routine for a Giant with a conscience, who will refuse to attack a mouse, but so that a player who becomes the Giant can be as cruel as he likes. The player is still alive for as long as the variable `deadflag` is zero. When set to 1, the player dies; when set to 2, the player wins; and all higher values are taken as more exotic forms of death. Now Inform does not know what to call these exotica: so if they should arise, it calls the `DeathMessage` routine, which is expected to look at `deadflag` and can then print something like "You have changed''. Many games allow reincarnation (or, as David M. Baggett points out, in fact resurrection). You too can allow this, by providing an `AfterLife`. This routine gets the chance to do as it pleases before any "You are dead'' type message appears, including resetting `deadflag` back to 0 -- which causes the game to proceed in the normal way, rather than end. `AfterLife` routines can be tricky to write, though, because the game has to be set to a state which convincingly reflects what has happened.
| REFERENCES: The magic words "xyzzy'' and "plugh'' in 'Advent' make use of `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.

Contents / Back / Forward
Chapter I / Chapter II / Chapter III / Chapter IV / Chapter V / Chapter VI / Appendix

Mechanically translated to HTML from third edition as revised 16 May 1997. Copyright © Graham Nelson 1993, 1994, 1995, 1996, 1997: all rights reserved.