Determining if input is the response to a disambiguation request?

Is there any way (outside of parser internals) for an arbitrary function/method to check if it was called in the middle of a disambiguation response? For example:

What do you want to take?


During the processing of the “pebble” input, is there anything in the environment/globals that indicates that processing got there via a disambiguation prompt?


Not at a computer, but yes, the parser passes rmcDisambig around… look up where the library uses the rmcXXX enums and you can see which methods they extend to. I used that so that verbs like ‘water’ and ‘hook’ etc will not push the parser into a new command if it’s asking for disambig

1 Like

How are you accessing rmcDisambig? It’s used internally in the parsing process—the two points where it might originate are both in BasicResolveResults.ambiguousNounPhrase(), and from there it can be passed in the arglist for readMainCommandTokens() and tryOops(), but the closest thing to a external “hook” to check if it’s there seems to be something like writing a StringPreParser or something like that. I don’t think it gets recorded in gAction or anything like that.

readMainCommandTokens(), for example, can get rmcDisambig as its one argument (which). It passes that argument on to readMainCommand() (which just uses it to select the prompt) and to StringPreParser.runAll() (from where it will be passed to each pre-parser’s doParsing()).

So if you want to check in an action’s verify() or something like that, I don’t know how you’d approach it apart from something like making a string pre-parser that doesn’t do anything but set a global flag that can be checked from anywhere.

1 Like

I didn’t need to query anything from verify so I just did it in rmctoks. I added dontPreempt as a prop to Action and at the point where the parser decides if it’s going to recast the disambig as a new command or not I used “if !action.dontPreempt” as an add.
So if you need to query from verify I’d just try to set a flag on gAction in a try finally block wherever rmcDisambig or rmcAskObject are first passed…


Experimenting with trying to add flags in a StringPreParser, it looks like the specific disambiguation example I used (>TAKE without an object) actually ends up using rmcAskObject instead of rmcDisambig, for whatever that’s worth.

So, back at a computer. rmctoks is me hating using a mobile phone for readMainCommandTokens.
It turns out that what I did was first

replace readMainCommandTokens(which) { 
    if(which!=rmcCommand) libGlobal.disambigOrAskMode = true;     
    try { ...
    finally {
        libGlobal.disambigOrAskMode = nil;                   

Subsequent to which I discovered the use of rmcDisambig/askForObject, and then for my purposes all I did was

replace tryAskingForObject(...args...) {
    if (cmdMatchList != [] )  //this block is library, but I added the check
            //* solving an issue where player types 'water cabbages'. "What with?" 'water' "What do you want to water?"
            local ac = cmdMatchList[1].resolveFirstAction(issuingActor,targetActor);
            if(ac && ac.dontPreempt) ; //pass
            else if (!match.isSpecialResponseMatch)     {
                throw new ReplacementCommandStringException(str, nil, nil);   }
1 Like

Thanks, that makes sense.

But ooooof, man is it a lot of work to twiddle the parser like this. It feels like I’m going to end up patching or replacing half of the original parser to make this work.

1 Like

I’ve frequently wished some of the parser top level functions were broken into smaller parts…

1 Like

Yeah, when I’ve had to touch/replace things like this and executeCommand(), I’ve ended up implementing the replacement as a singleton, breaking out the different parts of the loop as methods.

I assume part of the reason most of the core parser methods are implemented as big flat functions was to avoid context switches in the core gameplay loops, out of performance concerns. I don’t know how well breaking things out into a bunch of methods would fare on early 2000s desktop hardware, but it seems to be fine on modern hardware.

   M O O D

(Apparently I cannot post such a short reply, according to the forum)

I feel this way with a lot of the travel code, too. So many phases of travel are just dumped into one method.

1 Like

I don’t remember Lite’s process, but travel is (I think) decently broken up in adv3?

1 Like