TADS3 Adv3: How to best fake the quantity of a singular item?

Referencing from my previous thread ( TADS3 Adv3: Advice on minimizing/optimizing inventory lag? - #8 by McGuireA )…

I have a singular “representative” item that is meant to represent several quantities of that singular item without actually having that quantity of items as physical objects (for performance reasons). Each representative item has its own “count“ that is kept track of separately from its physical quantity (which is never more than one). As I was refining and implementing this into my game, I ran into a hiccup with the parser.

Obviously, when attempting to specify a quantity of the representative item that is more than one, the parser throws the message “You don’t see that many (x) here”… which is expected. I figured I could get around this by creating a specific action for “depositing” these representative tokens, or overriding with DobjFor, but it would seem that any action yields the same message. This message doesn’t seem tied to the action itself but with the parser?

When there isn’t a quantity specified for my action, the action works as expected, so I’m less worried about that, but now I’m not sure how exactly to go about this. Is it possible to get the parser to refer to the representative objects “count” rather than it’s physical quantity? Alternatively, is there a way to get the parser to ignore the specified quantity, but at the same time retain that numerical information so I can apply it to the “count” of the representative item instead?

I don’t feel like collectiveGroups or isPlural will help in any way here. I don’t know much about resolving nouns, but maybe that’s the way to go?

Looking into this, I realize that that I might be opening a can of worms that I’m not skilled enough to tackle quite yet. But I’m sure that I’m definitely not the only person to implement “representative” items.

Any pointers?

Woof. I can tell you I ran at a similar problem last year, only to conclude I was not up to the challenge. Or, said differently, was more work than justifiable for my needs. Here are two threads that discuss adjacent aspects of this problem: @jbg’s legitimate deep dive, and my initial design musings that convinced me the elephant was too large.

I’m not sure how many of these threads’ concerns are applicable to your situation. In my case, I reverted to just creating and instantiating potentially large numbers of instances. So far, their specialized use has not translated to detectable performance issues, even when hundreds are in existence (not least of which because I hide them in an inventory container). I spent a LOT of time confirming that trash collection cleaned them up when disposed of.

I guess what I’m saying is good luck! With all these big brains on the problem, it’ll crack EVENTUALLY!

Thank you! Yikes, I was beginning to wonder. I’ve definitely browsed those threads and witnessed jbg’s descent into madness on the topic a few times, which is where I quickly realized that this issue is likely outside of my skillset. I’m unsure of how to adapt their findings to suit my issue, which I feel is very similar but (maybe?)slightly less complex than theirs.

I’ll keep poking around.

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.