I have a problem involving a car object. For in-game reasons the choice of car seat is important, and I’d rather remove the inelegance of allowing the player to enter the car without choosing a seat (or worse, requiring the player to enter the car before choosing a seat). Ideally there would be a way to redirect player attempts to enter the car to seat selection. And I have found a way to do so, as illustrated in the code below, using the predicate (rewrite $ as $). One problem with this solution is that it seems like a hack solution – like there ought to be a simpler and faster solution. The bigger problem is that currently if I want to allow another object, a truck, say, to be referred to as a vehicle, the player will be redirected to the car seats.
Is there a better way?
(current player #jenny)
(#jenny is #in #garage)
#garage
(room *)
(name *) garage
#car
(name *) car
(dict *) vehicle
(singleton *)
(actor container *)
(* is #in #garage)
(rewrite [$Verb | $Words] into [enter seat])
{
($Verb is one of [enter go])
(match car dict $Words)
(or)
($Verb is one of [go get])
([$Head | $Tail] = $Words)
($Head is one of [in into])
(match car dict $Tail)
}
(match car dict [])
(match car dict [$Head | $Tail])
(collect words)
*(dict *)
(into $List)
($Head is one of $List)
(match car dict $Tail)
#driver-seat
(name *) driver's seat
(dict *) driver bucket
(in-seat *)
(* is #in #car)
#passenger-seat
(name *) passenger seat
(dict *) passenger's bucket
(in-seat *)
(* is #in #car)
#right-side
(name *) right side of the back seat
(dict *) rear bench
(singleton *)
(in-seat *)
(* is #in #car)
#left-side
(name *) left side of the back seat
(dict *) rear bench
(singleton *)
(in-seat *)
(* is #in #car)
It’s possible! I’ll write up a better explanation tomorrow, but you’ll want to make a list of possible actions, call (disambiguate action $List $Result) which asks the player to pick one, then (try $Result).
So, this is a good question! I hadn’t really thought about it before, and my first instinct was “no, it’s not possible”. But since the whole Dialog parser is written in plain Dialog code, it’s worth cracking it open to have a look.
Searching for “did you want” brings up this predicate:
(disambiguate action $List $Result)
(collect $Action)
*($Action is one of $List)
~{
*($Action recursively contains $Obj)
($Obj is hidden)
}
(into $NonSpoilery)
(if) (empty $NonSpoilery) (then)
($AskList = $List)
(else)
($AskList = $NonSpoilery)
(endif)
(if) ($AskList = [$Single]) (then)
($Result = $Single)
(elseif)
(rephrase as object disambiguation
$AskList
$ComplexAction
$Template
$ObjList)
(then)
(div @meta) {
Did you want to (describe action $ComplexAction)?
}
(par)
(prompt and input $Words)
{
(now) (head noun is required)
(disambiguate by object name $Words $Template $ObjList $Result)
(or)
(now) ~(head noun is required)
(disambiguate by object name $Words $Template $ObjList $Result)
(or)
(now) (deferred commandline $Words)
(stop)
}
(else)
(div @meta) {
Did you want to: (line)
(enumerate actions $AskList 1 $)
(if) ~{ (library links enabled) (interpreter supports links) } (then)
\( Type the corresponding number \)
(endif)
}
(par)
(prompt and input $Words)
{
(understand $Words as number $N)
($N > 0)
(nth $AskList $N $Result)
(or)
(now) (deferred commandline $Words)
(stop)
}
(endif)
Which actually seems perfect for your needs. What it does is:
Takes a list of actions
Filters out any “spoilery” ones (ones that involve ($ is hidden) objects), unless that would filter out all of them
Checks if all of the actions are the same except for one specific object that varies between them
If so:
Asks which of those objects you want to act on
Gets a line of input
Tries to use the player’s input to disambiguate, first via (heads $), then (if that fails) via (dict $)
If that works, unifies $Result with the chosen action
If that doesn’t work, stashes the player’s input in (deferred commandline $) and (stop)s
If not:
Presents a numbered list of the actions
Gets a line of input
Tries to match that input to a number
If that works, unifies $Result with the chosen action
If that doesn’t work, stashes the player’s input in (deferred commandline $) and (stop)s
In other words, calling this predicate will ask the player to choose one of these actions, and if they choose one, it’ll put the result in $Result. If they don’t (they type a new command instead), it’ll put that new command in a global variable, then (stop) to jump back to the main read-parse-execute loop. That loop will check the global variable, see there’s a command there, and parse it.
So if you want an action to redirect to disambiguation, all you have to do is: