Skip to content

Commit

Permalink
fix issue #1305 - failed #untrap from doorway
Browse files Browse the repository at this point in the history
From NetHack 3.7.0 commit b2b9b68:

'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'
  • Loading branch information
elunna committed Dec 16, 2024
1 parent be7cd65 commit a5acd81
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 30 deletions.
2 changes: 2 additions & 0 deletions include/extern.h
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,7 @@ extern boolean in_town(coordxy, coordxy);
extern void check_special_room(boolean);
extern int dopickup(void);
extern void lookaround(void);
extern boolean doorless_door(coordxy, coordxy);
extern boolean crawl_destination(coordxy, coordxy);
extern int monster_nearby(void);
extern void end_running(boolean);
Expand Down Expand Up @@ -3355,6 +3356,7 @@ extern void drain_en(int, boolean);
extern int dountrap(void);
extern int could_untrap(boolean, boolean);
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 boolean openholdingtrap(struct monst *, boolean *) NO_NNARGS;
extern boolean closeholdingtrap(struct monst *, boolean *) NO_NNARGS;
Expand Down
24 changes: 4 additions & 20 deletions src/hack.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ staticfn boolean furniture_present(int, int);
staticfn void move_update(boolean);
staticfn int pickup_checks(void);
staticfn void interesting_room(void);
staticfn boolean doorless_door(coordxy, coordxy);
staticfn void maybe_wail(void);
staticfn boolean water_turbulence(coordxy *, coordxy *);

Expand Down Expand Up @@ -968,7 +967,7 @@ invocation_pos(coordxy x, coordxy 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 */
boolean
test_move(
Expand Down Expand Up @@ -2815,23 +2814,8 @@ domove_core(void)
|| Hallucination)) {
char qbuf[QBUFSZ];
int traptype = (Hallucination ? rnd(TRAPNUM - 1) : (int) trap->ttyp);
boolean into = FALSE; /* "onto" the trap vs "into" */

switch (traptype) {
case BEAR_TRAP:
case PIT:
case SPIKED_PIT:
case HOLE:
case TELEP_TRAP:
case LEVEL_TELEP:
case MAGIC_PORTAL:
case WEB:
case ARROW_TRAP:
case DART_TRAP:
case ROCKTRAP:
into = TRUE;
break;
}
boolean into = into_vs_onto(traptype);

Snprintf(qbuf, sizeof qbuf, "Really %s %s that %s?",
u_locomotion("step"),
into ? "into" : "onto",
Expand Down Expand Up @@ -4173,7 +4157,7 @@ interesting_room(void)
}

/* check for a doorway which lacks its door (NODOOR or BROKEN) */
staticfn boolean
boolean
doorless_door(coordxy x, coordxy y)
{
struct rm *lev_p = &levl[x][y];
Expand Down
36 changes: 33 additions & 3 deletions src/trap.c
Original file line number Diff line number Diff line change
Expand Up @@ -6101,6 +6101,27 @@ cnv_trap_obj(
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:
case ARROW_TRAP:
case DART_TRAP:
case ROCKTRAP:
return TRUE;
}
return FALSE;
}

/* while attempting to disarm an adjacent trap, we've fallen into it */
staticfn void
move_into_trap(struct trap *ttmp)
Expand All @@ -6110,9 +6131,13 @@ move_into_trap(struct trap *ttmp)
boolean unused;

bx = by = cx = cy = 0; /* lint suppression */
/* we know there's no monster in the way, and we're not trapped */
if (!Punished
|| drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused, TRUE)) {
/* we know there's no monster in the way and we're not trapped, but
need to make sure the move is not diagonally into or out of a
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;
/* set u.ux,u.uy and u.usteed->mx,my plus handle CLIPPING */
u_on_newpos(x, y);
Expand All @@ -6137,6 +6162,11 @@ move_into_trap(struct trap *ttmp)
if ((ttmp = t_at(u.ux, u.uy)) != 0)
ttmp->tseen = 1;
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");
}
}

Expand Down
27 changes: 20 additions & 7 deletions src/uhitm.c
Original file line number Diff line number Diff line change
Expand Up @@ -6379,6 +6379,26 @@ mhitm_knockback(
if (rn2(6))
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 (u_def && u.usteed) {
if ((otmp = which_armor(u.usteed, W_SADDLE)) != 0 && otmp->cursed) {
Expand Down Expand Up @@ -6430,13 +6450,6 @@ mhitm_knockback(
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 */
knockedhow = dismount ? "out of your saddle"
: will_hurtle(mdef, defx + dx, defy + dy) ? "backward"
Expand Down

0 comments on commit a5acd81

Please sign in to comment.