Doors remember keys, keys don't remember doors

Unless I’m missing something, in TADS3/adv3 an instance of LockableWithKey by default “remembers” what keys have been successfully used to lock or unlock it, but instances of Key don’t remember what locks they’ve been successfully used on.

Assuming this isn’t a feature of the library I’ve missed, is there a simpler approach than something like:

#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>

modify LockableWithKey
        lockOrUnlockAction(lock) {
                inherited(lock);
                lockOrUnlockActionNotifyKey();
        }
        lockOrUnlockActionNotifyKey() {
                local ko;

                // Make sure we have an indirect object for the current
                // action, and it's a key.
                if((gIobj == nil) || !gIobj.ofKind(SmartKey))
                        return;
                
                // See if the key is now known.
                ko = getKnownKeyOwner();
                if((ko.knownKeyList == nil) ||
                        (ko.knownKeyList.indexOf(gIobj) == nil))
                        return;

                gIobj.smartKeyLearn(self);
        }
;

class SmartKey: Key
        smartKeyKnownFlag = nil
        smartKeyLockList = nil

        smartKeyKnown() { return(smartKeyKnownFlag == true); }
        smartKeyLearn(obj?) {
                if(smartKeyKnownFlag != nil)
                        return;
                smartKeyKnownFlag = true;
                smartKeyAddLock(obj);
        }
        smartKeyAddLock(obj) {
                smartKeyLockList = obj;
                return(true);
        }
;

class SmartKeyMulti: SmartKey
        smartKeyAddLock(obj) {
                if(obj == nil) return(nil);
                if(smartKeyLockList == nil)
                        smartKeyLockList == new Vector(16);
                if(smartKeyLockList.indexOf(obj) != nil)
                        return(nil);
                smartKeyLockList.append(obj);
                return(true);
        }
;

startRoom: Room 'Void'
        "This is a featureless void.  There's a red door to the north
                and a blue door to the south. "
        north = redDoor
        south = blueDoor
;
+redDoor: LockableWithKey, Door '(red) (north) door' 'red door'
        destination = otherRoom
        initiallyLocked = true
        keyList = [ redKey ]
;
+blueDoor: LockableWithKey, Door '(blue) (south) door' 'blue door'
        destination = additionalRoom
        initiallyLocked = true
        keyList = [ blueKey ]
;
+me: Person;
+redKey: SmartKey 'small brass key' 'brass key'
        "It's small brass key.  Its lock is currently
                <<(smartKeyKnown ? 'known' : 'unknown')>>. "
;
+blueKey: SmartKey 'small bronze key' 'bronze key'
        "It's small bronze key.  Its lock is currently
                <<(smartKeyKnown ? 'known' : 'unknown')>>. "
;

otherRoom: Room 'Other Room'
        "This is the other room.  There's a door to the south. "
        south = redDoorCopy
;
+redDoorCopy: Lockable, Door -> redDoor '(red) (south) door' 'red door';

additionalRoom: Room 'Additional Room'
        "This is the additional room.  There's a door to the north. "
        north = blueDoorCopy
;
+blueDoorCopy: Lockable, Door -> blueDoor '(blue) (north) door' 'blue door';

versionInfo: GameID;
gameMain: GameMainDef initialPlayerChar = me;

This creates two new abstract classes for key-type items: SmartKey and SmartKeyMulti (for keys that work for exactly one luck and keys that work with multiple locks, respectively). It also modifies LockableWithKey to ping SmartKey instances whenever one is successfully used to lock or unlock it.

This just handles the “knowledge” element; I’m separately working on a general solution to creating objects that dynamically react to current player knowledge…so automagically converting “a small brass key” into “the key to the red door” once the lock is known, and that kind of thing.

2 Likes