Section 25: Plural names for duplicated objects

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.