]> granicus.if.org Git - nethack/commitdiff
fix github issue #594 - special attacks
authorPatR <rankin@nethack.org>
Thu, 30 Sep 2021 12:26:04 +0000 (05:26 -0700)
committerPatR <rankin@nethack.org>
Thu, 30 Sep 2021 12:26:04 +0000 (05:26 -0700)
by the Riders that only damage the hero, not other monsters.

Noticed and diagnosed by vultur-cadens.  Attacks dishing out the
damage type AD_DETH (Death), AD_FAMN (Famine), AD_PEST (Pestilence),
and also AD_DISE (Demogorgon, Juiblex, Scorpius) did 0 damage if
inflicted against monsters.  That made Death harmless to other
monsters.  The others have additional attacks (in the two Rider's
cases, only if both instances of their special attack hit on the
same move so that the second one is converted into a stun attack)
and could manage to kill other monsters.

The uhitm case can't happen.  I suspect that the mhitm case was
originally intentionally omitted as something which won't happen,
but that's just a guess.

Fixes #594

doc/fixes37.0
src/uhitm.c

index 69599746d22ea2ac46c6ca78c5a5854af2db2fce..faf7ba8c9085b6e8096078d2873e19f3f94272a6 100644 (file)
@@ -622,6 +622,8 @@ Izchak occasionally stocks wands/scrolls/spellbooks of light
 data tracking for #overview was mis-using u.urooms[] and after being in a
        situation where hero was in multiple rooms at once, visiting other
        levels might flag unvisisted rooms as having been visited
+special damage attacks by the Riders and by fatal-illness inflictors such as
+       Demogorgon did no damage against other monsters, only against the hero
 
 
 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
index f510686f96cdebc15cb4446b5763811b67a3c9c9..064779286161a8766cafd5a59ad7aa665c2bf3bb 100644 (file)
@@ -2046,7 +2046,8 @@ mhitm_ad_fire(struct monst *magr, struct attack *mattk, struct monst *mdef,
                 mhm->done = TRUE;
                 return;
             }
-            mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
+            mhm->hitflags = (MM_DEF_DIED
+                             | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
             mhm->done = TRUE;
             return;
         }
@@ -2242,6 +2243,7 @@ mhitm_ad_acid(struct monst *magr, struct attack *mattk, struct monst *mdef,
     }
 }
 
+/* steal gold */
 void
 mhitm_ad_sgld(struct monst *magr, struct attack *mattk, struct monst *mdef,
               struct mhitm_data *mhm)
