]> granicus.if.org Git - nethack/commitdiff
Unify monster-hits-monster
authorPasi Kallinen <paxed@alt.org>
Mon, 30 Nov 2020 17:08:59 +0000 (19:08 +0200)
committerPasi Kallinen <paxed@alt.org>
Fri, 4 Dec 2020 07:30:14 +0000 (09:30 +0200)
include/extern.h
include/monattk.h
src/mhitm.c
src/mhitu.c
src/uhitm.c

index 64df72baa1d3bb91f4eec867ec7aa009b3835598..78417eba6295795536c8ef178ddeae1ec9e46010 100644 (file)
@@ -1282,6 +1282,7 @@ E void FDECL(rustm, (struct monst *, struct obj *));
 
 /* ### mhitu.c ### */
 
+E void FDECL(hitmsg, (struct monst *, struct attack *));
 E const char *FDECL(mpoisons_subj, (struct monst *, struct attack *));
 E void NDECL(u_slow_down);
 E struct monst *NDECL(cloneu);
@@ -2754,6 +2755,8 @@ E boolean FDECL(attack, (struct monst *));
 E boolean FDECL(hmon, (struct monst *, struct obj *, int, int));
 E boolean FDECL(shade_miss, (struct monst *, struct monst *, struct obj *,
                              BOOLEAN_P, BOOLEAN_P));
+E void FDECL(mhitm_ad_rust, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
+E void FDECL(mhitm_ad_corr, (struct monst *, struct attack *, struct monst *, struct mhitm_data *));
 E int FDECL(damageum, (struct monst *, struct attack *, int));
 E void FDECL(missum, (struct monst *, struct attack *, BOOLEAN_P));
 E int FDECL(passive, (struct monst *, struct obj *, BOOLEAN_P, int,
index a836f3eabc461083968e41de956b6debf9022311..8f2d7c12f082412065a296cf398f2a78cbd1a0e0 100644 (file)
 #define AD_SAMU 252 /* hits, may steal Amulet (Wizard) */
 #define AD_CURS 253 /* random curse (ex. gremlin) */
 
+struct mhitm_data {
+    int damage;
+    int hitflags; /* MM_DEF_DIED | MM_AGR_DIED | ... */
+    boolean done;
+};
+
 /*
  *  Monster to monster attacks.  When a monster attacks another (mattackm),
  *  any or all of the following can be returned.  See mattackm() for more
index efed25f152552baf62ef84358a56939b29cba1f2..397673396b0ef7650697cc60f0fd164d315e6409 100644 (file)
@@ -858,10 +858,11 @@ int dieroll;
     struct obj *obj;
     char buf[BUFSZ];
     struct permonst *pa = magr->data, *pd = mdef->data;
-    int armpro, num,
-        tmp = d((int) mattk->damn, (int) mattk->damd),
-        res = MM_MISS;
+    int armpro, num;
     boolean cancelled;
+    struct mhitm_data mhm;
+    mhm.damage = d((int) mattk->damn, (int) mattk->damd);
+    mhm.hitflags = MM_MISS;
 
     if ((touch_petrifies(pd) /* or flesh_petrifies() */
          || (mattk->adtyp == AD_DGST && pd == &mons[PM_MEDUSA]))
@@ -914,7 +915,7 @@ int dieroll;
         }
         if (flags.verbose && !Deaf)
             verbalize("Burrrrp!");
-        tmp = mdef->mhp;
+        mhm.damage = mdef->mhp;
         /* Use up amulet of life saving */
         if ((obj = mlifesaver(mdef)) != 0)
             m_useup(mdef, obj);
@@ -955,7 +956,7 @@ int dieroll;
         goto physical;
     case AD_LEGS:
         if (magr->mcan) {
-            tmp = 0;
+            mhm.damage = 0;
             break;
         }
         goto physical;
@@ -967,11 +968,11 @@ int dieroll;
             mwep = 0;
 
         if (shade_miss(magr, mdef, mwep, FALSE, TRUE)) {
-            tmp = 0;
+            mhm.damage = 0;
         } else if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
             /* [no 'kicking boots' check needed; monsters with kick attacks
                can't wear boots and monsters that wear boots don't kick] */
-            tmp = 0;
+            mhm.damage = 0;
         } else if (mwep) { /* non-Null 'mwep' implies AT_WEAP || AT_CLAW */
             struct obj *marmg;
 
@@ -979,19 +980,19 @@ int dieroll;
                 && touch_petrifies(&mons[mwep->corpsenm]))
                 goto do_stone;
 
-            tmp += dmgval(mwep, mdef);
+            mhm.damage += dmgval(mwep, mdef);
             if ((marmg = which_armor(magr, W_ARMG)) != 0
                 && marmg->otyp == GAUNTLETS_OF_POWER)
-                tmp += rn1(4, 3); /* 3..6 */
-            if (tmp < 1) /* is this necessary?  mhitu.c has it... */
-                tmp = 1;
+                mhm.damage += rn1(4, 3); /* 3..6 */
+            if (mhm.damage < 1) /* is this necessary?  mhitu.c has it... */
+                mhm.damage = 1;
             if (mwep->oartifact) {
                 /* when magr's weapon is an artifact, caller suppressed its
                    usual 'hit' message in case artifact_hit() delivers one;
                    now we'll know and might need to deliver skipped message
                    (note: if there's no message there'll be no auxilliary
                    damage so the message here isn't coming too late) */
-                if (!artifact_hit(magr, mdef, mwep, &tmp, dieroll)) {
+                if (!artifact_hit(magr, mdef, mwep, &mhm.damage, dieroll)) {
                     if (g.vis)
                         pline("%s hits %s.", Monnam(magr),
                               mon_nam_too(mdef, magr));
@@ -1003,20 +1004,20 @@ int dieroll;
                     return (MM_DEF_DIED
                             | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
             }
-            if (tmp)
+            if (mhm.damage)
                 rustm(mdef, mwep);
         } else if (pa == &mons[PM_PURPLE_WORM] && pd == &mons[PM_SHRIEKER]) {
             /* hack to enhance mm_aggression(); we don't want purple
                worm's bite attack to kill a shrieker because then it
                won't swallow the corpse; but if the target survives,
                the subsequent engulf attack should accomplish that */
-            if (tmp >= mdef->mhp && mdef->mhp > 1)
-                tmp = mdef->mhp - 1;
+            if (mhm.damage >= mdef->mhp && mdef->mhp > 1)
+                mhm.damage = mdef->mhp - 1;
         }
         break;
     case AD_FIRE:
         if (cancelled) {
-            tmp = 0;
+            mhm.damage = 0;
             break;
         }
         if (g.vis && canseemon(mdef))
@@ -1033,22 +1034,22 @@ int dieroll;
                 return 0;
             return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
         }
-        tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
-        tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
+        mhm.damage += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
+        mhm.damage += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
         if (resists_fire(mdef)) {
             if (g.vis && canseemon(mdef))
                 pline_The("fire doesn't seem to burn %s!", mon_nam(mdef));
             shieldeff(mdef->mx, mdef->my);
-            golemeffects(mdef, AD_FIRE, tmp);
-            tmp = 0;
+            golemeffects(mdef, AD_FIRE, mhm.damage);
+            mhm.damage = 0;
         }
         /* only potions damage resistant players in destroy_item */
-        tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
+        mhm.damage += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
         ignite_items(mdef->minvent);
         break;
     case AD_COLD:
         if (cancelled) {
-            tmp = 0;
+            mhm.damage = 0;
             break;
         }
         if (g.vis && canseemon(mdef))
@@ -1057,39 +1058,39 @@ int dieroll;
             if (g.vis && canseemon(mdef))
                 pline_The("frost doesn't seem to chill %s!", mon_nam(mdef));
             shieldeff(mdef->mx, mdef->my);
-            golemeffects(mdef, AD_COLD, tmp);
-            tmp = 0;
+            golemeffects(mdef, AD_COLD, mhm.damage);
+            mhm.damage = 0;
         }
