]> granicus.if.org Git - nethack/commitdiff
Fix: monster hurtling and liquid
authorMichael Meyer <me@entrez.cc>
Wed, 23 Feb 2022 17:58:43 +0000 (12:58 -0500)
committerPasi Kallinen <paxed@alt.org>
Thu, 24 Feb 2022 12:53:48 +0000 (14:53 +0200)
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.

include/hack.h
src/cmd.c
src/dothrow.c
src/teleport.c

index 032cc9946aef89ca096968f6e1338202f3fb1fb8..e940c50b878283c091c7c8ae3658f724314cf768 100644 (file)
@@ -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 "<mon> 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
index 9c16566bc57d03921823f6fa019224a08fab45e8..fc6cab1d1c0af591fab93d52b3088a0692124237 100644 (file)
--- 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;
 
index da6f311099effda97160743a38da7cdd453a0fe4..498e2742294c8e8b2a6726138e01827291684159 100644 (file)
@@ -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;
 }
 
index 305cc929164a58b33e6f12b27d828bd327061227..0f2a0ec3ecb4090e48142650c022f3baf836f896 100644 (file)
@@ -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;
     }