exercise/abuse while polyd (trunk only)

Three years ago <Someone> reported that even though exercise of
attributes other than wisdom is suppressed while the hero is polymorphed,
attribute gains or losses due to pre-existing exercise can still take
place in that situation.  Since it's an entirely different set of attrs
which will be replaced upon rehumanizing, there's not much point.  (The
same is actually true for wisdom, but I didn't change how exercise works
for it.)  Adopt his one-liner fix:  old exercise won't cause attribute
changes while polymorphed; it will silently fade as it does when its
magnitude is insufficient to trigger a change.

     While checking that out, I noticed that exerchk() was using `/= 2'
to fade out old exercise/abuse.  That will produce platform-dependent
results for negative values (ie, for the abuse case) since C's integer
division doesn't specify whether to truncate towards zero or towards
negative infinity.  In particular, -1 / 2 could yield -1 rather than 0
as the code expected.  (Its impact on play was negligible though.)

     This reduces the code for displaying the messages which accompany
attribute gain/loss.  A few were repharsed in order to simplify that.
This commit is contained in:
nethack.rankin
2008-02-03 06:42:25 +00:00
parent 6968f45024
commit d3b9d28f06
2 changed files with 44 additions and 29 deletions

View File

@@ -278,6 +278,7 @@ potion thrown by monster which hit a long worm's tail gave feedback about
hitting its head
implement energy vortex's previously unused energy drain attack
changing alignment type resets alignment record to 0 (nomimally aligned)
while polymorphed, suppress attribute gain/lose earned by pre-poly exercise
Platform- and/or Interface-Specific Fixes

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)attrib.c 3.5 2008/01/21 */
/* SCCS Id: @(#)attrib.c 3.5 2008/02/02 */
/* Copyright 1988, 1989, 1990, 1992, M. Stephenson */
/* NetHack may be freely redistributed. See license for details. */
@@ -440,10 +440,21 @@ exerper()
}
}
/* exercise/abuse text (must be in attribute order, not botl order);
phrased as "You must have been [][0]." or "You haven't been [][1]." */
static NEARDATA const char * const exertext[A_MAX][2] = {
{ "exercising diligently", "exercising properly" }, /* Str */
{ 0, 0 }, /* Int */
{ "very observant", "paying attention" }, /* Wis */
{ "working on your reflexes", "working on reflexes lately" }, /* Dex */
{ "leading a healthy life-style", "watching your health" }, /* Con */
{ 0, 0 }, /* Cha */
};
void
exerchk()
{
int i, mod_val;
int i, ax, mod_val, lolim, hilim;
/* Check out the periodic accumulations */
exerper();
@@ -465,15 +476,30 @@ exerchk()
* increase/decrease, you lose some of the
* accumulated effects.
*/
for(i = 0; i < A_MAX; AEXE(i++) /= 2) {
for (i = 0; i < A_MAX; ++i) {
ax = AEXE(i);
/* nothing to do here if no exercise or abuse has occurred
(Int and Cha always fall into this category) */
if (!ax) continue; /* ok to skip nextattrib */
if(ABASE(i) >= 18 || !AEXE(i)) continue;
if(i == A_INT || i == A_CHA) continue;/* can't exercise these */
mod_val = sgn(ax); /* +1 or -1; used below */
/* no further effect for exercise if at max or abuse if at min;
can't exceed 18 via exercise even if actual max is higher */
lolim = ATTRMIN(i); /* usually 3; might be higher */
hilim = ATTRMAX(i); /* usually 18; maybe lower or higher */
if (hilim > 18) hilim = 18;
if ((ax < 0) ? (ABASE(i) <= lolim) : (ABASE(i) >= hilim))
goto nextattrib;
/* can't exercise non-Wisdom while polymorphed; previous
exercise/abuse gradually wears off without impact then */
if (Upolyd && i != A_WIS) goto nextattrib;
#ifdef DEBUG
pline("exerchk: testing %s (%d).",
(i == A_STR) ? "Str" : (i == A_WIS) ? "Wis" :
(i == A_DEX) ? "Dex" : "Con", AEXE(i));
(i == A_STR) ? "Str" : (i == A_INT) ? "Int?" :
(i == A_WIS) ? "Wis" : (i == A_DEX) ? "Dex" :
(i == A_CON) ? "Con" : (i == A_CHA) ? "Cha?" : "???",
ax);
#endif
/*
* Law of diminishing returns (Part III):
@@ -481,9 +507,8 @@ exerchk()
* You don't *always* gain by exercising.
* [MRS 92/10/28 - Treat Wisdom specially for balance.]
*/
if(rn2(AVAL) > ((i != A_WIS) ? abs(AEXE(i)*2/3) : abs(AEXE(i))))
continue;
mod_val = sgn(AEXE(i));
if (rn2(AVAL) > ((i != A_WIS) ? (abs(ax) * 2 / 3) : abs(ax)))
goto nextattrib;
#ifdef DEBUG
pline("exerchk: changing %d.", i);
@@ -493,32 +518,21 @@ exerchk()
pline("exerchk: changed %d.", i);
#endif
/* if you actually changed an attrib - zero accumulation */
AEXE(i) = 0;
AEXE(i) = ax = 0;
/* then print an explanation */
switch(i) {
case A_STR: You((mod_val >0) ?
"must have been exercising." :
"must have been abusing your body.");
break;
case A_WIS: You((mod_val >0) ?
"must have been very observant." :
"haven't been paying attention.");
break;
case A_DEX: You((mod_val >0) ?
"must have been working on your reflexes." :
"haven't been working on reflexes lately.");
break;
case A_CON: You((mod_val >0) ?
"must be leading a healthy life-style." :
"haven't been watching your health.");
break;
}
You("%s %s.",
(mod_val > 0) ? "must have been" : "haven't been",
exertext[i][(mod_val > 0) ? 0 : 1]);
}
}
context.next_attrib_check += rn1(200,800);
#ifdef DEBUG
pline("exerchk: next check at %ld.", context.next_attrib_check);
#endif
nextattrib:
/* this used to be ``AEXE(i) /= 2'' but that would produce
platform-dependent rounding/truncation for negative values */
AEXE(i) = (abs(ax) / 2) * mod_val;
}
}