-        tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
+        mhm.damage += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
         break;
     case AD_ELEC:
         if (cancelled) {
-            tmp = 0;
+            mhm.damage = 0;
             break;
         }
         if (g.vis && canseemon(mdef))
             pline("%s gets zapped!", Monnam(mdef));
-        tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
+        mhm.damage += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
         if (resists_elec(mdef)) {
             if (g.vis && canseemon(mdef))
                 pline_The("zap doesn't shock %s!", mon_nam(mdef));
             shieldeff(mdef->mx, mdef->my);
-            golemeffects(mdef, AD_ELEC, tmp);
-            tmp = 0;
+            golemeffects(mdef, AD_ELEC, mhm.damage);
+            mhm.damage = 0;
         }
         /* only rings damage resistant players in destroy_item */
-        tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
+        mhm.damage += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
         break;
     case AD_ACID:
         if (magr->mcan) {
-            tmp = 0;
+            mhm.damage = 0;
             break;
         }
         if (resists_acid(mdef)) {
             if (g.vis && canseemon(mdef))
                 pline("%s is covered in %s, but it seems harmless.",
                       Monnam(mdef), hliquid("acid"));
-            tmp = 0;
+            mhm.damage = 0;
         } else if (g.vis && canseemon(mdef)) {
             pline("%s is covered in %s!", Monnam(mdef), hliquid("acid"));
             pline("It burns %s!", mon_nam(mdef));
@@ -1100,27 +1101,14 @@ int dieroll;
             acid_damage(MON_WEP(mdef));
         break;
     case AD_RUST:
-        if (magr->mcan)
-            break;
-        if (completelyrusts(pd)) { /* PM_IRON_GOLEM */
-            if (g.vis && canseemon(mdef))
-                pline("%s %s to pieces!", Monnam(mdef),
-                      !mlifesaver(mdef) ? "falls" : "starts to fall");
-            monkilled(mdef, (char *) 0, AD_RUST);
-            if (!DEADMONSTER(mdef))
-                return 0;
-            return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
-        }
-        erode_armor(mdef, ERODE_RUST);
-        mdef->mstrategy &= ~STRAT_WAITFORU;
-        tmp = 0;
+        mhitm_ad_rust(magr, mattk, mdef, &mhm);
+        if (mhm.done)
+            return mhm.hitflags;
         break;
     case AD_CORR:
-        if (magr->mcan)
-            break;
-        erode_armor(mdef, ERODE_CORRODE);
-        mdef->mstrategy &= ~STRAT_WAITFORU;
-        tmp = 0;
+        mhitm_ad_corr(magr, mattk, mdef, &mhm);
+        if (mhm.done)
+            return mhm.hitflags;
         break;
     case AD_DCAY:
         if (magr->mcan)
@@ -1138,7 +1126,7 @@ int dieroll;
         }
         erode_armor(mdef, ERODE_CORRODE);
         mdef->mstrategy &= ~STRAT_WAITFORU;
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_STON:
         if (magr->mcan)
@@ -1149,7 +1137,7 @@ int dieroll;
             goto post_stone;
         if (poly_when_stoned(pd)) {
             mon_to_stone(mdef);
-            tmp = 0;
+            mhm.damage = 0;
             break;
         }
         if (!resists_ston(mdef)) {
@@ -1163,10 +1151,10 @@ int dieroll;
                 You(brief_feeling, "peculiarly sad");
             return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
         }
-        tmp = (mattk->adtyp == AD_STON ? 0 : 1);
+        mhm.damage = (mattk->adtyp == AD_STON ? 0 : 1);
         break;
     case AD_TLPT:
-        if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) {
+        if (!cancelled && mhm.damage < mdef->mhp && !tele_restrict(mdef)) {
             char mdef_Monnam[BUFSZ];
             boolean wasseen = canspotmon(mdef);
 
@@ -1178,10 +1166,10 @@ int dieroll;
             (void) rloc(mdef, TRUE);
             if (g.vis && wasseen && !canspotmon(mdef) && mdef != u.usteed)
                 pline("%s suddenly disappears!", mdef_Monnam);
-            if (tmp >= mdef->mhp) { /* see hitmu(mhitu.c) */
+            if (mhm.damage >= mdef->mhp) { /* see hitmu(mhitu.c) */
                 if (mdef->mhp == 1)
                     ++mdef->mhp;
-                tmp = mdef->mhp - 1;
+                mhm.damage = mdef->mhp - 1;
             }
         }
         break;
@@ -1240,7 +1228,7 @@ int dieroll;
             mdef->mcansee = 0;
             mdef->mstrategy &= ~STRAT_WAITFORU;
         }
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_HALU:
         if (!magr->mcan && haseyes(pd) && mdef->mcansee) {
@@ -1250,7 +1238,7 @@ int dieroll;
             mdef->mconf = 1;
             mdef->mstrategy &= ~STRAT_WAITFORU;
         }
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_CURS:
         if (!night() && (pa == &mons[PM_GREMLIN]))
@@ -1283,7 +1271,7 @@ int dieroll;
         }
         break;
     case AD_SGLD:
-        tmp = 0;
+        mhm.damage = 0;
         if (magr->mcan)
             break;
         /* technically incorrect; no check for stealing gold from
@@ -1312,11 +1300,11 @@ int dieroll;
         break;
     case AD_DRLI: /* drain life */
         if (!cancelled && !rn2(3) && !resists_drli(mdef)) {
-            tmp = d(2, 6); /* Stormbringer uses monhp_per_lvl(usually 1d8) */
+            mhm.damage = d(2, 6); /* Stormbringer uses monhp_per_lvl(usually 1d8) */
             if (g.vis && canspotmon(mdef))
                 pline("%s becomes weaker!", Monnam(mdef));
-            if (mdef->mhpmax - tmp > (int) mdef->m_lev) {
-                mdef->mhpmax -= tmp;
+            if (mdef->mhpmax - mhm.damage > (int) mdef->m_lev) {
+                mdef->mhpmax -= mhm.damage;
             } else {
                 /* limit floor of mhpmax reduction to current m_lev + 1;
                    avoid increasing it if somehow already less than that */
@@ -1324,7 +1312,7 @@ int dieroll;
                     mdef->mhpmax = (int) mdef->m_lev + 1;
             }
             if (mdef->m_lev == 0) /* automatic kill if drained past level 0 */
-                tmp = mdef->mhp;
+                mhm.damage = mdef->mhp;
             else
                 mdef->m_lev--;
 
@@ -1386,13 +1374,13 @@ int dieroll;
                     pline("%s suddenly disappears!", buf);
             }
         }
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_DREN:
         if (!cancelled && !rn2(4))
             xdrainenergym(mdef, (boolean) (g.vis && canspotmon(mdef)
                                            && mattk->aatyp != AT_ENGL));
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_DRST:
     case AD_DRDX:
