From 9ae2ec1f98a9c6d87f9f639ad8596c49166c84cf Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 24 Feb 2022 18:55:11 +0200 Subject: [PATCH] Most traps now require touching the floor to trigger It was silly how some clearly mechanical traps didn't consider flight or levitation when to trigger. Do those checks in dotrap/mintrap making hero and monster trap triggering match more closely. --- doc/fixes3-7-0.txt | 1 + src/trap.c | 84 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index c67d7ae34..df96a2524 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -818,6 +818,7 @@ discovering an object on first turn with persistent inventory enabled might not update inventory info for that item (autopickup a blank scroll or spellbook and read it as first action; it becomes discovered but will still be shown as if undiscovered until next inventory update) +most traps now require touching the floor to trigger Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/trap.c b/src/trap.c index 9db2e3cc2..d3127dfd0 100644 --- a/src/trap.c +++ b/src/trap.c @@ -11,6 +11,8 @@ static boolean keep_saddle_with_steedcorpse(unsigned, struct obj *, struct obj *); static boolean mu_maybe_destroy_web(struct monst *, boolean, struct trap *); static struct obj *t_missile(int, struct trap *); +static boolean floor_trigger(int); +static boolean check_in_air(struct monst *, unsigned); static int trapeffect_arrow_trap(struct monst *, struct trap *, unsigned); static int trapeffect_dart_trap(struct monst *, struct trap *, unsigned); static int trapeffect_rocktrap(struct monst *, struct trap *, unsigned); @@ -930,6 +932,43 @@ reset_utrap(boolean msg) } } +/* is trap type ttyp triggered by touching the floor? */ +static boolean +floor_trigger(int ttyp) +{ + switch (ttyp) { + case ARROW_TRAP: + case DART_TRAP: + case ROCKTRAP: + case SQKY_BOARD: + case BEAR_TRAP: + case LANDMINE: + case ROLLING_BOULDER_TRAP: + case SLP_GAS_TRAP: + case RUST_TRAP: + case FIRE_TRAP: + case PIT: + case SPIKED_PIT: + case HOLE: + case TRAPDOOR: + return TRUE; + default: + return FALSE; + } +} + +/* return TRUE if monster mtmp is up in the air, considering trap flags */ +static boolean +check_in_air(struct monst *mtmp, unsigned trflags) +{ + boolean plunged = (trflags & TOOKPLUNGE) != 0; + + return (is_floater(mtmp->data) + || (is_flyer(mtmp->data) && !plunged) + || (mtmp == &g.youmonst ? + (Levitation || (Flying && !plunged)) : 0)); +} + static int trapeffect_arrow_trap( struct monst *mtmp, @@ -2456,15 +2495,17 @@ dotrap(register struct trap* trap, unsigned int trflags) a_your[trap->madeby_u], trapname(ttype, TRUE)); /* do force "pit" while hallucinating */ /* then proceed to normal trap effect */ - } else if (already_seen && !forcetrap) { - if ((Levitation || (Flying && !plunged)) - && (is_pit(ttype) || ttype == HOLE || ttype == BEAR_TRAP)) { - You("%s over %s %s.", Levitation ? "float" : "fly", - a_your[trap->madeby_u], - trapname(ttype, FALSE)); + } else if (!forcetrap) { + if (floor_trigger(ttype) && check_in_air(&g.youmonst, trflags)) { + if (already_seen) { + You("%s over %s %s.", Levitation ? "float" : "fly", + (ttype == ARROW_TRAP && !trap->madeby_u) + ? "an" : a_your[trap->madeby_u], + trapname(ttype, FALSE)); + } return; } - if (!Fumbling && !undestroyable_trap(ttype) + if (already_seen && !Fumbling && !undestroyable_trap(ttype) && ttype != ANTI_MAGIC && !forcebungle && !plunged && !conj_pit && !adj_pit && (!rn2(5) || (is_pit(ttype) @@ -3130,21 +3171,24 @@ mintrap(register struct monst *mtmp, long mintrapflags) } else { register int tt = trap->ttyp; boolean forcetrap = ((mintrapflags & FORCETRAP) != 0); - boolean inescapable = (forcetrap - || ((tt == HOLE || tt == PIT) - && Sokoban && !trap->madeby_u)); - - /* true when called from dotrap, inescapable is not an option */ - if (mtmp == u.usteed) - inescapable = TRUE; - if (!inescapable && ((mtmp->mtrapseen & (1 << (tt - 1))) != 0 - || (tt == HOLE && !mindless(mptr)))) { - /* it has been in such a trap - perhaps it escapes */ - if (rn2(4)) + /* monster has seen such a trap before */ + boolean already_seen = ((mtmp->mtrapseen & (1 << (tt - 1))) != 0 + || (tt == HOLE && !mindless(mptr))); + + if (mtmp == u.usteed) { + /* true when called from dotrap, inescapable is not an option */ + } else if (Sokoban && (is_pit(tt) || is_hole(tt)) && !trap->madeby_u) { + /* nothing here, the trap effects will handle messaging */ + } else if (!forcetrap) { + if (floor_trigger(tt) && check_in_air(mtmp, mintrapflags)) { + return Trap_Effect_Finished; + } + if (already_seen && rn2(4)) return Trap_Effect_Finished; - } else { - mtmp->mtrapseen |= (1 << (tt - 1)); } + + mtmp->mtrapseen |= (1 << (tt - 1)); + /* Monster is aggravated by being trapped by you. Recognizing who made the trap isn't completely unreasonable; everybody has their own style. */ -- 2.50.1