A TADS3/adv3 module for handling failure messages involving actors not in scope

The fundamental problem:

>X ALICE
You see no alice here.

I’ve previously implemented a number of partial fixes to this in a couple of places. I was in the process of re-factoring one of them to use with the memoryEngine module I’m working on and discovered a couple of corner-cases that needed fixes. That resulted in a bunch of digging through parser internals, and that in turn produced enough stuff that I think it probably should be a standalone module.

The Problem

The basic problem with the just-fiddle-with-the-scope fixes I’d used previously is that the underlying behavior (outputting the generic “You see no [typed word] here” failure message) comes from more than one place in the code. I.e.:

>x alice
You see no alice here.

>alice, take pebble
You see no alice here.

>give pebble to alice
You see no alice here.

In the first case the message is coming from noun resolution by a resolved Action instance, in the second case it’s coming from ActorResolveResults (via the parser’s exception handler) when actor resolution fails in the parser’s inner loop, and in the last case it’s in the completely separate noun resolution logic in TIAction.

A Solution

The approach I settled on here is to wrap the message (on in this case playerMessages).

The method takes the noun phrase the parser didn’t like, creates a new command with it as the only noun phrase, tokenizes, parses, and resolves the action for it, then marks the Action instance with a flag that puts all Person objects in scope, and then attempts noun resolution. If noun resolution succeeds, it’s checked if there’s exactly one direct object and that it is a Person. If so, we output our bespoke failure messages:

>x alice
There isn't anyone named Alice here.

>alice, take pebble
There isn't anyone named Alice here.

>give pebble to alice
There isn't anyone named Alice here.

This is one of those things where the solution is just a couple hundred lines of code but it took way too much fiddling around with parser internals to figure out all the weird corner cases.

Anyway, here’s the repo: personScope github repo.

The behavior is enabled by setting usePersonScope = true on the player character. That is, on the Actor instance that issues the commands, not the actor or actors being referred to in the commands.

3 Likes

Congrats, it’s an excellent starting point.

Yes, starting point: there can be two actors, general case being

Alice, give the pebble to Bob

obviously, when Bob isn’t in scope, Alice should point the problem to the PC, and the resulting failure answer should also be in-character…

Hope that you enjoy the large dish presented to your excellent brain, and
Best regards from Italy,
dott. Piergiorgio.

Easy-peasy. The important change is to the actorActionMessages module I posted about elsewhere. It already allowed creation of per-actor action messages, but it turns out that this kind of thing is a parser message. But it was easy enough to update the module to also support per-actor (and per-ActorState) parser message objects as well.

So we have to add a message object for Alice containing the behavior we want:

alice: Person 'alice' 'Alice'
        "She looks like the first person you'd turn to in a problem. "
        isHer = true
        isProperName = true
;
+NPCParserMessages
        personNotHere(a0, a1) {
                gMessageParams(a0, a1);
                "<q>{You a1/Him}?  Who's that?</q> {you/she a0} asks{s a0}. ";
        }
;

…to get…

North Room
This is the north room.  There's another room to the south.

Alice is standing here.

>alice, give pebble to bob
"Bob?  Who's that?"  Alice askss.

>