@@ -1407,11 +1395,11 @@ int dieroll;
                               mon_nam(mdef));
             } else {
                 if (rn2(10))
-                    tmp += rn1(10, 6);
+                    mhm.damage += rn1(10, 6);
                 else {
                     if (g.vis && canspotmon(mdef))
                         pline_The("poison was deadly...");
-                    tmp = mdef->mhp;
+                    mhm.damage = mdef->mhp;
                 }
             }
         }
@@ -1421,7 +1409,7 @@ int dieroll;
             if (g.vis && canspotmon(mdef))
                 pline("%s doesn't seem harmed.", Monnam(mdef));
             /* Not clear what to do for green slimes */
-            tmp = 0;
+            mhm.damage = 0;
             /* don't bother with additional DRIN attacks since they wouldn't
                be able to hit target on head either */
             g.skipdrin = TRUE; /* affects mattackm()'s attack loop */
@@ -1435,7 +1423,7 @@ int dieroll;
             }
             break;
         }
-        res = eat_brains(magr, mdef, g.vis, &tmp);
+        mhm.hitflags = eat_brains(magr, mdef, g.vis, &mhm.damage);
         break;
     case AD_SLIM:
         if (cancelled)
@@ -1446,41 +1434,41 @@ int dieroll;
                             (boolean) (g.vis && canseemon(mdef))))
                     pd = mdef->data;
                 mdef->mstrategy &= ~STRAT_WAITFORU;
-                res = MM_HIT;
+                mhm.hitflags = MM_HIT;
             }
             /* munslime attempt could have been fatal,
                potentially to multiple monsters (SCR_FIRE) */
             if (DEADMONSTER(magr))
-                res |= MM_AGR_DIED;
+                mhm.hitflags |= MM_AGR_DIED;
             if (DEADMONSTER(mdef))
-                res |= MM_DEF_DIED;
-            tmp = 0;
+                mhm.hitflags |= MM_DEF_DIED;
+            mhm.damage = 0;
         }
         break;
     case AD_STCK:
         if (cancelled)
-            tmp = 0;
+            mhm.damage = 0;
         break;
     case AD_WRAP: /* monsters cannot grab one another, it's too hard */
         if (magr->mcan)
-            tmp = 0;
+            mhm.damage = 0;
         break;
     case AD_ENCH:
         /* there's no msomearmor() function, so just do damage */
         /* if (cancelled) break; */
         break;
     case AD_POLY:
-        if (!magr->mcan && tmp < mdef->mhp)
-            tmp = mon_poly(magr, mdef, tmp);
+        if (!magr->mcan && mhm.damage < mdef->mhp)
+            mhm.damage = mon_poly(magr, mdef, mhm.damage);
         break;
     default:
-        tmp = 0;
+        mhm.damage = 0;
         break;
     }
-    if (!tmp)
-        return res;
+    if (!mhm.damage)
+        return mhm.hitflags;
 
-    if ((mdef->mhp -= tmp) < 1) {
+    if ((mdef->mhp -= mhm.damage) < 1) {
         if (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */
             remove_monster(mdef->mx, mdef->my);
             mdef->mhp = 1; /* otherwise place_monster will complain */
@@ -1495,8 +1483,8 @@ int dieroll;
         monkilled(mdef, "", (int) mattk->adtyp);
         g.zombify = FALSE; /* reset */
         if (!DEADMONSTER(mdef))
-            return res; /* mdef lifesaved */
-        else if (res == MM_AGR_DIED)
+            return mhm.hitflags; /* mdef lifesaved */
+        else if (mhm.hitflags == MM_AGR_DIED)
             return (MM_DEF_DIED | MM_AGR_DIED);
 
         if (mattk->adtyp == AD_DGST) {
@@ -1518,7 +1506,7 @@ int dieroll;
 
         return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
     }
-    return (res == MM_AGR_DIED) ? MM_AGR_DIED : MM_HIT;
+    return (mhm.hitflags == MM_AGR_DIED) ? MM_AGR_DIED : MM_HIT;
 }
 
 int
index b9df18ce7224b52248cd9fc0f3b0a3dc3bbbaa34..767ed19e77724df2daa08e32898a9b13e6c8d07e 100644 (file)
@@ -8,7 +8,6 @@
 
 static NEARDATA struct obj *mon_currwep = (struct obj *) 0;
 
-static void FDECL(hitmsg, (struct monst *, struct attack *));
 static void FDECL(missmu, (struct monst *, BOOLEAN_P, struct attack *));
 static void FDECL(mswings, (struct monst *, struct obj *));
 static void FDECL(wildmiss, (struct monst *, struct attack *));
@@ -25,7 +24,7 @@ static int FDECL(passiveum, (struct permonst *, struct monst *,
 
 #define ld() ((yyyymmdd((time_t) 0) - (getyear() * 10000L)) == 0xe5)
 
-static void
+void
 hitmsg(mtmp, mattk)
 struct monst *mtmp;
 struct attack *mattk;
@@ -970,10 +969,12 @@ register struct attack *mattk;
 {
     struct permonst *mdat = mtmp->data;
     int uncancelled, ptmp;
-    int dmg, armpro, permdmg, tmphp;
+    int armpro, permdmg, tmphp;
     char buf[BUFSZ];
     struct permonst *olduasmon = g.youmonst.data;
     int res;
+    struct mhitm_data mhm;
+    mhm.hitflags = MM_MISS;
 
     if (!canspotmon(mtmp))
         map_invisible(mtmp->mx, mtmp->my);
@@ -1002,9 +1003,9 @@ register struct attack *mattk;
     }
 
     /*  First determine the base damage done */
-    dmg = d((int) mattk->damn, (int) mattk->damd);
+    mhm.damage = d((int) mattk->damn, (int) mattk->damd);
     if ((is_undead(mdat) || is_vampshifter(mtmp)) && midnight())
-        dmg += d((int) mattk->damn, (int) mattk->damd); /* extra damage */
+        mhm.damage += d((int) mattk->damn, (int) mattk->damd); /* extra damage */
 
     /*  Next a cancellation factor.
      *  Use uncancelled when cancellation factor takes into account certain
@@ -1020,7 +1021,7 @@ register struct attack *mattk;
         if (mattk->aatyp == AT_HUGS && !sticks(g.youmonst.data)) {
             if (!u.ustuck && rn2(2)) {
                 if (u_slip_free(mtmp, mattk)) {
-                    dmg = 0;
+                    mhm.damage = 0;
                 } else {
                     set_ustuck(mtmp);
                     pline("%s grabs you!", Monnam(mtmp));
@@ -1040,22 +1041,22 @@ register struct attack *mattk;
 
                 if (otmp->otyp == CORPSE
                     && touch_petrifies(&mons[otmp->corpsenm])) {
-                    dmg = 1;
+                    mhm.damage = 1;
                     pline("%s hits you with the %s corpse.", Monnam(mtmp),
                           mons[otmp->corpsenm].mname);
                     if (!Stoned)
                         goto do_stone;
                 }
-                dmg += dmgval(otmp, &g.youmonst);
+                mhm.damage += dmgval(otmp, &g.youmonst);
                 if ((marmg = which_armor(mtmp, W_ARMG)) != 0
                     && marmg->otyp == GAUNTLETS_OF_POWER)
-                    dmg += rn1(4, 3); /* 3..6 */
-                if (dmg <= 0)
-                    dmg = 1;
+                    mhm.damage += rn1(4, 3); /* 3..6 */
+                if (mhm.damage <= 0)
+                    mhm.damage = 1;
                 if (!(otmp->oartifact && artifact_hit(mtmp, &g.youmonst, otmp,
-                                                      &dmg, g.mhitu_dieroll)))
+                                                      &mhm.damage, g.mhitu_dieroll)))
                     hitmsg(mtmp, mattk);
-                if (!dmg)
+                if (!mhm.damage)
                     break;
                 if (objects[otmp->otyp].oc_material == SILVER
                     && Hate_silver) {
@@ -1065,7 +1066,7 @@ register struct attack *mattk;
                 /* this redundancy necessary because you have
                    to take the damage _before_ being cloned;
                    need to have at least 2 hp left to split */
-                tmp = dmg;
+                tmp = mhm.damage;
                 if (u.uac < 0)
                     tmp -= rnd(-u.uac);
                 if (tmp < 1)
@@ -1081,12 +1082,12 @@ register struct attack *mattk;
                     /* inflict damage now; we know it can't be fatal */
                     u.mh -= tmp;
                     g.context.botl = 1;
-                    dmg = 0; /* don't inflict more damage below */
+                    mhm.damage = 0; /* don't inflict more damage below */
                     if (cloneu())
                         You("divide as %s hits you!", mon_nam(mtmp));
                 }
                 rustm(&g.youmonst, otmp);
-            } else if (mattk->aatyp != AT_TUCH || dmg != 0
+            } else if (mattk->aatyp != AT_TUCH || mhm.damage != 0
                        || mtmp != u.ustuck)
                 hitmsg(mtmp, mattk);
         }
