more Master Key of Thievery: lock/unlock vs traps

Always find traps when using the rogue's quest Key to lock or unlock a
trapped door or chest provided that the Key is not cursed (for rogues)
or is blessed (for non-rogues).  When a trap is found, the player is
given the opportunity to disarm it, and doing so will always succeed.
(It isn't disarmed automatically; the player may prefer to leave traps
in place, presumably hoping to set up a dangerous bones file.  Or he
or she may be unaware of the guaranteed success and be too timid to
risk trying to disarm the trap.)

TODO:  make #untrap of a door or chest while carrying that Key always
find traps (with same bless/curse requirements as above).  And maybe
change its #invoke property from untrap to detect unseen/secret door
detection since current invoke power would become redundant.

Also, move a bunch of new artifact abilities from the fixes section to
the new features section in fixes36.1.
This commit is contained in:
PatR
2017-10-07 02:28:20 -07:00
parent 9a6c3b4192
commit 468fc1a925
2 changed files with 75 additions and 15 deletions

View File

@@ -4,18 +4,21 @@
#include "hack.h"
STATIC_PTR int NDECL(picklock);
STATIC_PTR int NDECL(forcelock);
/* at most one of `door' and `box' should be non-null at any given time */
STATIC_VAR NEARDATA struct xlock_s {
struct rm *door;
struct obj *box;
int picktyp, /* key|pick|card for unlock, sharp vs blunt for #force */
chance, usedtime;
boolean magic_key;
} xlock;
/* occupation callbacks */
STATIC_PTR int NDECL(picklock);
STATIC_PTR int NDECL(forcelock);
STATIC_DCL const char *NDECL(lock_action);
STATIC_DCL boolean FDECL(is_magic_key, (struct monst *, struct obj *));
STATIC_DCL boolean FDECL(obstructed, (int, int, BOOLEAN_P));
STATIC_DCL void FDECL(chest_shatter_msg, (struct obj *));
@@ -105,6 +108,40 @@ picklock(VOID_ARGS)
if (rn2(100) >= xlock.chance)
return 1; /* still busy */
/* using the Master Key of Thievery finds traps if its bless/curse
state is adequate (non-cursed for rogues, blessed for others;
checked when setting up 'xlock') */
if ((!xlock.door ? (int) xlock.box->otrapped
: (xlock.door->doormask & D_TRAPPED) != 0)
&& xlock.magic_key) {
xlock.chance += 20; /* less effort needed next time */
/* unfortunately we don't have a 'tknown' flag to record
"known to be trapped" so declining to disarm and then
retrying lock manipulation will find it all over again */
if (yn("You find a trap! Do you want to try to disarm it?") == 'y') {
const char *what;
boolean alreadyunlocked;
/* disarming while using magic key always succeeds */
if (xlock.door) {
xlock.door->doormask &= ~D_TRAPPED;
what = "door";
alreadyunlocked = !(xlock.door->doormask & D_LOCKED);
} else {
xlock.box->otrapped = 0;
what = (xlock.box->otyp == CHEST) ? "chest" : "box";
alreadyunlocked = !xlock.box->olocked;
}
You("succeed in disarming the trap. The %s is still %slocked.",
what, alreadyunlocked ? "un" : "");
exercise(A_WIS, TRUE);
} else {
You("stop %s.", lock_action());
exercise(A_WIS, FALSE);
}
return ((xlock.usedtime = 0));
}
You("succeed in %s.", lock_action());
if (xlock.door) {
if (xlock.door->doormask & D_TRAPPED) {
@@ -225,6 +262,7 @@ void
reset_pick()
{
xlock.usedtime = xlock.chance = xlock.picktyp = 0;
xlock.magic_key = FALSE;
xlock.door = 0;
xlock.box = 0;
}
@@ -237,6 +275,21 @@ maybe_reset_pick()
reset_pick();
}
/* Master Key is magic key if its bless/curse state meets our criteria:
not cursed for rogues or blessed for non-rogues */
STATIC_OVL boolean
is_magic_key(mon, obj)
struct monst *mon; /* if null, non-rogue is assumed */
struct obj *obj;
{
if (((obj && obj->oartifact == ART_MASTER_KEY_OF_THIEVERY)
&& ((mon == &youmonst) ? Role_if(PM_ROGUE)
: (mon && mon->data == &mons[PM_ROGUE])))
? !obj->cursed : obj->blessed)
return TRUE;
return FALSE;
}
/* for doapply(); if player gives a direction or resumes an interrupted
previous attempt then it costs hero a move even if nothing ultimately
happens; when told "can't do that" before being asked for direction
@@ -264,6 +317,7 @@ struct obj *pick;
if (nohands(youmonst.data)) {
const char *what = (picktyp == LOCK_PICK) ? "pick" : "key";
if (picktyp == CREDIT_CARD)
what = "card";
pline(no_longer, "hold the", what);
@@ -277,6 +331,7 @@ struct obj *pick;
const char *action = lock_action();
You("resume your attempt at %s.", action);
xlock.magic_key = is_magic_key(&youmonst, pick);
set_occupation(picklock, action, 0);
return PICKLOCK_DID_SOMETHING;
}
@@ -291,8 +346,9 @@ struct obj *pick;
return PICKLOCK_DID_NOTHING;
}
if ((picktyp != LOCK_PICK && picktyp != CREDIT_CARD
&& picktyp != SKELETON_KEY)) {
if (picktyp != LOCK_PICK
&& picktyp != CREDIT_CARD
&& picktyp != SKELETON_KEY) {
impossible("picking lock with object %d?", picktyp);
return PICKLOCK_DID_NOTHING;
}
@@ -375,7 +431,6 @@ struct obj *pick;
if (otmp->cursed)
ch /= 2;
xlock.picktyp = picktyp;
xlock.box = otmp;
xlock.door = 0;
break;
@@ -407,7 +462,7 @@ struct obj *pick;
} else if (mtmp && is_door_mappear(mtmp)) {
/* "The door actually was a <mimic>!" */
stumble_onto_mimic(mtmp);
/* mimic might keep the key (50% chance, 10% for PYEC) */
/* mimic might keep the key (50% chance, 10% for PYEC or MKoT) */
maybe_absorb_item(mtmp, pick, 50, 10);
return PICKLOCK_LEARNED_SOMETHING;
}
@@ -462,6 +517,7 @@ struct obj *pick;
context.move = 0;
xlock.chance = ch;
xlock.picktyp = picktyp;
xlock.magic_key = is_magic_key(&youmonst, pick);
xlock.usedtime = 0;
set_occupation(picklock, lock_action(), 0);
return PICKLOCK_DID_SOMETHING;
@@ -531,6 +587,7 @@ doforce()
xlock.box = otmp;
xlock.chance = objects[uwep->otyp].oc_wldam * 2;
xlock.picktyp = picktyp;
xlock.magic_key = FALSE;
xlock.usedtime = 0;
break;
}