Replying to myself with a kludge/workaround.
It looks like the problem is in ComplexComponent.initializeLocation(). It is:
initializeLocation()
{
/* set our location to our lexical parent */
location = lexicalParent;
/* inherit default so we initialize our container's 'contents' list */
inherited();
}
…which forces the component’s location to be lexicalParent. This means any attempt to declare the components as their own classes/instances is going to have unexpected consequences.
The examples in the comments assume that you’ll declare things something like (this is from extras.t:
*. + washingMachine: ComplexContainer 'washing machine' 'washing machine'
*. subContainer: ComplexComponent, Container { etc }
*. subSurface: ComplexComponent, Surface { etc }
Unfortunately, this default expectation only works if each ComplexContainer is a unique in-game object. Because declared this way, each component is per class, not instance. So in my example (of a dresser) if the game contains multiple dressers (which is in fact what I’m working on) then each dresser would share a single common drawer…meaning you could put something in one dresser and it would be present in all of them.
Anyway, here’s a kinda/sorta workaround:
#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
class Furniture: Heavy;
class MyComplexComponent: ComplexComponent
initializeLocation() {
local oldLoc;
oldLoc = location;
inherited();
if(!lexicalParent && oldLoc)
self.baseMoveInto(oldLoc);
}
;
class DresserDrawer: MyComplexComponent, OpenableContainer
'(dresser) drawer' 'drawer'
;
class DresserTop: MyComplexComponent, Surface
'on (dresser) top' 'top'
;
class Dresser: ComplexContainer, Furniture 'dresser' 'dresser'
subContainer = perInstance(new DresserDrawer())
subSurface = perInstance(new DresserTop())
drawer = subContainer
top = subSurface
initializeThing() {
subSurface.baseMoveInto(self);
subSurface.targetObj = self;
subContainer.baseMoveInto(self);
subContainer.targetObj = self;
inherited();
}
;
startRoom: Room 'Void'
"This is a featureless void with a wooden dresser in one corner. "
;
+ dresser: Dresser 'plain wooden dresser' 'dresser'
"It's a plain wooden dresser with one drawer. "
;
++ pebble: Thing 'small round pebble' 'pebble'
"A small, round pebble. "
subLocation = &drawer
;
++ widget: Thing 'nondescript widget' 'widget'
"It's a nondescript widget. "
subLocation = &top
;
me: Person
location = startRoom
;
versionInfo: GameID
name = 'sample'
byline = 'nobody'
authorEmail = 'nobody <foo@bar.com>'
desc = '[This space intentionally left blank]'
version = '1.0'
IFID = '12345'
;
gameMain: GameMainDef
initialPlayerChar = me
;
This implements MyComplexComponent, which overwrites initializeLocation() to check lexicalParent and restores the component’s defined location if lexicalParent is nil.
This seems to work at least as far as my test cases go:
Void
This is a featureless void with a wooden dresser in one corner.
On the dresser is a widget.
>open dresser
Opening the dresser reveals a pebble.
>take all from dresser
widget: Taken.
pebble: Taken.
>undo
Taking back one turn: "take all from dresser".
Void
This is a featureless void with a wooden dresser in one corner.
On the dresser is a widget. The dresser contains a pebble.
>take all from drawer
pebble: Taken.
I don’t know if this interferes with some other expected behavior(s) of ComplexComponent/ComplexContainer…because they’re not really documented.
I’ll also mention that this affects the solution proposed at the end of this thread, which is one of the references I turned up when I was trying to implement this.