@@ -3155,9 +3157,13 @@ void
 mhitm_ad_famn(struct monst *magr, struct attack *mattk UNUSED,
               struct monst *mdef, struct mhitm_data *mhm)
 {
+    struct permonst *pd = mdef->data;
+
     if (magr == &g.youmonst) {
-        /* uhitm */
-        mhm->damage = 0;
+        /* uhitm; hero can't polymorph into anything with this attack
+           so this won't happen; if it could, it would be the same as
+           the mhitm case except for messaging */
+        goto mhitm_famn;
     } else if (mdef == &g.youmonst) {
         /* mhitu */
         pline("%s reaches out, and your body shrivels.", Monnam(magr));
@@ -3166,28 +3172,39 @@ mhitm_ad_famn(struct monst *magr, struct attack *mattk UNUSED,
             morehungry(rn1(40, 40));
         /* plus the normal damage */
     } else {
-        /* mhitm */
-        mhm->damage = 0;
+ mhitm_famn:
+        /* mhitm; it's possible for Famine to hit another monster;
+           if target is something that doesn't eat, it won't be harmed;
+           otherwise, just inflict the normal damage */
+        if (!(carnivorous(pd) || herbivorous(pd) || metallivorous(pd)))
+            mhm->damage = 0;
     }
 }
 
 void
-mhitm_ad_pest(struct monst *magr, struct attack *mattk UNUSED,
+mhitm_ad_pest(struct monst *magr, struct attack *mattk,
               struct monst *mdef, struct mhitm_data *mhm)
 {
+    struct attack alt_attk;
     struct permonst *pa = magr->data;
 
     if (magr == &g.youmonst) {
-        /* uhitm */
-        mhm->damage = 0;
+        /* uhitm; hero can't polymorph into anything with this attack
+           so this won't happen; if it could, it would be the same as
+           the mhitm case except for messaging */
+        goto mhitm_pest;
     } else if (mdef == &g.youmonst) {
         /* mhitu */
         pline("%s reaches out, and you feel fever and chills.", Monnam(magr));
         (void) diseasemu(pa);
         /* plus the normal damage */
     } else {
-        /* mhitm */
-        mhm->damage = 0;
+ mhitm_pest:
+        /* mhitm; it's possible for Pestilence to hit another monster;
+           treat it the same as an attack for AD_DISE damage */
+        alt_attk = *mattk;
+        alt_attk.adtyp = AD_DISE;
+        mhitm_ad_dise(magr, &alt_attk, mdef, mhm);
     }
 }
 
@@ -3198,13 +3215,16 @@ mhitm_ad_deth(struct monst *magr, struct attack *mattk UNUSED,
     struct permonst *pd = mdef->data;
 
     if (magr == &g.youmonst) {
-        /* uhitm */
-        mhm->damage = 0;
+        /* uhitm; hero can't polymorph into anything with this attack
+           so this won't happen; if it could, it would be the same as
+           the mhitm case except for messaging */
+        goto mhitm_deth;
     } else if (mdef == &g.youmonst) {
         /* mhitu */
         pline("%s reaches out with its deadly touch.", Monnam(magr));
         if (is_undead(pd)) {
-            /* Still does normal damage */
+            /* still does some damage */
+            mhm->damage = (mhm->damage + 1) / 2;
             pline("Was that the touch of death?");
             return;
         }
@@ -3220,7 +3240,7 @@ mhitm_ad_deth(struct monst *magr, struct attack *mattk UNUSED,
             /*FALLTHRU*/
         default: /* case 16: ... case 5: */
             You_feel("your life force draining away...");
-            mhm->permdmg = 1; /* actual damage done below */
+            mhm->permdmg = 1; /* actual damage done by caller */
             return;
         case 4:
         case 3:
@@ -3234,8 +3254,18 @@ mhitm_ad_deth(struct monst *magr, struct attack *mattk UNUSED,
             return;
         }
     } else {
-        /* mhitm */
-        mhm->damage = 0;
+ mhitm_deth:
+        /* mhitm; it's possible for Death to hit another monster;
+           if target is undead, it will take some damage but less than an
+           undead hero would; otherwise, just inflict the normal damage */
+        if (is_undead(pd) && mhm->damage > 1)
+            mhm->damage = rnd(mhm->damage / 2);
+        /*
+         * FIXME?
+         *  most monsters should be vulnerable to Death's touch
+         *  instead of only receiving ordinary damage, but is it
+         *  worth bothering with?
+         */
     }
 }
 
@@ -3855,26 +3885,37 @@ mhitm_ad_samu(struct monst *magr, struct attack *mattk, struct monst *mdef,
     }
 }
 
+/* disease */
 void
 mhitm_ad_dise(struct monst *magr, struct attack *mattk, struct monst *mdef,
               struct mhitm_data *mhm)
 {
-    struct permonst *pa = magr->data;
+    struct obj *mwep;
+    struct permonst *pa = magr->data, *pd = mdef->data;
 
     if (magr == &g.youmonst) {
-        /* uhitm */
-        mhm->damage = 0;
+        /* uhitm; hero can't polymorph into anything with this attack so
+           this won't happen; if it could, it would be the same as the
+           mhitm case except for messaging */
+        goto mhitm_dise;
     } else if (mdef == &g.youmonst) {
         /* mhitu */
         hitmsg(magr, mattk);
         if (!diseasemu(pa))
             mhm->damage = 0;
     } else {
-        /* mhitm */
-        mhm->damage = 0;
+ mhitm_dise:
+        /* mhitm; protected monsters use the same criteria as for
+           poly'd hero gaining sick resistance combined with any hero
+           [hypothetically] wielding a weapon that guards against disease */
+        if (pd->mlet == S_FUNGUS || pd == &mons[PM_GHOUL]
+            || ((mwep = MON_WEP(mdef)) != 0 && defends(AD_DISE, mwep)))
+            mhm->damage = 0;
+        /* else does ordinary damage */
     }
 }
 
+/* seduce and also steal item */
 void
 mhitm_ad_sedu(struct monst *magr, struct attack *mattk, struct monst *mdef,
               struct mhitm_data *mhm)
@@ -3981,7 +4022,8 @@ mhitm_ad_sedu(struct monst *magr, struct attack *mattk, struct monst *mdef,
             mdef->mstrategy &= ~STRAT_WAITFORU;
             mselftouch(mdef, (const char *) 0, FALSE);
             if (DEADMONSTER(mdef)) {
-                mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
+                mhm->hitflags = (MM_DEF_DIED
+                                 | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
                 mhm->done = TRUE;
                 return;
             }