I wasn’t aware of the _GuessMissingNoun routine. I always do this:
Step 1: Before including globals.h, tell the library that the following two routines will be replaced.
Replace LockSub;
Replace UnlockSub;
Step 2: Somewhere after including puny.h, replace those routines.
[ LockSub k;
if (ObjectIsUntouchable(noun))
rtrue;
if (noun hasnt lockable)
{
PrintMsg(MSG_LOCK_NOT_A_LOCK, 'lock');
rtrue;
}
if (noun has locked)
{
PrintMsg(MSG_LOCK_ALREADY_LOCKED);
rtrue;
}
if (noun has open)
{
PrintMsg(MSG_LOCK_CLOSE_FIRST);
rtrue;
}
k = RunRoutines(noun, with_key);
if (k == nothing)
"You can't see how to lock ", (ItOrThem)noun, ".";
if (second == nothing && k ~= nothing && k in player)
{
second = k;
print "(with ", (the)second, ")^";
}
if (second == nothing)
"You don't have the key.";
if (second ~= k)
{
PrintMsg(MSG_LOCK_KEY_DOESNT_FIT);
rtrue;
}
give noun locked;
run_after_routines_msg = MSG_LOCK_DEFAULT;
run_after_routines_arg_1 = 'lock';
];
[ UnlockSub k;
if (ObjectIsUntouchable(noun))
rtrue;
if (noun hasnt lockable)
{
PrintMsg(MSG_UNLOCK_NOT_A_LOCK, 'unlock');
rtrue;
}
if (noun hasnt locked)
{
PrintMsg(MSG_UNLOCK_ALREADY_UNLOCKED, 'unlock');
rtrue;
}
k = RunRoutines(noun, with_key);
if (k == nothing)
"You can't see how to unlock ", (ItOrThem)noun, ".";
if (second == nothing && k ~= nothing && k in player)
{
second = k;
print "(with ", (the)second, ")^";
}
if (second == nothing)
"You don't have the key.";
if (second ~= k)
{
PrintMsg(MSG_UNLOCK_KEY_DOESNT_FIT);
rtrue;
}
give noun ~locked;
run_after_routines_msg = MSG_UNLOCK_DEFAULT;
run_after_routines_arg_1 = 'unlock';
];
Step 3: Extend the grammar.
Extend 'lock' first
* noun -> Lock;
Extend 'unlock' first
* noun -> Unlock;
Let’s assume the locked object is a door. The end result of all this is that if you enter UNLOCK DOOR, it no longer gives you that stupid message about ‘I think you wanted to say “unlock door” with something.’ Instead, it takes a look at the with_key property to work out what key to use and if you’re carrying it, then it implicitly uses that key, otherwise it says you don’t have the key.
The library changes are negligible, but the benefit to the player is enormous. I include this code in the skeleton I use for every single game, so I don’t have to think about it.
If you have an object that looks like it’s unlockable, but it isn’t because its key isn’t in the game, just create a dummy key:
Object dummy_key;
and put that in the with_key property for the locked object:
with_key dummy_key,
The only shortcoming that I can think of is that this might only work for one key per lockable object. If you have an object that can be unlocked by either of two keys, say a front door key and a skeleton key, then you might need to do something special, but I’ve never struck that situation.