]> granicus.if.org Git - nethack/commitdiff
Improve consistency of polearm targeting rules
authorMichael Meyer <me@entrez.cc>
Fri, 11 Dec 2020 23:13:56 +0000 (18:13 -0500)
committerPasi Kallinen <paxed@alt.org>
Sun, 13 Dec 2020 09:05:48 +0000 (11:05 +0200)
Multiple functions are involved in the process of targeting and
attacking an enemy with a polearm or lance, and these functions
previously used inconsistent tests to determine which targets were
legal.  For instance, find_poleable_mon would give up immediately if the
hero was blind, while neither get_valid_polearm_position nor use_pole
cared as long as the hero could detect a target on the square (e.g. by
ESP).  find_poleable_mon considered warning symbols as potential
targets, but use_pole discarded them.  get_valid_polearm_position
considered moats and pools to be illegal targets, but use_pole would
let the hero successfully hit a monster on those squares; on the
other hand, get_valid_polearm_position would mark squares that were not
visible and did not contain a known monster as legal targets, while
find_poleable_mon and use_pole would exclude them.

Obviously this was inconsistent and could introduce confusion for
polearm users, who would potentially need to explicitly target squares
marked "(illegal)" at some point over the course of their game, among
other problems.  This commit makes polearm targeting tests more
consistent; the following rules are applied to positions within the
appropriate range:

* Monsters which are detected by any means that reveals an actual
  monster glyph are legal to target, even if the hero is blind

* Monsters the hero cannot detect, but is aware of -- i.e. those
  represented by an 'I' -- are similarly legal to target

* Monsters detected via warning are not legal targets, since the hero
  does not have as strong a sense of where exactly they are, their shape
  and size, etc

* Statues are legal targets, but will not be suggested by
  find_poleable_mon unless the hero is impaired (confused, stunned, or
  hallucinating); the same is true of tame/peaceful monsters

* Apparently empty squares, including those containing an undetected
  monster, are legal to target unless they cannot be seen (whether due
  to blindness or a very dark room/level)

* Positions which are otherwise legal but are blocked by an obstruction like a
  tree or pillar are not legal targets

src/apply.c

index a7cc2d82cda483b7ef57b2b29c093805ff0974a0..daa2b9c4bed07c0288a2205c2baf1326aa624320 100644 (file)
@@ -2945,6 +2945,9 @@ static const char
     cant_see_spot[] = "won't hit anything if you can't see that spot.",
     cant_reach[] = "can't reach that spot from here.";
 
+#define glyph_is_poleable(G) \
+    (glyph_is_monster(G) || glyph_is_invisible(G) || glyph_is_statue(G))
+
 /* find pos of monster in range, if only one monster */
 static boolean
 find_poleable_mon(pos, min_range, max_range)
@@ -2956,8 +2959,6 @@ int min_range, max_range;
     boolean impaired;
     int x, y, lo_x, hi_x, lo_y, hi_y, rt, glyph;
 
-    if (Blind)
-        return FALSE; /* must be able to see target location */
     impaired = (Confusion || Stunned || Hallucination);
     mpos.x = mpos.y = 0; /* no candidate location yet */
     rt = isqrt(max_range);
@@ -2974,10 +2975,8 @@ int min_range, max_range;
                 && (mtmp = m_at(x, y)) != 0
                 && (mtmp->mtame || (mtmp->mpeaceful && flags.confirm)))
                 continue;
-            if (glyph_is_monster(glyph)
-                || glyph_is_warning(glyph)
-                || glyph_is_invisible(glyph)
-                || (glyph_is_statue(glyph) && impaired)) {
+            if (glyph_is_poleable(glyph)
+                    && (!glyph_is_statue(glyph) || impaired)) {
                 if (mpos.x)
                     return FALSE; /* more than one candidate location */
                 mpos.x = x, mpos.y = y;
@@ -2994,9 +2993,14 @@ static boolean
 get_valid_polearm_position(x, y)
 int x, y;
 {
-    return (isok(x, y) && ACCESSIBLE(levl[x][y].typ)
-            && distu(x, y) >= g.polearm_range_min
-            && distu(x, y) <= g.polearm_range_max);
+    int glyph;
+
+    glyph = glyph_at(x, y);
+
+    return (isok(x, y) && distu(x, y) >= g.polearm_range_min
+            && distu(x, y) <= g.polearm_range_max
+            && (cansee(x, y) || (couldsee(x, y)
+                                 && glyph_is_poleable(glyph))));
 }
 
 static void
@@ -3076,7 +3080,7 @@ struct obj *obj;
     cc.x = u.ux;
     cc.y = u.uy;
     if (!find_poleable_mon(&cc, min_range, max_range) && hitm
-        && !DEADMONSTER(hitm) && cansee(hitm->mx, hitm->my)
+        && !DEADMONSTER(hitm) && sensemon(hitm)
         && distu(hitm->mx, hitm->my) <= max_range
         && distu(hitm->mx, hitm->my) >= min_range) {
         cc.x = hitm->mx;
@@ -3093,8 +3097,7 @@ struct obj *obj;
     } else if (distu(cc.x, cc.y) < min_range) {
         pline("Too close!");
         return res;
-    } else if (!cansee(cc.x, cc.y) && !glyph_is_monster(glyph)
-               && !glyph_is_invisible(glyph) && !glyph_is_statue(glyph)) {
+    } else if (!cansee(cc.x, cc.y) && !glyph_is_poleable(glyph)) {
         You(cant_see_spot);
         return res;
     } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */