Oh, man, this one was a while ago! I need to refresh my memory for how this works!
Okay. Let’s imagine we’re giving the command ALICE AND BOB, GO NORTH.
The way the parser works by default, if it sees a comma, it jumps back to the beginning of the command and calls NounDomain
. NounDomain
is the routine that tries to parse the name of a single object, so most of the other parsing routines delegate to it.
That’s the bit that I modified: instead of calling NounDomain
, I make it instead call ParseToken(ELEMENTARY_TT, MULTI_TOKEN)
—that is, try to parse a “[things]” token.
This “[things]” token will fail, because we already know the list of actors ends with a comma—that’s how we ended up here in the first place. (If “[things]” sees something after a comma that it can’t understand, it thinks there’s a bad entry in the list.) But as it works, it puts the list of things it parses into the multiple object list, and it doesn’t clear that out when it fails! So now the multiple object list is {Alice, Bob}.
Once it fails, we go back into Inform 7 by calling the “multiple actor rulebook”, which takes the multiple object list, makes sure it’s a valid list of people, and stores it in a global variable of its own. It then takes the rest of the command—everything that comes after—and sticks this in another global variable. If this rulebook succeeds (the list was valid), then the parser continues after the comma, attempting to parse the rest of the line as a normal command. If it fails, then the parser reacts the same way it originally would if NounDomain
failed—deciding the part before the comma isn’t an actor name after all, and trying to parse it as a verb instead (the .NotConversation
label).
So now we have the list of intended actors {Alice, Bob} stored in a global variable, and the intended command GO NORTH in another global variable. Once we have this, a “rule for reading a command” takes over. As long as the list of intended actors isn’t empty, we set the player to the first element of that list, and parse the intended command. The player is now Alice, and the parser is given the text GO NORTH.
But wait, we don’t want this action to be performed as the player! We want it to be performed by an NPC! So a “first before doing anything” rule sees what’s happening, resets who the player is, and turns the action into a request: “going north” becomes “asking Alice to try going north”. It executes that action, then removes the first entry from the intended actor list.
This continues until the multiple actor list is empty. Since the command is actually parsed separately for each actor, it can deal with the actors having different surroundings: ALICE AND BOB, TAKE ROCK when each one has a different rock in their room, for example. The “rule for reading a command” also pauses when a disambiguation question is asked, letting the player answer before going back to multicommand processing.
As a side bonus, the extension also creates the action COMMAND [things] TO [text], which I used to test the multicommand machinery. In other words, this extension gives you a way to create new actions that convert to giving orders, which normally is nigh impossible! It just puts the list of actors and the intended command into the appropriate global variables, without any of the parser trickery.