The problem is that dobjFor(All) does what it says, which is preempt all other action handlers. Which is not what I want. What I want is to preempt any action without an explicit action handler (which is what dobjFor(Default) does)…but only if some condition applies. And if the condition doesn’t apply, I want it to fall through to whatever behavior would have happened if the check wasn’t there in the first place.
As a concrete example: like I said, I was looking at card-playing items in and out of a game. Here let’s just consider a deck of cards. Outside of a game, it should just be more or less a normal Thing: you can pick it up, put it in containers, try to light it on fire, whatever. In a game, it should block all actions except those specifically permitted as part of gameplay. Some code:
#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
startRoom: Room 'Void' "This is a featureless void. ";
+me: Person;
+deck: Thing 'deck (of) cards' 'deck of cards'
"It's a deck of playing cards. "
gameFlag = true
// THIS DOESN'T WORK, DON'T COPY IT
dobjFor(Default) {
verify() {
if(gameFlag == true)
illogicalNow('{You/He} can\'t mess with
the deck during a game. ');
inherited();
}
}
dobjFor(Examine) { verify() {} }
dobjFor(Shuffle) {
verify() {
if(gameFlag == true)
illogicalNow('They\'ve already been shuffled. ');
}
action() {
defaultReport('Okay, the cards are now shuffled. ');
}
}
dobjFor(Discard) {
verify() {
if(gameFlag == nil)
illogicalNow('{You/He} can only discard during
a game. ');
}
action() {
defaultReport('Okay, the cards have been discarded. ');
}
}
;
versionInfo: GameID;
gameMain: GameMainDef initialPlayerChar = me;
DefineTAction(Shuffle);
VerbRule(Shuffle)
'shuffle' singleDobj
: ShuffleAction
verbPhrase = 'shuffle/shuffling (what)'
;
modify Thing
dobjFor(Shuffle) {
verify() { illogical('{You/He} can\'t shuffle that. '); }
}
;
DefineTAction(Discard);
VerbRule(Discard)
'discard' singleDobj
: DiscardAction
verbPhrase = 'discard/discarding (what)'
;
modify Thing
dobjFor(Discard) {
verify() { illogical('{You/He} can\'t discard that. '); }
}
;
We get two new actions, >SHUFFLE [something] and >DISCARD [something] (neither of which actually do anything except output informational messages in this example).
As written, the above code does what I want when there is a game in progress (that is, when the gameFlag on the deck is true. Then most actions will fail with a message telling the player they can’t mess with the deck during a game, with the exception of >EXAMINE and the card-specific actions.
But then if gameFlag is not true:
Void
This is a featureless void.
You see a deck of cards here.
>sit
(in the deck of cards)
…the normal behavior of the object is borked.
If instead of using dobjFor(Default) we use dobjFor(All), then everything works find when we’re not in a game, but when we are in a game the things we want to be exceptions still fail.
I guess one solution is to go down the road of basically building the entire action-handling logic for the object in a catchall dobjFor(All), but that’s going to rapidly get out of hand for the kind of things I want to do (in this example the conditional being checked has a single clause—is the game flag set—but in the real code different actions are valid only during specific phases of play) and it’ud make it very challenging to handle things in abstract classes.