]> granicus.if.org Git - nethack/commitdiff
fix github issue #907 - bad shade logic
authorPatR <rankin@nethack.org>
Sun, 23 Oct 2022 08:11:14 +0000 (01:11 -0700)
committerPatR <rankin@nethack.org>
Sun, 23 Oct 2022 08:11:14 +0000 (01:11 -0700)
Issue reported by vultur-cadens:  one of the checks for whether a
shade would be harmed by an attack was erroneously inside a block
of code that only executed when you could see the attack.  Basic
physical damage wasn't affected but some monster (or poly'd hero)
damage types that shouldn't affect shades didn't when seen but did
when unseen.

Could also get "attack passes harmlessly through the shade" when
an unseen attack for physical damage hit and failed to deal damage.

fixes #907

doc/fixes3-7-0.txt
src/mhitm.c
src/uhitm.c

index 0ca6561d308940547d2e3a186b09c617002d6e9d..72f99bebc63791e3ac90d7494348bfbd9dcce201 100644 (file)
@@ -1048,6 +1048,8 @@ guardian nagas' constriction attack could never hit because the two preceding
        attacks must both hit and those were mutually exclusive: bite and spit
 explicitly throwing 1 for non-gold stack of more than 1 and then canceling at
        direction prompt left a pair of stacks of 1 and N-1 with same invlet
+some attack damage which shouldn't affect shades operated as intended when
+       hero could see it happen but erroneously affected them when not seen
 
 
 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
index 629dd7b0e9ba3c2ca640e3ab50a34222c783e774..4c10f4b17ba3eec82d9fcdd0da960fed3cb1fe10 100644 (file)
@@ -9,8 +9,8 @@
 static const char brief_feeling[] =
     "have a %s feeling for a moment, then it passes.";
 
-static int hitmm(struct monst *, struct monst *, struct attack *, struct obj *,
-                 int);
+static int hitmm(struct monst *, struct monst *, struct attack *,
+                 struct obj *, int);
 static int gazemm(struct monst *, struct monst *, struct attack *);
 static int gulpmm(struct monst *, struct monst *, struct attack *);
 static int explmm(struct monst *, struct monst *, struct attack *);
@@ -556,9 +556,14 @@ mattackm(register struct monst *magr, register struct monst *mdef)
 
 /* Returns the result of mdamagem(). */
 static int
