Contents
Back
Forward

25. Plural names for duplicated objects


Abiit ad plures.

...Petronius (?--c. 66), Cena Trimalchionis

A notorious problem 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. This is relatively easy in Inform, and only in really hard cases do you have to provide code. 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 similar silver and bronze coin classes here)
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:

(a) -- have a plural set,

(b) -- 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, the library is cleverer than this. What it groups together depends slightly on the context of the list it's writing out. When it's writing a list which prints out details of which objects are providing light, for instance (like an inventory), 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 all gets even more complicated when the objects have a parse_name routine supplied, because then the library can't use the name fields to tell them apart. If they have different parse_name routines, it decides that they're different. But if they have the same parse_name routine, there is no alternative but to ask them. What happens is that
1. A variable called parser_action is set to ##TheSame;
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.
##TheSame is a fake action. The implementation of the 'Spellbreaker cubes' in the 'Balances' game is an example of such a routine, so that if the player writes the same name on several of the cubes, they become grouped together. Note that this whole set-up is such that if the author of a parse_name routine has never read this paragraph, it doesn't matter and the usual rules take their course.

/\/\ You may even want to provide a parse_name routine just to speed up the process of telling two objects apart -- if there were 30 gold coins the parser would be doing a lot of work comparing all their names, but you can make the decision much faster.

Secondly, the player talking to the computer. This goes a little further than just copies of the same object: many games involve collecting a number of similar items, say 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 their name lists is not quite right, because the parser will still think that "crowns'' might refer to a specific item. Instead, put in the word "crowns//p". The //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 was a single game object; you should give that object the pluralname attribute instead.) For example the GoldCoin class would read:
        
Class  GoldCoin
  with name "gold" "coin" "coins//p",
       short_name "gold coin",
       plural "gold coins";
and 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 fake action. 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 64:
(link to
the answer)
Write a 'cherub' class so that if the player tries to call them "cherubs", a message like "I'll let this go by for now, but the plural of cherub is cherubim" appears.

*REFERENCES:
See the coinage of 'Balances'.

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.