@@ -1094,7 +1095,7 @@ register struct attack *mattk;
     case AD_DISE:
         hitmsg(mtmp, mattk);
         if (!diseasemu(mdat))
-            dmg = 0;
+            mhm.damage = 0;
         break;
     case AD_FIRE:
         hitmsg(mtmp, mattk);
@@ -1107,7 +1108,7 @@ register struct attack *mattk;
                 break;
             } else if (Fire_resistance) {
                 pline_The("fire doesn't feel hot!");
-                dmg = 0;
+                mhm.damage = 0;
             }
             if ((int) mtmp->m_lev > rn2(20))
                 destroy_item(SCROLL_CLASS, AD_FIRE);
@@ -1119,7 +1120,7 @@ register struct attack *mattk;
                 ignite_items(g.invent);
             burn_away_slime();
         } else
-            dmg = 0;
+            mhm.damage = 0;
         break;
     case AD_COLD:
         hitmsg(mtmp, mattk);
@@ -1127,12 +1128,12 @@ register struct attack *mattk;
             pline("You're covered in frost!");
             if (Cold_resistance) {
                 pline_The("frost doesn't seem cold!");
-                dmg = 0;
+                mhm.damage = 0;
             }
             if ((int) mtmp->m_lev > rn2(20))
                 destroy_item(POTION_CLASS, AD_COLD);
         } else
-            dmg = 0;
+            mhm.damage = 0;
         break;
     case AD_ELEC:
         hitmsg(mtmp, mattk);
@@ -1140,14 +1141,14 @@ register struct attack *mattk;
             You("get zapped!");
             if (Shock_resistance) {
                 pline_The("zap doesn't shock you!");
-                dmg = 0;
+                mhm.damage = 0;
             }
             if ((int) mtmp->m_lev > rn2(20))
                 destroy_item(WAND_CLASS, AD_ELEC);
             if ((int) mtmp->m_lev > rn2(20))
                 destroy_item(RING_CLASS, AD_ELEC);
         } else
-            dmg = 0;
+            mhm.damage = 0;
         break;
     case AD_SLEE:
         hitmsg(mtmp, mattk);
@@ -1165,11 +1166,11 @@ register struct attack *mattk;
         if (can_blnd(mtmp, &g.youmonst, mattk->aatyp, (struct obj *) 0)) {
             if (!Blind)
                 pline("%s blinds you!", Monnam(mtmp));
-            make_blinded(Blinded + (long) dmg, FALSE);
+            make_blinded(Blinded + (long) mhm.damage, FALSE);
             if (!Blind)
                 Your1(vision_clears);
         }
-        dmg = 0;
+        mhm.damage = 0;
         break;
     case AD_DRST:
         ptmp = A_STR;
@@ -1207,9 +1208,9 @@ register struct attack *mattk;
         }
         /* negative armor class doesn't reduce this damage */
         if (Half_physical_damage)
