From b93cfecbaf93023078676cafd48062937bafff2c Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 12 Sep 2024 12:16:40 -0700 Subject: [PATCH] fix github issue #1252 - current HP > maximum HP Sanity check failure generated by running the fuzzer, reported by mkuoppal. The check discovered that the hero's current hit points were greater than the maximum. Comments by elunna pointed out where the problem most likely was, and this attempts to fix the situation, but without a test case I can't be sure that the fix works. Both cases being fixed are for formerly fatal incidents (random chance that poison is fatal, monster touch of death spell) being 'softened' to heavy HP damage (including reduction of maxHP). The earlier commit I made (045d608) was done without having seen the relevant comments. It didn't fix anything but did attempt to make finding the problem(s) easier. It wasn't much help. Fixes #1252 --- src/attrib.c | 25 +++++++++++++++++++------ src/mcastu.c | 15 +++++++++++++-- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/attrib.c b/src/attrib.c index ccd5af9a7..c9d3df950 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 attrib.c $NHDT-Date: 1725138479 2024/08/31 21:07:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.127 $ */ +/* NetHack 3.7 attrib.c $NHDT-Date: 1726168587 2024/09/12 19:16:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.129 $ */ /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ @@ -355,14 +355,25 @@ poisoned( i = !fatal ? 1 : rn2(fatal + (thrown_weapon ? 20 : 0)); if (i == 0 && typ != A_CHA) { /* sometimes survivable instant kill */ - loss = 6 + d(4, 6); + loss = 6 + d(4, 6); /* 6 + 4d6 => 10..34 */ if (u.uhp <= loss) { u.uhp = -1; disp.botl = TRUE; pline_The("poison was deadly..."); } else { /* survived, but with severe reaction */ - u.uhpmax = max(3, u.uhpmax - (loss / 2)); + int olduhp = u.uhp, + 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; + } + losehp(loss, pkiller, kprefix); /* poison damage */ if (adjattrib(A_CON, (typ != A_CON) ? -1 : -3, TRUE)) poisontell(A_CON, TRUE); @@ -1221,7 +1232,8 @@ acurrstr(void) to distinguish between observable +0 result and no-visible-effect due to an attribute not being able to exceed maximum or minimum */ boolean -extremeattr(int attrindx) /* does attrindx's value match its max or min? */ +extremeattr( + int attrindx) /* does attrindx's value match its max or min? */ { /* Fixed_abil and racial MINATTR/MAXATTR aren't relevant here */ int lolimit = 3, hilimit = 25, curval = ACURR(attrindx); @@ -1272,8 +1284,9 @@ adjalign(int n) /* change hero's alignment type, possibly losing use of artifacts */ void -uchangealign(int newalign, - int reason) /* A_CG_CONVERT, A_CG_HELM_ON, or A_CG_HELM_OFF */ +uchangealign( + int newalign, + int reason) /* A_CG_CONVERT, A_CG_HELM_ON, or A_CG_HELM_OFF */ { aligntyp oldalign = u.ualign.type; diff --git a/src/mcastu.c b/src/mcastu.c index 90f9bd9c3..0836fa87d 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mcastu.c $NHDT-Date: 1705428596 2024/01/16 18:09:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.95 $ */ +/* NetHack 3.7 mcastu.c $NHDT-Date: 1726168598 2024/09/12 19:16:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.105 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -390,7 +390,18 @@ touch_of_death(struct monst *mtmp) Strcpy(svk.killer.name, kbuf); done(DIED); } else { - u.uhpmax -= drain; + /* HP manipulation similar to poisoned(attrib.c) */ + int olduhp = u.uhp, + 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; + } losehp(dmg, kbuf, KILLED_BY); } svk.killer.name[0] = '\0'; /* not killed if we get here... */