/* ### 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);
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,
#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
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]))
}
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);
goto physical;
case AD_LEGS:
if (magr->mcan) {
- tmp = 0;
+ mhm.damage = 0;
break;
}
goto physical;
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;
&& 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));
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))
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))
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));
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)
}
erode_armor(mdef, ERODE_CORRODE);
mdef->mstrategy &= ~STRAT_WAITFORU;
- tmp = 0;
+ mhm.damage = 0;
break;
case AD_STON:
if (magr->mcan)
goto post_stone;
if (poly_when_stoned(pd)) {
mon_to_stone(mdef);
- tmp = 0;
+ mhm.damage = 0;
break;
}
if (!resists_ston(mdef)) {
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);
(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;
mdef->mcansee = 0;
mdef->mstrategy &= ~STRAT_WAITFORU;
}
- tmp = 0;
+ mhm.damage = 0;
break;
case AD_HALU:
if (!magr->mcan && haseyes(pd) && mdef->mcansee) {
mdef->mconf = 1;
mdef->mstrategy &= ~STRAT_WAITFORU;
}
- tmp = 0;
+ mhm.damage = 0;
break;
case AD_CURS:
if (!night() && (pa == &mons[PM_GREMLIN]))
}
break;
case AD_SGLD:
- tmp = 0;
+ mhm.damage = 0;
if (magr->mcan)
break;
/* technically incorrect; no check for stealing gold from
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 */
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--;
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:
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;
}
}
}
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 */
}
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)
(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 */
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) {
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
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 *));
#define ld() ((yyyymmdd((time_t) 0) - (getyear() * 10000L)) == 0xe5)
-static void
+void
hitmsg(mtmp, mattk)
struct monst *mtmp;
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);
}
/* 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
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));
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) {
/* 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)
/* 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);
}
case AD_DISE:
hitmsg(mtmp, mattk);
if (!diseasemu(mdat))
- dmg = 0;
+ mhm.damage = 0;
break;
case AD_FIRE:
hitmsg(mtmp, 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);
ignite_items(g.invent);
burn_away_slime();
} else
- dmg = 0;
+ mhm.damage = 0;
break;
case AD_COLD:
hitmsg(mtmp, 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);
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);
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;
}
/* 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
*/
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
} else {
pline("%s scratches your %s boot!", Monst_name,
sidestr);
- dmg = 0;
+ mhm.damage = 0;
break;
}
} else
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));
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);
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
}
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);
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);
}
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:
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);
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));
g.killer.format = KILLED_BY_AN;
Strcpy(g.killer.name, "touch of death");
done(DIED);
- dmg = 0;
+ mhm.damage = 0;
break;
}
/*FALLTHRU*/
if (Antimagic)
shieldeff(u.ux, u.uy);
pline("Lucky for you, it didn't work!");
- dmg = 0;
+ mhm.damage = 0;
break;
}
break;
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);
}
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;
* 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;
g.context.botl = 1;
}
- mdamageu(mtmp, dmg);
+ mdamageu(mtmp, mhm.damage);
}
- if (dmg)
+ if (mhm.damage)
res = passiveum(olduasmon, mtmp, mattk);
else
res = 1;
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;
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 */
case AD_LEGS:
#if 0
if (u.ucancelled) {
- tmp = 0;
+ mhm.damage = 0;
break;
}
#endif
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)
(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)
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
}
}
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)
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;
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) {
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 */
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 */
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:
} 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;
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.");
break;
}
- (void) eat_brains(&g.youmonst, mdef, TRUE, &tmp);
+ (void) eat_brains(&g.youmonst, mdef, TRUE, &mhm.damage);
break;
}
case AD_STCK:
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);
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));
/* 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) */
}
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;
}