Skip to content

Commit

Permalink
Fix: Draining monsters to level 0. Fixes #488. There were a lot of sl…
Browse files Browse the repository at this point in the history
…oppy life drain checks around the code that were likely causing dmonsfree errors to pop up. Basically, a drain attack was checking if the monster was not level 0, but then draining from level 1 to 0 anyway. I solved this by adding a companion macro to DEADMONSTER called DRAINEDMONSTER that checks if a monsters maxhp or level is 0 or less.
  • Loading branch information
elunna committed Oct 2, 2023
1 parent 063c18e commit 895bb39
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 51 deletions.
2 changes: 2 additions & 0 deletions include/monst.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ struct monst {
#define MON_NOWEP(mon) ((mon)->mw = (struct obj *) 0)

#define DEADMONSTER(mon) ((mon)->mhp < 1)
#define DRAINEDMONSTER(mon) ((mon)->mhpmax < 1 || (mon)->m_lev < 1)

#define is_starting_pet(mon) ((mon)->m_id == context.startingpet_mid)
#define is_vampshifter(mon) \
((mon)->cham == PM_VAMPIRE \
Expand Down
41 changes: 22 additions & 19 deletions src/artifact.c
Original file line number Diff line number Diff line change
Expand Up @@ -3024,28 +3024,31 @@ int dieroll; /* needed for Magicbane and vorpal blades */
update_inventory();
}
}
if (mdef->m_lev == 0) {
*dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
} else {
int drain = monhp_per_lvl(mdef);
/* Monsters die as soon as they reach level 0 or below. */

*dmgptr += drain;
mdef->mhpmax -= drain;
mdef->m_lev--;
drain /= 2;
if (drain) {
if (youattack)
healup(drain, 0, FALSE, FALSE);
else if (magr && magr->mhp < magr->mhpmax) {
magr->mhp += drain;
if (magr->mhp > magr->mhpmax)
magr->mhp = magr->mhpmax;
}
if (mdef->data == &mons[PM_HYDRA])
pline("One of %s heads swells up and explodes!",
s_suffix(mon_nam(mdef)));
int drain = monhp_per_lvl(mdef);

*dmgptr += drain;
mdef->mhpmax -= drain;
mdef->m_lev--;
drain /= 2;
if (drain) {
if (youattack)
healup(drain, 0, FALSE, FALSE);
else if (magr && magr->mhp < magr->mhpmax) {
magr->mhp += drain;
if (magr->mhp > magr->mhpmax)
magr->mhp = magr->mhpmax;
}
if (mdef->data == &mons[PM_HYDRA])
pline("One of %s heads swells up and explodes!",
s_suffix(mon_nam(mdef)));
}
if (DEADMONSTER(mdef) || DRAINEDMONSTER(mdef)) {
pline("%s dies!", Monnam(mdef));
xkilled(mdef, XKILL_NOMSG);
}

return vis;
} else { /* youdefend */
int oldhpmax = u.uhpmax;
Expand Down
17 changes: 7 additions & 10 deletions src/mhitm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2234,10 +2234,9 @@ struct obj **ootmp; /* to return worn armor for caller to disintegrate */
if (vis && canspotmon(mdef))
pline("%s suddenly seems weaker!", Monnam(mdef));
mdef->mhpmax -= tmp;
if (mdef->m_lev == 0)
mdef->m_lev--;
if (DEADMONSTER(mdef) || DRAINEDMONSTER(mdef))
tmp = mdef->mhp;
else
mdef->m_lev--;
/* Automatic kill if drained past level 0 */
}
}
Expand Down Expand Up @@ -3234,16 +3233,15 @@ struct obj *mwep;
pline("%s suddenly seems weaker!", Monnam(magr));
magr->mhpmax -= xtmp;
damage_mon(magr, xtmp, AD_DRLI);

magr->m_lev--;
/* !m_lev: level 0 monster is killed regardless of hit points
rather than drop to level -1 */
if (DEADMONSTER(magr) || !magr->m_lev) {
if (DEADMONSTER(magr) || DRAINEDMONSTER(magr)) {
if (canseemon(magr))
pline("%s dies!", Monnam(magr));
monkilled(magr, "", AD_DRLI);
return (mdead | mhit | MM_AGR_DIED);
} else
magr->m_lev--;
}
}
break;
default: /* all other types of armor, just pass on through */
Expand Down Expand Up @@ -3398,10 +3396,9 @@ struct obj *mwep;
if (vis && canspotmon(magr))
pline("%s suddenly seems weaker!", Monnam(magr));
magr->mhpmax -= tmp;
if (magr->m_lev == 0)
magr->m_lev--;
if (DEADMONSTER(magr) || DRAINEDMONSTER(magr))
tmp = magr->mhp;
else
magr->m_lev--;
/* Automatic kill if drained past level 0 */
}
}
Expand Down
7 changes: 3 additions & 4 deletions src/mhitu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4925,16 +4925,15 @@ struct attack *mattk;
pline("%s suddenly seems weaker!", Monnam(mtmp));
mtmp->mhpmax -= xtmp;
damage_mon(mtmp, xtmp, AD_DRLI);

