From a3f176c9dce83014ae53d20303deb8053b1074c3 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 24 Sep 2024 13:59:28 -0700 Subject: [PATCH] probably fix #K4269 - sanity failure for u.mh \ being greater than u.mhmax I think this will fix the situation where current HP as a monster was greater than maximum HP as a monster, triggering a sanity_check failure. No promises though. [poisoned() needs some missing Upolyd handling.] --- include/extern.h | 1 + src/attrib.c | 59 +++++++++++++++++++++++++++++++++++------------- src/mcastu.c | 10 +++----- 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/include/extern.h b/include/extern.h index 2b675eb3b..357131d5c 100644 --- a/include/extern.h +++ b/include/extern.h @@ -203,6 +203,7 @@ extern void adjabil(int, int); extern int newhp(void); extern int minuhpmax(int); extern void setuhpmax(int); +extern int adjuhploss(int, int); extern schar acurr(int); extern schar acurrstr(void); extern boolean extremeattr(int); diff --git a/src/attrib.c b/src/attrib.c index c9d3df950..78fd1d3ca 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -243,7 +243,7 @@ losestr(int num, const char *knam, schar k_format) if (Upolyd) { /* when still poly'd, reduce you-as-monst maxHP; never below 1 */ - u.mhmax -= min(dmg, u.mhmax - 1); + setuhpmax(max(u.mhmax - dmg, 1)); /* acts as setmhmax() */ } else if (!waspolyd) { /* not polymorphed now and didn't rehumanize when taking damage; reduce max HP, but not below uhpmin */ @@ -352,6 +352,11 @@ poisoned( kprefix = KILLED_BY; } + /* + * FIXME: + * this operates on u.uhp[max] even when hero is polymorphed.... + */ + i = !fatal ? 1 : rn2(fatal + (thrown_weapon ? 20 : 0)); if (i == 0 && typ != A_CHA) { /* sometimes survivable instant kill */ @@ -366,13 +371,7 @@ poisoned( newuhpmax = u.uhpmax - (loss / 2); setuhpmax(max(newuhpmax, minuhpmax(3))); - /* reduce pending loss if uhp has already been reduced due to - drop in uhpmax */ - if (u.uhp < olduhp) { - loss -= (olduhp - u.uhp); - if (loss < 1) - loss = 1; - } + loss = adjuhploss(loss, olduhp); losehp(loss, pkiller, kprefix); /* poison damage */ if (adjattrib(A_CON, (typ != A_CON) ? -1 : -3, TRUE)) @@ -1146,18 +1145,46 @@ minuhpmax(int altmin) return max(u.ulevel, altmin); } -/* update u.uhpmax and values of other things that depend upon it */ +/* update u.uhpmax or u.mhmax and values of other things that depend upon + whichever of them is relevant */ void setuhpmax(int newmax) { - if (newmax != u.uhpmax) { - u.uhpmax = newmax; - if (u.uhpmax > u.uhppeak) - u.uhppeak = u.uhpmax; - disp.botl = TRUE; + if (!Upolyd) { + if (newmax != u.uhpmax) { + u.uhpmax = newmax; + if (u.uhpmax > u.uhppeak) + u.uhppeak = u.uhpmax; + disp.botl = TRUE; + } + if (u.uhp > u.uhpmax) + u.uhp = u.uhpmax, disp.botl = TRUE; + } else { /* Upolyd */ + if (newmax != u.mhmax) { + u.mhmax = newmax; + disp.botl = TRUE; + } + if (u.mh > u.mhmax) + u.mh = u.mhmax, disp.botl = TRUE; } - if (u.uhp > u.uhpmax) - u.uhp = u.uhpmax, disp.botl = TRUE; +} + +/* called after setuhpmax() when damage is pending; + if uhpmax (or mhmax) has been reduced, it might have caused uhp (or mh) + to be reduced too; if so, recalculate pending loss to account for that */ +int +adjuhploss( + int loss, /* pending hp loss */ + int olduhp) /* does double duty as oldmh when Upolyd */ +{ + if (!Upolyd) { + if (u.uhp < olduhp) + loss -= (olduhp - u.uhp); + } else { + if (u.mh < olduhp) + loss -= (olduhp - u.mh); + } + return max(loss, 1); } /* return the current effective value of a specific characteristic diff --git a/src/mcastu.c b/src/mcastu.c index 0836fa87d..1eb8e5dfd 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -395,13 +395,9 @@ touch_of_death(struct monst *mtmp) newuhpmax = u.uhpmax - drain; setuhpmax(max(newuhpmax, minuhpmax(3))); - /* reduce pending loss if uhp has already been reduced due to - drop in uhpmax */ - if (u.uhp < olduhp) { - dmg -= (olduhp - u.uhp); - if (dmg < 1) - dmg = 1; - } + dmg = adjuhploss(dmg, olduhp); /* reduce pending damage if uhp has + * already been reduced due to drop + * in uhpmax */ losehp(dmg, kbuf, KILLED_BY); } svk.killer.name[0] = '\0'; /* not killed if we get here... */