I have absolutely no insight to offer for this TADS problem, so apologies for butting in…
…but I find the issue particularly interesting because I just spent the last five months, give or take, implementing fungible objects in the IF system I’m working on. It doesn’t help at all with your TADS problem but FWIW it reinforces how hard this problem is. This was a feature I had put on the back-burner for years, and always considered a simple problem, until I actually had to build it for a particular puzzle I wanted to make.
I started out with a multiple-identical-objects model, which had so many complications…
- an author could set a built-in class to be fungible, which meant I had be able to dynamically add a static is_fungible variable to an already built-in class so every new instance would be fungible
- for better or worse, my system doesn’t acknowledge words for objects until there’s one of them in the game world, so I wound up creating a special Platonic class which could act as a stand-in for fungible assets that hadn’t been created yet, and then at startup copied all of a fungible class’s language to a platonic instance which sat off stage (so to speak)
- I had to revise all my object listing routines (i.e. for inventory, room content, disambiguation prompts, etc) to be aware of multiple fungibles, so as not to say things like “you have a pistachio and a pistachio and a pistachio” or “which pistachio did you mean, the pistachio or the pistachio?”
- Samesies for pronouns/contractions/verbs (it’s vs they’re depending on number of objects)
- And then, because keeping track of multiple identical assets was becoming problematic, I implemented a special Bundle class which could stand in for them.
At this point, I was already two or three months in when I realized: this is stupid. I had three distinct classes to manage fungible objects: Fungibles, Platonics, Bundles; two of which weren’t even proper object classes, but special abstract classes,
I ripped it all out and started over.
This time I wound up with a concept of Stacks. There’s only one stack object, which has a quantity. The Stack itself is an add-on class that can be plugged into any object of any class (technically it’s a specialized state management class, which is a common pattern in my system). The Stack class owns all the methods to handle quantity, merge multiple stacks, divide into new stacks, delete empty stacks, and control options for how to handle enumeration, like “you have 3 pistachios” vs “you have three pistachios” vs “you have several pistachios”. I still had to re-revise my object listing methods and pronoun/verb/contraction handling, but that went more smoothly now that I didn’t have to account for relationships between three interlocking classes.
In the end I wound up with an object definition that looks like this:
MyGame.createAsset({
class: "Pistachio",
name: "handful of pistachios in the pouch",
place: { in: "small pouch" },
description: `The small handful of pistachios isn't much, but it's about all {we've} got. `,
stack: {
use_stack_name: false,
dispenser: true,
quantity: -1, // infinite
max_quantity: -1, // infinite
max_per_take: 3,
max_stacks_in_game: 20,
max_quantity_in_game: -1, // infinite
spawn_properties: {
max_quantity: 10,
},
},
})
Everything else is handled automatically under the hood. If you take three pistachios from the pouch, now “you have a pouch and three pistachios”. The spawned set of pistachios are distinct from the original dispenser, but they’re both pistachios. Disambiguation has per-verb preferences to decide which type of pistachio object you’re likely to be referring to, so there’s no “which pistachio did you mean?” nonsense.
Anyhow, all of that is just to say, yeah, I feel ya. Maybe you can apply a similar approach in TADS…? Good luck with it.