| |
Contents Back Forward |
|
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;##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 crownsPutting 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'. |