From 045d60848b24fa3651ea34805c9e16dcbc221bb1 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 6 Sep 2024 13:35:00 -0700 Subject: [PATCH] hero health manipulation I've been investigating issue #1252 (while the fuzzer was running, sanity_check complained that hero's current health was greater than maximum health) off and on for three months and haven't found the cause. I've checked all the places that lower maximum HP that I've managed to find, but not spent much time looking for places that raise current HP. These changes might provide some more information. They don't rely on sanity_check being enabled. Issue #1252 is still open. --- src/exper.c | 2 +- src/hack.c | 11 ++++++++--- src/mcastu.c | 13 +++++++++++-- src/mhitu.c | 17 ++++++++++++++--- src/uhitm.c | 4 ++-- 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/exper.c b/src/exper.c index d55f9abab..1fe07dcd1 100644 --- a/src/exper.c +++ b/src/exper.c @@ -321,8 +321,8 @@ pluslvl( u.mh += hpinc; } hpinc = newhp(); - setuhpmax(u.uhpmax + hpinc); u.uhp += hpinc; + setuhpmax(u.uhpmax + hpinc); /* will lower u.uhp if it exceeds uhpmax */ /* increase spell power/energy points */ eninc = newpw(); diff --git a/src/hack.c b/src/hack.c index 2b9ca664c..1e249a68c 100644 --- a/src/hack.c +++ b/src/hack.c @@ -4039,10 +4039,15 @@ maybe_wail(void) int saving_grace(int dmg) { - if (!u.usaving_grace && (u.uhp <= dmg) - && (u.uhp * 100 / u.uhpmax) > 90) { + if (dmg < 0) { + impossible("saving_grace check for negative damage? (%d)", dmg); + return 0; + } + + if (!u.usaving_grace && dmg >= u.uhp && (u.uhp * 100 / u.uhpmax) > 90) { + /* note: this could reduce dmg to 0 if u.uhpmax==1 */ dmg = u.uhp - 1; - u.usaving_grace = TRUE; /* used up */ + u.usaving_grace = 1; /* used up */ end_running(TRUE); if (u.usleep) unmul("Suddenly you wake up!"); diff --git a/src/mcastu.c b/src/mcastu.c index 68a8a8119..90f9bd9c3 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -342,14 +342,12 @@ castmu( break; case AD_SPEL: /* wizard spell */ case AD_CLRC: /* clerical spell */ - { if (mattk->adtyp == AD_SPEL) cast_wizard_spell(mtmp, dmg, spellnum); else cast_cleric_spell(mtmp, dmg, spellnum); dmg = 0; /* done by the spell casting functions */ break; - } } /* switch */ if (dmg) mdamageu(mtmp, dmg); @@ -441,6 +439,11 @@ death_inflicted_by( staticfn void cast_wizard_spell(struct monst *mtmp, int dmg, int spellnum) { + if (dmg < 0) { + impossible("monster cast wizard spell (%d) with negative dmg (%d)?", + spellnum, dmg); + return; + } if (dmg == 0 && !is_undirected_spell(AD_SPEL, spellnum)) { impossible("cast directed wizard spell (%d) with dmg=0?", spellnum); return; @@ -620,6 +623,12 @@ staticfn void cast_cleric_spell(struct monst *mtmp, int dmg, int spellnum) { int orig_dmg = 0; + + if (dmg < 0) { + impossible("monster cast cleric spell (%d) with negative dmg (%d)?", + spellnum, dmg); + return; + } if (dmg == 0 && !is_undirected_spell(AD_CLRC, spellnum)) { impossible("cast directed cleric spell (%d) with dmg=0?", spellnum); return; diff --git a/src/mhitu.c b/src/mhitu.c index b7f338294..33e738189 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1211,7 +1211,7 @@ hitmu(struct monst *mtmp, struct attack *mattk) else if (*hpmax_p > lowerlimit) *hpmax_p = lowerlimit; /* else unlikely... - * already at or below minimum threshold; do nothing */ + * already at or below minimum threshold, do nothing to hpmax */ disp.botl = TRUE; } @@ -1846,16 +1846,27 @@ gazemu(struct monst *mtmp, struct attack *mattk) void mdamageu(struct monst *mtmp, int n) { + if (n < 0) { + impossible("mdamageu for negative damage? (%d)", n); + n = 0; + } + disp.botl = TRUE; if (Upolyd) { u.mh -= n; showdamage(n); + /* caller might have reduced mhmax before calling mdamageu() */ + if (u.mh > u.mhmax) + u.mh = u.mhmax; if (u.mh < 1) rehumanize(); } else { n = saving_grace(n); u.uhp -= n; showdamage(n); + /* caller might have reduced uhpmax before calling mdamageu() */ + if (u.uhp > u.uhpmax) + u.uhp = u.uhpmax; if (u.uhp < 1) done_in_by(mtmp, DIED); } @@ -2422,10 +2433,10 @@ passiveum( break; } pline("%s is suddenly very cold!", Monnam(mtmp)); - u.mh += tmp / 2; + u.mh += (tmp + rn2(2)) / 2; if (u.mhmax < u.mh) u.mhmax = u.mh; - if (u.mhmax > ((gy.youmonst.data->mlevel + 1) * 8)) + if (u.mhmax > (((int) gy.youmonst.data->mlevel + 1) * 8)) (void) split_mon(&gy.youmonst, mtmp); break; case AD_STUN: /* Yellow mold */ diff --git a/src/uhitm.c b/src/uhitm.c index 307883235..bda3557f0 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5906,11 +5906,11 @@ passive( You("are suddenly very cold!"); mdamageu(mon, tmp); /* monster gets stronger with your heat! */ - mon->mhp += tmp / 2; + mon->mhp += (tmp + rn2(2)) / 2; if (mon->mhpmax < mon->mhp) mon->mhpmax = mon->mhp; /* at a certain point, the monster will reproduce! */ - if (mon->mhpmax > ((int) (mon->m_lev + 1) * 8)) + if (mon->mhpmax > (((int) mon->m_lev) + 1) * 8) (void) split_mon(mon, &gy.youmonst); } break;