Platypus Tips

From IFWiki

Adding a "Go Back" Verb

The pathfinding functionality in Platypus makes a "GO BACK" verb fairly trivial to implement. I've written a small library extension that does this. Follow the instructions in that file once you've downloaded it.

--Two-star 18:08, 26 Feb 2005 (Central Standard Time)

Using the Adjective Property

Platypus provides the adjective property, which allows an author to give a list of words that will match a noun but less strongly than a word in a name property.

Suppose you have a location with the following objects:

Object KeyLime "key lime"
  with name 'lime',
  adjective 'key';

Object HouseKey "house key"
  with name 'key',
  adjective 'house';

Object House "white house"
  with name 'house',
  adjective 'white';

With these object definitions, the player can refer to "key", "key lime", "house", "house key", and "white", and the game will pick the object that you would expect for each.

Platypus lets you define WEAK_ADJECTIVES as a constant; if you do, the game will require at least one word in a name property to be present for an object to be matched. I suggest that you not do this; you'll only end up annoying players who, for example, type >X WHITE knowing that the game should be able to tell that they mean the white house.

Platypus does not care about the order of adjectives and nouns. So a if a game contains a "pot plant", and a "plant pot", and you set up the name and adjective properties in the obvious way, the correct object will be chosen if the player refers to "pot" or "plant", but "pot plant" and "plant pot" cannot be distinguished, and will cause a disambiguation message to be printed. For something like this you'll still want to use a parse_name property.

An important thing to remember is that words in the adjective property need not be literally adjectives. For example, if your game contains both a motorcycle and a copy of Zen and the Art of Motorcycle Maintenance, making 'motorcycle' an adjective in the latter will ensure that the word "motorcycle" alone will refer to the motorcycle. If you have implemented both the player's nose and a giant nose statue, you could make 'nose' an adjective for the former, since the player is less likely to be refering to it.

Another reason the adjective property is useful is simply that now there are two properties for name words instead of one. You can put generic names that apply to all of the objects in a class in the class definition, and put words that distinguish particular instances of that class in the adjective property of each instance. And if during the game you want to change how an object is referred to, (for instance, a "green light" becomes a "red light",) you can change just the adjective property while leaving the name property alone.

Platypus also helpfully provides a words property, which is intermediate in both power and complexity between using name and adjective, and using parse_name. Individual words that the parser is trying to map to an object are passed into the words function, which should return the property, (name or adjective,) that the word would fit into if you were using those properties.

Object Amulet
  with
    damage 0,
    words [wd;
      switch (wd)
      {
        'gleaming':  if (self.damage == 0) return adjective;
        'dented':    if (self.damage == 1) return adjective;
        'broken':    if (self.damage == 2) return adjective;
        'amulet':    return name;
      }
    ];
    short_name [;
      switch (self.damage)
      {
        0: print "gleaming";
        1: print "dented";
        2: print "broken";
      }
      print " amulet"; rtrue;
    ],
    description [;
      "It's just some ", name (self), " your aunt gave to you.";
    ],

Note that objects with a words property should not have name or adjective properties.

--Two-star 18:08, 26 Feb 2005 (Central Standard Time)

Using the Disambiguate Property

Suppose you are coding a knife object, and you want the game to infer that the player wants to use the knife for cutting when he or she types >CUT STEAK. In the standard inform lib, this is handled by the ChooseObjects entry point routine. In Platypus a more convenient per object ChooseObjects is avalable: the disambiguate property. It works exactly like ChooseObjects, so you can refer to the DM4 to see how it works. For our purposes it will suffice to note that it is called with an argument that is a code for the circumstance in which it is called, which is equal to 2 when it is trying to pick an object to disambiguate to. We'll also need to look at the action_to_be global, which contains the action corresponding to the current grammar line. (Since we haven't yet determined the grammar line to use at this point, the action global isn't set yet.)

For verbs with more than one object, it's important to know which object you're looking at in the disambiguation process. (We want the knife to be the inferred object for what you cut with, but not what you cut.) Here's a useful utility function for telling whether we are looking at the direct object:

[ ObjectIsDirect;
  if (action_reversed)
    return parameters;
  else
    return ~~parameters;
];

The parameters global tells us which object we're on, and action_reversed tells us whether the grammar line is reversed, with the indirect object first. Now here's our knife example:

Object SteakKnife "steak knife"
  with name 'knife',
    adjective 'steak',
    description "It's your trusty serrated steak knife.",
    disambiguate [code;
      if ((action_to_be == ##Cut) && (code == 2))
      {
	if (ObjectIsDirect())
	  rfalse;
	else
	  return 4;
      }
    ];

The value returned by disambiguate should be 0 if the object should not be considered a match, and between 1 and 9 if it should. (Higher numbers indicate better matches.)

--Two-star 18:08, 26 Feb 2005 (Central Standard Time)