From: Michael Meyer Date: Wed, 23 Feb 2022 17:58:43 +0000 (-0500) Subject: Fix: monster hurtling and liquid X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1e951db9bca3f979994da8b43a9c2ce5dd689a78;p=nethack Fix: monster hurtling and liquid A monster hurtling over liquid would drown immediately the instant it touched the first square of water, even if normally it would have kept moving (e.g. hurtling over a short moat). Additionally, its placement on liquid would not take into consideration other monsters, so it could overwrite an existing monster on that spot and lead to an impossible, and/or two monsters occupying a single position. Fix these issues, so that liquid effects like drowning only happen if the monster ends up in liquid at the end of the hurtle, and so that other monsters in the way will stop it early even if they're floating over or swimming on a pool/water/lava square. Also use canspotmon instead of canseemon for the wiztelekinesis debug command. --- diff --git a/include/hack.h b/include/hack.h index 032cc9946..e940c50b8 100644 --- a/include/hack.h +++ b/include/hack.h @@ -297,6 +297,7 @@ typedef struct sortloot_item Loot; * to make an extra call to goodpos()] */ #define GP_ALLOW_U 0x100000L /* don't reject hero's location */ #define MM_NOEXCLAM 0x200000L /* more sedate " appears." mesg for ^G */ +#define MM_IGNORELAVA 0x400000L /* ignore lava when positioning */ /* flags for make_corpse() and mkcorpstat(); 0..7 are recorded in obj->spe */ #define CORPSTAT_NONE 0x00 diff --git a/src/cmd.c b/src/cmd.c index 9c16566bc..fc6cab1d1 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1236,7 +1236,7 @@ wiz_telekinesis(void) pline("Pick a monster to hurtle."); do { - if (mtmp && !DEADMONSTER(mtmp) && canseemon(mtmp)) { + if (mtmp && !DEADMONSTER(mtmp) && canspotmon(mtmp)) { cc.x = mtmp->mx; cc.y = mtmp->my; } @@ -1245,7 +1245,7 @@ wiz_telekinesis(void) if (ans < 0 || cc.x < 0) return ECMD_CANCEL; - if (((mtmp = m_at(cc.x, cc.y)) != 0) && canseemon(mtmp)) { + if (((mtmp = m_at(cc.x, cc.y)) != 0) && canspotmon(mtmp)) { if (!getdir("which direction?")) return ECMD_CANCEL; diff --git a/src/dothrow.c b/src/dothrow.c index da6f31109..498e27422 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -907,21 +907,11 @@ mhurtle_step(genericptr_t arg, int x, int y) struct monst *mon = (struct monst *) arg; struct monst *mtmp; - if (is_pool(x, y) || is_lava(x, y)) { - remove_monster(mon->mx, mon->my); - newsym(mon->mx, mon->my); - place_monster(mon, x, y); - newsym(mon->mx, mon->my); - set_apparxy(mon); - if (minliquid(mon)) - return FALSE; - return is_waterwall(x, y) ? FALSE : TRUE; - } - /* TODO: Treat walls, doors, iron bars, etc. specially * rather than just stopping before. */ - if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) { + if (goodpos(x, y, mon, MM_IGNOREWATER | MM_IGNORELAVA) + && m_in_out_region(mon, x, y)) { int res; remove_monster(mon->mx, mon->my); @@ -929,6 +919,8 @@ mhurtle_step(genericptr_t arg, int x, int y) place_monster(mon, x, y); newsym(mon->mx, mon->my); set_apparxy(mon); + if (is_waterwall(x, y)) + return FALSE; ++g.force_mintrap; res = mintrap(mon); --g.force_mintrap; @@ -1047,6 +1039,7 @@ mhurtle(struct monst *mon, int dx, int dy, int range) cc.x = mon->mx + (dx * range); cc.y = mon->my + (dy * range); (void) walk_path(&mc, &cc, mhurtle_step, (genericptr_t) mon); + (void) minliquid(mon); return; } diff --git a/src/teleport.c b/src/teleport.c index 305cc9291..0f2a0ec3e 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -43,6 +43,7 @@ goodpos(int x, int y, struct monst* mtmp, long gpflags) { struct permonst *mdat = (struct permonst *) 0; boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0), + ignorelava = ((gpflags & MM_IGNORELAVA) != 0), allow_u = ((gpflags & GP_ALLOW_U) != 0); if (!isok(x, y)) @@ -94,7 +95,7 @@ goodpos(int x, int y, struct monst* mtmp, long gpflags) && !grounded(mdat))); } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) { return FALSE; - } else if (is_lava(x, y)) { + } else if (is_lava(x, y) && !ignorelava) { /* 3.6.3: floating eye can levitate over lava but it avoids that due the effect of the heat causing it to dry out */ if (mdat == &mons[PM_FLOATING_EYE]) @@ -114,7 +115,8 @@ goodpos(int x, int y, struct monst* mtmp, long gpflags) return TRUE; } if (!accessible(x, y)) { - if (!(is_pool(x, y) && ignorewater)) + if (!(is_pool(x, y) && ignorewater) + && !(is_lava(x, y) && ignorelava)) return FALSE; }