cannot intercept "wear" action in code

I have a character in bed in a bedroom. The bedroom contains several items of clothing and furniture and whatnot defined as Thing, Surface; Container; Thing, Wearable; and Decoration. Harry is supposed to get out of bed then wear the wearables. That part works.

Except…

If the command is “wear all” the game itemizes a long list of things that cannot be worn in addition to the things that can be worn.

I would like to trap the “Wear all” command and abort the process with a single, simple (“too much; be more specific”) message.

But I can’t find where the “wear” command—much less “wear all”—gets executed.

I’ve tried adding a dobjFor(Wear) block and setting a Workbench debugger break point at the if() statement, but it does not work.

dobjFor(Wear) { action() { if(gDobj == 'all') "Boo!"; } }

If I change that to dobjFor(Take), the break point works and I can fiddle with the code. But when it’s Wear, PutOn, or Don (the synonyms for Wear defined in the Wear VerbRule in garramar.t), the break point does not trap the action.

Here’s a complete workable testbed game, pared down to just a few items in the room to more easily isolate the problem…

#charset "us-ascii"

#include <tads.h>
#include "advlite.h"

versionInfo: GameID
    IFID = '47ca87f1-2d0e-4b54-a776-2bc128e30927'
    name = 'TADS 3 Lite Test Bed'
    byline = 'by Jerry Ford'
    htmlByline = 'by <a href="mailto:jerry.o.ford@gmail.com">
                  Jerry Ford</a>'
    version = '1'
    authorEmail = 'Jerry Ford <jerry.o.ford@gmail.com>'
    desc = 'Test bed for experimenting with TADS 3 Lite.'
    htmlDesc = 'Test bed for experimenting with TADS 3 Lite.'
;

gameMain: GameMainDef
    initialPlayerChar = harry
    usePastTense = true
;

// harry, main character
harry: Actor 'Harry;;man self' @harrysBed
    ""
    contType = Carrier
    globalParamName = 'harry'
    isFixed = true   
    isHim = true
    isInitState = true
    ownsContents = true
    person = 3   
    proper = true
    
;

harrysBedroom: Room
    'Bedroom' 'bedroom'
    "The bedroom."
    
;
+ harrysBed: Container 'bed;;bed'
    "The bed."
    
    dobjFor(Take)
    {
        action()
        {
            if(gDobj == 'all')
                "Boo!";
        }
    }
;

And here’s the game outpout…

Ignore the cheeky “Yeah, right, as if…” responses; that’s just me experimenting with custom messaging. What I’m after is getting rid of the entire list of things that can’t be worn.

Jerry

The simplest thing to do is simply to add the following to your code:

modify Wear
    allowAll = nil
;

This simply disallows the use of ALL altogether with the WEAR command.

A more discriminating method is to restrict what ALL refers to with the WEAR command, thus:

modify Wear
    getAll(cmd, role)
    {
        return scopeList.subset({ x: x.isWearable});
    }
;

The above code means '"With the WEAR command, take ALL to refer to everything in scope that’s wearable. "

Although at the moment this produces such a seemingly odd response to WEAR ALL when there’s nothing wearable in scope that I’ll need to take a look at it.

Incidentally, the following code is absolutely guaranteed not to work:

+ harrysBed: Container 'bed;;bed'
    "The bed."
   
    dobjFor(Take)
    {
        action()
        {
            if(gDobj == 'all')
                "Boo!";
        }
    }
;

Firstly, gObj is always an object (unless it’s nil), so it can never be a string, which means that the if condition can never be met. Second, as you’ve written it, the TAKE action will never to anything with the bed since you’ve overridden the inherited handling with code that can never be executed. You probably meant to write something like:

+ harrysBed: Container 'bed;;bed'
    "The bed."
   
    dobjFor(Take)
    {
        action()
        {
            if(gCommand.matchedAll)
                "Boo!";
            else
                inherited;
        }
    }
;

Which would at least execute the normal handling when the condition isn’t true, and which at least tests correctly for the use of ALL (though I grant you that how to do this is probably far from obvious).

Possibly what’s needed here is a hideFromAll() method similar to that in the adv3 library. I’ll look into adding it for the next release, along with dealing with a number of issues this example throws up, but in the meantime the first suggestion given at the beginning of this post should probably solve your immediate problem.

Thanks. Your suggestions look good, and I agree, either of them will likely solve my immediate problem.

However, I am still curious as to why a break point works for dobjFor(Take) but not dobjFor(Wear).

They are both valid verbs and they both refer to the same object (the bed). Even though the if() statement isn’t valid, it’s the same if() statement in both cases and it isn’t being evaluated yet.

Why isn’t the process halting at the break point for the Wear action?

Jerry

I’m guessing that you’re setting the break-point in the action routine in each case. As you’ve defined the bed it’s takeable but not wearable. That means that with the bed the WEAR action is ruled out at the verify stage, so the action stage is never executed. Provided Harry isn’t in the bed, however, the TAKE action passes the verify stage and so reaches the action stage.

Remember that the whole point of the verify stage is to rule out actions that are obviously impossible. If they’re ruled out at the verify stage, they won’t go on to any later stage.

Bingo!

That was it, break point in verify() works as advertised.

Thanks.

Jerry

(uh, not sure… is “Bingo!” as for “Yes, that’s it!” an Americanism or does it work in the Queen’s English as well?)

“Bingo” in this sense is perfectly at home in British English. So much so, in fact, that had I used the expression I might have asked your question the other way round!