Section 20: Miscellaneous constants and scoring

Contents Back Forward | ### 20. Miscellaneous constants and scoring
| For when the One Great Scorer comes To write against your name, He marks -- not that you won or lost -- But how you played the game. ...Grantland Rice (1880--1954), Alumnus Football Some game rules can be altered by defining 'constants' at the start of the program. Two constants you must provide (and before including any of the library files) are the strings `Story` and `Headline`:
    Constant Story "ZORK II";
    Constant Headline "^An Interactive Plagiarism^
                 Copyright (c) 1995 by Ivan O. Ideas.^";
All the rest are optional, but should be defined before `Verblib` is included if they're to take effect. The library won't allow the player to carry an indefinite number of objects: the limit allowed is the constant `MAX_CARRIED`, which you may define if you wish. If you don't define it, it's 100, which nearly removes the rule. In fact you can change this during play, since it is actually the `capacity` of the `player` which is consulted; the only use of `MAX_CARRIED` is to set this up to an initial value. If you define `SACK_OBJECT` to be some container, then the player will automatically put old, least-used objects away in it as the game progresses, provided it is being carried. This is a feature which endears the designer greatly to players. For instance, the following code appears (in between inclusion of `Parser` and `Verblib`) in 'Toyshop':
    Object satchel "satchel"
      with description "Big and with a smile painted on it.",
           name "satchel", article "your",
           when_closed "Your satchel lies on the floor.",
           when_open "Your satchel lies open on the floor.",
      has  container open openable;
    Constant SACK_OBJECT satchel;
'Ruins' isn't going to provide this feature, because there are few portable objects and those there are would be incongruous if described as being in a rucksack. Another constant is `AMUSING_PROVIDED`. If you define this, the library knows to put an "amusing" option on the menu after the game is won. It will then call `Amusing` from your code when needed. You can use this to roll closing credits, or tell the player various strange things about the game, now that there's no surprise left to spoil. The other constants you are allowed to define help the score routines along. There are two scoring systems provided by the library, side by side: you can use both or neither. You can always do what you like to the `score` variable in any case, though the "fullscore'' verb might then not fully account for what's happened. One scores points for getting certain items or reaching certain places; the other for completing certain actions. These constants are:
`MAX_SCORE` | the maximum game score (by default 0);
`NUMBER_TASKS` | number of individual "tasks" to perform (1);
`OBJECT_SCORE` | bonus for first picking up a `scored` object (4);
`ROOM_SCORE` | bonus for first entering a `scored` room (5)
and then the individual tasks have scores, as follows:
    Array task_scores -> t1 t2 ... tn;
As this is a byte array, the task scores must be between 0 and 255. Within your code, when a player achieves something, call `Achieved(task)` to mark that the task has been completed. It will only award points if this task has not been completed before. There do not have to be any "tasks": there's no need to use the scoring system provided. Tasks (and the verb "full" for full score) will only work at all if you define the constant `TASKS_PROVIDED`. The entry point `PrintTaskName` prints the name of a game task (but, of course, is only ever called in a game with `TASKS_PROVIDED` defined). For instance, ('Toyshop' again)
    [ PrintTaskName ach;
      switch(ach)
      {   0: "eating a sweet";
          1: "driving the car";
          2: "shutting out the draught";
          3: "building a tower of four";
          4: "seeing which way the mantelpiece leans";
      }
    ];
Another entry point, called `PrintRank`, gets the chance to print something additional to the score (traditionally, though not necessarily, rankings). For instance, we bid farewell to the 'Ruins' with the following:
    [ PrintRank;
      print ", earning you the rank of ";
      switch(score)
      {   0 to 9:   "humble rainforest Tourist.";
          10 to 19: "Investigator.";
          20 to 29: "Acquisitor.";
          30 to 49: "Archaeologist.";
          50:       "Master Archaeologist.";
      }
    ];
Normally, an Inform game will print messages like [Your score has gone up by three points.] when the score changes (by whatever means). The player can turn this on and off with the "notify'' verb; by default it is on. (You can alter the flag `notify_mode` yourself to control this.) The verbs "objects'' and "places'' are usually provided, so the player can get a list of all handled objects (and where they now are), and all places visited. If you don't want these to be present, define the constant `NO_PLACES` before inclusion of the library.
| EXERCISE 46: (link to the answer)
| Suppose one single room object is used internally for the 64 squares of a gigantic chessboard, each of which is a different location to the player. Then "places'' is likely to result in only the last-visited square being listed. Fix this.
| REFERENCES: 'Advent' contains ranks and an `Amusing` reward (but doesn't use either of these scoring systems, instead working by hand). 'Balances' uses `scored` objects (for its cubes). 'Toyshop' has tasks, as above. 'Adventureland' uses its `TimePasses` entry point to recalculate the score every turn (and watch for victory).

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.