Putting things into classes? [TADS 3]

So, I was wondering is it possible to create classes with sub-objects for repeat performances?

Consider this example

class WoodenLeg: Thing 'wooden leg' 'wooden leg'
    "It's a wooden leg that came off the chair. "
;

+ chair: Chair 'wooden chair' 'wooden chair'
    "It's a wooden chair with four legs. "
;

++ WoodenLeg;
++ WoodenLeg;
++ WoodenLeg;
++ WoodenLeg;

where we have a chair with four wooden legs, implemented as a class so we don’t have to spell out identical descriptions. [This example is buggy in many ways, in production, but I wanted to keep the example short.] What happens if we want to have two, or four chairs, each with detachable legs? We may not see it in this example, but the + operator here has no effect on class definitions.

Is it possible to create classes that automatically construct embedded objects, either detachable like above, or fixtures, or mixtures thereof? In an ideal world, such classes should work both for objects defined in source code and with the new operator.

Yes, you can have classes that have nested objects, but I don’t recommend it. By default, we wanted all NPCs in the game “Thaumistry” to have hands, feet, hair, a nose, mouth, etc. At first, nested objects seemed like the obvious way to do it.

Nested objects look like this:

bedroom: Room {
    name = 'Bedroom';
    desc = "Your bedroom.  There's a large hole in the ceiling. ";
    up: MsgConnector {
        desc = "You reach for the hole in the ceiling and pull yourself up... ";
        destination = attic;
   }
}

This works works well for that kind of stuff, but it gets tricky when vocabulary is involved. I forgot the details (this was back in 2016,) but I had big problems with the vocabulary words of those nested objects. IIRC, scope and ownership was also very wonky.

Instead, you can add properties in the class with modify Chair, or by subclassing Chair and then use that subclass instead of Chair, depending on whether or not you want all chairs to have these parts or only specific ones. You then create objects and store them in those properties. You do that in the initializeThing() method of Chair (or its subclass). To create the instances of those objects use the createInstance() method of the object’s class. To create a new WoodenLeg for example, you’d do:

leg = WoodenLeg.createInstance();

Here is the source code for the module from Thaumistry that creates body part and clothes object for NPCs. You should be able to adapt it to instead create wooden legs for chairs:

However, you could try nested objects first and only use the above if you run into problems. Our use case was somewhat different and it could be that nested objects will work just fine for yours.

3 Likes

Off topic: Thaumistry is such an incredible game. IMHO, it is the best modern IF game. I hope to see more like it in the future.

Nikos, before I even saw this module, I had started to implement something similar in my own game. Do you know if there is a possibility of lag in game execution when there get to be dozens of detail objects in scope? I thought I was noticing a little lag in my game as it got more detailed, and then I started adding less insignificant component objects because I wasn’t sure…

Is Thaumistry a free download anywhere?

I have never seen it free. It is well worth $3.99.

Thaumistry Website

I got my copy on Steam, for indeed $3.99.

Thank you. I hope this is something I can build upon.

Thanks for the link, that sounds good…

1 Like

I haven’t noticed anything. But you can run a test for this. Create lots of new objects at runtime with new and add them to your start room. You can create a test verb for that. Just give the objects random names. See if there’s a difference in parsing speed when you have, say, 20 objects vs 200 objects.

I think I already know it to be true, unfortunately, I just don’t know what the count is before it becomes noticeable or if the amount of object disambiguation comes into play. For instance, I tried making a puzzle that involved using the right number of equivalent tiny items in the right places. I made 150 equivalent small objects in one container, and when they were in scope, there was almost a full second of lag after hitting enter on every command. I would recode it if I could using objects that represent a collective group of a variable number, but I wouldn’t know how to get the parser to interact with them properly. Even in other rooms, if my PC has 20+ items in inventory, I feel like I can see a bit of lag in comparison with the instant response of a barebones game. For this reason I’ve unfortunately become a bit gunshy about adding too many extra scope objects, but I wish I had a better understanding of where the lag comes from…

Have you tried stepping through a simple [test?] verb when you have many objects in scope?

Does that even help?

I haven’t done any explicit tests yet, but I probably will… I am also using an inventory window that I wonder if it’s contributing to processing time. When you say “stepping through” a simple verb, do you mean some specific kind of process?

I mean, in the debugger, see if you notice the specific function that’s slow.

Narrowing it down can help. I have not seen any profiling tools in the Workbench, nor mentions of any, so it looks like those don’t exist.

To fix the prerformance problem, it may be possible to use a different data structure, but being new to TADS, I’m not sure how. I don’t know yet how the system works internally. That means I will not try to make suggestions nor guess what the problem actually is.

Aha, the debugger… I’m actually on a Mac, I don’t have Workbench. Also not a programmer outside of TADS, so never used a debugger before…