TADS3 Adv3: Modifying Wide/Tall Inventory Listing

Hey, I have a question related to actor inventory, specifically the player’s. I’m trying to customize the way things are listed and formatted. After poking my head around inventory listers, I realize some of the coding is a little above my head, and I’d like some input on how to best approach this, please.

So, I’m aware that there are wide and tall inventory listings, and I like the look of tall inventory, but I’d also like worn items and carried items to be separated out and described like they are in wide listings (without “being worn”). Sort of like:

>inventory 
You are wearing boots, a hat, and a coat.

You are carrying:
     x1 hatchet
     x5 sticks

Can this be done just by modifying either the wide or tall lister? Or is this more complex than I am realizing?

Thanks for any advice!

3 Likes

You can certainly do what you’re trying to do! Unfortunately, I’m not really available right away to whip up a code sample. I’ll check back soon if no one else has gotten to your question!

2 Likes

I second the question, sometimes I think that differentiating better than (which contains X, Y, and Z) the rucksack/pocket(s) contents when doing inventory can be a massive player’s QoL improvement…

Best regards from Italy,
dott. Piergiorgio.

ps. I have taken the liberty of editing the title and adding an appropriate tag :wink:

3 Likes

This is a rather clumsy and inflexible way to do it, but I didn’t have a lot of time and hopefully it can point you in the right direction.

divTallLister: InventoryLister
	showList(pov, parent, lst, options, indent, infoTab, parentGroup) {

        if (!lst.length) {
            "You are empty-handed. ";
                //or however you want to deal with empty inv
            return;
        }
		local wornObjs = lst.subset({x:x.isWornBy(gPlayerChar)});
		lst = lst.subset({x:!x.isWornBy(gPlayerChar)});
		if (wornObjs.length) {
			local wlister = new WearingLister();
			"You're wearing ";
			wlister.showList(pov, parent, wornObjs, options & ~ListTall, indent, infoTab, parentGroup);
			". <.p>";
		}
		if (lst.length) {
			"You're carrying: ";
			inherited(pov, parent, lst, options | ListTall, indent, infoTab, parentGroup);
			"<.p>";
		}
	}
;

modify me  // or whatever the playerChar is
    inventoryLister = divTallLister
;
3 Likes

Ok JZ, you leave a door open, Imma charge in!

The subclass you want to override is actorInventoryLister, either overriding the showCombinedInventoryList method, or rewriting to use something different. I found it easier to manipulate the former, but really a personal choice. Definitely reference the stock implementation in msg_neu.t Note you can override under Actor, or the pc ‘me’ depending on your needs.

Here is what that might look like:

me : Actor
    inventoryLister : actorInventoryLister
    {
        /*
         *   New routine to append vertical carrying list to standard worn listing
         */
        showTallInventoryList(parent, carrying) {
            // 'carried' is string of form '[a|an] [obj1.name],
            //   [a|an] [obj2.name],... and [a|an] [objN.name]
            if (carrying == '') {
                "<<buildSynthParam('The/he', parent)>> {is} carrying nothing. ";
            } else {
                // split carried string  into components, then create lookup table of counts
                // untested match string, test it! 
                local carriedList = carrying.split(R'(<Punct><Space>)?(and<Space>)?(a|an)<Space>'); 
                local invLookup = new LookupTable();
       		carriedList.forEach(function(itm) {
                    local itmCount = 0;              
       		    parent.contents.forEach(function(inv) {
                        if (itm == inv.name) itmCount++;
                    });
                    invLookup[itm] = itmCount;
                 });
                 "<.p>You are carrying:\n";
                 invLookup.keysToList().forEach(function(inv) {
                     "\tx<<invLookup[inv]>> <<inv>>\n";
                 });
            }
        }
        showCombinedInventoryList(parent, carrying, wearing) {
            inherited(parent, '', wearing);  // overkill, but using default with no carrying list
            showTallInventoryList(parent, carrying);  // add the vertical item list
        }
        showInventoryWearingOnly(parent, wearing) {
            /* called by showCombined... inherited code.  Tweaking it from original...  
            "<<buildSynthParam('The/he', parent)>> {is} carrying nothing,
            and {is} wearing <<wearing>>. "; */
            "<<buildSynthParam('The/he', parent)>> {is} wearing <<wearing>>. ";
        }
        showInventoryEmpty(parent) {
            /* also mod this, as only refers to clothing now
            "<<buildSynthParam('The/he', parent)>> {is} empty-handed. "; */
            "<<buildSynthParam('The/he', parent)>> {is} nekkid! ";
        }
    }

This is untested code, so can’t promise no gotchas in there. Will test later when I have time, but maybe this gets you going?

3 Likes

Lol, shoulda known we were racing! Crosspost!

Q: does TallLister give an item count by default? Never played with that.

2 Likes

Ha ha… didn’t know if anyone was going to pick this up so I just hashed something out.
Answering from phone, I’d think ListGroups would get the counting done…

2 Likes

A: TallLister visually counts your items in the same way that WideLister seems to, only it’s formatted vertically.

Also, thank you! You both have given me more than enough to work with - I appreciate it!

2 Likes

Also, JJ, not sure if you saw the countPhrases method of actorInventoryLister… seems like that might be what you’re looking for.

1 Like

Even better, it also provisions
phraseSepPat = static new RexPattern(',(?! and )|;| and |<rparen>')
which is a much better pattern match than my off the cuff one above. As I think about it further, I do not have enough experience with multiple copied objects to have too much confidence in my split separator. Relying on existing stable code seems a better way to go about it.

1 Like