]> granicus.if.org Git - nethack/commitdiff
Port the autounlock feature from UnNetHack
authorcopperwater <aosdict@gmail.com>
Tue, 1 Oct 2019 00:56:03 +0000 (20:56 -0400)
committercopperwater <aosdict@gmail.com>
Tue, 1 Oct 2019 01:32:11 +0000 (21:32 -0400)
This adds a boolean option, autounlock, defaulting to true. When this is
set to TRUE, messages stating that some door or container is locked are
automatically followed by a prompt asking if you would like to unlock
it, if you are carrying an unlocking tool (key, lock pick, or credit
card).

Architecturally, this extends the pick_lock function to take three
additional arguments (door coordinates or a box on the ground you are
autounlocking).

Because this adds a new field to struct flag, this is not a
save-compatible change. I have not adjusted EDITLEVEL or
VERSION_COMPATIBILITY, though.

The code that selects an unlocking tool will always look first for a
skeleton key, then a lock pick, then a credit card. Since curses, rust,
and other attributes don't really have an effect on the viability of the
unlocking device, it didn't seem to warrant making a more complex
function for that.

include/extern.h
include/flag.h
src/apply.c
src/lock.c
src/options.c
src/pickup.c

index 7c37297b35f8fb6a8b364df26b1f385657f88b7b..e408f4845f2b8b65a4078c9c498a57b3506515ee 100644 (file)
@@ -1100,7 +1100,7 @@ E boolean FDECL(picking_at, (int, int));
 E void FDECL(breakchestlock, (struct obj *, BOOLEAN_P));
 E void NDECL(reset_pick);
 E void FDECL(maybe_reset_pick, (struct obj *));
-E int FDECL(pick_lock, (struct obj *));
+E int FDECL(pick_lock, (struct obj *, xchar, xchar, struct obj *));
 E int NDECL(doforce);
 E boolean FDECL(boxlock, (struct obj *, struct obj *));
 E boolean FDECL(doorlock, (struct obj *, int, int));
