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

View File

@@ -32,6 +32,7 @@ Platform- and/or Interface-Specific New Features
NetHack Community Patches (or Variation) Included
-------------------------------------------------
autounlock feature originally from unnethack in github pull request #228
Code Cleanup and Reorganization

View File

@@ -1101,7 +1101,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));

View 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 */

View File

@@ -3580,7 +3580,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:

View File

@@ -294,14 +294,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;
@@ -348,8 +352,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;
@@ -372,7 +381,9 @@ struct obj *pick;
count = 0;
c = 'n'; /* in case there are no boxes here */
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;
if (!can_reach_floor(TRUE)) {
You_cant("reach %s from up here.", the(xname(otmp)));
@@ -388,17 +399,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;
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;
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));
@@ -484,8 +502,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')
@@ -685,6 +705,8 @@ int x, y;
if (!(door->doormask & D_CLOSED)) {
const char *mesg;
boolean locked = FALSE;
struct obj* unlocktool;
switch (door->doormask) {
case D_BROKEN:
@@ -698,9 +720,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;
}

View File

@@ -88,6 +88,7 @@ static const 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

View File

@@ -1702,6 +1702,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");
@@ -1710,6 +1711,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() */