From ce018468c4e6d55a12ca9e13ef1a83f52915e6be Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Tue, 17 Jul 2007 00:29:44 +0000 Subject: [PATCH] crossing long worms' tails (trunk only) This is one of the items from "#Q397: List of Bugs from #nethack" sent in Janurary by 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 | 1 + include/extern.h | 1 + src/hack.c | 6 +++++- src/mon.c | 32 ++++++++++++++++--------------- src/worm.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 72 insertions(+), 17 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index af3876185..235f1e552 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -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 diff --git a/include/extern.h b/include/extern.h index db0add319..094193712 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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 ### */ diff --git a/src/hack.c b/src/hack.c index de3bb16cb..d95b4c38a 100644 --- a/src/hack.c +++ b/src/hack.c @@ -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 and */ + 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]]; diff --git a/src/mon.c b/src/mon.c index 96b78daa2..bfe8ed5cc 100644 --- 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)); } diff --git a/src/worm.c b/src/worm.c index d896165ee..95af0fc28 100644 --- a/src/worm.c +++ b/src/worm.c @@ -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 to 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 and at ? */ + 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 or 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*/