I am curious what the expectation is for a parser game in a specific situation.
Say there is a hat in a closed box in the room the player is in.
What would be a reasonable response at this point? If it says "There is no hat here." we know that is not true; there is a hat in the box!
Should the game note that the player has seen the hat? "You cannot see the hat whilst the box is closed." Should it remember that for the rest of the game, or until the player leaves the room? Or do we go with a bland "You cannot see that.", just the same as if the player typed X BANDERSNATCH?
I cannot decide what is most appropriate; what do you guys think?
This convention goes back to the days when it would have been prohibitively expensive to track the player’s recollection of the location of every object. (You don’t want to include objects that the player has no knowledge of.)
It only now occurs to me that Hadean Lands has such a system; you can type RECALL OBJECT and get a message about where you left it. So I could have implemented a smarter parser error here. “You last saw the hat in the box [here / in the closet]”, as appropriate.
But I didn’t do that! And nobody’s bugged me about it in all these years. Like I said, we’re used to this.
Repeating back the player’s words for an unrecognized entity is risky. You can wind up with outputs like:
You can try to recognize out-of-scope objects and print their names sensibly, but again, this involves tracking what the player knows (Epistemology style). Otherwise people are tempted to exploit the parser error system to probe the game contents, which is a lousy use of your and their gameplay time.
Information about how to name objects (in output text) is attached to objects, not words. At the point this parser error occurs, the parser only has words. It doesn’t know which out-of-scope object the player meant, if indeed the player’s intention maps to any game object at all. (It very often doesn’t, even if the word is meaningful elsewhere in the game.)
Also, if I understand correctly from discussions of “how did my game get to be so slow?”, it’s checking the words in the command against every possible game object (as opposed to the objects in scope) that gets computationally expensive. If you’re going to check the command against every object you may as well do a smarter parser error to tell you where you last saw the object, or just that you’ve seen the object before. That’s not very expensive, once you’re mapping the words to the object.
Also also, this allows the player to exploit the parser error system to probe the games’ contents again.
This is just repeating zarf’s comment three up, but still, the point is that getting to to behave at all nicely is nontrivial. Which is why it’s handy to have a totally generic response.
If you want to write your own parser that works that way, I’d be interested to see it. (I mean, seriously. I like new parsers. But it’d be a lot of work.)
That’s not the way the Inform parser works, though, and I’m not sure if there are other parsers that work that way. When the user enters “look hat” it resolves “hat” against every object in scope. If there is a hat not in scope, it doesn’t check it. So when it hits the parser error, it doesn’t know that “hat” matches something not in scope.
There can be some grammar tokens that match against every object in the world whether it’s in scope or not, but that requires looping over every object in the world when it’s parsing the command, which takes time.
And then your suggestion about the “silver teapot”… phew. Now if the player types “look top hat” and there’s no top hat in sight, the parser is to respond “You don’t see a hat here,” unless presumably there’s a hat that’s not a top hat there, in which case it had better be “You don’t see a top hat here.” And if the player typed “x silver” (no noun) then it needs to print “You don’t see anything silver here,” which means the parser has to individually keep track of which words are adjectives and which words are nouns instead of referring to the object. This is hard.
Whereas keeping track of individual objects and which ones the player has seen is relatively doable and allows “x silver” to sensibly respond “You last saw the tarnished silver teapot in the mudroom” if the player has seen the teapot, or “You haven’t seen anything that can be described that way” if they haven’t.
I’m generally with zarf and matt w on this matter. In a largish game with, say, 500 objects, you certainly don’t want to be looping over every object-and-input-word combination at runtime. This is not just a matter of performance: A limited scope is helpful because it helps with disambiguation. “PICK UP CLOSED” may reasonably ask the player which of the closed, portable objects in scope to take. If there are no closed, portable objects nearby, but there are two closed doors in the room, it gets more interesting: I think it’s all right (but perhaps not ideal) to ask the player which of the closed doors to attempt to take. It would be distracting to ask whether they perhaps meant the cigar case that’s inside the safe, over in the library.
Indeed. English, in particular, strikes me as a language where words are often used ambiguously as adjectives or nouns. The green house, the golf green, the green party. The antique silver, the silver antique.
But let’s get back to the original example of the hat in the box. It would be interesting to try an approach where containers can be flagged as having known contents. The flag is set when the container is first opened or examined/searched. When computing the current scope, descend into open or transparent containers as usual, but also into containers with known contents. Then, when attempting to pick up the hat, the action should be deemed unlikely during disambiguation, because the hat is out of reach. If the action is attempted anyway (because “hat” truly only refers to the object that’s currently out of reach, albeit in scope), then it would perhaps be prudent to attempt an automatic action like “first opening the box”, and then ultimately rely on the normal reachability rules to determine whether taking the hat is possible.
Nah. I’m suffering from having to use, and design around, the existing Inform parser, because writing a parser that would work a different way would be a lot a lot of work.
I think I’ve elsewhere said that it’d be cool to have a parser that worked by associating things with dictionary words, and for each dictionary word looking up a list of things that could be associated with it at that moment and seeing if it was applicable–rather than the Inform model, which if I’m not mistaken associates dictionary words with things and for each word loops over applicable things to apply the dictionary words to it. But I don’t have a few spare years to write such a parser. (And if I’m not mistaken that model is built in to the z-machine and glulx virtual machines, so I’d have to write more than a new parser.)
The Jinxter model could be fine if I could program in it, but there isn’t a readily available language for writing Magnetic Scrolls-format adventures, is there?
My primary argument was about disambiguation. I even made a suggestion about how to solve the problem, by carefully altering the definition of scope.
That being said, I happen to care about performance. Many recent text games are noticeably laggy on modern hardware, suggesting that something is seriously wrong inside them. The Dialog parser is fast, declarative and amenable to custom modifications, so I recommend using it as a sandbox for trying out new parser ideas. I’m currently looking at techniques for making it even faster, by combining compile-time analysis with runtime code for dealing with object names that change during play (such as “open” and “closed”).
Disambiguation is important, because it helps mapping user input to game objects without asking unnecessary questions (like which of 2 items the player wants to drop while he is only carrying 1 of them).
I made a disambiguation system where the story author can add disambiguation rules to actions.
If the parser finds more than one hit for a subject, it will check with the action if there are disambiguation rules. Next it runs the possible hits by the disambiguation rules and the candidates get points awarded if they comply. In the end, the one with the most points wins.
With this system, each action can have its own rules.
“drop [o_object1] in [o_object2]”
if testflag(o_object1.f_takeable) then score(5) endif
If owns(o_actor, o_object1) then score(10) endif
If testflag(o_object2.f_container) then score(10) endif
The parser will make permutations if there is more than 1 disambiguity in the user input. So if there are 3 hits for object1 and 2 hits for object 2, it will run 2 x 3 = 6 evaluations against the disambiguation rules.
ADRIFT has four levels of scope to decide which object(s) you are probably referring to.
Does it exist
Have you ever seen it
Can you currently see it
Will it pass the restrictions of the task
Here is what it does:
It keeps adjectives and nouns separate in object names, always using adjectives for disambiguation.
Get automatically figures out that there is only one hat nearby that you are not already holding.
Put hats recognises the plural and looks for all objects in inventory that match the noun “hat”.