PR #862 - try XLII

When strength loss is so big as to cause HP damage, but reduce
strength if the damage causes hero to revert to normal form.  There's
no point in adjusting strength before rehumanization and not fair to
do so afterward.

Also, validate strength and its intended adjustment before doing
anything else.  (Just paranoia; there's no reason to suspect that any
bad data ever gets passed in.)
This commit is contained in:
PatR
2022-10-15 12:28:53 -04:00
committed by nhmall
parent d0ad02b616
commit 96e933f974
2 changed files with 33 additions and 21 deletions
+12 -7
View File
@@ -216,7 +216,12 @@ losestr(int num, const char *knam, schar k_format)
{ {
int uhpmin = minuhpmax(1), olduhpmax = u.uhpmax; int uhpmin = minuhpmax(1), olduhpmax = u.uhpmax;
int ustr = ABASE(A_STR) - num, amt, dmg; int ustr = ABASE(A_STR) - num, amt, dmg;
boolean waspolyd = Upolyd;
if (num <= 0 || ABASE(A_STR) < ATTRMIN(A_STR)) {
impossible("losestr: %d - %d", ABASE(A_STR), num);
return;
}
dmg = 0; dmg = 0;
while (ustr < ATTRMIN(A_STR)) { while (ustr < ATTRMIN(A_STR)) {
++ustr; ++ustr;
@@ -225,8 +230,6 @@ losestr(int num, const char *knam, schar k_format)
dmg += amt; dmg += amt;
} }
if (dmg) { if (dmg) {
boolean waspolyd = Upolyd;
/* in case damage is fatal and caller didn't supply killer reason */ /* in case damage is fatal and caller didn't supply killer reason */
if (!knam || !*knam) { if (!knam || !*knam) {
knam = "terminal frailty"; knam = "terminal frailty";
@@ -237,10 +240,9 @@ losestr(int num, const char *knam, schar k_format)
if (Upolyd) { if (Upolyd) {
/* if still polymorhed, reduce you-as-monst maxHP; never below 1 */ /* if still polymorhed, reduce you-as-monst maxHP; never below 1 */
u.mhmax -= min(dmg, u.mhmax - 1); u.mhmax -= min(dmg, u.mhmax - 1);
} else if (waspolyd) { } else if (!waspolyd) {
; /* rehumanization was triggered; don't reduce no-polyd HP */ /* not polymorphed now and didn't rehumanize when taking damage;
} else { reduce max HP, but not below below uhpmin */
/* not polymorphed; reduce max HP, but not below below uhpmin */
if (u.uhpmax > uhpmin) if (u.uhpmax > uhpmin)
setuhpmax(max(u.uhpmax - dmg, uhpmin)); setuhpmax(max(u.uhpmax - dmg, uhpmin));
} }
@@ -255,7 +257,10 @@ losestr(int num, const char *knam, schar k_format)
#else #else
nhUse(olduhpmax); nhUse(olduhpmax);
#endif #endif
(void) adjattrib(A_STR, -num, 1); /* 'num' chould have been reduced to 0 in the minimum strength loop;
'(Upolyd || !waspolyd)' is True unless damage caused rehumanization */
if (num > 0 && (Upolyd || !waspolyd))
(void) adjattrib(A_STR, -num, 1);
} }
/* combined strength loss and damage from some poisons */ /* combined strength loss and damage from some poisons */
+21 -14
View File
@@ -42,8 +42,7 @@ static int m_cure_self(struct monst *, int);
static void cast_wizard_spell(struct monst *, int, int); static void cast_wizard_spell(struct monst *, int, int);
static void cast_cleric_spell(struct monst *, int, int); static void cast_cleric_spell(struct monst *, int, int);
static boolean is_undirected_spell(unsigned int, int); static boolean is_undirected_spell(unsigned int, int);
static boolean static boolean spell_would_be_useless(struct monst *, unsigned int, int);
spell_would_be_useless(struct monst *, unsigned int, int);
/* feedback when frustrated monster couldn't cast a spell */ /* feedback when frustrated monster couldn't cast a spell */
static void static void
@@ -173,10 +172,11 @@ choose_clerical_spell(int spellnum)
* 0: unsuccessful spell * 0: unsuccessful spell
*/ */
int int
castmu(register struct monst *mtmp, castmu(
register struct attack *mattk, register struct monst *mtmp, /* caster */
boolean thinks_it_foundyou, register struct attack *mattk, /* caster's current attack */
boolean foundyou) boolean thinks_it_foundyou, /* might be mistaken if displaced */
boolean foundyou) /* knows hero's precise location */
{ {
int dmg, ml = mtmp->m_lev; int dmg, ml = mtmp->m_lev;
int ret; int ret;
@@ -347,6 +347,7 @@ m_cure_self(struct monst *mtmp, int dmg)
void void
touch_of_death(void) touch_of_death(void)
{ {
static const char touchodeath[] = "touch of death";
int dmg = 50 + d(8, 6); int dmg = 50 + d(8, 6);
int drain = dmg / 2; int drain = dmg / 2;
@@ -354,15 +355,18 @@ touch_of_death(void)
if (drain >= u.uhpmax) { if (drain >= u.uhpmax) {
g.killer.format = KILLED_BY_AN; g.killer.format = KILLED_BY_AN;
Strcpy(g.killer.name, "touch of death"); Strcpy(g.killer.name, touchodeath);
done(DIED); done(DIED);
} else { } else {
u.uhpmax -= drain; u.uhpmax -= drain;
losehp(dmg, "touch of death", KILLED_BY_AN); losehp(dmg, touchodeath, KILLED_BY_AN);
} }
} }
/* monster wizard and cleric spellcasting functions */ /*
* Monster wizard and cleric spellcasting functions.
*/
/* /*
If dmg is zero, then the monster is not casting at you. If dmg is zero, then the monster is not casting at you.
If the monster is intentionally not casting at you, we have previously If the monster is intentionally not casting at you, we have previously
@@ -463,6 +467,8 @@ cast_wizard_spell(struct monst *mtmp, int dmg, int spellnum)
} else { } else {
You("suddenly feel weaker!"); You("suddenly feel weaker!");
dmg = mtmp->m_lev - 6; dmg = mtmp->m_lev - 6;
if (dmg < 1) /* paranoia since only chosen when m_lev is high */
dmg = 1;
if (Half_spell_damage) if (Half_spell_damage)
dmg = (dmg + 1) / 2; dmg = (dmg + 1) / 2;
losestr(rnd(dmg), (const char *) 0, 0); losestr(rnd(dmg), (const char *) 0, 0);
@@ -615,7 +621,8 @@ cast_cleric_spell(struct monst *mtmp, int dmg, int spellnum)
if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data)) if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data))
break; break;
if ((pm = mkclass(let, 0)) != 0 if ((pm = mkclass(let, 0)) != 0
&& (mtmp2 = makemon(pm, bypos.x, bypos.y, MM_ANGRY|MM_NOMSG)) != 0) { && (mtmp2 = makemon(pm, bypos.x, bypos.y, MM_ANGRY | MM_NOMSG))
!= 0) {
success = TRUE; success = TRUE;
mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0; mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0;
set_malign(mtmp2); set_malign(mtmp2);
@@ -678,6 +685,7 @@ cast_cleric_spell(struct monst *mtmp, int dmg, int spellnum)
/* note: resists_blnd() doesn't apply here */ /* note: resists_blnd() doesn't apply here */
if (!Blinded) { if (!Blinded) {
int num_eyes = eyecount(g.youmonst.data); int num_eyes = eyecount(g.youmonst.data);
pline("Scales cover your %s!", (num_eyes == 1) pline("Scales cover your %s!", (num_eyes == 1)
? body_part(EYE) ? body_part(EYE)
: makeplural(body_part(EYE))); : makeplural(body_part(EYE)));
@@ -694,17 +702,16 @@ cast_cleric_spell(struct monst *mtmp, int dmg, int spellnum)
monstseesu(M_SEEN_MAGR); monstseesu(M_SEEN_MAGR);
if (g.multi >= 0) if (g.multi >= 0)
You("stiffen briefly."); You("stiffen briefly.");
nomul(-1); dmg = 1; /* to produce nomul(-1), not actual damage */
g.multi_reason = "paralyzed by a monster";
} else { } else {
if (g.multi >= 0) if (g.multi >= 0)
You("are frozen in place!"); You("are frozen in place!");
dmg = 4 + (int) mtmp->m_lev; dmg = 4 + (int) mtmp->m_lev;
if (Half_spell_damage) if (Half_spell_damage)
dmg = (dmg + 1) / 2; dmg = (dmg + 1) / 2;
nomul(-dmg);
g.multi_reason = "paralyzed by a monster";
} }
nomul(-dmg);
g.multi_reason = "paralyzed by a monster";
g.nomovemsg = 0; g.nomovemsg = 0;
dmg = 0; dmg = 0;
break; break;