Merge branch 'autounlock' of https://github.com/copperwater/NetHack into copperwater-autounlock-3.7

github pull request #228 commentary follows:

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.

closes #228
This commit is contained in:
nhmall
2019-10-02 13:47:33 -04:00
7 changed files with 58 additions and 17 deletions
+1
View File
@@ -32,6 +32,7 @@ Platform- and/or Interface-Specific New Features
NetHack Community Patches (or Variation) Included NetHack Community Patches (or Variation) Included
------------------------------------------------- -------------------------------------------------
autounlock feature originally from unnethack in github pull request #228
Code Cleanup and Reorganization Code Cleanup and Reorganization
+1 -1
View File
@@ -1101,7 +1101,7 @@ E boolean FDECL(picking_at, (int, int));
E void FDECL(breakchestlock, (struct obj *, BOOLEAN_P)); E void FDECL(breakchestlock, (struct obj *, BOOLEAN_P));
E void NDECL(reset_pick); E void NDECL(reset_pick);
E void FDECL(maybe_reset_pick, (struct obj *)); 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 int NDECL(doforce);
E boolean FDECL(boxlock, (struct obj *, struct obj *)); E boolean FDECL(boxlock, (struct obj *, struct obj *));
E boolean FDECL(doorlock, (struct obj *, int, int)); E boolean FDECL(doorlock, (struct obj *, int, int));
+1
View File
@@ -20,6 +20,7 @@ struct flag {
boolean autodig; /* MRKR: Automatically dig */ boolean autodig; /* MRKR: Automatically dig */
boolean autoquiver; /* Automatically fill quiver */ boolean autoquiver; /* Automatically fill quiver */
boolean autoopen; /* open doors by walking into them */ boolean autoopen; /* open doors by walking into them */
boolean autounlock; /* automatically apply unlocking tools */
boolean beginner; boolean beginner;
boolean biff; /* enable checking for mail */ boolean biff; /* enable checking for mail */
boolean bones; /* allow saving/loading bones */ boolean bones; /* allow saving/loading bones */
+1 -1
View File
@@ -3580,7 +3580,7 @@ doapply()
case LOCK_PICK: case LOCK_PICK:
case CREDIT_CARD: case CREDIT_CARD:
case SKELETON_KEY: case SKELETON_KEY:
res = (pick_lock(obj) != 0); res = (pick_lock(obj, 0, 0, NULL) != 0);
break; break;
case PICK_AXE: case PICK_AXE:
case DWARVISH_MATTOCK: case DWARVISH_MATTOCK:
+44 -15
View File
@@ -294,14 +294,18 @@ struct obj *container; /* passed from obfree() */
/* player is applying a key, lock pick, or credit card */ /* player is applying a key, lock pick, or credit card */
int int
pick_lock(pick) pick_lock(pick, rx, ry, container)
struct obj *pick; 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; int picktyp, c, ch;
coord cc; coord cc;
struct rm *door; struct rm *door;
struct obj *otmp; struct obj *otmp;
char qbuf[QBUFSZ]; char qbuf[QBUFSZ];
boolean autounlock = (rx != 0 && ry != 0) || (container != NULL);
picktyp = pick->otyp; picktyp = pick->otyp;
@@ -348,8 +352,13 @@ struct obj *pick;
} }
ch = 0; /* lint suppression */ 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; return PICKLOCK_DID_NOTHING;
}
if (cc.x == u.ux && cc.y == u.uy) { /* pick lock on a container */ if (cc.x == u.ux && cc.y == u.uy) { /* pick lock on a container */
const char *verb; const char *verb;
@@ -372,7 +381,9 @@ struct obj *pick;
count = 0; count = 0;
c = 'n'; /* in case there are no boxes here */ c = 'n'; /* in case there are no boxes here */
for (otmp = g.level.objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere) for (otmp = g.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; ++count;
if (!can_reach_floor(TRUE)) { if (!can_reach_floor(TRUE)) {
You_cant("reach %s from up here.", the(xname(otmp))); You_cant("reach %s from up here.", the(xname(otmp)));
@@ -388,17 +399,24 @@ struct obj *pick;
else else
verb = "pick"; verb = "pick";
/* "There is <a box> here; <verb> <it|its lock>?" */ if (autounlock) {
Sprintf(qsfx, " here; %s %s?", verb, it ? "it" : "its lock"); Sprintf(qbuf, "Unlock it with %s?", yname(pick));
(void) safe_qbuf(qbuf, "There is ", qsfx, otmp, doname, c = yn(qbuf);
ansimpleoname, "a box"); if (c == 'n')
otmp->lknown = 1; 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); c = ynq(qbuf);
if (c == 'q') if (c == 'q')
return 0; return 0;
if (c == 'n') if (c == 'n')
continue; continue;
}
if (otmp->obroken) { if (otmp->obroken) {
You_cant("fix its broken lock with %s.", doname(pick)); You_cant("fix its broken lock with %s.", doname(pick));
@@ -484,8 +502,10 @@ struct obj *pick;
return PICKLOCK_LEARNED_SOMETHING; return PICKLOCK_LEARNED_SOMETHING;
} }
Sprintf(qbuf, "%s it?", Sprintf(qbuf, "%s it%s%s?",
(door->doormask & D_LOCKED) ? "Unlock" : "Lock"); (door->doormask & D_LOCKED) ? "Unlock" : "Lock",
autounlock ? " with " : "",
autounlock ? yname(pick) : "");
c = yn(qbuf); c = yn(qbuf);
if (c == 'n') if (c == 'n')
@@ -685,6 +705,8 @@ int x, y;
if (!(door->doormask & D_CLOSED)) { if (!(door->doormask & D_CLOSED)) {
const char *mesg; const char *mesg;
boolean locked = FALSE;
struct obj* unlocktool;
switch (door->doormask) { switch (door->doormask) {
case D_BROKEN: case D_BROKEN:
@@ -698,9 +720,16 @@ int x, y;
break; break;
default: default:
mesg = " is locked"; mesg = " is locked";
locked = TRUE;
break; break;
} }
pline("This door%s.", mesg); 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; return res;
} }
+1
View File
@@ -88,6 +88,7 @@ static const struct Bool_Opt {
{ "autoopen", &flags.autoopen, TRUE, SET_IN_GAME }, { "autoopen", &flags.autoopen, TRUE, SET_IN_GAME },
{ "autopickup", &flags.pickup, TRUE, SET_IN_GAME }, { "autopickup", &flags.pickup, TRUE, SET_IN_GAME },
{ "autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME }, { "autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME },
{ "autounlock", &flags.autounlock, TRUE, SET_IN_GAME },
#if defined(MICRO) && !defined(AMIGA) #if defined(MICRO) && !defined(AMIGA)
{ "BIOS", &iflags.BIOS, FALSE, SET_IN_FILE }, { "BIOS", &iflags.BIOS, FALSE, SET_IN_FILE },
#else #else
+9
View File
@@ -1702,6 +1702,7 @@ int cindex, ccount; /* index of this container (1..N), number of them (N) */
if (!cobj) if (!cobj)
return 0; return 0;
if (cobj->olocked) { if (cobj->olocked) {
struct obj *unlocktool;
if (ccount < 2) if (ccount < 2)
pline("%s locked.", pline("%s locked.",
cobj->lknown ? "It is" : "Hmmm, it turns out to be"); cobj->lknown ? "It is" : "Hmmm, it turns out to be");
@@ -1710,6 +1711,14 @@ int cindex, ccount; /* index of this container (1..N), number of them (N) */
else else
pline("Hmmm, %s turns out to be locked.", the(xname(cobj))); pline("Hmmm, %s turns out to be locked.", the(xname(cobj)));
cobj->lknown = 1; 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; return 0;
} }
cobj->lknown = 1; /* floor container, so no need for update_inventory() */ cobj->lknown = 1; /* floor container, so no need for update_inventory() */