fix issue #1305 - failed #untrap from doorway
Issue reported by loggersviii: attempting #untrap from an adjacent doorway can move the hero diagonally out of the doorway. A followup comment by elunna pointed out that a monster's attack that results in knockback can produce similar result. Fixes #1305
This commit is contained in:
@@ -1173,6 +1173,7 @@ extern boolean in_town(coordxy, coordxy);
|
|||||||
extern void check_special_room(boolean);
|
extern void check_special_room(boolean);
|
||||||
extern int dopickup(void);
|
extern int dopickup(void);
|
||||||
extern void lookaround(void);
|
extern void lookaround(void);
|
||||||
|
extern boolean doorless_door(coordxy, coordxy);
|
||||||
extern boolean crawl_destination(coordxy, coordxy);
|
extern boolean crawl_destination(coordxy, coordxy);
|
||||||
extern int monster_nearby(void);
|
extern int monster_nearby(void);
|
||||||
extern void end_running(boolean);
|
extern void end_running(boolean);
|
||||||
@@ -3218,6 +3219,7 @@ extern void drain_en(int, boolean);
|
|||||||
extern int dountrap(void);
|
extern int dountrap(void);
|
||||||
extern int could_untrap(boolean, boolean);
|
extern int could_untrap(boolean, boolean);
|
||||||
extern void cnv_trap_obj(int, int, struct trap *, boolean) NONNULLARG3;
|
extern void cnv_trap_obj(int, int, struct trap *, boolean) NONNULLARG3;
|
||||||
|
extern boolean into_vs_onto(int);
|
||||||
extern int untrap(boolean, coordxy, coordxy, struct obj *) NO_NNARGS;
|
extern int untrap(boolean, coordxy, coordxy, struct obj *) NO_NNARGS;
|
||||||
extern boolean openholdingtrap(struct monst *, boolean *) NO_NNARGS;
|
extern boolean openholdingtrap(struct monst *, boolean *) NO_NNARGS;
|
||||||
extern boolean closeholdingtrap(struct monst *, boolean *) NO_NNARGS;
|
extern boolean closeholdingtrap(struct monst *, boolean *) NO_NNARGS;
|
||||||
|
|||||||
+3
-16
@@ -47,7 +47,6 @@ staticfn struct monst *monstinroom(struct permonst *, int) NONNULLARG1;
|
|||||||
staticfn boolean furniture_present(int, int);
|
staticfn boolean furniture_present(int, int);
|
||||||
staticfn void move_update(boolean);
|
staticfn void move_update(boolean);
|
||||||
staticfn int pickup_checks(void);
|
staticfn int pickup_checks(void);
|
||||||
staticfn boolean doorless_door(coordxy, coordxy);
|
|
||||||
staticfn void maybe_wail(void);
|
staticfn void maybe_wail(void);
|
||||||
staticfn boolean water_turbulence(coordxy *, coordxy *);
|
staticfn boolean water_turbulence(coordxy *, coordxy *);
|
||||||
|
|
||||||
@@ -963,7 +962,7 @@ invocation_pos(coordxy x, coordxy y)
|
|||||||
&& x == svi.inv_pos.x && y == svi.inv_pos.y);
|
&& x == svi.inv_pos.x && y == svi.inv_pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return TRUE if (dx,dy) is an OK place to move;
|
/* return TRUE if (ux+dx,ux+dy) is an OK place to move;
|
||||||
mode is one of DO_MOVE, TEST_MOVE, TEST_TRAV, or TEST_TRAP */
|
mode is one of DO_MOVE, TEST_MOVE, TEST_TRAV, or TEST_TRAP */
|
||||||
boolean
|
boolean
|
||||||
test_move(
|
test_move(
|
||||||
@@ -2749,20 +2748,8 @@ domove_core(void)
|
|||||||
|| Hallucination)) {
|
|| Hallucination)) {
|
||||||
char qbuf[QBUFSZ];
|
char qbuf[QBUFSZ];
|
||||||
int traptype = (Hallucination ? rnd(TRAPNUM - 1) : (int) trap->ttyp);
|
int traptype = (Hallucination ? rnd(TRAPNUM - 1) : (int) trap->ttyp);
|
||||||
boolean into = FALSE; /* "onto" the trap vs "into" */
|
boolean into = into_vs_onto(traptype);
|
||||||
|
|
||||||
switch (traptype) {
|
|
||||||
case BEAR_TRAP:
|
|
||||||
case PIT:
|
|
||||||
case SPIKED_PIT:
|
|
||||||
case HOLE:
|
|
||||||
case TELEP_TRAP:
|
|
||||||
case LEVEL_TELEP:
|
|
||||||
case MAGIC_PORTAL:
|
|
||||||
case WEB:
|
|
||||||
into = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Snprintf(qbuf, sizeof qbuf, "Really %s %s that %s?",
|
Snprintf(qbuf, sizeof qbuf, "Really %s %s that %s?",
|
||||||
u_locomotion("step"), into ? "into" : "onto",
|
u_locomotion("step"), into ? "into" : "onto",
|
||||||
defsyms[trap_to_defsym(traptype)].explanation);
|
defsyms[trap_to_defsym(traptype)].explanation);
|
||||||
@@ -3910,7 +3897,7 @@ lookaround(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check for a doorway which lacks its door (NODOOR or BROKEN) */
|
/* check for a doorway which lacks its door (NODOOR or BROKEN) */
|
||||||
staticfn boolean
|
boolean
|
||||||
doorless_door(coordxy x, coordxy y)
|
doorless_door(coordxy x, coordxy y)
|
||||||
{
|
{
|
||||||
struct rm *lev_p = &levl[x][y];
|
struct rm *lev_p = &levl[x][y];
|
||||||
|
|||||||
+30
-3
@@ -5267,6 +5267,24 @@ cnv_trap_obj(
|
|||||||
deltrap(ttmp);
|
deltrap(ttmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* whether moving to a trap location is moving "into" the trap or "onto" it */
|
||||||
|
boolean
|
||||||
|
into_vs_onto(int traptype)
|
||||||
|
{
|
||||||
|
switch (traptype) {
|
||||||
|
case BEAR_TRAP:
|
||||||
|
case PIT:
|
||||||
|
case SPIKED_PIT:
|
||||||
|
case HOLE:
|
||||||
|
case TELEP_TRAP:
|
||||||
|
case LEVEL_TELEP:
|
||||||
|
case MAGIC_PORTAL:
|
||||||
|
case WEB:
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* while attempting to disarm an adjacent trap, we've fallen into it */
|
/* while attempting to disarm an adjacent trap, we've fallen into it */
|
||||||
staticfn void
|
staticfn void
|
||||||
move_into_trap(struct trap *ttmp)
|
move_into_trap(struct trap *ttmp)
|
||||||
@@ -5276,9 +5294,13 @@ move_into_trap(struct trap *ttmp)
|
|||||||
boolean unused;
|
boolean unused;
|
||||||
|
|
||||||
bx = by = cx = cy = 0; /* lint suppression */
|
bx = by = cx = cy = 0; /* lint suppression */
|
||||||
/* we know there's no monster in the way, and we're not trapped */
|
/* we know there's no monster in the way and we're not trapped, but
|
||||||
if (!Punished
|
need to make sure the move is not diagonally into or out of a
|
||||||
|| drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused, TRUE)) {
|
doorway; the sgn() calls are redundant since ttmp is adjacent */
|
||||||
|
if (test_move(u.ux, u.uy, sgn(x - u.ux), sgn(y - u.uy), TEST_MOVE)
|
||||||
|
&& (!Punished
|
||||||
|
|| drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused, TRUE))) {
|
||||||
|
/* move hero and update map */
|
||||||
u.ux0 = u.ux, u.uy0 = u.uy;
|
u.ux0 = u.ux, u.uy0 = u.uy;
|
||||||
/* set u.ux,u.uy and u.usteed->mx,my plus handle CLIPPING */
|
/* set u.ux,u.uy and u.usteed->mx,my plus handle CLIPPING */
|
||||||
u_on_newpos(x, y);
|
u_on_newpos(x, y);
|
||||||
@@ -5303,6 +5325,11 @@ move_into_trap(struct trap *ttmp)
|
|||||||
if ((ttmp = t_at(u.ux, u.uy)) != 0)
|
if ((ttmp = t_at(u.ux, u.uy)) != 0)
|
||||||
ttmp->tseen = 1;
|
ttmp->tseen = 1;
|
||||||
exercise(A_WIS, FALSE);
|
exercise(A_WIS, FALSE);
|
||||||
|
} else {
|
||||||
|
/* caller has just printed "Whoops..." so if hero is prevented from
|
||||||
|
moving, a followup message is needed */
|
||||||
|
pline("Fortunately, you don't move %s it.",
|
||||||
|
into_vs_onto(ttmp->ttyp) ? "into" : "onto");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-7
@@ -5140,6 +5140,26 @@ mhitm_knockback(
|
|||||||
if (rn2(6))
|
if (rn2(6))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* decide where the first step will place the target; not accurate
|
||||||
|
for being knocked out of saddle but doesn't need to be; used for
|
||||||
|
test_move() and for message before actual hurtle */
|
||||||
|
defx = u_def ? u.ux : mdef->mx;
|
||||||
|
defy = u_def ? u.uy : mdef->my;
|
||||||
|
dx = sgn(defx - (u_agr ? u.ux : magr->mx));
|
||||||
|
dy = sgn(defy - (u_agr ? u.uy : magr->my));
|
||||||
|
|
||||||
|
/* can't move most targets into or out of a doorway diagonally */
|
||||||
|
if (u_def) {
|
||||||
|
if (!test_move(defx, defy, dx, dy, TEST_MOVE))
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
/* subset of test_move() */
|
||||||
|
if (IS_DOOR(levl[defx][defy].typ)
|
||||||
|
&& (defx - magr->mx && defy - magr->my)
|
||||||
|
&& !doorless_door(defx, defy))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* if hero is stuck to a cursed saddle, knock the steed back */
|
/* if hero is stuck to a cursed saddle, knock the steed back */
|
||||||
if (u_def && u.usteed) {
|
if (u_def && u.usteed) {
|
||||||
if ((otmp = which_armor(u.usteed, W_SADDLE)) != 0 && otmp->cursed) {
|
if ((otmp = which_armor(u.usteed, W_SADDLE)) != 0 && otmp->cursed) {
|
||||||
@@ -5191,13 +5211,6 @@ mhitm_knockback(
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* decide where the first step will place the target; not accurate
|
|
||||||
for being knocked out of saddle but doesn't need to be; used for
|
|
||||||
message before actual hurtle */
|
|
||||||
defx = u_def ? u.ux : mdef->mx;
|
|
||||||
defy = u_def ? u.uy : mdef->my;
|
|
||||||
dx = sgn(defx - (u_agr ? u.ux : magr->mx));
|
|
||||||
dy = sgn(defy - (u_agr ? u.uy : magr->my));
|
|
||||||
/* subtly vary the message text if monster won't actually move */
|
/* subtly vary the message text if monster won't actually move */
|
||||||
knockedhow = dismount ? "out of your saddle"
|
knockedhow = dismount ? "out of your saddle"
|
||||||
: will_hurtle(mdef, defx + dx, defy + dy) ? "backward"
|
: will_hurtle(mdef, defx + dx, defy + dy) ? "backward"
|
||||||
|
|||||||
Reference in New Issue
Block a user