Counting direct/indirect objects in action

I’ve been working around with TADS 3 and using a lot of the bookshelf files to figure things out, but I seem to be having a bit of trouble figuring out where to look for this one:

I’ve found a (probably pretty unusual) scenario in which an action which defines its verb rule with iobjList should behave a little bit differently on a particular direct object depending on the number of indirect objects actually given. I think that checking gIobj in the dobjFor block would only return one indirect object at a time, so is there a gIobjList? Or would I have to do something a little more complicated than that? As a semi-pseudocode example:

dobjFor(Verb){ check(){ if (gIobjList.length() > 3) failCheck('{You/he} cannot perform that action on more than 3 things at one time!'); } action(){ switch(gIobjList.length()){ case 1: //Call internal method 3 times on the current iobj case 2: //Some logic to determine if the current iobj should get 1 or 2 of the 3 calls case 3: //Call internal method on the current iobj once } } }

I assume that whatever the answer is, it would be similar if I ever needed to do this with direct objects from the iobjFor block?

The Following code appears to do what you’re describing. It uses the beforeActionMain action-level handler to veto the execution of the action if there are more than three objects, and it uses the (fairly obscure) iobjList_ property (defined on the Action instance that’s currently executing) to get the object count (and yes, there is a corresponding dobjList_ property). Note that the lists in question contain ResolveInfo objects, not the simulation objects directly.

DefineTIAction(SmurfWith)
    
    /* Helper flag for two-objects logic */
    smurfed = nil
    
    beforeActionMain()
    {
        if (iobjList_.length > 3)
        {
            "{You/he} cannot perform that action on more than 3 things at one time! ";
            exitAction;
        }
 
        smurfed = nil;
    }
;

modify Thing
    
    dobjFor(SmurfWith)
    {
        action() {
            switch (gAction.iobjList_.length)
            {
            case 1:
                "{You/he} smurf{s} {the dobj/him} three times with {the iobj/him}. ";
                break;
            case 2:
                "{You/he} smurf{s} {the dobj/him} <<if gAction.smurfed>>once<<else>>twice<<end>> with {the iobj/him}. ";
                break;
            case 3:
                "{You/he} smurf{s} {the dobj/him} once with {the iobj/him}. ";
                break;
            }
 
            gAction.smurfed = true;
        }
    }
;

To find out about those object list properties, I had a look at how the doActionMain method is implemented in both the TAction and TIAction classes (in action.t). This is a good starting point to get a deeper understanding of the action execution sequence.

Thank you! I’ll definitely have to look through the doActionMain method as you suggested, a better understanding the execution sequence would be very beneficial!

A quick look at the library reference on the ResolveInfo class makes it sound like the contained object will be after resolving group nouns and “all,” and thus the number of ResolveInfo objects in the lists should be the true number of objects; is this accurate?

I think so. Those list properties are the ones that are iterated through to generate the object announcements that precede the reports of the individual action results, so there should be exactly one element per action report.