§29   Plural names for duplicated objects

A notorious challenge for adventure game parsers is to handle a collection of, say, ten gold coins, allowing the player to use them independently of each other, while gathering them together into groups in descriptions and inventories. Two problems must be overcome: firstly, the game has to be able to talk to the player in plurals, and secondly vice versa. First, then, game to player:

Class GoldCoin
  with name 'gold' 'coin',
       short_name "gold coin",
       plural "gold coins";

(and then similar silver and bronze coin classes)

Object bag "bag"
  with name 'bag',
  has  container open openable;
GoldCoin ->;
GoldCoin ->;
GoldCoin ->;
SilverCoin ->;
SilverCoin ->;
BronzeCoin ->;

Now we have a bag of six coins. The player looking inside the bag will get

>look inside bag
In the bag are three gold coins, two silver coins and a bronze coin.

How does the library know that the three gold coins are the same as each other, but the others different? It doesn't look at the classes but the names. It will only group together things which:

  1. have a plural set, and
  2. are “indistinguishable” from each other.

“Indistinguishable” means they have the same name words as each other, possibly in a different order, so that nothing the player can type will separate the two.

Actually, it's a little more subtle than this. What it groups together depends slightly on the context of the list being written. When it's writing a list which prints out details of which objects are providing light, for instance (as an inventory does), it won't group together two objects if one is lit but the other isn't. Similarly for objects with visible possessions or which can be worn.

▲▲ This ramifies further when the objects have a parse_name routine supplied. If they have different parse_name routines, the library decides that they are distinguishable. But if they have the same parse_name routine, for instance by inheriting it from a class definition, then the library has no alternative but to ask them. What happens is that:

  1. A variable called parser_action is set to the special value ##TheSame, a value it never has at any other time;
  2. Two variables, called parser_one and parser_two are set to the two objects in question;
  3. Their parse_name routine is called. If it returns:
    −1   the objects are declared “indistinguishable";
    −2   they are declared different.
  4. Otherwise, the usual rules apply and the library looks at the ordinary name fields of the objects.

▲▲ You may even want to provide a parse_name routine for objects which otherwise don't need one, just to speed up the process of the library telling if two objects are distinguishable – if there were 30 gold coins in one place the parser would be doing a lot of work comparing names, but you can make the decision much faster.

▲▲ EXERCISE 79
Perhaps the neatest trick of parsing in any Infocom game occurs in ‘Spellbreaker’, which has a set of white cubes which are indistinguishable until the player writes words onto them with a magic burin (a medieval kind of pen), after which it's possible to tell them apart. Imitate this in Inform.

Secondly, the player talking to the computer. Suppose a game involves collecting a number of similar items, such as a set of nine crowns in different colours. Then you'd want the parser to recognise things like:

>drop all of the crowns except green
>drop the three other crowns

Putting the word 'crowns' in the name lists of the crown objects is not quite right, because the parser will still think that “crowns” might refer to a single specific item. Instead, put in the word 'crowns//p'. The suffix //p marks out the dictionary word “crowns” as one that can refer to more than one game object at once. (So that you shouldn't set this for the word “grapes” if a bunch of grapes is a single game object; you should give that object the pluralname attribute instead, as in §26 back at the start of this chapter.) For example the GoldCoin class would read:

Class GoldCoin
  with name 'gold' 'coin' 'coins//p',
       short_name "gold coin",
       plural "gold coins";

Now when the player types “take coins”, the parser interprets this as “take all the coins within reach”.

The only snag is that now the word 'coins' is marked as //p everywhere in the game, in all circumstances. Here is a more complicated way to achieve the same result, but strictly in context of these objects alone. We need to make the parse_name routine tell the parser that yes, there was a match, but that it was a plural. The way to do this is to set parser_action to ##PluralFound, another special value. So, for example:

Class Crown
  with parse_name [ i j;
           for (::) {
               j = NextWord();
               if (j == 'crown' or self.name) i++;
               else {
                   if (j == 'crowns') {
                       parser_action = ##PluralFound; i++;
                   }
                   else return i;
               }
           }
       ];

This code assumes that the crown objects have just one name each, their colours.

EXERCISE 80
Write a ‘cherub’ class so that if the player tries to call them “cherubs”, a message like “I'll let this go once, but the plural of cherub is cherubim” appears.

REFERENCES
See the coinage of ‘Balances’.