From f411d303ea1c8a464619e15c982fd796b3038044 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Thu, 28 Dec 2006 02:45:38 +0000 Subject: [PATCH] monster ranged attacks (trunk only) Newsgroup posts mention "boulder forts" from time to time, where the player surrounds the hero with boulders in order to prevent the majority of monsters from being able to attack. Since the hero can shoot or throw or zap over/around/through boulders, monsters ought to be able to do so too. This makes the test for whether a monster is lined up properly for its ranged attacks try harder when the original line-of-sight check fails. If there aren't any terrain obstacles found, it allows a chance to attack based on the number of locations in the path that contain any boulders. Giants and any monster carrying a boulder-destroying wand of striking get to ignore boulders, overriding the random chance. --- doc/fixes35.0 | 1 + include/extern.h | 2 +- src/mthrowu.c | 29 +++++++++++++++++++++++++---- src/priest.c | 7 +++---- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 1396e8c21..3afad9964 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -182,6 +182,7 @@ allow corpses on floor to be offered at high altars allow hero to attempt to offer the Amulet at ordinary altars shooting range for crossbow isn't affected by strength; multi-shot volley is right-handed boomerang throw travels counterclockwise +monsters can use ranged attacks over/around boulders, same as hero Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index 60aa32df4..e5370436a 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1421,7 +1421,7 @@ E int FDECL(ohitmon, (struct monst *,struct obj *,int,BOOLEAN_P)); E void FDECL(thrwmu, (struct monst *)); E int FDECL(spitmu, (struct monst *,struct attack *)); E int FDECL(breamu, (struct monst *,struct attack *)); -E boolean FDECL(linedup, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P)); +E boolean FDECL(linedup, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,int)); E boolean FDECL(lined_up, (struct monst *)); E struct obj *FDECL(m_carrying, (struct monst *,int)); E void FDECL(m_useupall, (struct monst *,struct obj *)); diff --git a/src/mthrowu.c b/src/mthrowu.c index 48b7af415..f258c9981 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -708,9 +708,12 @@ breamu(mtmp, mattk) /* monster breathes at you (ranged) */ } boolean -linedup(ax, ay, bx, by) +linedup(ax, ay, bx, by, boulderhandling) register xchar ax, ay, bx, by; +int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */ { + int dx, dy, boulderspots; + tbx = ax - bx; /* These two values are set for use */ tby = ay - by; /* after successful return. */ @@ -720,8 +723,22 @@ register xchar ax, ay, bx, by; if((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */ && distmin(tbx, tby, 0, 0) < BOLT_LIM) { - if(ax == u.ux && ay == u.uy) return((boolean)(couldsee(bx,by))); - else if(clear_path(ax,ay,bx,by)) return TRUE; + if ((ax == u.ux && ay == u.uy) ? (boolean)couldsee(bx, by) : + clear_path(ax, ay, bx, by)) return TRUE; + /* don't have line of sight, but might still be lined up + if that lack of sight is due solely to boulders */ + if (boulderhandling == 0) return FALSE; + dx = sgn(ax - bx), dy = sgn(ay - by); + boulderspots = 0; + do { + /* is guaranteed to eventually converge with */ + bx += dx, by += dy; + if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by)) + return FALSE; + if (sobj_at(BOULDER, bx, by)) ++boulderspots; + } while (bx != ax && by != ay); + /* reached target position without encountering obstacle */ + if (boulderhandling == 1 || rn2(2 + boulderspots) < 2) return TRUE; } return FALSE; } @@ -730,7 +747,11 @@ boolean lined_up(mtmp) /* is mtmp in position to use ranged attack? */ register struct monst *mtmp; { - return(linedup(mtmp->mux,mtmp->muy,mtmp->mx,mtmp->my)); + boolean ignore_boulders = (throws_rocks(mtmp->data) || + m_carrying(mtmp, WAN_STRIKING)); + + return linedup(mtmp->mux, mtmp->muy, mtmp->mx, mtmp->my, + ignore_boulders ? 1 : 2); } /* Check if a monster is carrying a particular item. diff --git a/src/priest.c b/src/priest.c index f791b01e0..1e60d104d 100644 --- a/src/priest.c +++ b/src/priest.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)priest.c 3.5 2006/05/26 */ +/* SCCS Id: @(#)priest.c 3.5 2006/12/27 */ /* Copyright (c) Izchak Miller, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -710,9 +710,8 @@ struct monst *priest; ay = y = EPRI(priest)->shrpos.y; troom = &rooms[roomno - ROOMOFFSET]; - if((u.ux == x && u.uy == y) || !linedup(u.ux, u.uy, x, y)) { + if ((u.ux == x && u.uy == y) || !linedup(u.ux, u.uy, x, y, 1)) { if(IS_DOOR(levl[u.ux][u.uy].typ)) { - if(u.ux == troom->lx - 1) { x = troom->hx; y = u.uy; @@ -734,7 +733,7 @@ struct monst *priest; default: x = troom->hx; y = u.uy; break; } } - if(!linedup(u.ux, u.uy, x, y)) return; + if (!linedup(u.ux, u.uy, x, y, 1)) return; } switch(rn2(3)) { -- 2.40.0