This is another case where this is something I need but I’m not sure how many other TADS3/adv3 authors will: modularExecuteAction github repo.
This is similar to my previous modular replacement for executeCommand(), but this time replacing executeAction()
.
In stock adv3 executeAction()
is called after the verb is resolved but before nouns are resolved (mostly). So it has an Action
instance and wraps a call to Action.resolveNouns()
in a try/catch
block, calling the action’s doAction()
if there are no surprises. In the middle it does some bookkeeping (deciding on whether or not to create an savepoint for undo
and a couple of checks for things to do when one actor is giving another actor orders).
The main gimmick of the new process is that (like modularExecuteCommand
) it provides a class for exception handlers, allowing you to add bespoke exception handlers without having to touch the underlying method.
As an example, here’s the replacement code for the one catch
block in the stock function:
// Replacement for the single stock exception handler.
eaRemapActionSignalHandler: EaExceptionHandler
type = RemapActionSignal
handle(ex, st) {
ex.action_.setRemapped(st.action);
st.action = ex.action_;
return(eaRestart);
}
;
The type
is a the subclass of Exception
the handler handles (in this case RemapActionSignal
).
The handle()
method is what actually handles the exception. The arguments are the exception instance (ex
here) and a state object for the current executeAction()
process (st
here). The latter will contain the arguments to executeAction()
as well as the ResolveResults
instance used for noun resolution. More details on that below.
After the handle()
method does whatever it’s going to do, its return value should be one of:
eaRestart
— tellsexecuteAction()
to start over from the beginning. This is done by the example above to handle action remappingeaContinue
— tellsexecuteAction()
to continue processing after the exception. By default this means the exception will be re-thrown (to allow it to be handled by something outside ofexecuteAction()
)eaHandled
— tellsexecuteAction()
to NOT re-throw the exception, finish normal execution, and return
And for completeness, the properties of EaExceptionHandler
mentioned above are:
dstActor
— the actor the action is directed atdstActorPhrase
— the phrase from the command referring to the actor the action is directed atsrcActor
— the actor initiating the actioncountsAsIssuerTurn
— a boolean flag that’ll betrue
if the command being processed is an order being given by one actor to another and this is the originating actor’s action for the turnaction
— the resolvedAction
instanceresults
— theBasicResolveResults
instance created byexecuteAction()
for noun resolution
The last one is created by executeAction()
, the rest are its arguments.
Dunno how useful this will be to anyone else. I got here in the process of writing code for handling “complex” player-to-NPC instructions, like for example telling an actor to go get an object that’s currently out of scope. I’d previously been handling this via elaborate tweaking of Action.objInScope()
but that felt like it was getting out of hand as the number of cases it was necessary (and the number of objects affected) increased.
I might end up going back and re-tweaking my personScope
module (that handles replacing the stock “You see no alice here.” failure message with something like “Alice isn’t here right now.” or “You don’t know anyone named Alice.” for Person
instances) to use this as well.