I stripped down one of the root causes of why I’m having such a hard time with what I’m working on, and I have a simple example below of a little dummy TADS game file that gives unexpected behavior. What am I not understanding here?
The problem is with inner classes. If I define a class like this:
class MyClass : Thing
// stuff
innerObj : Object
// stuff
;
;
Then I would expect that each time I make an instance of MyClass, it would make an instance of innerObj inside it also. But it doesn’t. I made a proof that it doesn’t by using PreinitObject objects that would print messages reporting their existence when first running. Here is the code:
#include <adv3.h>
#include <en_us.h>
gameMain: GameMainDef
initialPlayerChar = me
showIntro() { "A small game file to test how TADS behaves. "; }
;
versionInfo: GameID
name = 'dummy for this test'
byline = 'dummy for this test'
authorEmail = 'dummy for this test'
desc = 'So far this is a dummy placeholder string'
version = '1' // dummy for this test
IFID = 'ffffffff-ffff-ffff-ffff-aaaaaaaaaaaa' // dummy for this test
;
class MyType : Thing, PreinitObject
name = 'dummy MyType'
execute()
{
// This is a debug test so at execution time it will print
// a report from each instance of this class that exists:
"Preinit Debug: I am an instance of MyType with a name of '<<name>>'.\n";
}
innerObj : Thing, PreinitObject
{
location = lexicalParent
name = 'inside dummy'
execute()
{
// This is a debug test so at execution time it will print
// a report from each instance of this class that exists:
"Preinit Debug: I am an instance of innerObj inside of an object with a name of '<<location.name>>'.\n";
}
}
;
testingRoom: Room
'Testing Room'
"This is the testing room. \n"
;
+ me: Actor
name = 'player'
npcDesc = "your self"
;
// Two objects of type "MyType" with different names so when their
// PreinitObject execute() methods run, they will report different
// names and I can tell them apart.
+ outerInstance1 : MyType 'red thing' 'red thing' "A red thing"
;
+ outerInstance2 : MyType 'blue thing' 'blue thing' "A blue thing"
;
This is the output I get when I run this:
$ frob -i plain tadsexperiment.t3
Preinit Debug: I am an instance of MyType with a name of 'red thing'.
Preinit Debug: I am an instance of MyType with a name of 'blue thing'.
Preinit Debug: I am an instance of innerObj inside of an object with a name of 'dummy MyType'.
A small game file to test how TADS behaves.
Testing Room
This is the testing room.
You see a red thing (which contains an inside dummy) and a blue thing (which
contains an inside dummy) here. In the dummy MyType, you see an inside dummy.
>quit
Do you really want to quit? (Y is affirmative) > y
[Hit any key to exit.]
Notice how despite the fact that two messages print for the outer things, one for ‘red thing’ and one for ‘blue thing’, only one message prints for the innerObj, and furthermore, it’s for neither of the two actual instances of the outer object. It’s contained inside of the class (with it’s dummy name). Also, notice the odd printout of the room contents. It knows the ‘red thing’ contains an inner object and that the ‘blue thing’ also contains an inner object, and yet these other two inner objects never appear in the Preinit output. I suspect the engine only made one instance of the inner object, and added a reference to that one instance to the contents of all the outer things (which I’m sure would get buggy if I tried running this game further past this point.)
This is at the core of the problem I’m having with using Actor States in an inheritable way. I can’t seem to find a way to say “all instances of objects of type Foo will also contain instances of objects of type Bar which contain location properties that point to the parent Foo they are in”. I have to do this in order to make an Actor subclass that always contains an instance of a certain ActorState that always contains an instance of a certain ConvNode. The linkage between these object’s location properties doesn’t seem to be inheritable.
I know the usual reasons for saying it’s bad to manipulate location directly and moveInto() should always be used instead. Keep in mind, though, that moveInto() is code, and I’m trying to make a solution that has all the data values set correctly in the compiled image BEFORE any code executes. This is necessary because I don’t get to control when the adv3 library runs its own Preinit code (It runs before my Preinits run - I checked), and its that Preinit code that sets things up in the ActorStates and ConvNodes. I need the static image the compiler generates to already have the variables set up correctly before I get to run anything executable like moveInto().