fix #H1816 - polearm/grapnel/whip fixes (trunk only)

From a bug report, applying a polearm to make a
short-range ranged attack didn't scuff any engraving you were standing on,
unlike ordinary melee and throwing/shooting attacks.  Grappling hooks had
the same omission.  Fixing it led to several other minor bugs.  Attempting
to target an unseen monster's spot with polearm or grapnel would yield some
permutation of "wait, there's something there" but draw the 'I' glyph at
the wrong spot.  It used <u.ux+u.dx,u.uy+u.dy> instead of the actual target,
so put the 'I' one step in front of your most recent move (or throw or zap
or whatever last set u.dx and u.dy).  Giving ESC when prompted for target
spot failed to use up a turn even when the polearm or grappling hook had
just been auto-wielded for use.  Neither use_pole() nor use_grapple() set
`notonhead' for hmon() (called via thitmonst() in their cases; this was
academic since plain physical damage attacks don't actually care about it).
[The bad 'I' placement was a post-3.4.3 bug.]

     Applying a bullwhip to attack an adjacent monster didn't have any of
those issues but did have the possibility of targetting off the edge of
the map when standing at that edge while confused or stunned.

     Applying a polearm to target an 'I' would yield "nothing happens" if
the unseen monster wasn't there anymore, and it didn't bother to remove
that 'I' from the map.  After changing it to do so, the phrasing no longer
made any sense.  This led to a slightly bigger change than I intended:
since statues are now shown as gray monsters (does that work for tiles?)
instead of as chunks of stone, they are likely to be intentional targets
sometimes, so polearm attacks now handle them differently from other
non-monster locations.  [I hope that other attack forms don't need
similar handling.  Melee certainly doesn't, since walking onto the spot
is enough to distinguish statues from monsters.  Having the missile pass
right through a statue's location probably suffices for ranged attacks.]
This commit is contained in:
nethack.rankin
2009-02-23 01:20:32 +00:00
parent a2257ebb1a
commit e11c136bc9
3 changed files with 91 additions and 28 deletions

View File

@@ -310,6 +310,10 @@ poly'd or mimicking hero who was hidden from monsters would still be treated
as a normal target for their ranged attacks
hero would remain stuck to an adjacent monster after rehumanizing if he had
been attacked while hiding via #monster when poly'd into a small mimic
attacking via applied polearm never scuffed engraving underneath hero
auto-wielding a polearm took no time if ESC was used to cancel target choice
applying a bullwhip while at very edge of map could target beyond edge when
hero was stunned or confused, potentially leading to a panic or crash
Platform- and/or Interface-Specific Fixes

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)apply.c 3.5 2008/10/14 */
/* SCCS Id: @(#)apply.c 3.5 2009/02/21 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -2328,10 +2328,20 @@ struct obj *obj;
}
if (!getdir((char *)0)) return res;
if (Stunned || (Confusion && !rn2(5))) confdir();
rx = u.ux + u.dx;
ry = u.uy + u.dy;
mtmp = m_at(rx, ry);
if (u.uswallow) {
mtmp = u.ustuck;
rx = mtmp->mx;
ry = mtmp->my;
} else {
if (Stunned || (Confusion && !rn2(5))) confdir();
rx = u.ux + u.dx;
ry = u.uy + u.dy;
if (!isok(rx, ry)) {
You("miss.");
return res;
}
mtmp = m_at(rx, ry);
}
/* fake some proficiency checks */
proficient = 0;
@@ -2571,11 +2581,10 @@ STATIC_OVL int
use_pole(obj)
struct obj *obj;
{
int res = 0, typ, max_range = 4, min_range = 4;
int res = 0, typ, max_range, min_range, glyph;
coord cc;
struct monst *mtmp;
/* Are you allowed to use the pole? */
if (u.uswallow) {
pline(not_enough_room);
@@ -2592,13 +2601,29 @@ use_pole(obj)
cc.x = u.ux;
cc.y = u.uy;
if (getpos(&cc, TRUE, "the spot to hit") < 0)
return 0; /* user pressed ESC */
return res; /* ESC; uses turn iff polearm became wielded */
/* Calculate range */
glyph = glyph_at(cc.x, cc.y);
/*
* Calculate allowable range (pole's reach is always 2 steps):
* unskilled and basic: orthogonal direction, 4..4;
* skilled: as basic, plus knight's jump position, 4..5;
* expert: as skilled, plus diagonal, 4..8.
* ...9...
* .85458.
* .52125.
* 9410149
* .52125.
* .85458.
* ...9...
* (Note: no roles in nethack can become expert or better
* for polearm skill; Yeoman in slash'em can become expert.)
*/
min_range = 4;
typ = uwep_skill_type();
if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4;
else if (P_SKILL(typ) == P_SKILLED) max_range = 5;
else max_range = 8;
else max_range = 8; /* (P_SKILL(typ) >= P_EXPERT) */
if (distu(cc.x, cc.y) > max_range) {
pline("Too far!");
return (res);
@@ -2606,8 +2631,9 @@ use_pole(obj)
pline("Too close!");
return (res);
} else if (!cansee(cc.x, cc.y) &&
((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0 ||
!canseemon(mtmp))) {
!glyph_is_monster(glyph) &&
!glyph_is_invisible(glyph) &&
!glyph_is_statue(glyph)) {
You(cant_see_spot);
return (res);
} else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */
@@ -2616,14 +2642,38 @@ use_pole(obj)
}
/* Attack the monster there */
if ((mtmp = m_at(cc.x, cc.y)) != (struct monst *)0) {
bhitpos = cc;
bhitpos = cc;
if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != (struct monst *)0) {
if (attack_checks(mtmp, uwep)) return res;
check_caitiff(mtmp);
notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
(void) thitmonst(mtmp, uwep);
} else
/* Now you know that nothing is there... */
pline(nothing_happens);
} else if (glyph_is_statue(glyph) && /* might be hallucinatory */
sobj_at(STATUE, bhitpos.x, bhitpos.y)) {
struct trap *t = t_at(bhitpos.x, bhitpos.y);
if (t && t->ttyp == STATUE_TRAP &&
activate_statue_trap(t, t->tx, t->ty, FALSE)) {
; /* feedback has been give by animate_statue() */
} else {
/* Since statues look like monsters now, we say something
different from "you miss" or "there's nobody there".
Note: we only do this when a statue is displayed here,
because the player is probably attempting to attack it;
other statues obscured by anything are just ignored. */
pline("Thump! Your blow bounces harmlessly off the statue.");
wake_nearto(bhitpos.x, bhitpos.y, 25);
}
} else {
/* no monster here and no statue seen or remembered here */
if (glyph_is_invisible(glyph)) {
/* now you know that nothing is there... */
unmap_object(bhitpos.x, bhitpos.y);
newsym(bhitpos.x, bhitpos.y);
}
You("miss; there is no one there to hit.");
}
u_wipe_engr(2); /* same as for melee or throwing */
return (1);
}
@@ -2667,7 +2717,7 @@ struct obj *obj;
}
STATIC_OVL int
use_grapple (obj)
use_grapple(obj)
struct obj *obj;
{
int res = 0, typ, max_range = 4, tohit;
@@ -2692,9 +2742,9 @@ use_grapple (obj)
cc.x = u.ux;
cc.y = u.uy;
if (getpos(&cc, TRUE, "the spot to hit") < 0)
return 0; /* user pressed ESC */
return res; /* ESC; uses turn iff grapnel became wielded */
/* Calculate range */
/* Calculate range; unlike use_pole(), there's no minimum for range */
typ = uwep_skill_type();
if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4;
else if (P_SKILL(typ) == P_SKILLED) max_range = 5;
@@ -2741,6 +2791,10 @@ use_grapple (obj)
destroy_nhwindow(tmpwin);
}
/* possibly scuff engraving at your feet;
any engraving at the target location is unaffected */
if (tohit == 2 || !rn2(2)) u_wipe_engr(rnd(2));
/* What did you hit? */
switch (tohit) {
case 0: /* Trap */
@@ -2758,6 +2812,7 @@ use_grapple (obj)
case 2: /* Monster */
bhitpos = cc;
if ((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0) break;
notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
save_confirm = flags.confirm;
if (verysmall(mtmp->data) && !rn2(4) &&
enexto(&cc, u.ux, u.uy, (struct permonst *)0)) {

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)uhitm.c 3.5 2007/12/19 */
/* SCCS Id: @(#)uhitm.c 3.5 2009/02/21 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -116,8 +116,8 @@ struct obj *wep; /* uwep for attack(), null for kick_monster() */
* not stay there, so the player will have suddenly forgotten
* the square's contents for no apparent reason.
if (!canspotmon(mtmp) &&
!glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph))
map_invisible(u.ux+u.dx, u.uy+u.dy);
!glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph))
map_invisible(bhitpos.x, bhitpos.y);
*/
return FALSE;
}
@@ -131,12 +131,12 @@ struct obj *wep; /* uwep for attack(), null for kick_monster() */
* the screen, so you know something is there.
*/
if (!canspotmon(mtmp) &&
!glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy)) &&
!glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph) &&
!glyph_is_warning(glyph_at(bhitpos.x,bhitpos.y)) &&
!glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph) &&
!(!Blind && mtmp->mundetected && hides_under(mtmp->data))) {
pline("Wait! There's %s there you can't see!",
something);
map_invisible(u.ux+u.dx, u.uy+u.dy);
map_invisible(bhitpos.x, bhitpos.y);
/* if it was an invisible mimic, treat it as if we stumbled
* onto a visible mimic
*/
@@ -152,7 +152,7 @@ struct obj *wep; /* uwep for attack(), null for kick_monster() */
if (mtmp->m_ap_type && !Protection_from_shape_changers &&
!sensemon(mtmp) &&
!glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy))) {
!glyph_is_warning(glyph_at(bhitpos.x,bhitpos.y))) {
/* If a hidden mimic was in a square where a player remembers
* some (probably different) unseen monster, the player is in
* luck--he attacks it even though it's hidden.
@@ -166,7 +166,7 @@ struct obj *wep; /* uwep for attack(), null for kick_monster() */
}
if (mtmp->mundetected && !canseemon(mtmp) &&
!glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy)) &&
!glyph_is_warning(glyph_at(bhitpos.x,bhitpos.y)) &&
(hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)) {
mtmp->mundetected = mtmp->msleeping = 0;
newsym(mtmp->mx, mtmp->my);
@@ -360,6 +360,10 @@ register struct monst *mtmp;
/* possibly set in attack_checks;
examined in known_hitum, called via hitum or hmonas below */
override_confirmation = FALSE;
/* attack_checks() used to use <u.ux+u.dx,u.uy+u.dy> directly, now
it uses bhitpos instead; it might map an invisible monster there */
bhitpos.x = u.ux + u.dx;
bhitpos.y = u.uy + u.dy;
if (attack_checks(mtmp, uwep)) return(TRUE);
if (Upolyd) {