!--------------------------------------------------------------------------
! A chest and a padlock.  There are actually two chests.  Chest1 is an
! ordinary chest - you can put objects in it, open it, shut it, etc.  If
! you lock it with the padlock, it gets removed and Chest2 put in its
! place.  Chest2 pretends to be a container, but is actually a supporter
! with one child - the padlock.  When you unlock the padlock and remove it
! from Chest2, then Chest2 is swapped for Chest1 again.
! 
! Note: the verb "lock" is extended so that "lock padlock" allows you to
! lock the padlock (without the parser asking you what you want to lock it
! with).
! 
! Note: the verb "unlock" is extended so that "unlock padlock" chooses a
! default object when it is sensible to do so (i.e. when the player is
! carrying a single key).  Although this may seem tempting to generalise
! this, in fact there are tricky issues involved - supposing that the keys
! are red herrings and the lock should be picked with the hairpin?  Do you
! choose the hairpin as the default, or do you choose the key
! (unsuccessfully), even when the player is carrying the hairpin?
! 
! Gareth Rees, 31/10/94, with thanks to Scott Harvey for the idea.
!--------------------------------------------------------------------------

Constant Story "PADLOCK";
Constant Headline "^An Interactive Locked-box Mystery^by Gareth Rees^";

Include "parser";
Include "verblib";
Include "grammar";

Attribute is_key;

[ Initialise;
    location = Dungeon1;
    print "^^^^^What is in the box?^^";
];

[ PadlockTest;
    if (noun == Padlock) rtrue; else rfalse;
];

[ PadlockLockSub;
    if (noun ~= Padlock) "error!";
    if (Padlock has locked) "It's already locked.";
    give Padlock locked;
    "You snap the padlock shut.";
];

[ OneKeyTest i j;
    objectloop (i in player) { if (i has is_key) j++; }
    if (j == 1) rtrue; else rfalse;
];

[ MyUnlockSub i j;
    objectloop (i in player) { if (i has is_key) j = i; }
    print "(with ", (the) j, ")^";
    <<Unlock noun j>>;
];

Extend "lock" first * noun=PadlockTest -> PadlockLock;

Extend "unlock" first * noun=OneKeyTest -> MyUnlock;

Object  Chest1 "chest" nothing
 has    container openable
 with   name "chest",
        capacity 5,
        before [ i;
         Lock:
            if (second == Padlock) {
                if (Padlock has locked) "The padlock is locked shut.";
                if (self has open) "The chest is open.";
                i = parent(self);
                remove self;
                move padlock to Chest2;
                move Chest2 to i;
                give padlock locked;
                "You snap the padlock shut on the chest.";
            }
            "The chest has no lock.";
        ];

Object  Dungeon1 "Cavern"
 has    light
 with   description "A dark and forbidding cavern.",
        cant_go "The only exit is a low passage to the north.",
        n_to Dungeon2;

Nearby  IronKey "iron key"
 has    is_key
 with   name "iron" "key";

Nearby  Chest2 "chest"
 has    supporter openable locked lockable
 with   name "chest",
        before [;
         Unlock: "The chest has no lock.  But you could try the padlock.";
         Open: "The chest is held shut by the padlock.";
         Receive:
            if (noun ~= Padlock)
                "Putting things on the chest would achieve nothing.";
        ];

Object  Padlock "padlock" Chest2
 has    concealed lockable locked
 with   name "padlock" "lock",
        before [;
         Take, Remove:
            if (self has locked && parent(self) == Chest2)
                "The padlock is securely attached to the chest.";
            if (parent(self) == Chest2) give self general;
         PutOn:
            if (second == Chest1) <<Lock Chest1 self>>;
        ],
        after [ i;
         Take, Remove:
            if (self has general) {
                i = parent(Chest2);
                remove Chest2;
                move Chest1 to i;
                give self ~general;
            }
        ],
        with_key BrassKey;

Object  Steve "the head of Steve Meretsky" Chest1
 with   name "head" "of" "Steve" "Meretsky",
        article "the",
        description "His eyes glint brightly in the gloomy light.";

Object  Dungeon2 "Narrow passage"
 has    light
 with   description "A difficult squeeze.",
        cant_go "The passage is too narrow to proceed further.  Better go \
            back south to the cavern.",
        s_to Dungeon1;

Nearby  BrassKey "brass key"
 has    is_key
 with   name "brass" "key";

End;