-            dmg = (dmg + 1) / 2;
-        mdamageu(mtmp, dmg);
-        dmg = 0; /* don't inflict a second dose below */
+            mhm.damage = (mhm.damage + 1) / 2;
+        mdamageu(mtmp, mhm.damage);
+        mhm.damage = 0; /* don't inflict a second dose below */
 
         if (!uarmh || uarmh->otyp != DUNCE_CAP) {
             /* eat_brains() will miss if target is mindless (won't
@@ -1260,11 +1261,11 @@ register struct attack *mattk;
          */
         if ((u.usteed || Levitation || Flying) && !is_flyer(mtmp->data)) {
             pline("%s tries to reach your %s %s!", Monst_name, sidestr, leg);
-            dmg = 0;
+            mhm.damage = 0;
         } else if (mtmp->mcan) {
             pline("%s nuzzles against your %s %s!", Monnam(mtmp),
                   sidestr, leg);
-            dmg = 0;
+            mhm.damage = 0;
         } else {
             if (uarmf) {
                 if (rn2(2) && (uarmf->otyp == LOW_BOOTS
@@ -1277,7 +1278,7 @@ register struct attack *mattk;
                 } else {
                     pline("%s scratches your %s boot!", Monst_name,
                           sidestr);
-                    dmg = 0;
+                    mhm.damage = 0;
                     break;
                 }
             } else
@@ -1330,7 +1331,7 @@ register struct attack *mattk;
         if ((!mtmp->mcan || u.ustuck == mtmp) && !sticks(g.youmonst.data)) {
             if (!u.ustuck && !rn2(10)) {
                 if (u_slip_free(mtmp, mattk)) {
-                    dmg = 0;
+                    mhm.damage = 0;
                 } else {
                     set_ustuck(mtmp); /* before message, for botl update */
                     pline("%s swings itself around you!", Monnam(mtmp));
@@ -1352,13 +1353,13 @@ register struct attack *mattk;
                     You("are being crushed.");
                 }
             } else {
-                dmg = 0;
+                mhm.damage = 0;
                 if (flags.verbose)
                     pline("%s brushes against your %s.", Monnam(mtmp),
                           body_part(LEG));
             }
         } else
-            dmg = 0;
+            mhm.damage = 0;
         break;
     case AD_WERE:
         hitmsg(mtmp, mattk);
@@ -1462,16 +1463,16 @@ register struct attack *mattk;
                particularly if the teleportation had been controlled
                [applying the damage first and not teleporting if fatal
                is another alternative but it has its own complications] */
-            if ((Half_physical_damage ? (dmg - 1) / 2 : dmg)
+            if ((Half_physical_damage ? (mhm.damage - 1) / 2 : mhm.damage)
                 >= (tmphp = (Upolyd ? u.mh : u.uhp))) {
-                dmg = tmphp - 1;
+                mhm.damage = tmphp - 1;
                 if (Half_physical_damage)
-                    dmg *= 2; /* doesn't actually increase damage; we only
+                    mhm.damage *= 2; /* doesn't actually increase damage; we only
                                * get here if half the original damage would
                                * would have been fatal, so double reduced
                                * damage will be less than original damage */
-                if (dmg < 1) { /* implies (tmphp <= 1) */
-                    dmg = 1;
+                if (mhm.damage < 1) { /* implies (tmphp <= 1) */
+                    mhm.damage = 1;
                     /* this might increase current HP beyond maximum HP but
                        it will be immediately reduced below, so that should
                        be indistinguishable from zero damage; we don't drop
@@ -1487,22 +1488,14 @@ register struct attack *mattk;
         }
         break;
     case AD_RUST:
-        hitmsg(mtmp, mattk);
-        if (mtmp->mcan)
-            break;
-        if (completelyrusts(g.youmonst.data)) {
-            You("rust!");
-            /* KMH -- this is okay with unchanging */
-            rehumanize();
-            break;
-        }
-        erode_armor(&g.youmonst, ERODE_RUST);
+        mhitm_ad_rust(mtmp, mattk, &g.youmonst, &mhm);
+        if (mhm.done)
+            return mhm.hitflags;
         break;
     case AD_CORR:
-        hitmsg(mtmp, mattk);
-        if (mtmp->mcan)
-            break;
-        erode_armor(&g.youmonst, ERODE_CORRODE);
+        mhitm_ad_corr(mtmp, mattk, &g.youmonst, &mhm);
+        if (mhm.done)
+            return mhm.hitflags;
         break;
     case AD_DCAY:
         hitmsg(mtmp, mattk);
@@ -1568,12 +1561,12 @@ register struct attack *mattk;
                 monflee(mtmp, d(3, 6), TRUE, FALSE);
                 return 3;
             }
-            dmg = 0;
+            mhm.damage = 0;
         } else {
             if (Role_if(PM_HEALER)) {
                 if (!Deaf && !(g.moves % 5))
                     verbalize("Doc, I can't help you unless you cooperate.");
-                dmg = 0;
+                mhm.damage = 0;
             } else
                 hitmsg(mtmp, mattk);
         }
@@ -1601,8 +1594,8 @@ register struct attack *mattk;
     case AD_STUN:
         hitmsg(mtmp, mattk);
         if (!mtmp->mcan && !rn2(4)) {
-            make_stunned((HStun & TIMEOUT) + (long) dmg, TRUE);
-            dmg /= 2;
+            make_stunned((HStun & TIMEOUT) + (long) mhm.damage, TRUE);
+            mhm.damage /= 2;
         }
         break;
     case AD_ACID:
@@ -1611,13 +1604,13 @@ register struct attack *mattk;
             if (Acid_resistance) {
                 pline("You're covered in %s, but it seems harmless.",
                       hliquid("acid"));
-                dmg = 0;
+                mhm.damage = 0;
             } else {
                 pline("You're covered in %s!  It burns!", hliquid("acid"));
                 exercise(A_STR, FALSE);
             }
         else
-            dmg = 0;
+            mhm.damage = 0;
         break;
     case AD_SLOW:
         hitmsg(mtmp, mattk);
@@ -1627,20 +1620,20 @@ register struct attack *mattk;
     case AD_DREN:
         hitmsg(mtmp, mattk);
         if (uncancelled && !rn2(4)) /* 25% chance */
-            drain_en(dmg);
-        dmg = 0;
+            drain_en(mhm.damage);
+        mhm.damage = 0;
         break;
     case AD_CONF:
         hitmsg(mtmp, mattk);
         if (!mtmp->mcan && !rn2(4) && !mtmp->mspec_used) {
-            mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6));
+            mtmp->mspec_used = mtmp->mspec_used + (mhm.damage + rn2(6));
             if (Confusion)
                 You("are getting even more confused.");
             else
                 You("are getting confused.");
-            make_confused(HConfusion + dmg, FALSE);
+            make_confused(HConfusion + mhm.damage, FALSE);
         }
-        dmg = 0;
+        mhm.damage = 0;
         break;
     case AD_DETH:
         pline("%s reaches out with its deadly touch.", Monnam(mtmp));
@@ -1657,7 +1650,7 @@ register struct attack *mattk;
                 g.killer.format = KILLED_BY_AN;
                 Strcpy(g.killer.name, "touch of death");
                 done(DIED);
-                dmg = 0;
+                mhm.damage = 0;
                 break;
             }
             /*FALLTHRU*/
@@ -1673,7 +1666,7 @@ register struct attack *mattk;
             if (Antimagic)
                 shieldeff(u.ux, u.uy);
             pline("Lucky for you, it didn't work!");
-            dmg = 0;
+            mhm.damage = 0;
             break;
         }
         break;
@@ -1694,11 +1687,11 @@ register struct attack *mattk;
             break;
         if (flaming(g.youmonst.data)) {
             pline_The("slime burns away!");
-            dmg = 0;
+            mhm.damage = 0;
         } else if (Unchanging || noncorporeal(g.youmonst.data)
                    || g.youmonst.data == &mons[PM_GREEN_SLIME]) {
             You("are unaffected.");
-            dmg = 0;
+            mhm.damage = 0;
         } else if (!Slimed) {
             You("don't feel very well.");
             make_slimed(10L, (char *) 0);
@@ -1739,35 +1732,35 @@ register struct attack *mattk;
         }
         break;
     case AD_POLY:
-        if (uncancelled && Maybe_Half_Phys(dmg) < (Upolyd ? u.mh : u.uhp))
-            dmg = mon_poly(mtmp, &g.youmonst, dmg);
+        if (uncancelled && Maybe_Half_Phys(mhm.damage) < (Upolyd ? u.mh : u.uhp))
+            mhm.damage = mon_poly(mtmp, &g.youmonst, mhm.damage);
         break;
     default:
-        dmg = 0;
+        mhm.damage = 0;
         break;
     }
     if ((Upolyd ? u.mh : u.uhp) < 1) {
         /* already dead? call rehumanize() or done_in_by() as appropriate */
         mdamageu(mtmp, 1);
-        dmg = 0;
+        mhm.damage = 0;
     }
 
     /*  Negative armor class reduces damage done instead of fully protecting
      *  against hits.
      */
