EricEve/adv3lite — pull request #3 by Engelberg (2013-01-12 12:37:19+00:00)
Title: Added ground vocabulary to disambiguate objects.

I've put together a series of changes that implement disambiguating objects that don't have any other disambiguating description by describing them as "on the ground". This term is used both to distinguish the object from other locational descriptions (e.g., "under the box") and possessive descriptions (e.g., "Bob's").

The first step was to make it add "on the ground" as a disambiguating description for both the locational and possessive case.

The next step was to make it recognize either "ground" or "on the ground" when the player types that in as either a disambiguating phrase, or just as an ordinary command intended to discriminate against other options.

Making it recognize "ground" was pretty straightforward, and just involved adding the vocab word to the words matched by any object whose location is the actor's outermost room (I believe this is the logical way to test if something is on the floor, and I used it extensively).

Making it recognize "on the ground" was somewhat more problematic because it is a locational phrase, but I found a couple of ways to handle it.

One problem I then had was that once the vocabulary of "ground" was introduced and attached to all objects that were sitting out in the open, that really opens the question of what to do when the player starts typing things like "examine ground" "put axe on ground" "hit ground", etc.

I figured that you didn't implement T3's floor system for a reason (presumably too complex), so I asked myself what would be the simplest possible way to implement a ground object just to intercept the most obvious commands.

So I set up an object DefaultGround that is both a MultiLoc and a Decoration. It supports examine and "put Thing on ground". Everything else gives the standard decoration message. On the plus side, once I made the DefaultGround object, this also served as a resolution for the "on the ground" locational phrasing that was problematic.

To make the whole DefaultGround idea work, I needed the notion of a region encompassing all the rooms, so I created an object called EverywhereRegion which initializes with all the rooms.

Finally, I made it so the word "ground" could be easily customized for a given room, using the property groundName.

As you know, the goal was to come up with a way to handle the craziness that resulted when the Mercury parser would print things like "Which one, the match or the match of yours?", but if you just typed "the match" in response it would keep prompting you over and over with the same message because all the matches qualified as "the match".

My previous implementation used the phrase "unheld", which had the advantage of being unlikely to conflict with other vocabulary. I like the "on the ground" implementation better in that it feels more natural, but it definitely introduced complicating factors (it's a prepositional locational phrase that implies the existence of a universal ground object). This was the simplest way I could find to resolve those complicating factors.

Some criticisms of this code:

This isn't as flexible as T3s floor system if you do desire to implement your own floor. The problem is that the DefaultGround must be there to handle disambiguation properly. So if you create another object in a given room that is just called "ground" but has some custom methods, how will that work? I tried this, making a single room's ground a fresh Fixture object to hopefully give it a bit more precedence than DefaultGround. The good news is that, for the most part, it seemed to work well, with disambiguation messages routed through DefaultGround, and other interactions routed through the custom ground object. This means that users can basically ignore the existence of DefaultGround and just create their own special ground object in the room if they want. I did spot one weirdness:
When I typed DROP GROUND in this dual-ground scenario, I got the very odd (and very Zen) error message "The ground is part of you."

simpleMatchName has too much custom class logic, and I can easily imagine scenarios where others would want to extend their classes with custom, dynamic vocabulary. The state system covers the most common case, but doesn't seem rich enough to cover all the possibilities. simpleMatchName should call a method on the object which returns a list of any dynamic vocabulary words that should be added. Then the custom cases I added in simpleMatchName should be pulled out and placed in the appropriate objects.