diff --git a/include/extern.h b/include/extern.h index e45fcdbd3..cf5f18597 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2758,6 +2758,7 @@ E boolean FDECL(shade_miss, (struct monst *, struct monst *, struct obj *, 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 void FDECL(mhitm_ad_dcay, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_dren, (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, diff --git a/src/mhitm.c b/src/mhitm.c index 875884b37..90cf855e8 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -1364,10 +1364,9 @@ int dieroll; mhm.damage = 0; break; case AD_DREN: - if (!cancelled && !rn2(4)) - xdrainenergym(mdef, (boolean) (g.vis && canspotmon(mdef) - && mattk->aatyp != AT_ENGL)); - mhm.damage = 0; + mhitm_ad_dren(magr, mattk, mdef, &mhm); + if (mhm.done) + return mhm.hitflags; break; case AD_DRST: case AD_DRDX: diff --git a/src/mhitu.c b/src/mhitu.c index ec8988807..c8567e114 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1611,10 +1611,9 @@ register struct attack *mattk; u_slow_down(); break; case AD_DREN: - hitmsg(mtmp, mattk); - if (uncancelled && !rn2(4)) /* 25% chance */ - drain_en(mhm.damage); - mhm.damage = 0; + mhitm_ad_dren(mtmp, mattk, &g.youmonst, &mhm); + if (mhm.done) + return mhm.hitflags; break; case AD_CONF: hitmsg(mtmp, mattk); diff --git a/src/uhitm.c b/src/uhitm.c index 859122d6f..7bd27ee0a 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1832,6 +1832,50 @@ struct mhitm_data *mhm; } } +void +mhitm_ad_dren(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 */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + + if (!negated && !rn2(4)) + xdrainenergym(mdef, TRUE); + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + /* Next a cancellation factor. + * Use uncancelled when cancellation factor takes into account certain + * armor's special magic protection. Otherwise just use !mtmp->mcan. + */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled && !rn2(4)) /* 25% chance */ + drain_en(mhm->damage); + mhm->damage = 0; + } else { + /* mhitm */ + /* cancellation factor is the same as when attacking the hero */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (!cancelled && !rn2(4)) + xdrainenergym(mdef, (boolean) (g.vis && canspotmon(mdef) + && mattk->aatyp != AT_ENGL)); + mhm->damage = 0; + } +} + /* Template for monster hits monster for AD_FOO. - replace "break" with return - replace "return" with mhm->done = TRUE @@ -2125,9 +2169,9 @@ int specialdmg; /* blessed and/or silver bonus against various things */ return mhm.hitflags; break; case AD_DREN: - if (!negated && !rn2(4)) - xdrainenergym(mdef, TRUE); - mhm.damage = 0; + mhitm_ad_dren(&g.youmonst, mattk, mdef, &mhm); + if (mhm.done) + return mhm.hitflags; break; case AD_DRST: case AD_DRDX: