Replying with a kludgy mess that illustrates what I’m trying to do.
This example defines a simplistic Scene
class and a sceneController
that handles the instances. Each Scene
is triggered by matching three properties defined on the instance: actor
to match who’s doing the action; target
to match the direct object of the action; and action
to match the action itself. So in the example
target = Pebble
action = ExamineAction
…will cause the Scene
containing the above to match whenever anyone attempts to examine a pebble, thus:
>x pebble
The pebble will be examined. A small, round pebble. The pebble has been
examined.
The source:
#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
modify Action
construct() {
inherited();
self.addBeforeAfterObj(sceneController);
}
;
sceneController: PreinitObject
// List of all scenes, built at runtime
sceneList = []
execute() {
initSceneList();
}
// Create the scene list
initSceneList() {
local obj;
obj = firstObj(Scene);
while(obj) {
sceneList += obj;
obj = nextObj(obj, Scene);
}
}
// Get a list of all the scenes that match the given actor, object,
// and action
matchSceneList(actor, obj, action) {
local r;
r = [];
sceneList.forEach(function(o) {
if(!o.matchActionTuple(actor, obj, action))
return;
r += o;
});
return(r);
}
beforeAction() {
local l = matchSceneList(gActor, gDobj, gAction);
l.forEach(function(o) {
o.beforeAction();
});
}
afterAction() {
local l = matchSceneList(gActor, gDobj, gAction);
l.forEach(function(o) {
o.afterAction();
});
}
;
class Scene: object
// Actor, object, and action conditions for scene
actor = nil
target = nil
action = nil
// See if the passed actor, object, and action match our conditions
matchActionTuple(actor, obj, action) {
return(o.matchActor(actor) && o.matchTarget(obj)
&& o.matchAction(action));
}
// Utility method
_matchBit(v, cls) {
local r;
// No match criteria defined, always match
if(!cls) return(true);
// No argument, always fail
if(!v) return(nil);
// cls is a list, return true if we match any
if(cls.ofKind(List)) {
r = nil;
cls.forEach(function(o) {
if(!v.ofKind(o)) return;
r = true;
});
return(r);
}
// If the cls isn't a list, it must be a class
return(v.ofKind(cls));
}
matchActor(v) { return(_matchBit(v, actor)); }
matchTarget(v) { return(_matchBit(v, target)); }
matchAction(v) { return(_matchBit(v, action)); }
beforeAction() {}
afterAction() {}
;
beforeExamineScene: Scene
target = Pebble
action = ExamineAction
beforeAction() {
"The pebble will be examined. ";
}
;
afterExamineScene: Scene
target = Pebble
action = ExamineAction
afterAction() {
"The pebble has been examined. ";
}
;
class Pebble: Thing 'small round pebble' 'pebble'
"A small, round pebble. "
;
startRoom: Room 'Void'
"This is a featureless void. "
;
+ pebble: Pebble;
me: Actor
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
;
The thing that makes me unhappy with this is that it relies on modifying the Action
base class’ constructor:
modify Action
construct() {
inherited();
self.addBeforeAfterObj(sceneController);
}
;
This seems like it’s probably a pretty brittle “solution”: I don’t know how many actions overwrite the constructor themselves, for example.
So I’d be delighted if anyone knows of a better solution to this kind of thing. Just adding the example to better illustrate what I’m trying to do.