mtmp->m_lev--;
/* !m_lev: level 0 monster is killed regardless of hit points
rather than drop to level -1 */
if (DEADMONSTER(mtmp) || !mtmp->m_lev) {
if (DEADMONSTER(mtmp) || DRAINEDMONSTER(mtmp)) {
if (canseemon(mtmp))
pline("%s dies!", Monnam(mtmp));
xkilled(mtmp, XKILL_NOMSG);
return 1;
} else
mtmp->m_lev--;
}
}
break;
case BLACK_DRAGON_SCALES:
Expand Down
4 changes: 2 additions & 2 deletions src/muse.c
Original file line number Diff line number Diff line change
Expand Up @@ -2346,10 +2346,10 @@ register struct obj *otmp;
break; /* skip makeknown */
} else if (!resist(mtmp, otmp->oclass, tmp, NOTELL) && mtmp->mhp > 0) {
mtmp->mhpmax -= tmp;
if (mtmp->mhpmax <= 0 || mtmp->m_lev <= 0)
mtmp->m_lev--;
if (DEADMONSTER(mtmp) || DRAINEDMONSTER(mtmp))
monkilled(mtmp, "", AD_DRLI);
else {
mtmp->m_lev--;
if (canseemon(mtmp)) {
pline("%s suddenly seems weaker!", Monnam(mtmp));
}
Expand Down
9 changes: 4 additions & 5 deletions src/polyself.c
Original file line number Diff line number Diff line change
Expand Up @@ -1841,12 +1841,11 @@ dogaze()
dmg = mtmp->mhp;
mtmp->mhpmax -= dmg;
damage_mon(mtmp, dmg, AD_DRLI);

if (DEADMONSTER(mtmp) || !mtmp->m_lev) {
mtmp->m_lev--;
if (DEADMONSTER(mtmp) || DRAINEDMONSTER(mtmp)) {
pline("%s dies!", Monnam(mtmp));
xkilled(mtmp, XKILL_NOMSG);
} else
mtmp->m_lev--;
}
}
} else if (adtyp == AD_DRST) {
You("attack %s with a poison gaze!", mon_nam(mtmp));
Expand All @@ -1860,7 +1859,7 @@ dogaze()
dmg += rn1(10, 6);

damage_mon(mtmp, dmg, AD_DRST);
if (DEADMONSTER(mtmp) || !mtmp->m_lev) {
if (DEADMONSTER(mtmp)) {
pline("%s dies!", Monnam(mtmp));
xkilled(mtmp, XKILL_NOMSG);
}
Expand Down
20 changes: 11 additions & 9 deletions src/uhitm.c
Original file line number Diff line number Diff line change
Expand Up @@ -3369,13 +3369,15 @@ int specialdmg; /* blessed and/or silver bonus against various things */
if (maybe_polyd(is_vampiric(youmonst.data),
Race_if(PM_VAMPIRIC)) && u.uhunger <= 1420 &&
mattk->aatyp == AT_BITE && has_blood(pd)) {
/* For the life of a creature is in the blood (Lev 17:11) */
if (flags.verbose)
/* For the life of a creature is in the blood
(Lev 17:11) */
if (flags.verbose) {
You("feed on the lifeblood.");

/* [ALI] Biting monsters does not count against eating
* conducts. The draining of life is considered to be
* primarily a non-physical effect */
}
/* [ALI] Biting monsters does not count against
eating conducts. The draining of life is
considered to be primarily a non-physical
effect */
lesshungry(xtmp * 6);
}

Expand All @@ -3385,11 +3387,11 @@ int specialdmg; /* blessed and/or silver bonus against various things */
damage_mon(mdef, xtmp, AD_DRLI);
/* !m_lev: level 0 monster is killed regardless of hit points
rather than drop to level -1 */
if (DEADMONSTER(mdef) || !mdef->m_lev) {
mdef->m_lev--;
if (DEADMONSTER(mdef) || DRAINEDMONSTER(mdef)) {
pline("%s dies!", Monnam(mdef));
xkilled(mdef, XKILL_NOMSG);
} else
mdef->m_lev--;
}
tmp = 0;
}
break;
Expand Down
4 changes: 2 additions & 2 deletions src/zap.c
Original file line number Diff line number Diff line change
Expand Up @@ -722,13 +722,13 @@ struct obj *otmp;
&& !DEADMONSTER(mtmp)) {
damage_mon(mtmp, dmg, AD_DRIN);
mtmp->mhpmax -= dmg;
mtmp->m_lev--;
if (canseemon(mtmp))
learn_it = TRUE;
/* die if already level 0, regardless of hit points */
if (DEADMONSTER(mtmp) || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) {
if (DEADMONSTER(mtmp) || DRAINEDMONSTER(mtmp)) {
killed(mtmp);
} else {
mtmp->m_lev--;
if (canseemon(mtmp))
pline("%s suddenly seems weaker!", Monnam(mtmp));
}
Expand Down

0 comments on commit 895bb39

Please sign in to comment.