diff --git a/include/extern.h b/include/extern.h index 8eeaf7010..879fcc7dd 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1173,6 +1173,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); @@ -3218,6 +3219,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; diff --git a/src/hack.c b/src/hack.c index 6f8cce1d1..538a9b699 100644 --- a/src/hack.c +++ b/src/hack.c @@ -47,7 +47,6 @@ staticfn struct monst *monstinroom(struct permonst *, int) NONNULLARG1; staticfn boolean furniture_present(int, int); staticfn void move_update(boolean); staticfn int pickup_checks(void); -staticfn boolean doorless_door(coordxy, coordxy); staticfn void maybe_wail(void); 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); } -/* 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( @@ -2749,20 +2748,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" */ + 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?", u_locomotion("step"), into ? "into" : "onto", defsyms[trap_to_defsym(traptype)].explanation); @@ -3910,7 +3897,7 @@ lookaround(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]; diff --git a/src/trap.c b/src/trap.c index da39e4428..64e185d32 100644 --- a/src/trap.c +++ b/src/trap.c @@ -5267,6 +5267,24 @@ 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: + return TRUE; + } + return FALSE; +} + /* while attempting to disarm an adjacent trap, we've fallen into it */ staticfn void move_into_trap(struct trap *ttmp) @@ -5276,9 +5294,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); @@ -5303,6 +5325,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"); } } diff --git a/src/uhitm.c b/src/uhitm.c index 04e78d20e..82b50deda 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5140,6 +5140,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) { @@ -5191,13 +5211,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"