]> granicus.if.org Git - nethack/commitdiff
crossing long worms' tails (trunk only)
authornethack.rankin <nethack.rankin>
Tue, 17 Jul 2007 00:29:44 +0000 (00:29 +0000)
committernethack.rankin <nethack.rankin>
Tue, 17 Jul 2007 00:29:44 +0000 (00:29 +0000)
     This is one of the items from "#Q397: List of Bugs from #nethack" sent
in Janurary by <email deleted> and containing a list
of things collected from the IRC channel associated with nethack.alt.org's
public server.  Moving diagonally between segments of a worm tail is
conceptually passing right through the worm's body.  This patch prevents
moving in such a fashion for both the hero and monsters (it's still
possible to fight in that position though).  It only applies when the two
tail segments are consecutive.

|......  In the diagram here, where tail segments are represented by
|.w1?..  digits indicating relative sequence number, the @ can still
|..@2..  move between segments 2 and 5 to reach !, but can no longer
|.65!3.  move between 1 and 2 to reach ?.  [However, if there is a
|...4..  monster at the ? spot, it can still hit @ and vice versa.]

     Missiles and wand zaps still pass through such diagonals without
noticing or affecting the worm.  I'm not sure whether this ought to be
extended to change that--it might get pretty messy since it would need
to be considered during monsters' targetting as well as during the path
traversal itself.

doc/fixes35.0
include/extern.h
src/hack.c
src/mon.c
src/worm.c

index af38761859f02d2ce35319d5e6f1d7b36eb6fab1..235f1e5520d3c60a0b186219bfc4e85697912be2 100644 (file)
@@ -255,6 +255,7 @@ wizard mode: WIZKIT wishes could overflow inventory's 52 slots
 when loading bones files, censor suspect characters from player-supplied
        strings such as pet and fruit names
 can't swap places with tame grid bug when moving diagonally
+can't move diagonally through a long worm's body (can still fight that way)
 require confirmation to read a scroll of mail if doing so will be the first
        violation of illiteracy conduct
 
index db0add31950ed3f59e88b09d4691a90a4eabbab8..0941937126ffa4535f70480d42fc6a7a19890de4 100644 (file)
@@ -2588,6 +2588,7 @@ E void FDECL(remove_worm, (struct monst *));
 E void FDECL(place_worm_tail_randomly, (struct monst *,XCHAR_P,XCHAR_P));
 E int FDECL(count_wsegs, (struct monst *));
 E boolean FDECL(worm_known, (struct monst *));
+E boolean FDECL(worm_cross, (int,int,int,int));
 
 /* ### worn.c ### */
 
index de3bb16cb5725ecd23f1cddf3b1fb67f3e6e5451..d95b4c38a5c33a004e16bdd71be9d005abd69a51 100644 (file)
@@ -708,6 +708,10 @@ int mode;
        default:
            break;      /* can squeeze through */
        }
+    } else if (dx && dy && worm_cross(ux, uy, x, y)) {
+       /* consecutive long worm segments are at <ux,y> and <x,uy> */
+       if (mode == DO_MOVE) pline("%s is in your way.", Monnam(m_at(ux, y)));
+       return FALSE;
     }
     /* Pick travel path that does not require crossing a trap.
      * Avoid water and lava using the usual running rules.
@@ -828,7 +832,7 @@ boolean guess;
                int y = travelstepy[set][i];
                static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
                /* no diagonal movement for grid bugs */
