Dynamic CollectiveGroups

I have a need to identify a few objects as a group, which can be identified as a single object when they are all together. One example is a costume. Once you have all the pieces of a costume, you have the costume.

I’ve looked at CollectiveGroup and it seems to be close, but not quite.

As an example

#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>

class CostumeHeldPreCondition: PreCondition
    costumeItem = nil
    checkPreCondition(obj, allowImplicit) {

        if(costumeItem.isHeldBy(gActor))
            return nil;

        if (allowImplicit && tryImplicitAction(Take,costumeItem)) {
            if (!costumeItem.isHeldBy(gActor))
                exit;

            return true;
        }

        reportFailure('You don\'t have the costume component. ');
        exit;

    }
;

prettyDress: Wearable 'pretty dress*costume' 'pretty dress'
    "This is a pretty dress. It would go well with a flower as a costume. "
    location = road
    collectiveGroups = [prettyCostume]
;

prettyFlower: Wearable 'pretty flower*costume' 'pretty flower'
    "This is a pretty flower. It would go well with a dress as a costume. "
    location = road
    collectiveGroups = [prettyCostume]
;

prettyDressHeld: CostumeHeldPreCondition
    costumeItem = prettyDress
;

prettyFlowerHeld: CostumeHeldPreCondition
    costumeItem = prettyFlower
;

prettyCostume: ItemizingCollectiveGroup, Wearable 'pretty *costume' 'pretty costume'
    "This is a pretty costume. "

    isListedInContents = true
    isListedInInventory = true

    dobjFor(Examine) {
        verify() {}
        preCond = [prettyDressHeld, prettyFlowerHeld]
        }

    dobjFor(Wear) {
        verify() {}
        preCond = [prettyDressHeld, prettyFlowerHeld]
        }

    basicExamine {
        if(gActor.isLocationLit)
            desc;
        else
            desc;
    }

    isCollectiveAction(action, whichObj) {
        if( action.ofKind(ExamineAction) || action.ofKind(WearAction))
            return true;
        return nil;
    }
;

You can wear the costume no problem, but it never appears as its own object, even if I subclass Thing. Ideally I’d like the costume pieces to be grouped together in inventory or on the ground as “pretty costume (made up of pretty dress and pretty flower)” by my experiments with ListGroup didn’t go far.

Anyone solved problems like this?

1 Like

Without having gone to a computer and checked code, I’m wondering if you should even use collgroup there. Might just make costume a Wearable, PresentLater that goes in and out of nil based on whether dress and flower are held together. Dress and flower could be moved into costume’s containment and not listed when costume is listed. If this isn’t enough of a lead and nobody else responds, I’ll try to code up something concrete…

4 Likes

That’s a pretty good solution. In a way it’s automatically “fusing” the pieces together into another object. If I wanted to be specific and have a MAKE COSTUME WITH DRESS AND FLOWER, you could do a similar thing. I would still want to mention the components so as to not confuse a player (“I just picked up a flower, where did it go?”)

Something to think about!

I was presuming the flower and dress would be mentioned appropriately in the costume desc, but not listed by the normal listers (inventory, room contents…) Or they could be parenthesized in the costume’s listName if that’s what you want. They would still be in scope and it would be up to you which/how many of the actions directed at the components would then remap to the costume, or still be handled autonomously…
And yes, no need to fuse them into the costume until the player makes the attempt…

1 Like

Man, JZ is fast on the draw! I had a similar scenario I implemented exactly as he described: a PresentLater combined item that appeared when assembled. In my case, I didn’t need the components any more (they disappeared), but agree ListGroup can likely get what you need.

One of these days, I’ll be on the spot to help!

3 Likes

So I tried the PresentLater approach and it got a little complicated in terms of location. Turns out I was close with what I wanted:

prettyDress: Wearable 'pretty dress*costume' 'pretty dress'
    "This is a pretty dress. It would go well with a flower as a costume. "
    location = road
    listWith = [prettyCostumeList]
    collectiveGroups = [prettyCostume]
;

prettyFlower: Wearable 'pretty flower*costume' 'pretty flower'
    "This is a pretty flower. It would go well with a dress as a costume. "
    location = road
    listWith = [prettyCostumeList]
    collectiveGroups = [prettyCostume]
;

prettyCostume: CollectiveGroup 'pretty *costume' 'pretty costume'
    "This is a pretty costume. "
;

prettyCostumeList: ListGroupCustom
    showGroupMsg(lst) { "a pretty costume (made of a pretty flower and dress)"; }
;

If both pieces are in the same container (on the floor, or in inventory) they get combined into the one. If I remove one, they are treated as separate objects and work as normal. They are also treated as separate objects when together. The CollectiveGroup lets me redirect verbs to both, but by default it just does it one by one.

The potential wrinkle here will be the use of the hidden plural “costume”, which means different costumes might collide in awkward ways in disambiguation. I don’t know what might happen if a single item is good for two separate costumes. Might just design around that problem.

The PresentLater approach is good and I might use it on a similar problem elsewhere in my game. Thanks!

2 Likes