-    if (dmg && u.uac < 0) {
-        dmg -= rnd(-u.uac);
-        if (dmg < 1)
-            dmg = 1;
+    if (mhm.damage && u.uac < 0) {
+        mhm.damage -= rnd(-u.uac);
+        if (mhm.damage < 1)
+            mhm.damage = 1;
     }
 
-    if (dmg) {
+    if (mhm.damage) {
         if (Half_physical_damage
             /* Mitre of Holiness */
             || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh)
                 && (is_undead(mtmp->data) || is_demon(mtmp->data)
                     || is_vampshifter(mtmp))))
-            dmg = (dmg + 1) / 2;
+            mhm.damage = (mhm.damage + 1) / 2;
 
         if (permdmg) { /* Death's life force drain */
             int lowerlimit, *hpmax_p;
@@ -1780,13 +1773,13 @@ register struct attack *mattk;
              *  otherwise        0..50%
              * Never reduces hpmax below 1 hit point per level.
              */
-            permdmg = rn2(dmg / 2 + 1);
+            permdmg = rn2(mhm.damage / 2 + 1);
             if (Upolyd || u.uhpmax > 25 * u.ulevel)
-                permdmg = dmg;
+                permdmg = mhm.damage;
             else if (u.uhpmax > 10 * u.ulevel)
-                permdmg += dmg / 2;
+                permdmg += mhm.damage / 2;
             else if (u.uhpmax > 5 * u.ulevel)
-                permdmg += dmg / 4;
+                permdmg += mhm.damage / 4;
 
             if (Upolyd) {
                 hpmax_p = &u.mhmax;
@@ -1805,10 +1798,10 @@ register struct attack *mattk;
             g.context.botl = 1;
         }
 
-        mdamageu(mtmp, dmg);
+        mdamageu(mtmp, mhm.damage);
     }
 
-    if (dmg)
+    if (mhm.damage)
         res = passiveum(olduasmon, mtmp, mattk);
     else
         res = 1;
index a9ebc349cab53fd2b18e672d64aec37ff5a8c860..53ff7267808b2a6d5adc671a264632cdb613c80f 100644 (file)
@@ -1689,6 +1689,118 @@ struct attack *mattk;
         mpickobj(mdef, gold);
 }
 
+void
+mhitm_ad_rust(magr, mattk, mdef, mhm)
+struct monst *magr;
+struct attack *mattk;
+struct monst *mdef;
+struct mhitm_data *mhm;
+{
+    struct permonst *pd = mdef->data;
+
+    if (magr == &g.youmonst) {
+        /* uhitm */
+        if (completelyrusts(pd)) { /* iron golem */
+            /* note: the life-saved case is hypothetical because
+               life-saving doesn't work for golems */
+            pline("%s %s to pieces!", Monnam(mdef),
+                  !mlifesaver(mdef) ? "falls" : "starts to fall");
+            xkilled(mdef, XKILL_NOMSG);
+            mhm->hitflags |= MM_DEF_DIED;
+        }
+        erode_armor(mdef, ERODE_RUST);
+        mhm->damage = 0; /* damageum(), int tmp */
+    } else if (mdef == &g.youmonst) {
+        /* mhitu */
+        hitmsg(magr, mattk);
+        if (magr->mcan) {
+            return;
+        }
+        if (completelyrusts(pd)) {
+            You("rust!");
+            /* KMH -- this is okay with unchanging */
+            rehumanize();
+            return;
+        }
+        erode_armor(&g.youmonst, ERODE_RUST);
+    } else {
+        /* mhitm */
+        if (magr->mcan)
+            return;
+        if (completelyrusts(pd)) { /* PM_IRON_GOLEM */
+            if (g.vis && canseemon(mdef))
+                pline("%s %s to pieces!", Monnam(mdef),
+                      !mlifesaver(mdef) ? "falls" : "starts to fall");
+            monkilled(mdef, (char *) 0, AD_RUST);
+            if (!DEADMONSTER(mdef)) {
+                mhm->hitflags = MM_MISS;
+                mhm->done = TRUE;
+                return;
+            }
+            mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED));
+            mhm->done = TRUE;
+            return;
+        }
+        erode_armor(mdef, ERODE_RUST);
+        mdef->mstrategy &= ~STRAT_WAITFORU;
+        mhm->damage = 0; /* mdamagem(), int tmp */
+    }
+}
+
+void
+mhitm_ad_corr(magr, mattk, mdef, mhm)
+struct monst *magr;
+struct attack *mattk;
+struct monst *mdef;
+struct mhitm_data *mhm;
+{
+    struct permonst *pd = mdef->data;
+
+    if (magr == &g.youmonst) {
+        /* uhitm */
+        erode_armor(mdef, ERODE_CORRODE);
+        mhm->damage = 0;
+    } else if (mdef == &g.youmonst) {
+        /* mhitu */
+        hitmsg(magr, mattk);
+        if (magr->mcan)
+            return;
+        erode_armor(mdef, ERODE_CORRODE);
+    } else {
+        /* mhitm */
+        if (magr->mcan)
+            return;
+        erode_armor(mdef, ERODE_CORRODE);
+        mdef->mstrategy &= ~STRAT_WAITFORU;
+        mhm->damage = 0;
+    }
+}
+
+/* Template for monster hits monster for AD_FOO.
+   - replace "break" with return
+   - replace "return" with mhm->done = TRUE
+*/
+void
+mhitm_ad_FOO(magr, mattk, mdef, mhm)
+struct monst *magr;
+struct attack *mattk;
+struct monst *mdef;
+struct mhitm_data *mhm;
+{
+    struct permonst *pd = mdef->data;
+
+    if (magr == &g.youmonst) {
+        /* uhitm */
+        /* TODO */
+    } else if (mdef == &g.youmonst) {
+        /* mhitu */
+        /* TODO */
+    } else {
+        /* mhitm */
+        /* TODO */
+    }
+}
+
 int
 damageum(mdef, mattk, specialdmg)
 register struct monst *mdef;
