-/* NetHack 3.6 lock.c $NHDT-Date: 1446955300 2015/11/08 04:01:40 $ $NHDT-Branch: master $:$NHDT-Revision: 1.67 $ */
+/* NetHack 3.6 lock.c $NHDT-Date: 1521499715 2018/03/19 22:48:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.80 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Robert Patrick Rankin, 2011. */
/* NetHack may be freely redistributed. See license for details. */
/* JNetHack Copyright */
#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(obstructed, (int, int, BOOLEAN_P));
STATIC_DCL void FDECL(chest_shatter_msg, (struct obj *));
picklock(VOID_ARGS)
{
if (xlock.box) {
- if ((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy)) {
+ if (xlock.box->where != OBJ_FLOOR
+ || xlock.box->ox != u.ux || xlock.box->oy != u.uy) {
return ((xlock.usedtime = 0)); /* you or it moved */
}
} else { /* door */
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));
+ }
+
/*JP
You("succeed in %s.", lock_action());
*/
xlock.door->doormask = D_NODOOR;
unblock_point(u.ux + u.dx, u.uy + u.dy);
if (*in_rooms(u.ux + u.dx, u.uy + u.dy, SHOPBASE))
- add_damage(u.ux + u.dx, u.uy + u.dy, 0L);
+ add_damage(u.ux + u.dx, u.uy + u.dy, SHOP_DOOR_COST);
newsym(u.ux + u.dx, u.uy + u.dy);
} else if (xlock.door->doormask & D_LOCKED)
xlock.door->doormask = D_CLOSED;
reset_pick()
{
xlock.usedtime = xlock.chance = xlock.picktyp = 0;
+ xlock.magic_key = FALSE;
xlock.door = 0;
xlock.box = 0;
}
+/* level change; don't reset if hero is carrying xlock.box with him/her */
+void
+maybe_reset_pick()
+{
+ if (!xlock.box || !carried(xlock.box))
+ reset_pick();
+}
+
/* 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
const char *what = (picktyp == LOCK_PICK) ? "pick" : "key";
*/
const char *what = (picktyp == LOCK_PICK) ? "\8c®\8aJ\82¯\8aí\8bï" : "\8c®";
+
if (picktyp == CREDIT_CARD)
/*JP
what = "card";
You("resume your attempt at %s.", action);
*/
pline("%s\82Ì\82ð\8dÄ\8aJ\82µ\82½\81D", action);
+ xlock.magic_key = is_magic_key(&youmonst, pick);
set_occupation(picklock, action, 0);
return PICKLOCK_DID_SOMETHING;
}
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;
}
return PICKLOCK_LEARNED_SOMETHING;
} else if (is_pool(u.ux, u.uy) && !Underwater) {
/*JP
- pline_The("water has no lock.");
+ pline_The("%s has no lock.", hliquid("water"));
*/
- pline("\90\85\82É\8fù\91O\82Í\82È\82¢\81D");
+ pline_The("%s\82É\8fù\91O\82Í\82È\82¢\81D", hliquid("\90\85"));
return PICKLOCK_LEARNED_SOMETHING;
}
if (otmp->cursed)
ch /= 2;
- xlock.picktyp = picktyp;
xlock.box = otmp;
xlock.door = 0;
break;
} 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;
}
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;
for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere)
if (Is_box(otmp)) {
if (otmp->obroken || !otmp->olocked) {
+ /* force doname() to omit known "broken" or "unlocked"
+ prefix so that the message isn't worded redundantly;
+ since we're about to set lknown, there's no need to
+ remember and then reset its current value */
+ otmp->lknown = 0;
#if 0 /*JP*/
- There("is %s here, but its lock is already %s.", doname(otmp),
- otmp->obroken ? "broken" : "unlocked");
+ There("is %s here, but its lock is already %s.",
+ doname(otmp), otmp->obroken ? "broken" : "unlocked");
#else
- pline("\82±\82±\82É\82Í%s\82ª\82 \82é\81C\82µ\82©\82µ\82»\82Ì\8c®\82Í\82à\82¤%s\81D", doname(otmp),
+ pline("\82±\82±\82É\82Í%s\82ª\82 \82é\81D\82µ\82©\82µ\82»\82Ì\8c®\82Í\82à\82¤%s\81D",
+ doname(otmp),
otmp->obroken ? "\89ó\82ê\82Ä\82¢\82é" : "\82Í\82¸\82³\82ê\82Ä\82¢\82é");
#endif
otmp->lknown = 1;
(void) safe_qbuf(qbuf, "There is ", " here; force its lock?",
otmp, doname, ansimpleoname, "a box");
#else
- (void) safe_qbuf(qbuf, "\82±\82±\82É\82Í", "\82ª\82 \82é\81C\8c®\82ð\82±\82¶\8aJ\82¯\82Ü\82·\82©\81H",
+ (void) safe_qbuf(qbuf, "\82±\82±\82É\82Í", "\82ª\82 \82é\81D\8c®\82ð\82±\82¶\8aJ\82¯\82Ü\82·\82©\81H",
otmp, doname, ansimpleoname, "\94 ");
#endif
otmp->lknown = 1;
xlock.box = otmp;
xlock.chance = objects[uwep->otyp].oc_wldam * 2;
xlock.picktyp = picktyp;
+ xlock.magic_key = FALSE;
xlock.usedtime = 0;
break;
}
} else if (!get_adjacent_loc((char *) 0, (char *) 0, u.ux, u.uy, &cc))
return 0;
+ /* open at yourself/up/down */
if ((cc.x == u.ux) && (cc.y == u.uy))
- return 0;
+ return doloot();
if (stumble_on_door_mimic(cc.x, cc.y))
return 1;
pline_The("drawbridge is already open.");
*/
pline_The("\92µ\82Ë\8b´\82Í\82à\82¤\8aJ\82¢\82Ä\82¢\82é\81D");
+ else if (container_at(cc.x, cc.y, TRUE))
+ pline("%s like something lootable over there.",
+ Blind ? "Feels" : "Seems");
else
/*JP
You("%s no door there.", Blind ? "feel" : "see");
b_trapped("\94à", FINGER);
door->doormask = D_NODOOR;
if (*in_rooms(cc.x, cc.y, SHOPBASE))
- add_damage(cc.x, cc.y, 0L);
+ add_damage(cc.x, cc.y, SHOP_DOOR_COST);
} else
door->doormask = D_ISOPEN;
feel_newsym(cc.x, cc.y); /* the hero knows she opened it */