How do you deal with a situation where you want to suppress output “within” an action?
For example, one of the things I’m working on is providing a “third person” version of stock adv3 actions that only really work if the actor taking the action. >EXAMINE
, for example, which by default displays the examined object’s description. Having an object description show up in the transcript because Alice decided to examine something doesn’t make a lot of sense.
Say we’ve defined our game world like this:
startRoom: Room 'Void' "This is a featureless void. ";
+me: Person;
+pebble: Thing 'small round pebble' 'pebble' "A small, round pebble. ";
+alice: Person 'Alice' 'Alice'
"She looks like the first person you'd turn to in a problem. "
isHer = true
isProperName = true
;
+flower: Thing 'smelly flower' 'flower'
"A smelly flower. "
smellPresence = true
smellDesc = "It smells like a flower, only more so. "
;
The player, Alice, a pebble, and a flower in a single room. The flower has smell presence and a smell description. So we want to modify Thing.basicExamineSmell()
to allow Alice to smell the flower. In stock adv3, doing a newActorAction(alice, Smell, flower);
will work, but it will output “It smells like a flower, only more so.” the same as if the player had done >X FLOWER
themselves, without any indication that the message is appearing because Alice did something.
Because examining things can have side effects, I want to be able to do the default examine action but suppress the output, and then output an informational message to indicate an NPC just took an action. So, using the mainOutputStream
output toggle, something like:
modify Thing
// THIS DOESN'T WORK
basicExamineSmell(explicit) {
// Check to see if the current actor is the player. If
// so, just do the adv3 default stuff and return.
if(gActor == gPlayerChar) {
inherited(explicit);
return;
}
// We're not the player, so we're an NPC. So we turn
// off output, do whatever the default behavior is,
// and then turn output back on.
mainOutputStream.enabled = nil;
inherited(explicit);
mainOutputStream.enabled = true;
// Finally, report that the NPC is doing something.
defaultDescReport(&thirdPersonSmell, gActor, self);
}
;
That is, we check to see if the current gActor
is the player and if so just do the inherited behavior and return. Otherewise we (try to) turn off output, do the inherited behavior, turn output back on, and then output a stock report indicating that the actor took an action. Elsewhere I have:
modify playerActionMessages
thirdPersonSmell(actor, obj) {
return('{You/He} smell{s} <<obj.theName>>. ');
}
;
…along with stock message for other actions like this.
Anyway, as alluded to in the comments above, this doesn’t work. We implement a system action to initiate some NPC actions:
DefineSystemAction(Foozle)
execSystemAction() {
aioSay('\n===START===\n ');
newActorAction(alice, Smell, flower);
newActorAction(alice, Smell, pebble);
aioSay('\n===END===\n ');
}
;
VerbRule(Foozle) 'foozle': FoozleAction VerbPhrase = 'foozle/foozling';
And this gives us:
>foozle
===START===
It smells like a flower, only more so.
Alice smells nothing out of the ordinary. Alice smells the pebble.
===END===
Note that we have two separate failure modes here. The first is because the flower has an explicit smellDesc
, which is a double-quoted string that gets output directly. This suppresses the “NPC action” message we added, which is a defaultDescReport
. In the second case we get both the stock thingSmellDescMsg
and our “NPC action” message, both as defaultDescReport
s.
If we re-write the system action to wrap everything inside our output toggle and remove the output toggles from defaultExamineSmell()
:
DefineSystemAction(Foozle)
execSystemAction() {
mainOutputStream.enabled = nil;
aioSay('\n===START===\n ');
newActorAction(alice, Smell, flower);
newActorAction(alice, Smell, pebble);
aioSay('\n===END===\n ');
mainOutputStream.enabled = true;
}
;
modify Thing
basicExamineSmell(explicit) {
if(gActor == gPlayerChar) {
inherited(explicit);
return;
}
inherited(explicit);
defaultDescReport(&thirdPersonSmell, gActor, self);
}
;
…but then we get no output (not even our NPC action message):
>foozle
===START===
===END===
That’s a specific example (that I’m still having problems with, beacuse the fact that descriptions can either be reports (which are output after the action) or double-quoted strings (which are output “immediately”) complicates any output toggling scheme. Complicated by the fact that new actions are always executed with their own transcripts.
But it’s a general class of problem I’m dealing with. Namely, wanting to execute an action “normally” (to, for example, be able to read e.g. the failure flag in reports, so just implementing a ComandTranscript
class that silently discards reports won’t work)…while still suppressing all output.