autounlock:untrap
Implement 'untrap' as an 'autounlock' action. Quite a bit more work than anticipated. The new documentation is rather clumsy; too many if-this and if-not-that clauses have intruded. I'll be astonished if all the return values are correct.... [A couple of places were checking for (rx != 0 && ry != 0) to decide whether they were performating an autounlock action at <rx,ry> but that erroneously excludes the top line of the map if the current level extends that far. Just check rx for zero/non-zero.]
This commit is contained in:
16
dat/opthelp
16
dat/opthelp
@@ -148,12 +148,18 @@ Compound options are written as option_name:option_value.
|
||||
|
||||
Compound options which can be set during the game are:
|
||||
|
||||
autounlock when attempting to open a door or loot a [Apply-Key]
|
||||
container that is locked, specifies an action to take:
|
||||
can be None, or one or more of Apply-Key + Kick + Force;
|
||||
autounlock when attempting to open a locked door or loot [Apply-Key]
|
||||
a locked container, specifies an action to take: can be
|
||||
None, or one or more of Untrap + Apply-Key + Kick + Force;
|
||||
if Untrap is included, it will be handled first; the
|
||||
others apply if you answer "no" to "check for traps?";
|
||||
for "yes", it won't necessary find anything even when a
|
||||
trap happens to be present and will use up the rest of
|
||||
the current move regardless of whether it finds anything;
|
||||
Kick is only useful for doors and Force is only useful for
|
||||
containers; either will only be attempted if Apply-Key is
|
||||
omitted or you aren't carrying any unlocking tool
|
||||
containers; either will only be attempted if Untrap is
|
||||
omitted or skipped and Apply-Key is omitted or you aren't
|
||||
carrying an unlocking tool or you decline to use one
|
||||
boulder override the default boulder symbol [`]
|
||||
disclose the types of information you want [ni na nv ng nc no]
|
||||
offered at the end of the game
|
||||
|
||||
@@ -3662,15 +3662,26 @@ Persistent.
|
||||
Controls what action to take when attempting to walk into a locked door
|
||||
or to loot a locked container.
|
||||
Takes a plus-sign separated list of values:
|
||||
\fIapply-key\fP which will attempt to use a key or other unlocking tool
|
||||
if you have one;
|
||||
\fIkick\fP which will kick the door (if you lack a key or omit apply-key;
|
||||
.PS Apply-Key
|
||||
.PL Untrap
|
||||
prompt about whether to attempt to find a trap;
|
||||
it might fail to find one even when present; if it does find one, it
|
||||
will ask whether you want to try to disarm the trap; if you decline,
|
||||
your character will forget that the door or box is trapped;
|
||||
.PL Apply-Key
|
||||
if carrying a key or other unlocking tool, prompt about using it;
|
||||
.PL Kick
|
||||
kick the door (if you omit untrap or decline to attempt untrap and
|
||||
you omit apply-key or you lack a key or you decline to use the key;
|
||||
has no effect on containers);
|
||||
\fIforce\fP which will try to force a container's lid with your currently
|
||||
wielded weapon (if you lack a key or omit apply-key; has no effect on
|
||||
doors); or
|
||||
\fInone\fP which can't be combined with the other choices.
|
||||
.lp ""
|
||||
.PL Force
|
||||
try to force a container's lid with your currently
|
||||
wielded weapon (if you omit untrap or decline to attempt untrap and
|
||||
you omit apply-key or you lack a key or you decline to use the key;
|
||||
has no effect on doors);
|
||||
.PL None
|
||||
none of the above; can't be combined with the other choices.
|
||||
.PE
|
||||
Omitting the value is treated as if \f(CRautounlock:apply-key\fP.
|
||||
Preceding \f(CRautounlock\fP with \(oq!\(cq or \(lqno\(rq is treated as
|
||||
\f(CRautounlock:none\fP.
|
||||
@@ -3680,7 +3691,7 @@ Successfully kicking a door will break it and wake up nearby monsters.
|
||||
Successfully forcing a container open will break its lock and might also
|
||||
destroy some of its contents or damage your weapon or both.
|
||||
.lp ""
|
||||
The default is \fIapply-key\fP.
|
||||
The default is Apply-Key.
|
||||
Persistent.
|
||||
.lp blind
|
||||
Start the character permanently blind (default false).
|
||||
|
||||
@@ -3970,19 +3970,42 @@ If no weapon is found or the option is
|
||||
false, the `t' (throw) command is executed instead. Persistent.
|
||||
%.lp
|
||||
\item[\ib{autounlock}]
|
||||
%\hyphenation{apply\-key}%this needs to be tested...
|
||||
Controls what action to take when attempting to walk into a locked door
|
||||
or to loot a locked container.
|
||||
Takes a plus-sign separated list of values:
|
||||
{\it apply-key\/} which will attempt to use a key or other unlocking tool
|
||||
if you have one;
|
||||
{\it kick\/} which will kick the door (if you lack a key or omit apply-key;
|
||||
% paranoid
|
||||
% au => autounlock
|
||||
\newlength{\auwidth}
|
||||
%.PS Apply-Key
|
||||
\settowidth{\auwidth}{\tt Apply-Key}
|
||||
\addtolength{\auwidth}{\labelsep}
|
||||
\blist{\leftmargin \auwidth \topsep 1mm \itemsep 0mm}
|
||||
%.PL Untrap
|
||||
\item[{\tt Untrap}]
|
||||
prompt about whether to attempt to find a trap;
|
||||
it might fail to find one even when present; if it does find one, it
|
||||
will ask whether you want to try to disarm the trap; if you decline,
|
||||
your character will forget that the door or box is trapped;
|
||||
%.PL Apply-Key
|
||||
\item[{\tt Apply-Key}]
|
||||
if carrying a key or other unlocking tool, prompt about using it;
|
||||
%.PL Kick
|
||||
\item[{\tt Kick}]
|
||||
kick the door (if you omit untrap or decline to attempt untrap and
|
||||
you omit apply-key or you lack a key or you decline to use the key;
|
||||
has no effect on containers);
|
||||
{\it force\/} which will try to force a container's lid with your currently
|
||||
wielded weapon (if you lack a key or omit apply-key; has no effect on
|
||||
doors); or
|
||||
{\it none\/} which can't be combined with the other choices.
|
||||
\\
|
||||
%.lp ""
|
||||
%.PL Force
|
||||
\item[{\tt Force}]
|
||||
try to force a container's lid with your currently
|
||||
wielded weapon (if you omit untrap or decline to attempt untrap and
|
||||
you omit apply-key or you lack a key or you decline to use the key;
|
||||
has no effect on doors);
|
||||
%.PL None
|
||||
\item[{\tt None}]
|
||||
none of the above; can't be combined with the other choices.
|
||||
%.PE
|
||||
\elist
|
||||
Omitting the value is treated as if {\tt autounlock:apply-key}.
|
||||
Preceding {\tt autounlock} with `{\tt !}' or ``{\tt no}'' is treated as
|
||||
{\tt autounlock:none}.
|
||||
@@ -3994,7 +4017,7 @@ Successfully forcing a container open will break its lock and might also
|
||||
destroy some of its contents or damage your weapon or both.
|
||||
\\
|
||||
%.lp ""
|
||||
The default is {\it apply-key\/}.
|
||||
The default is Apply-Key.
|
||||
Persistent.
|
||||
%.lp
|
||||
\item[\ib{blind}]
|
||||
|
||||
@@ -1197,6 +1197,7 @@ using #wizmakemap on Plane of Water added a new set of air bubbles each time
|
||||
it was run and eventually replaced just about all the water; likewise
|
||||
with clouds on Plane of Air
|
||||
avoid new "where are we?" panic if player quits during character selection
|
||||
add Untrap as a potential 'autounlock' action
|
||||
|
||||
curses: 'msg_window' option wasn't functional for curses unless the binary
|
||||
also included tty support
|
||||
|
||||
@@ -2750,8 +2750,9 @@ extern void water_damage_chain(struct obj *, boolean);
|
||||
extern boolean drown(void);
|
||||
extern void drain_en(int);
|
||||
extern int dountrap(void);
|
||||
extern int could_untrap(boolean, boolean);
|
||||
extern void cnv_trap_obj(int, int, struct trap *, boolean);
|
||||
extern int untrap(boolean);
|
||||
extern int untrap(boolean, int, int, struct obj *);
|
||||
extern boolean openholdingtrap(struct monst *, boolean *);
|
||||
extern boolean closeholdingtrap(struct monst *, boolean *);
|
||||
extern boolean openfallingtrap(struct monst *, boolean, boolean *);
|
||||
|
||||
@@ -1720,7 +1720,7 @@ arti_invoke(struct obj *obj)
|
||||
break;
|
||||
}
|
||||
case UNTRAP: {
|
||||
if (!untrap(TRUE)) {
|
||||
if (!untrap(TRUE, 0, 0, (struct obj *) 0)) {
|
||||
obj->age = 0; /* don't charge for changing their mind */
|
||||
return ECMD_OK;
|
||||
}
|
||||
|
||||
58
src/lock.c
58
src/lock.c
@@ -356,14 +356,19 @@ pick_lock(
|
||||
* does not prompt for direction if these are set */
|
||||
struct obj *container) /* container, for autounlock */
|
||||
{
|
||||
struct obj dummypick;
|
||||
int picktyp, c, ch;
|
||||
coord cc;
|
||||
struct rm *door;
|
||||
struct obj *otmp;
|
||||
char qbuf[QBUFSZ];
|
||||
boolean autounlock = (((rx != 0 && ry != 0) || container != NULL)
|
||||
&& (flags.autounlock & AUTOUNLOCK_APPLY_KEY) != 0);
|
||||
boolean autounlock = (rx != 0 || container != NULL);
|
||||
|
||||
/* 'pick' might be Null [called by do_loot_cont() for AUTOUNLOCK_UNTRAP] */
|
||||
if (!pick) {
|
||||
dummypick = cg.zeroobj;
|
||||
pick = &dummypick; /* pick->otyp will be STRANGE_OBJECT */
|
||||
}
|
||||
picktyp = pick->otyp;
|
||||
|
||||
/* check whether we're resuming an interrupted previous attempt */
|
||||
@@ -401,15 +406,14 @@ pick_lock(
|
||||
return PICKLOCK_DID_NOTHING;
|
||||
}
|
||||
|
||||
if (picktyp != LOCK_PICK
|
||||
&& picktyp != CREDIT_CARD
|
||||
&& picktyp != SKELETON_KEY) {
|
||||
if (pick != &dummypick && picktyp != SKELETON_KEY
|
||||
&& picktyp != LOCK_PICK && picktyp != CREDIT_CARD) {
|
||||
impossible("picking lock with object %d?", picktyp);
|
||||
return PICKLOCK_DID_NOTHING;
|
||||
}
|
||||
ch = 0; /* lint suppression */
|
||||
|
||||
if (rx != 0 && ry != 0) { /* autounlock; caller has provided coordinates */
|
||||
if (rx != 0) { /* autounlock; caller has provided coordinates */
|
||||
cc.x = rx;
|
||||
cc.y = ry;
|
||||
} else if (!get_adjacent_loc((char *) 0, "Invalid location!",
|
||||
@@ -458,11 +462,25 @@ pick_lock(
|
||||
else
|
||||
verb = "pick";
|
||||
|
||||
if (autounlock) {
|
||||
Sprintf(qbuf, "Unlock it with %s?", yname(pick));
|
||||
c = yn(qbuf);
|
||||
if (c == 'n')
|
||||
return 0;
|
||||
if (autounlock && (flags.autounlock & AUTOUNLOCK_UNTRAP) != 0
|
||||
&& could_untrap(FALSE, TRUE)
|
||||
&& (c = ynq(safe_qbuf(qbuf, "Check ", " for a trap?",
|
||||
otmp, yname, ysimple_name, "this")))
|
||||
!= 'n') {
|
||||
if (c == 'q')
|
||||
return PICKLOCK_DID_NOTHING; /* c == 'q' */
|
||||
/* c == 'y' */
|
||||
untrap(FALSE, 0, 0, otmp);
|
||||
return PICKLOCK_DID_SOMETHING; /* even if no trap found */
|
||||
} else if (autounlock
|
||||
&& (flags.autounlock & AUTOUNLOCK_APPLY_KEY) != 0) {
|
||||
c = 'q';
|
||||
if (pick != &dummypick) {
|
||||
Sprintf(qbuf, "Unlock it with %s?", yname(pick));
|
||||
c = ynq(qbuf);
|
||||
}
|
||||
if (c != 'y')
|
||||
return PICKLOCK_DID_NOTHING;
|
||||
} else {
|
||||
/* "There is <a box> here; <verb> <it|its lock>?" */
|
||||
Sprintf(qsfx, " here; %s %s?",
|
||||
@@ -473,9 +491,9 @@ pick_lock(
|
||||
|
||||
c = ynq(qbuf);
|
||||
if (c == 'q')
|
||||
return 0;
|
||||
return PICKLOCK_DID_NOTHING;
|
||||
if (c == 'n')
|
||||
continue;
|
||||
continue; /* try next box */
|
||||
}
|
||||
|
||||
if (otmp->obroken) {
|
||||
@@ -561,6 +579,15 @@ pick_lock(
|
||||
pline("This door is broken.");
|
||||
return PICKLOCK_LEARNED_SOMETHING;
|
||||
default:
|
||||
if ((flags.autounlock & AUTOUNLOCK_UNTRAP) != 0
|
||||
&& could_untrap(FALSE, FALSE)
|
||||
&& (c = ynq("Check this door for a trap?")) != 'n') {
|
||||
if (c == 'q')
|
||||
return PICKLOCK_DID_NOTHING;
|
||||
/* c == 'y' */
|
||||
untrap(FALSE, cc.x, cc.y, (struct obj *) 0);
|
||||
return PICKLOCK_DID_SOMETHING; /* even if no trap found */
|
||||
}
|
||||
/* credit cards are only good for unlocking */
|
||||
if (picktyp == CREDIT_CARD && !(door->doormask & D_LOCKED)) {
|
||||
You_cant("lock a door with a credit card.");
|
||||
@@ -571,9 +598,8 @@ pick_lock(
|
||||
(door->doormask & D_LOCKED) ? "Unlock" : "Lock",
|
||||
autounlock ? " with " : "",
|
||||
autounlock ? yname(pick) : "");
|
||||
|
||||
c = yn(qbuf);
|
||||
if (c == 'n')
|
||||
c = ynq(qbuf);
|
||||
if (c != 'y')
|
||||
return 0;
|
||||
|
||||
/* note: for !autounlock, 'apply' already did touch check */
|
||||
|
||||
@@ -4534,8 +4534,6 @@ handler_autounlock(int optidx)
|
||||
start_menu(tmpwin, MENU_BEHAVE_STANDARD);
|
||||
any = cg.zeroany;
|
||||
for (i = 0; i < SIZE(unlocktypes); ++i) {
|
||||
if (i == 1) /*** suppress 'untrap' from the menu... ***/
|
||||
continue; /*** until it actually gets implemented ***/
|
||||
Sprintf(buf, "%-10.10s%c%.40s",
|
||||
unlocktypes[i][0], sep, unlocktypes[i][1]);
|
||||
presel = !i ? !flags.autounlock : (flags.autounlock & (1 << (i - 1)));
|
||||
|
||||
47
src/pickup.c
47
src/pickup.c
@@ -1863,43 +1863,64 @@ mon_beside(int x, int y)
|
||||
}
|
||||
|
||||
static int
|
||||
do_loot_cont(struct obj **cobjp,
|
||||
int cindex, /* index of this container (1..N)... */
|
||||
int ccount) /* ...number of them (N) */
|
||||
do_loot_cont(
|
||||
struct obj **cobjp,
|
||||
int cindex, /* index of this container (1..N)... */
|
||||
int ccount) /* ...number of them (N) */
|
||||
{
|
||||
struct obj *cobj = *cobjp;
|
||||
|
||||
if (!cobj)
|
||||
return ECMD_OK;
|
||||
if (cobj->olocked) {
|
||||
int res = ECMD_OK;
|
||||
|
||||
#if 0
|
||||
if (ccount < 2 && (g.level.objects[cobj->ox][cobj->oy] == cobj))
|
||||
pline("%s locked.",
|
||||
cobj->lknown ? "It is" : "Hmmm, it turns out to be");
|
||||
else if (cobj->lknown)
|
||||
else
|
||||
#endif
|
||||
if (cobj->lknown)
|
||||
pline("%s is locked.", The(xname(cobj)));
|
||||
else
|
||||
pline("Hmmm, %s turns out to be locked.", the(xname(cobj)));
|
||||
cobj->lknown = 1;
|
||||
|
||||
if (flags.autounlock) {
|
||||
struct obj *unlocktool;
|
||||
struct obj *otmp, *unlocktool = 0;
|
||||
xchar ox = cobj->ox, oy = cobj->oy;
|
||||
|
||||
/* TODO: handle AUTOUNLOCK_UNTRAP and maybe add kicking at
|
||||
self when chest present to handle AUTOUNLOCK_KICK */
|
||||
u.dz = 0; /* might be non-zero from previous command since
|
||||
* #loot isn't a move command; pick_lock() cares */
|
||||
if ((flags.autounlock & AUTOUNLOCK_APPLY_KEY) != 0
|
||||
&& (unlocktool = autokey(TRUE)) != 0) {
|
||||
/* if both the untrap and apply_key bits are set, untrap
|
||||
attempt will be performed first but we need to set up
|
||||
unlocktool in case "check for trap?" is declined */
|
||||
if (((flags.autounlock & AUTOUNLOCK_APPLY_KEY) != 0
|
||||
&& (unlocktool = autokey(TRUE)) != 0)
|
||||
|| (flags.autounlock & AUTOUNLOCK_UNTRAP) != 0) {
|
||||
/* pass ox and oy to avoid direction prompt */
|
||||
return (pick_lock(unlocktool, cobj->ox, cobj->oy, cobj) != 0);
|
||||
} else if ((flags.autounlock & AUTOUNLOCK_FORCE) != 0
|
||||
&& ccount == 1 && u_have_forceable_weapon()) {
|
||||
if (pick_lock(unlocktool, ox, oy, cobj))
|
||||
res = ECMD_TIME;
|
||||
/* attempting to untrap or unlock might trigger a trap
|
||||
which destroys 'cobj'; inform caller if that happens */
|
||||
for (otmp = g.level.objects[ox][oy]; otmp;
|
||||
otmp = otmp->nexthere)
|
||||
if (otmp == cobj)
|
||||
break;
|
||||
if (!otmp)
|
||||
*cobjp = (struct obj *) 0;
|
||||
return res;
|
||||
}
|
||||
if ((flags.autounlock & AUTOUNLOCK_FORCE) != 0
|
||||
&& res != ECMD_TIME
|
||||
&& ccount == 1 && u_have_forceable_weapon()) {
|
||||
/* single container, and we could #force it open... */
|
||||
cmdq_add_ec(doforce); /* doforce asks for confirmation */
|
||||
g.abort_looting = TRUE;
|
||||
}
|
||||
}
|
||||
return ECMD_OK;
|
||||
return res;
|
||||
}
|
||||
cobj->lknown = 1; /* floor container, so no need for update_inventory() */
|
||||
|
||||
|
||||
193
src/trap.c
193
src/trap.c
@@ -61,6 +61,7 @@ static void clear_conjoined_pits(struct trap *);
|
||||
static boolean adj_nonconjoined_pit(struct trap *);
|
||||
static int try_lift(struct monst *, struct trap *, int, boolean);
|
||||
static int help_monster_out(struct monst *, struct trap *);
|
||||
static void untrap_box(struct obj *, boolean, boolean);
|
||||
#if 0
|
||||
static void join_adjacent_pits(struct trap *);
|
||||
#endif
|
||||
@@ -4495,23 +4496,40 @@ drain_en(int n)
|
||||
int
|
||||
dountrap(void)
|
||||
{
|
||||
if (!could_untrap(TRUE, FALSE))
|
||||
return ECMD_OK;
|
||||
|
||||
return untrap(FALSE, 0, 0, (struct obj *) 0) ? ECMD_TIME : ECMD_OK;
|
||||
}
|
||||
|
||||
/* the #untrap command - disarm a trap */
|
||||
int
|
||||
could_untrap(boolean verbosely, boolean check_floor)
|
||||
{
|
||||
char buf[BUFSZ];
|
||||
|
||||
buf[0] = '\0';
|
||||
if (near_capacity() >= HVY_ENCUMBER) {
|
||||
pline("You're too strained to do that.");
|
||||
return ECMD_OK;
|
||||
}
|
||||
if ((nohands(g.youmonst.data) && !webmaker(g.youmonst.data))
|
||||
|| !g.youmonst.data->mmove) {
|
||||
pline("And just how do you expect to do that?");
|
||||
return ECMD_OK;
|
||||
Strcpy(buf, "You're too strained to do that.");
|
||||
} else if ((nohands(g.youmonst.data) && !webmaker(g.youmonst.data))
|
||||
|| !g.youmonst.data->mmove) {
|
||||
Strcpy(buf, "And just how do you expect to do that?");
|
||||
} else if (u.ustuck && sticks(g.youmonst.data)) {
|
||||
pline("You'll have to let go of %s first.", mon_nam(u.ustuck));
|
||||
return ECMD_OK;
|
||||
Sprintf(buf, "You'll have to let go of %s first.", mon_nam(u.ustuck));
|
||||
} else if (u.ustuck || (welded(uwep) && bimanual(uwep))) {
|
||||
Sprintf(buf, "Your %s seem to be too busy for that.",
|
||||
makeplural(body_part(HAND)));
|
||||
} else if (check_floor && !can_reach_floor(FALSE)) {
|
||||
/* only checked here for autounlock of chest/box and that will
|
||||
be !verbosely so precise details of the message don't matter */
|
||||
Sprintf(buf, "You can't reach the %s.", surface(u.ux, u.uy));
|
||||
}
|
||||
if (u.ustuck || (welded(uwep) && bimanual(uwep))) {
|
||||
Your("%s seem to be too busy for that.", makeplural(body_part(HAND)));
|
||||
return ECMD_OK;
|
||||
if (buf[0]) {
|
||||
if (verbosely)
|
||||
pline("%s", buf);
|
||||
return 0;
|
||||
}
|
||||
return untrap(FALSE) ? ECMD_TIME : ECMD_OK;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Probability of disabling a trap. Helge Hafting */
|
||||
@@ -4964,8 +4982,50 @@ help_monster_out(
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check a particular container for a trap and optionally disarm it */
|
||||
static void
|
||||
untrap_box(
|
||||
struct obj *box,
|
||||
boolean force,
|
||||
boolean confused)
|
||||
{
|
||||
if ((box->otrapped
|
||||
&& (force || (!confused && rn2(MAXULEV + 1 - u.ulevel) < 10)))
|
||||
|| (!force && confused && !rn2(3))) {
|
||||
You("find a trap on %s!", the(xname(box)));
|
||||
if (!confused)
|
||||
exercise(A_WIS, TRUE);
|
||||
|
||||
if (ynq("Disarm it?") == 'y') {
|
||||
if (box->otrapped) {
|
||||
int ch = ACURR(A_DEX) + u.ulevel;
|
||||
|
||||
if (Role_if(PM_ROGUE))
|
||||
ch *= 2;
|
||||
if (!force && (confused || Fumbling
|
||||
|| rnd(75 + level_difficulty() / 2) > ch)) {
|
||||
(void) chest_trap(box, FINGER, TRUE);
|
||||
/* 'box' might be gone now */
|
||||
} else {
|
||||
You("disarm it!");
|
||||
box->otrapped = 0;
|
||||
}
|
||||
exercise(A_DEX, TRUE);
|
||||
} else {
|
||||
pline("That %s was not trapped.", xname(box));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
You("find no traps on %s.", the(xname(box)));
|
||||
}
|
||||
}
|
||||
|
||||
/* hero is able to attempt untrap, so do so */
|
||||
int
|
||||
untrap(boolean force)
|
||||
untrap(
|
||||
boolean force,
|
||||
int rx, int ry,
|
||||
struct obj *container)
|
||||
{
|
||||
register struct obj *otmp;
|
||||
register int x, y;
|
||||
@@ -4975,22 +5035,35 @@ untrap(boolean force)
|
||||
const char *trapdescr;
|
||||
boolean here, useplural, deal_with_floor_trap,
|
||||
confused = (Confusion || Hallucination),
|
||||
trap_skipped = FALSE;
|
||||
trap_skipped = FALSE, autounlock_door = FALSE;
|
||||
int boxcnt = 0;
|
||||
char the_trap[BUFSZ], qbuf[QBUFSZ];
|
||||
|
||||
if (!getdir((char *) 0))
|
||||
return 0;
|
||||
x = u.ux + u.dx;
|
||||
y = u.uy + u.dy;
|
||||
/* 'force' is true for #invoke; if carrying MKoT, make it be true
|
||||
for #untrap or autounlock */
|
||||
if (!force && has_magic_key(&g.youmonst))
|
||||
force = TRUE;
|
||||
|
||||
if (!rx && !container) {
|
||||
/* usual case */
|
||||
if (!getdir((char *) 0))
|
||||
return 0;
|
||||
x = u.ux + u.dx;
|
||||
y = u.uy + u.dy;
|
||||
} else {
|
||||
/* autounlock's untrap; skip most prompting */
|
||||
if (container) {
|
||||
untrap_box(container, force, confused);
|
||||
return 1;
|
||||
}
|
||||
/* levl[rx][ry] is a locked or trapped door */
|
||||
x = rx, y = ry;
|
||||
autounlock_door = TRUE;
|
||||
}
|
||||
if (!isok(x, y)) {
|
||||
pline_The("perils lurking there are beyond your grasp.");
|
||||
return 0;
|
||||
}
|
||||
/* 'force' is true for #invoke; make it be true for #untrap if
|
||||
carrying MKoT */
|
||||
if (!force && has_magic_key(&g.youmonst))
|
||||
force = TRUE;
|
||||
|
||||
ttmp = t_at(x, y);
|
||||
if (ttmp && !ttmp->tseen)
|
||||
@@ -5006,7 +5079,9 @@ untrap(boolean force)
|
||||
}
|
||||
|
||||
deal_with_floor_trap = can_reach_floor(FALSE);
|
||||
if (!deal_with_floor_trap) {
|
||||
if (autounlock_door) {
|
||||
; /* skip a bunch */
|
||||
} else if (!deal_with_floor_trap) {
|
||||
*the_trap = '\0';
|
||||
if (ttmp)
|
||||
Strcat(the_trap, an(trapdescr));
|
||||
@@ -5095,6 +5170,11 @@ untrap(boolean force)
|
||||
} /* end if */
|
||||
|
||||
if (boxcnt) {
|
||||
/* 3.7: this used to allow searching for traps on multiple
|
||||
containers on the same move and needed to keep track of
|
||||
whether any had been found but not attempted to untrap;
|
||||
now at most one per move may be checked and we only
|
||||
continue on to door handling if they are all declined */
|
||||
for (otmp = g.level.objects[x][y]; otmp; otmp = otmp->nexthere)
|
||||
if (Is_box(otmp)) {
|
||||
(void) safe_qbuf(qbuf, "There is ",
|
||||
@@ -5103,59 +5183,34 @@ untrap(boolean force)
|
||||
switch (ynq(qbuf)) {
|
||||
case 'q':
|
||||
return 0;
|
||||
case 'n':
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((otmp->otrapped
|
||||
&& (force || (!confused
|
||||
&& rn2(MAXULEV + 1 - u.ulevel) < 10)))
|
||||
|| (!force && confused && !rn2(3))) {
|
||||
You("find a trap on %s!", the(xname(otmp)));
|
||||
if (!confused)
|
||||
exercise(A_WIS, TRUE);
|
||||
|
||||
switch (ynq("Disarm it?")) {
|
||||
case 'q':
|
||||
return 1;
|
||||
case 'n':
|
||||
trap_skipped = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (otmp->otrapped) {
|
||||
exercise(A_DEX, TRUE);
|
||||
ch = ACURR(A_DEX) + u.ulevel;
|
||||
if (Role_if(PM_ROGUE))
|
||||
ch *= 2;
|
||||
if (!force && (confused || Fumbling
|
||||
|| rnd(75 + level_difficulty() / 2)
|
||||
> ch)) {
|
||||
(void) chest_trap(otmp, FINGER, TRUE);
|
||||
} else {
|
||||
You("disarm it!");
|
||||
otmp->otrapped = 0;
|
||||
}
|
||||
} else
|
||||
pline("That %s was not trapped.", xname(otmp));
|
||||
return 1;
|
||||
} else {
|
||||
You("find no traps on %s.", the(xname(otmp)));
|
||||
return 1;
|
||||
case 'y':
|
||||
untrap_box(otmp, force, confused);
|
||||
return 1; /* even for 'no' at "Disarm it?" prompt */
|
||||
}
|
||||
/* 'n' => continue to next box */
|
||||
}
|
||||
|
||||
You(trap_skipped ? "find no other traps here."
|
||||
: "know of no traps here.");
|
||||
return 0;
|
||||
There("are no other chests or boxes here.");
|
||||
}
|
||||
|
||||
if (stumble_on_door_mimic(x, y))
|
||||
return 1;
|
||||
|
||||
} /* deal_with_floor_trap */
|
||||
/* doors can be manipulated even while levitating/unskilled riding */
|
||||
|
||||
/*
|
||||
* Doors can be manipulated even while levitating/unskilled riding.
|
||||
*
|
||||
* Ordinarily there won't be a closed or locked door at the same
|
||||
* location as a floor trap or a container. However, there could
|
||||
* be a container at a closed/locked door spot if it was dropped
|
||||
* there by a monster or poly'd hero with Passes_walls capability,
|
||||
* and poly'd hero could move onto that spot and attempt #untrap
|
||||
* in direction '.' or '>'. We'll get here for that situation if
|
||||
* player declines to check all containers for traps.
|
||||
*
|
||||
* The usual situation is #untrap toward an adjacent closed door.
|
||||
* No floor trap would be present and any containers would be
|
||||
* ignored because they're only checked when direction is '.'/'>'.
|
||||
*/
|
||||
if (!IS_DOOR(levl[x][y].typ)) {
|
||||
if (!trap_skipped)
|
||||
You("know of no traps there.");
|
||||
|
||||
Reference in New Issue
Block a user