adv3Lite: CollectiveGroup Problems

I’m probably the only person in the world who has ever encountered this problem, so this post is partly just a rant, but I’m hoping someone may have a useful suggestion.

I’m using adv3Lite (which I basically like a lot – I’m using Doers and regions, for example). The problem is, my WIP includes a set of six basically identical objects (short electrical cables) that are distinguished solely by their color property. They’re portable, so it would be quite practical for the player to carry two of them to a new location. Whenever more than one is present, it’s desirable that ‘take cables’ or ‘x cables’ should handle the command collectively on whatever cables are present, rather than listing them separately. Listing them separately produces this kind of ugliness:

Unfortunately, the adv3Lite implementation of the CollectiveGroup class seems inadequate to the task. It’s a great deal simpler than the identically named class in adv3.

There’s no description in “Learning T3 with Adv3Lite” of how to use a CollectiveGroup, but the “Optional Modules – Extras” page says this: “It’s normally best used as a Fixture representing other Fixtures, although with care it may be possible to use it for other situations.” What sort of care would be required is apparently an exercise left for the individual author. If the portable objects in the CollectiveGroup are in different locations, keeping the CollectiveGroup in scope at the proper times is likely to be an amusing process.

I don’t fault Eric for ignoring this particular thorny thicket. After all, adv3Lite is intended to handle the most common game situations in a streamlined manner, while ignoring certain edge-case scenarios that the author is unlikely to envision. Nonetheless, it’s looking as if I may be screwed here. My choices seem to be:

  1. Completely rejigger the adv3Lite CollectiveGroup class.
  2. Port my entire (very large) game over to adv3.
  3. Grit my teeth and put up with the ugly output.

Option 3 is not appealing. Option 2 would take days, but it may be practical (although I’d have to replace my Doers and regions with something else). Option 1 may be practical, but it’s an extensive library hack, and may be beyond my technical capability.

Suggestions would be much appreciated!

I don’t know if it will solve your problem, but have you taken a look at the adv3Lite Collective class, which is one of the extensions (you should be able to find it from the Extensions section of the adv3Lite library manual, and there’s also a link to it from the description of the CollectiveGroup class)?

Or it may be there is a way to get CollectiveGroup to do what you want. You don’t need to do anything special to handle TAKE CABLES in any case, since in adv3Lite that should be reported as:

Without your having to do anything special to make it happen.

Here’s a rough coding pattern that may help you with the EXAMINE command using the CollectiveGroup class:

+ redCable: Cable 'red cable'
;

+ blueCable: Cable 'blue cable'
;


class Cable: Thing
    collectiveGroups = [cableGroup]
    
;

cableGroup: CollectiveGroup 'cables'
    desc()
    {
        inherited();
        "Each cable is  essentially, a patch cord, less than a foot long, 
        with a shiny quarter-inch plug at each end. ";
    }  
;

cableScene: Scene
    startsWhen = true
    
    eachTurn()
    {
        if(cableList.countWhich({x: me.canSee(x)}) > 1)
            cableGroup.moveInto(me.location);
        else
            cableGroup.moveInto(nil);
    }
    
    cableList = [redCable, blueCable] // in your game list all the possible cable objects here
;

The idea is that the scene which runs throughout the game will move the cableGroup to the player’s location if the player can see more than one cable and will move it away otherwise. This may need more refinement to get it to work fully, but perhaps this will help point you in a fruitful direction.

Thanks, Eric. Using a Scene to move the CollectiveGroup seems to do what I need. The Collective class didn’t seem quite right, but now that you’ve reminded me of the extra extensions, I’ll have a look through them. I’ve never seen a need for Relations in Inform, but … hmm, maybe these electrical cables can be related to the places where they’re plugged in. I’ll think about it.

For future reference, here’s a MobileCollectiveGroup class that does the job without the need for a separate Scene object (although events.t must be present in the build) or the need to manually define which objects belong to the CollectiveGroup:

/* 
 *   A MobileCollectiveGroup is a CollectiveGroup that can be used to represent
 *   a collection of portable objects, different members of which may be in
 *   scope at any given moment. A MobileCollectiveGroup is moved into the
 *   player's location if more than one of its members is visible at the start
 *   of any turn and moved into nil otherwise.
 */

class MobileCollectiveGroup: PreinitObject, CollectiveGroup
    execute()
    {
        /* Set up a daemon to execute every turn */
        new Daemon(self, &scopeCheck, 1);
        
        /* Set up a prompt daemon to execute just before the first turn */
        new OneTimePromptDaemon(self, &scopeCheck);
        
        /* Create a new vector */
        local vec = new Vector;
        
        /* 
         *   Populate the vector with all the Things in the game that include
         *   this MobileCollectiveGroup in their collectiveGroups property.
         */
        for(local obj = firstObj(Thing); obj != nil; obj = nextObj(obj, Thing))
        {
            if(valToList(obj.collectiveGroups).indexOf(self))
                vec.append(obj);
        }
        
        /* 
         *   Convert the vector to a list and store the result in the myObjs
         *   property.
         */
        myObjs = vec.toList;
    }
    
    /*  
     *   If the player can see more than one of the objects that belong to this
     *   CollectiveGroup, move it to the player's location (so that it can stand
     *   in for those objects when required); otherwise move this
     *   CollectiveGroup out of the way.
     */
    scopeCheck()
    {
        if(myObjs.countWhich({x: gPlayerChar.canSee(x)}) > 1)
            moveInto(gPlayerChar.location);
        else
            moveInto(nil);        
    }
    
    /* 
     *   The list of objects belonging to this MobileCollectiveGroup; this is
     *   created automatically at PreInit.
     */
    myObjs = nil
;

In due course I’ll make this into an extension and add it to the library. In the meantime if anyone wants to test it out they can let me know if there are any problems with it!