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

@@ -350,14 +350,6 @@ pets start with apport equal to your charisma
sometimes generate the random mazes with wide corridors, thick walls,
or with dead ends changed to loops
put throne room gold in the chest
wielding Trollsbane prevents trolls from reviving
wielding Demonbane prevents demons summoning friends
wielding Dragonbane confers reflection
wielding Ogresmasher grants 25 constitution
Cleaver can hit three monsters with one swing
Master Key of Thievery warns about undetected traps if wielded
Elbereth must now be on a square by itself to function
Elbereth now erodes based on attacks by the player, not monsters scared
novels are made of paper, not gold
movement speeds are made less predictable by using random rounding, rather
than via adding a random offset
@@ -681,6 +673,17 @@ new paranoid_confirm settings: wand-break to require "yes" rather than 'y'
option force_invmenu to make commands asking for inventory items always
use a menu instead of a text line query
option hitpointbar to show a bar graph of hit points behind title field
wielding Trollsbane prevents troll corpses from reviving
wielding Demonbane prevents demons summoning friends
wielding Dragonbane confers reflection
wielding Ogresmasher grants 25 constitution
Cleaver can hit three adjacent monsters with one swing
Master Key of Thievery warns about undetected traps if wielded without gloves
Master Key of Thievery always finds door and chest traps if used to lock or
unlock a trapped door or chest while non-cursed (for rogues) or
blessed (for non-rogues); player is offered the opportunity to disarm
"Elbereth" must now be the only engraved text on a square to function
"Elbereth" now erodes based on attacks by the player, not monsters scared
Platform- and/or Interface-Specific New Features

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;
}