diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 2e2f93d51..8e82ed345 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -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 diff --git a/include/extern.h b/include/extern.h index f8544f150..562ac1553 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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)); diff --git a/include/flag.h b/include/flag.h index 135cf0f54..5f010d162 100644 --- a/include/flag.h +++ b/include/flag.h @@ -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 */ diff --git a/src/apply.c b/src/apply.c index 257c12f98..66fcfb4f9 100644 --- a/src/apply.c +++ b/src/apply.c @@ -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: diff --git a/src/lock.c b/src/lock.c index 1ebb9cdac..76922deb7 100644 --- a/src/lock.c +++ b/src/lock.c @@ -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 here; ?" */ - 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 here; ?" */ + 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; } diff --git a/src/options.c b/src/options.c index 2ba829eb1..433bc279b 100644 --- a/src/options.c +++ b/src/options.c @@ -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 diff --git a/src/pickup.c b/src/pickup.c index 999f34bb1..2d1cec607 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -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() */