Disallowing 'take all' (adv3Lite)

As I start to tidy up my Comp game, I notice that one reviewer had issues when using the ‘take all’ command. I never use this command, so it never occurred to me that I need to disallow it. Unfortunately, that’s harder than it might appear.

The adv3Lite library defines Take as allowing multiDobj. That’s appropriate, as the player might want to ‘take rug and matches’ in a single command line. So I tried this:

VerbRule(TakeAll)
    (('take' | 'get' | ('pick' 'up') | 'grab') ('all' | 'everything'))
    | ('pick' ('all' | 'everything') 'up')
    : VerbProduction
    action = TakeAll
    verbPhrase = 'take/taking everything'
    missingQ = 'what all do you want to take'
;
DefineIAction(TakeAll)
    execAction(cmd)
    {
        "Sorry -- the TAKE ALL command is not implemented in this game. ";
    }
;

Unfortunately, that just plain doesn’t work. ‘take all’ still grabs all of the individual items in the room. And I don’t think there’s a way to give a priority to a VerbRule.

Next I tried using a Doer. This fails to work, however, because the syntax of a command line in a Doer requires a specific object, and ‘all’ is not an object. This causes a run-time error.

gameMainDef has a true/nil switch for allVerbsAllowAll – but this is what the docs say: “…if you set this to nil, only the basic inventory management verbs (TAKE, TAKE FROM, DROP, PUT IN, PUT ON) will allow ALL.” That’s exactly the opposite of what I want!

Can anyone suggest a way to disallow ‘take all’?

Turns out there’s a brute-force way to do it:

+ me: Thing 'you'   
    isFixed = true       
    person = 2
    contType = Carrier    
;
++ theAll: Unthing 'all; ; everything'
    'Sorry: Commands with ALL are not allowed in this game. '
;

This has the undesirable side effect that ‘drop all’ is no longer allowed. But it does work.

What about the allowAll property of Action? The source comment in action.t says

   /* 
     *   Can ALL be used with this action? By default we take our value from
     *   gameMain.allVerbsAllowAll, though basic inventory-handling actions in
     *   the library will override this. This property is really only relevant
     *   on TAction and its descendents, but we define it here just to make sure
     *   no cases are missed.
     */
    allowAll = (gameMain.allVerbsAllowAll)

Which makes me think perhaps you could just modify the Take action?

Possibly – but modify can’t be used with DefineTAction(Take). I just now tried it, and the compiler didn’t like it. Now, DefineTAction is of course a macro, but it’s not at all clear to me from the Library Reference Manual and the source code what the macro expands into, or how the allowAll line (which is in the usage of the macro) gets passed on to the actual action.

I have not compiled this, but wouldn’t it work to do:

modify TakeAction
   allowAll = nil ;

?

That does indeed seem to work, though I changed it slightly to

modify Take
    allowAll = false  // edit: should be nil
;

which produces the output

The Lab

A not entirely sterile room filled with bubbling retorts, oscilloscopes, and discarded candy wrappers.

drop all

You drop the plank.

take all

Sorry; ALL is not allowed with this command.

I think you meant nil, not false? Yes, this works, but I think I’m going to do it the brute-force way using an Unthing. The reason being, the point of disallowing all is to avoid letting the player shortcut (cheat) by finding out exactly what’s in the room. If I just set allowAll to nil on Take and Examine, for instance, then the command ‘feel all’ will report, line by line, everything that’s in scope.

Yes you’re right, thanks.

What about

modify Action
   allowAll = nil
;
modify DropAction
   allowAll = true
;

?

Looking at this in the reference manual in action.t:

/* 
 *   Get a list of all the objects this action will act on if the player
 *   types ALL for role (DirectObject or IndirectObject). This is the method
 *   actually called by the Parser. We first obtain the list of objects
 *   returned by getAll() and then filter out any objects for which
 *   hideFromAll(action) is true for this action. Subclasses should normally
 *   override getAll() rather than this method.
 */
getAllUnhidden(cmd, role)
{
    return getAll(cmd, role).subset({x: x.hideFromAll(self) == nil});
}

It seems there is some predefined behavior to remove unseen items from the list of ‘all’. Maybe this is a more player-friendly way to write it?

Nope. That compiles, if you switch it to “modify Drop” (DropAction is not an object). But it doesn’t work. If you do that, ‘take all’ still works. I just checked.

OK… again, going from adv3 only, so it was just a shot. That ought to work for adv3 though, right?

Unlike adv3, in adv3lite the class for the “take” action is Take, not TakeAction. So just do:

modify Take {
    allowAll = nil;
}

The DefineTAction macro of adv3lite does not add the Action suffix to the generated class name. So DefineTAction(Foo) creates a class named Foo, not FooAction.

1 Like