-hitmm(register struct monst *magr, register struct monst *mdef,
-      struct attack *mattk, struct obj *mwep, int dieroll)
+hitmm(
+    struct monst *magr,
+    struct monst *mdef,
+    struct attack *mattk,
+    struct obj *mwep,
+    int dieroll)
 {
+    int compat;
     boolean weaponhit = (mattk->aatyp == AT_WEAP
                          || (mattk->aatyp == AT_CLAW && mwep)),
             silverhit = (weaponhit && mwep
@@ -566,47 +571,47 @@ hitmm(register struct monst *magr, register struct monst *mdef,
 
     pre_mm_attack(magr, mdef);
 
+    compat = !magr->mcan ? could_seduce(magr, mdef, mattk) : 0;
+    if (!compat && shade_miss(magr, mdef, mwep, FALSE, g.vis))
+        return MM_MISS; /* bypass mdamagem() */
+
     if (g.vis) {
-        int compat;
-        char buf[BUFSZ];
+        char buf[BUFSZ], magr_name[BUFSZ];
 
-        if ((compat = could_seduce(magr, mdef, mattk)) && !magr->mcan) {
-            Sprintf(buf, "%s %s", Monnam(magr),
+        Strcpy(magr_name, Monnam(magr));
+        if (compat) {
+            Sprintf(buf, "%s %s", magr_name,
                     mdef->mcansee ? "smiles at" : "talks to");
             pline("%s %s %s.", buf, mon_nam(mdef),
-                  compat == 2 ? "engagingly" : "seductively");
-        } else if (shade_miss(magr, mdef, mwep, FALSE, TRUE)) {
-            return MM_MISS; /* bypass mdamagem() */
+                  (compat == 2) ? "engagingly" : "seductively");
         } else {
-            char magr_name[BUFSZ];
-
-            Strcpy(magr_name, Monnam(magr));
             buf[0] = '\0';
             switch (mattk->aatyp) {
             case AT_BITE:
-                Snprintf(buf, sizeof(buf), "%s bites", magr_name);
+                Snprintf(buf, sizeof buf, "%s bites", magr_name);
                 break;
             case AT_STNG:
-                Snprintf(buf, sizeof(buf), "%s stings", magr_name);
+                Snprintf(buf, sizeof buf, "%s stings", magr_name);
                 break;
             case AT_BUTT:
-                Snprintf(buf, sizeof(buf), "%s butts", magr_name);
+                Snprintf(buf, sizeof buf, "%s butts", magr_name);
                 break;
             case AT_TUCH:
-                Snprintf(buf, sizeof(buf), "%s touches", magr_name);
+                Snprintf(buf, sizeof buf, "%s touches", magr_name);
                 break;
             case AT_TENT:
-                Snprintf(buf, sizeof(buf), "%s tentacles suck", s_suffix(magr_name));
+                Snprintf(buf, sizeof buf, "%s tentacles suck",
+                         s_suffix(magr_name));
                 break;
             case AT_HUGS:
                 if (magr != u.ustuck) {
-                    Snprintf(buf, sizeof(buf), "%s squeezes", magr_name);
+                    Snprintf(buf, sizeof buf, "%s squeezes", magr_name);
                     break;
                 }
                 /*FALLTHRU*/
             default:
                 if (!weaponhit || !mwep || !mwep->oartifact)
-                    Snprintf(buf, sizeof(buf), "%s hits", magr_name);
+                    Snprintf(buf, sizeof buf, "%s hits", magr_name);
                 break;
             }
             if (*buf)
index 25041fd392a695c99d9dc949690ee8a49995e614..2180dfd13147dfc545f6db76b94d0b9bdc9d4a80 100644 (file)
@@ -1306,6 +1306,8 @@ hmon_hitmon(
         tmp = (get_dmg_bonus && !mon_is_shade) ? 1 : 0;
         if (mon_is_shade && !hittxt
             && thrown != HMON_THROWN && thrown != HMON_KICKED)
+            /* this gives "harmlessly passes through" feedback even when
+               hero doesn't see it happen; presumably sensed by touch? */
             hittxt = shade_miss(&g.youmonst, mon, obj, FALSE, TRUE);
     }
 
@@ -1591,8 +1593,12 @@ shade_aware(struct obj *obj)
 /* used for hero vs monster and monster vs monster; also handles
    monster vs hero but that won't happen because hero can't be a shade */
 boolean
-shade_miss(struct monst *magr, struct monst *mdef, struct obj *obj,
-           boolean thrown, boolean verbose)
+shade_miss(
+    struct monst *magr,
+    struct monst *mdef,
+    struct obj *obj,
+    boolean thrown,
+    boolean verbose)
 {
     const char *what, *whose, *target;
     boolean youagr = (magr == &g.youmonst), youdef = (mdef == &g.youmonst);
@@ -3427,8 +3433,9 @@ do_stone_mon(struct monst *magr, struct attack *mattk UNUSED,
 }
 
 void
-mhitm_ad_phys(struct monst *magr, struct attack *mattk, struct monst *mdef,
-              struct mhitm_data *mhm)
+mhitm_ad_phys(
+    struct monst *magr, struct attack *mattk,
+    struct monst *mdef, struct mhitm_data *mhm)
 {
     struct permonst *pa = magr->data;
     struct permonst *pd = mdef->data;
@@ -3556,11 +3563,12 @@ mhitm_ad_phys(struct monst *magr, struct attack *mattk, struct monst *mdef,
     } else {
         /* mhitm */
         struct obj *mwep = MON_WEP(magr);
+        boolean vis = canseemon(magr) && canseemon(mdef);
 
         if (mattk->aatyp != AT_WEAP && mattk->aatyp != AT_CLAW)
             mwep = 0;
 
-        if (shade_miss(magr, mdef, mwep, FALSE, TRUE)) {
+        if (shade_miss(magr, mdef, mwep, FALSE, vis)) {
             mhm->damage = 0;
         } else if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
             /* [no 'kicking boots' check needed; monsters with kick attacks