-               int dirmax = u.umonnum == PM_GRID_BUG ? 4 : 8;
+               int dirmax = NODIAG(u.umonnum) ? 4 : 8;
 
                for (dir = 0; dir < dirmax; ++dir) {
                    int nx = x+xdir[ordered[dir]];
index 96b78daa2324cf74142e6fcd514933a96199dcdb..bfe8ed5ccd0b16e5d1aca36362c3078d8c811c17 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -1018,7 +1018,7 @@ mfndpos(mon, poss, info, flag)
        y = mon->my;
        nowtyp = levl[x][y].typ;
 
-       nodiag = (mdat == &mons[PM_GRID_BUG]);
+       nodiag = NODIAG(mdat - mons);
        wantpool = mdat->mlet == S_EEL;
        poolok = is_flyer(mdat) || is_clinger(mdat) ||
                 (is_swimmer(mdat) && !wantpool);
@@ -1063,21 +1063,23 @@ nexttry:        /* eels prefer the water, but if there is no water nearby,
               !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx,ny))) continue;
            /* KMH -- Added iron bars */
            if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue;
-           if(IS_DOOR(ntyp) && !(amorphous(mdat) || can_fog(mon)) &&
-              ((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) ||
-               (levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))) &&
-              !thrudoor) continue;
-           if(nx != x && ny != y && (nodiag ||
+           if (IS_DOOR(ntyp) && !(amorphous(mdat) || can_fog(mon)) &&
+               (((levl[nx][ny].doormask & D_CLOSED) &&
+                       !(flag & OPENDOOR)) ||
+                ((levl[nx][ny].doormask & D_LOCKED) &&
+                       !(flag & UNLOCKDOOR))) &&
+               !thrudoor) continue;
+           /* first diagonal checks (tight squeezes handled below) */
+           if (nx != x && ny != y && (nodiag ||
+               (IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) ||
+               (IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN)) ||
 #ifdef REINCARNATION
-              ((IS_DOOR(nowtyp) &&
-                ((levl[x][y].doormask & ~D_BROKEN) || Is_rogue_level(&u.uz))) ||
-               (IS_DOOR(ntyp) &&
-                ((levl[nx][ny].doormask & ~D_BROKEN) || Is_rogue_level(&u.uz))))
-#else
-              ((IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) ||
-               (IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN)))
+               ((IS_DOOR(nowtyp) || IS_DOOR(ntyp)) && Is_rogue_level(&u.uz)) ||
 #endif
-              ))
+               /* mustn't pass between adjacent long worm segments,
+                  but can attack that way */
+               (m_at(x, ny) && m_at(nx, y) && worm_cross(x, y, nx, ny) &&
+                !m_at(nx, ny) && (nx != u.ux || ny != u.uy))))
                continue;
            if((is_pool(nx,ny) == wantpool || poolok) &&
               (lavaok || !is_lava(nx,ny))) {
@@ -1279,7 +1281,7 @@ register int x,y;
 {
        register int distance = dist2(mon->mx, mon->my, x, y);
 
-       if (distance==2 && mon->data==&mons[PM_GRID_BUG]) return 0;
+       if (distance == 2 && NODIAG(mon->data - mons)) return 0;
        return((boolean)(distance < 3));
 }
 
index d896165eece6377e4b1bf9783d657005d6c87a44..95af0fc285bb3de973899d87c3080e07bbdfcdc5 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)worm.c     3.5     2005/07/13      */
+/*     SCCS Id: @(#)worm.c     3.5     2007/07/15      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -746,4 +746,51 @@ struct monst *worm;
     return FALSE;
 }
 
+/* would moving from <x1,y1> to <x2,y2> involve passing between two
+   consecutive segments of the same worm? */
+boolean
+worm_cross(x1, y1, x2, y2)
+int x1, y1, x2, y2;
+{
+    struct monst *worm;
+    struct wseg *curr, *wnxt;
+
+    /*
+     * With digits representing relative sequence number of the segments,
+     * returns true when testing between @ and ? (passes through worm's
+     * body), false between @ and ! (stays on same side of worm).
+     * .w1?..
+     * ..@2..
+     * .65!3.
+     * ...4..
+     */
+
+    if (distmin(x1, y1, x2, y2) != 1) {
+       impossible("worm_cross checking for non-adjacent location?");
+       return FALSE;
+    }
+    /* attempting to pass between worm segs is only relevant for diagonal */
+    if (x1 == x2 || y1 == y2) return FALSE;
+
+    /* is the same monster at <x1,y2> and at <x2,y1>? */
+    worm = m_at(x1, y2);
+    if (!worm || m_at(x2, y1) != worm) return FALSE;
+
+    /* same monster is at both adjacent spots, so must be a worm; we need
+       to figure out if the two spots are occupied by consecutive segments */
+    for (curr = wtails[worm->wormno]; curr; curr = wnxt) {
+       wnxt = curr->nseg;
+       if (!wnxt) break;       /* no next segment; can't continue */
+
+       /* we don't know which of <x1,y2> or <x2,y1> we'll hit first, but
+          whichever it is, they're consecutive iff next seg is the other */
+       if (curr->wx == x1 && curr->wy == y2)
+           return (boolean)(wnxt->wx == x2 && wnxt->wy == y1);
+       if (curr->wx == x2 && curr->wy == y1)
+           return (boolean)(wnxt->wx == x1 && wnxt->wy == y2);
+    }
+    /* should never reach here... */
+    return FALSE;
+}
+
 /*worm.c*/