index daef72bc44a7251c567b7c27fbb6106c4cc6bc59..957981a576171cab1790e21a04f26aa7f38c38d7 100644 (file)
@@ -20,6 +20,7 @@ struct flag {
     boolean autodig;    /* MRKR: Automatically dig */
     boolean autoquiver; /* Automatically fill quiver */
     boolean autoopen;   /* open doors by walking into them */
+    boolean autounlock; /* automatically apply unlocking tools */
     boolean beginner;
     boolean biff;      /* enable checking for mail */
     boolean bones;     /* allow saving/loading bones */
index 11bd09d03a8842813d6eb7edd955aa541f9b8e32..5bb06aef6aeb299bc46c7b8397d5971f57d8cc00 100644 (file)
@@ -3606,7 +3606,7 @@ doapply()
     case LOCK_PICK:
     case CREDIT_CARD:
     case SKELETON_KEY:
-        res = (pick_lock(obj) != 0);
+        res = (pick_lock(obj, 0, 0, NULL) != 0);
         break;
     case PICK_AXE:
     case DWARVISH_MATTOCK:
index 270ab18660538b51a6356d64277d7af50d57105b..8645b66a147e5aa74ee4f8070136de58e0483dcc 100644 (file)
@@ -303,14 +303,18 @@ struct obj *container; /* passed from obfree() */
 
 /* player is applying a key, lock pick, or credit card */
 int
-pick_lock(pick)
+pick_lock(pick, rx, ry, container)
 struct obj *pick;
+xchar rx, ry; /* coordinates of doors/container, for autounlock: does not
+                 prompt for direction if these are set */
+struct obj *container; /* container, for autounlock */
 {
     int picktyp, c, ch;
     coord cc;
     struct rm *door;
     struct obj *otmp;
     char qbuf[QBUFSZ];
+    boolean autounlock = (rx != 0 && ry != 0) || (container != NULL);
 
     picktyp = pick->otyp;
 
@@ -357,8 +361,13 @@ struct obj *pick;
     }
     ch = 0; /* lint suppression */
 
-    if (!get_adjacent_loc((char *) 0, "Invalid location!", u.ux, u.uy, &cc))
+    if (rx != 0 && ry != 0) { /* autounlock; caller has provided coordinates */
+        cc.x = rx;
+        cc.y = ry;
+    }
+    else if (!get_adjacent_loc((char *) 0, "Invalid location!", u.ux, u.uy, &cc)) {
         return PICKLOCK_DID_NOTHING;
+    }
 
     if (cc.x == u.ux && cc.y == u.uy) { /* pick lock on a container */
         const char *verb;
@@ -381,7 +390,9 @@ struct obj *pick;
         count = 0;
         c = 'n'; /* in case there are no boxes here */
         for (otmp = level.objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere)
-            if (Is_box(otmp)) {
+            /* autounlock on boxes: only the one that just informed you it was
+             * locked. Don't include any other boxes which might be here. */
+            if ((!autounlock && Is_box(otmp)) || (otmp == container)) {
                 ++count;
                 if (!can_reach_floor(TRUE)) {
                     You_cant("reach %s from up here.", the(xname(otmp)));
@@ -397,17 +408,24 @@ struct obj *pick;
                 else
                     verb = "pick";
 
-                /* "There is <a box> here; <verb> <it|its lock>?" */
-                Sprintf(qsfx, " here; %s %s?", verb, it ? "it" : "its lock");
-                (void) safe_qbuf(qbuf, "There is ", qsfx, otmp, doname,
-                                 ansimpleoname, "a box");
-                otmp->lknown = 1;
-
-                c = ynq(qbuf);
-                if (c == 'q')
-                    return 0;
-                if (c == 'n')
-                    continue;
+                if (autounlock) {
+                    Sprintf(qbuf, "Unlock it with %s?", yname(pick));
+                    c = yn(qbuf);
+                    if (c == 'n')
+                        return 0;
+                } else {
+                    /* "There is <a box> here; <verb> <it|its lock>?" */
+                    Sprintf(qsfx, " here; %s %s?", verb, it ? "it" : "its lock");
+                    (void) safe_qbuf(qbuf, "There is ", qsfx, otmp, doname,
+                                    ansimpleoname, "a box");
+                    otmp->lknown = 1;
+
+                    c = ynq(qbuf);
+                    if (c == 'q')
+                        return 0;
+                    if (c == 'n')
+                        continue;
+                }
 
                 if (otmp->obroken) {
                     You_cant("fix its broken lock with %s.", doname(pick));
@@ -493,8 +511,10 @@ struct obj *pick;
                 return PICKLOCK_LEARNED_SOMETHING;
             }
 
-            Sprintf(qbuf, "%s it?",
-                    (door->doormask & D_LOCKED) ? "Unlock" : "Lock");
+            Sprintf(qbuf, "%s it%s%s?",
+                    (door->doormask & D_LOCKED) ? "Unlock" : "Lock",
+                    autounlock ? " with " : "",
+                    autounlock ? yname(pick) : "");
 
             c = yn(qbuf);
             if (c == 'n')
@@ -694,6 +714,8 @@ int x, y;
 
     if (!(door->doormask & D_CLOSED)) {
         const char *mesg;
+        boolean locked = FALSE;
+        struct obj* unlocktool;
 
         switch (door->doormask) {
         case D_BROKEN:
@@ -707,9 +729,16 @@ int x, y;
             break;
         default:
             mesg = " is locked";
+            locked = TRUE;
             break;
         }
         pline("This door%s.", mesg);
+        if (locked && flags.autounlock &&
+            ((unlocktool = carrying(SKELETON_KEY)) ||
+             (unlocktool = carrying(LOCK_PICK)) ||
+             (unlocktool = carrying(CREDIT_CARD)))) {
+            pick_lock(unlocktool, cc.x, cc.y, (struct obj *) 0);
+        }
         return res;
     }
 
index 50f92ca8698326a30c08ba6573e943e28b5ff862..605e42b0385f9aeafa0fddad79c8631cde39cbd4 100644 (file)
@@ -87,6 +87,7 @@ static struct Bool_Opt {
     { "autoopen", &flags.autoopen, TRUE, SET_IN_GAME },
     { "autopickup", &flags.pickup, TRUE, SET_IN_GAME },
     { "autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME },
+    { "autounlock", &flags.autounlock, TRUE, SET_IN_GAME },
 #if defined(MICRO) && !defined(AMIGA)
     { "BIOS", &iflags.BIOS, FALSE, SET_IN_FILE },
 #else
index e47d989da9bd73037a74bd427e4d3e071d97026d..e3ab9ae115786cfb20a37c5f731d13812bc2b12b 100644 (file)
@@ -1720,6 +1720,7 @@ int cindex, ccount; /* index of this container (1..N), number of them (N) */
     if (!cobj)
         return 0;
     if (cobj->olocked) {
+        struct obj *unlocktool;
         if (ccount < 2)
             pline("%s locked.",
                   cobj->lknown ? "It is" : "Hmmm, it turns out to be");
@@ -1728,6 +1729,14 @@ int cindex, ccount; /* index of this container (1..N), number of them (N) */
         else
             pline("Hmmm, %s turns out to be locked.", the(xname(cobj)));
         cobj->lknown = 1;
+
+        if (flags.autounlock &&
+            ((unlocktool = carrying(SKELETON_KEY)) ||
+             (unlocktool = carrying(LOCK_PICK)) ||
+             (unlocktool = carrying(CREDIT_CARD)))) {
+            /* pass ox and oy to avoid direction prompt */
+            pick_lock(unlocktool, cobj->ox, cobj->oy, cobj);
+        }
         return 0;
     }
     cobj->lknown = 1; /* floor container, so no need for update_inventory() */