]> granicus.if.org Git - nethack/commitdiff
more Master Key of Thievery: lock/unlock vs traps
authorPatR <rankin@nethack.org>
Sat, 7 Oct 2017 09:28:20 +0000 (02:28 -0700)
committerPatR <rankin@nethack.org>
Sat, 7 Oct 2017 09:28:20 +0000 (02:28 -0700)
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.

doc/fixes36.1
src/lock.c

index 34502e489e71a29a7f125039224ebc131d4f12a7..8e2d0f4863f958c4f56332cab5a38d5f4213d3f1 100644 (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
index 94073f3ae401b88613cc759806acafee82579b61..19dfabe461a372e8e1de6d23b7e2ceaca0d10841 100644 (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;
         }