crossing long worms' tails (trunk only)

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.
This commit is contained in:
nethack.rankin
2007-07-17 00:29:44 +00:00
parent 557650ac55
commit ce018468c4
5 changed files with 72 additions and 17 deletions

View 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 when loading bones files, censor suspect characters from player-supplied
strings such as pet and fruit names strings such as pet and fruit names
can't swap places with tame grid bug when moving diagonally 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 require confirmation to read a scroll of mail if doing so will be the first
violation of illiteracy conduct violation of illiteracy conduct

View 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 void FDECL(place_worm_tail_randomly, (struct monst *,XCHAR_P,XCHAR_P));
E int FDECL(count_wsegs, (struct monst *)); E int FDECL(count_wsegs, (struct monst *));
E boolean FDECL(worm_known, (struct monst *)); E boolean FDECL(worm_known, (struct monst *));
E boolean FDECL(worm_cross, (int,int,int,int));
/* ### worn.c ### */ /* ### worn.c ### */

View File

@@ -708,6 +708,10 @@ int mode;
default: default:
break; /* can squeeze through */ 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. /* Pick travel path that does not require crossing a trap.
* Avoid water and lava using the usual running rules. * Avoid water and lava using the usual running rules.
@@ -828,7 +832,7 @@ boolean guess;
int y = travelstepy[set][i]; int y = travelstepy[set][i];
static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 }; static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 };
/* no diagonal movement for grid bugs */ /* 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) { for (dir = 0; dir < dirmax; ++dir) {
int nx = x+xdir[ordered[dir]]; int nx = x+xdir[ordered[dir]];

View File

@@ -1018,7 +1018,7 @@ mfndpos(mon, poss, info, flag)
y = mon->my; y = mon->my;
nowtyp = levl[x][y].typ; nowtyp = levl[x][y].typ;
nodiag = (mdat == &mons[PM_GRID_BUG]); nodiag = NODIAG(mdat - mons);
wantpool = mdat->mlet == S_EEL; wantpool = mdat->mlet == S_EEL;
poolok = is_flyer(mdat) || is_clinger(mdat) || poolok = is_flyer(mdat) || is_clinger(mdat) ||
(is_swimmer(mdat) && !wantpool); (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; !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx,ny))) continue;
/* KMH -- Added iron bars */ /* KMH -- Added iron bars */
if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue; if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue;
if(IS_DOOR(ntyp) && !(amorphous(mdat) || can_fog(mon)) && if (IS_DOOR(ntyp) && !(amorphous(mdat) || can_fog(mon)) &&
((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) || (((levl[nx][ny].doormask & D_CLOSED) &&
(levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))) && !(flag & OPENDOOR)) ||
!thrudoor) continue; ((levl[nx][ny].doormask & D_LOCKED) &&
if(nx != x && ny != y && (nodiag || !(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 #ifdef REINCARNATION
((IS_DOOR(nowtyp) && ((IS_DOOR(nowtyp) || IS_DOOR(ntyp)) && Is_rogue_level(&u.uz)) ||
((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)))
#endif #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; continue;
if((is_pool(nx,ny) == wantpool || poolok) && if((is_pool(nx,ny) == wantpool || poolok) &&
(lavaok || !is_lava(nx,ny))) { (lavaok || !is_lava(nx,ny))) {
@@ -1279,7 +1281,7 @@ register int x,y;
{ {
register int distance = dist2(mon->mx, mon->my, 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)); return((boolean)(distance < 3));
} }

View 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. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -746,4 +746,51 @@ struct monst *worm;
return FALSE; 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*/ /*worm.c*/