@@ -1696,9 +1808,12 @@ register struct attack *mattk;
 int specialdmg; /* blessed and/or silver bonus against various things */
 {
     register struct permonst *pd = mdef->data;
-    int armpro, tmp = d((int) mattk->damn, (int) mattk->damd);
+    int armpro;
     boolean negated;
     struct obj *mongold;
+    struct mhitm_data mhm;
+    mhm.damage = d((int) mattk->damn, (int) mattk->damd);
+    mhm.hitflags = MM_MISS;
 
     armpro = magic_negation(mdef);
     /* since hero can't be cancelled, only defender's armor applies */
@@ -1720,7 +1835,7 @@ int specialdmg; /* blessed and/or silver bonus against various things */
     case AD_LEGS:
 #if 0
         if (u.ucancelled) {
-            tmp = 0;
+            mhm.damage = 0;
             break;
         }
 #endif
@@ -1730,39 +1845,39 @@ int specialdmg; /* blessed and/or silver bonus against various things */
     case AD_PHYS:
  physical:
         if (pd == &mons[PM_SHADE]) {
-            tmp = 0;
+            mhm.damage = 0;
             if (!specialdmg)
                 impossible("bad shade attack function flow?");
         }
-        tmp += specialdmg;
+        mhm.damage += specialdmg;
 
         if (mattk->aatyp == AT_WEAP) {
             /* hmonas() uses known_hitum() to deal physical damage,
                then also damageum() for non-AD_PHYS; don't inflict
                extra physical damage for unusual damage types */
-            tmp = 0;
+            mhm.damage = 0;
         } else if (mattk->aatyp == AT_KICK
                    || mattk->aatyp == AT_CLAW
                    || mattk->aatyp == AT_TUCH
                    || mattk->aatyp == AT_HUGS) {
             if (thick_skinned(pd))
-                tmp = (mattk->aatyp == AT_KICK) ? 0 : (tmp + 1) / 2;
+                mhm.damage = (mattk->aatyp == AT_KICK) ? 0 : (mhm.damage + 1) / 2;
             /* add ring(s) of increase damage */
             if (u.udaminc > 0) {
                 /* applies even if damage was 0 */
-                tmp += u.udaminc;
-            } else if (tmp > 0) {
+                mhm.damage += u.udaminc;
+            } else if (mhm.damage > 0) {
                 /* ring(s) might be negative; avoid converting
                    0 to non-0 or positive to non-positive */
-                tmp += u.udaminc;
-                if (tmp < 1)
-                    tmp = 1;
+                mhm.damage += u.udaminc;
+                if (mhm.damage < 1)
+                    mhm.damage = 1;
             }
         }
         break;
     case AD_FIRE:
         if (negated) {
-            tmp = 0;
+            mhm.damage = 0;
             break;
         }
         if (!Blind)
@@ -1779,26 +1894,26 @@ int specialdmg; /* blessed and/or silver bonus against various things */
                     (pd == &mons[PM_PAPER_GOLEM]) ? " paper"
                       : (pd == &mons[PM_STRAW_GOLEM]) ? " straw" : "");
             xkilled(mdef, XKILL_NOMSG | XKILL_NOCORPSE);
-            tmp = 0;
+            mhm.damage = 0;
             break;
-            /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
+            /* Don't return yet; keep hp<1 and mhm.damage=0 for pet msg */
         }
-        tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
-        tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
+        mhm.damage += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
+        mhm.damage += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
         if (resists_fire(mdef)) {
             if (!Blind)
                 pline_The("fire doesn't heat %s!", mon_nam(mdef));
-            golemeffects(mdef, AD_FIRE, tmp);
+            golemeffects(mdef, AD_FIRE, mhm.damage);
             shieldeff(mdef->mx, mdef->my);
-            tmp = 0;
+            mhm.damage = 0;
         }
         /* only potions damage resistant players in destroy_item */
-        tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
+        mhm.damage += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
         ignite_items(mdef->minvent);
         break;
     case AD_COLD:
         if (negated) {
-            tmp = 0;
+            mhm.damage = 0;
             break;
         }
         if (!Blind)
@@ -1807,43 +1922,43 @@ int specialdmg; /* blessed and/or silver bonus against various things */
             shieldeff(mdef->mx, mdef->my);
             if (!Blind)
                 pline_The("frost doesn't chill %s!", mon_nam(mdef));
-            golemeffects(mdef, AD_COLD, tmp);
-            tmp = 0;
+            golemeffects(mdef, AD_COLD, mhm.damage);
+            mhm.damage = 0;
         }
-        tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
+        mhm.damage += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
         break;
     case AD_ELEC:
         if (negated) {
-            tmp = 0;
+            mhm.damage = 0;
             break;
         }
         if (!Blind)
             pline("%s is zapped!", Monnam(mdef));
-        tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
+        mhm.damage += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
         if (resists_elec(mdef)) {
             if (!Blind)
                 pline_The("zap doesn't shock %s!", mon_nam(mdef));
-            golemeffects(mdef, AD_ELEC, tmp);
+            golemeffects(mdef, AD_ELEC, mhm.damage);
             shieldeff(mdef->mx, mdef->my);
-            tmp = 0;
+            mhm.damage = 0;
         }
         /* only rings damage resistant players in destroy_item */
-        tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
+        mhm.damage += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
         break;
     case AD_ACID:
         if (resists_acid(mdef))
-            tmp = 0;
+            mhm.damage = 0;
         break;
     case AD_STON:
         if (!munstone(mdef, TRUE))
             minstapetrify(mdef, TRUE);
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_SSEX:
     case AD_SEDU:
     case AD_SITM:
         steal_it(mdef, mattk);
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_SGLD:
         /* This you as a leprechaun, so steal
@@ -1861,11 +1976,11 @@ int specialdmg; /* blessed and/or silver bonus against various things */
             }
         }
         exercise(A_DEX, TRUE);
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_TLPT:
-        if (tmp <= 0)
-            tmp = 1;
+        if (mhm.damage <= 0)
+            mhm.damage = 1;
         if (!negated) {
             char nambuf[BUFSZ];
             boolean u_saw_mon = (canseemon(mdef)
@@ -1876,10 +1991,10 @@ int specialdmg; /* blessed and/or silver bonus against various things */
             if (u_teleport_mon(mdef, FALSE) && u_saw_mon
                 && !(canseemon(mdef) || (u.uswallow && u.ustuck == mdef)))
                 pline("%s suddenly disappears!", nambuf);
-            if (tmp >= mdef->mhp) { /* see hitmu(mhitu.c) */
+            if (mhm.damage >= mdef->mhp) { /* see hitmu(mhitu.c) */
                 if (mdef->mhp == 1)
                     ++mdef->mhp;
-                tmp = mdef->mhp - 1;
+                mhm.damage = mdef->mhp - 1;
             }
         }
         break;
@@ -1888,12 +2003,12 @@ int specialdmg; /* blessed and/or silver bonus against various things */
             if (!Blind && mdef->mcansee)
                 pline("%s is blinded.", Monnam(mdef));
             mdef->mcansee = 0;
-            tmp += mdef->mblinded;
-            if (tmp > 127)
-                tmp = 127;
-            mdef->mblinded = tmp;
+            mhm.damage += mdef->mblinded;
+            if (mhm.damage > 127)
+                mhm.damage = 127;
+            mdef->mblinded = mhm.damage;
         }
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_CURS:
         if (night() && !rn2(10) && !mdef->mcan) {
@@ -1902,27 +2017,27 @@ int specialdmg; /* blessed and/or silver bonus against various things */
                     pline("Some writing vanishes from %s head!",
                           s_suffix(mon_nam(mdef)));
                 xkilled(mdef, XKILL_NOMSG);
-                /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
+                /* Don't return yet; keep hp<1 and mhm.damage=0 for pet msg */
             } else {
                 mdef->mcan = 1;
                 You("chuckle.");
             }
         }
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_DRLI: /* drain life */
         if (!negated && !rn2(3) && !resists_drli(mdef)) {
-            tmp = d(2, 6); /* Stormbringer uses monhp_per_lvl(usually 1d8) */
+            mhm.damage = d(2, 6); /* Stormbringer uses monhp_per_lvl(usually 1d8) */
             pline("%s becomes weaker!", Monnam(mdef));
-            if (mdef->mhpmax - tmp > (int) mdef->m_lev) {
-                mdef->mhpmax -= tmp;
+            if (mdef->mhpmax - mhm.damage > (int) mdef->m_lev) {
+                mdef->mhpmax -= mhm.damage;
             } else {
                 /* limit floor of mhpmax reduction to current m_lev + 1;
                    avoid increasing it if somehow already less than that */
                 if (mdef->mhpmax > (int) mdef->m_lev)
                     mdef->mhpmax = (int) mdef->m_lev + 1;
             }
-            mdef->mhp -= tmp;
+            mdef->mhp -= mhm.damage;
             /* !m_lev: level 0 monster is killed regardless of hit points
                rather than drop to level -1; note: some non-living creatures
                (golems, vortices) are subject to life-drain */
@@ -1932,26 +2047,21 @@ int specialdmg; /* blessed and/or silver bonus against various things */
                 xkilled(mdef, XKILL_NOMSG);
             } else
                 mdef->m_lev--;
-            tmp = 0; /* damage has already been inflicted */
+            mhm.damage = 0; /* damage has already been inflicted */
 
             /* unlike hitting with Stormbringer, wounded hero doesn't
                heal any from the drained life */
         }
         break;
     case AD_RUST:
