From: Pasi Kallinen Date: Thu, 24 Feb 2022 16:55:11 +0000 (+0200) Subject: Most traps now require touching the floor to trigger X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9ae2ec1f98a9c6d87f9f639ad8596c49166c84cf;p=nethack 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. --- 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. */