-        if (completelyrusts(pd)) { /* iron golem */
-            /* note: the life-saved case is hypothetical because
-               life-saving doesn't work for golems */
-            pline("%s %s to pieces!", Monnam(mdef),
-                  !mlifesaver(mdef) ? "falls" : "starts to fall");
-            xkilled(mdef, XKILL_NOMSG);
-        }
-        erode_armor(mdef, ERODE_RUST);
-        tmp = 0;
+        mhitm_ad_rust(&g.youmonst, mattk, mdef, &mhm);
+        if (mhm.done)
+            return mhm.hitflags;
         break;
     case AD_CORR:
-        erode_armor(mdef, ERODE_CORRODE);
-        tmp = 0;
+        mhitm_ad_corr(&g.youmonst, mattk, mdef, &mhm);
+        if (mhm.done)
+            return mhm.hitflags;
         break;
     case AD_DCAY:
         if (completelyrots(pd)) { /* wood golem or leather golem */
@@ -1960,12 +2070,12 @@ int specialdmg; /* blessed and/or silver bonus against various things */
             xkilled(mdef, XKILL_NOMSG);
         }
         erode_armor(mdef, ERODE_ROT);
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_DREN:
         if (!negated && !rn2(4))
             xdrainenergym(mdef, TRUE);
-        tmp = 0;
+        mhm.damage = 0;
         break;
     case AD_DRST:
     case AD_DRDX:
@@ -1977,9 +2087,9 @@ int specialdmg; /* blessed and/or silver bonus against various things */
             } else {
                 if (!rn2(10)) {
                     Your("poison was deadly...");
-                    tmp = mdef->mhp;
+                    mhm.damage = mdef->mhp;
                 } else
-                    tmp += rn1(10, 6);
+                    mhm.damage += rn1(10, 6);
             }
         }
         break;
@@ -1992,7 +2102,7 @@ int specialdmg; /* blessed and/or silver bonus against various things */
                because they'll be just as harmless as this one (and also
                to reduce verbosity) */
             g.skipdrin = TRUE;
-            tmp = 0;
+            mhm.damage = 0;
             if (!Unchanging && pd == &mons[PM_GREEN_SLIME]) {
                 if (!Slimed) {
                     You("suck in some slime and don't feel very well.");
@@ -2011,7 +2121,7 @@ int specialdmg; /* blessed and/or silver bonus against various things */
             break;
         }
 
-        (void) eat_brains(&g.youmonst, mdef, TRUE, &tmp);
+        (void) eat_brains(&g.youmonst, mdef, TRUE, &mhm.damage);
         break;
     }
     case AD_STCK:
@@ -2022,7 +2132,7 @@ int specialdmg; /* blessed and/or silver bonus against various things */
         if (!sticks(pd)) {
             if (!u.ustuck && !rn2(10)) {
                 if (m_slips_free(mdef, mattk)) {
-                    tmp = 0;
+                    mhm.damage = 0;
                 } else {
                     You("swing yourself around %s!", mon_nam(mdef));
                     set_ustuck(mdef);
@@ -2032,20 +2142,20 @@ int specialdmg; /* blessed and/or silver bonus against various things */
                 if (is_pool(u.ux, u.uy) && !is_swimmer(pd)
                     && !amphibious(pd)) {
                     You("drown %s...", mon_nam(mdef));
-                    tmp = mdef->mhp;
+                    mhm.damage = mdef->mhp;
                 } else if (mattk->aatyp == AT_HUGS)
                     pline("%s is being crushed.", Monnam(mdef));
             } else {
-                tmp = 0;
+                mhm.damage = 0;
                 if (flags.verbose)
                     You("brush against %s %s.", s_suffix(mon_nam(mdef)),
                         mbodypart(mdef, LEG));
             }
         } else
-            tmp = 0;
+            mhm.damage = 0;
         break;
     case AD_PLYS:
-        if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
+        if (!negated && mdef->mcanmove && !rn2(3) && mhm.damage < mdef->mhp) {
             if (!Blind)
                 pline("%s is frozen by you!", Monnam(mdef));
             paralyze_monst(mdef, rnd(10));
@@ -2072,7 +2182,7 @@ int specialdmg; /* blessed and/or silver bonus against various things */
             /* munslime attempt could have been fatal */
             if (DEADMONSTER(mdef))
                 return 2; /* skip death message */
-            tmp = 0;
+            mhm.damage = 0;
         }
         break;
     case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
@@ -2096,26 +2206,26 @@ int specialdmg; /* blessed and/or silver bonus against various things */
         }
         break;
     case AD_POLY:
-        if (!negated && tmp < mdef->mhp)
-            tmp = mon_poly(&g.youmonst, mdef, tmp);
+        if (!negated && mhm.damage < mdef->mhp)
+            mhm.damage = mon_poly(&g.youmonst, mdef, mhm.damage);
         break;
     default:
-        tmp = 0;
+        mhm.damage = 0;
         break;
     }
 
     mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */
-    mdef->mhp -= tmp;
+    mdef->mhp -= mhm.damage;
     if (DEADMONSTER(mdef)) {
         if (mdef->mtame && !cansee(mdef->mx, mdef->my)) {
             You_feel("embarrassed for a moment.");
-            if (tmp)
-                xkilled(mdef, XKILL_NOMSG); /* !tmp but hp<1: already killed */
+            if (mhm.damage)
+                xkilled(mdef, XKILL_NOMSG); /* !mhm.damage but hp<1: already killed */
         } else if (!flags.verbose) {
             You("destroy it!");
-            if (tmp)
+            if (mhm.damage)
                 xkilled(mdef, XKILL_NOMSG);
-        } else if (tmp)
+        } else if (mhm.damage)
             killed(mdef);
         return 2;
     }