diff --git a/doc/fixes36.1 b/doc/fixes36.1 index e6f3e7c78..19c92f722 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -451,6 +451,7 @@ give feedback when released from a bear trap depending upon how the dynamically inserted pattern-match phrase fit #version output left out "pattern matching via " if the basic NetHack features entry was split across two lines +recovery of strength lost due to weakness from hunger was vulnerable to abuse Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/src/apply.c b/src/apply.c index e5df1b904..c477a4fb8 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1951,9 +1951,8 @@ struct obj *obj; if (ABASE(idx) >= AMAX(idx)) continue; val_limit = AMAX(idx); - /* don't recover strength lost from hunger */ - if (idx == A_STR && u.uhs >= WEAK) - val_limit--; + /* this used to adjust 'val_limit' for A_STR when u.uhs was + WEAK or worse, but that's handled via ATEMP(A_STR) now */ if (Fixed_abil) { /* potion/spell of restore ability override sustain ability intrinsic but unicorn horn usage doesn't */ diff --git a/src/attrib.c b/src/attrib.c index e0021632f..a3812d54b 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -366,20 +366,27 @@ set_moreluck() void restore_attrib() { - int i; + int i, equilibrium;; + + /* + * Note: this gets called on every turn but ATIME() is never set + * to non-zero anywhere, and ATEMP() is only used for strength loss + * from hunger, so it doesn't actually do anything. + */ for (i = 0; i < A_MAX; i++) { /* all temporary losses/gains */ - - if (ATEMP(i) && ATIME(i)) { + equilibrium = (i == A_STR && u.uhs >= WEAK) ? -1 : 0; + if (ATEMP(i) != equilibrium && ATIME(i) != 0) { if (!(--(ATIME(i)))) { /* countdown for change */ - ATEMP(i) += ATEMP(i) > 0 ? -1 : 1; - + ATEMP(i) += (ATEMP(i) > 0) ? -1 : 1; + context.botl = 1; if (ATEMP(i)) /* reset timer */ ATIME(i) = 100 / ACURR(A_CON); } } } - (void) encumber_msg(); + if (context.botl) + (void) encumber_msg(); } #define AVAL 50 /* tune value for exercise gains */ diff --git a/src/eat.c b/src/eat.c index 9bd6346b0..6bbc1836b 100644 --- a/src/eat.c +++ b/src/eat.c @@ -112,8 +112,11 @@ register struct obj *obj; void init_uhunger() { + context.botl = (u.uhs != NOT_HUNGRY || ATEMP(A_STR) < 0); u.uhunger = 900; u.uhs = NOT_HUNGRY; + if (ATEMP(A_STR) < 0) + ATEMP(A_STR) = 0; } /* tin types [SPINACH_TIN = -1, overrides corpsenm, nut==600] */ @@ -2961,10 +2964,23 @@ boolean incr; } if (newhs != u.uhs) { - if (newhs >= WEAK && u.uhs < WEAK) - losestr(1); /* this may kill you -- see below */ - else if (newhs < WEAK && u.uhs >= WEAK) - losestr(-1); + if (newhs >= WEAK && u.uhs < WEAK) { + /* this used to be losestr(1) which had the potential to + be fatal (still handled below) by reducing HP if it + tried to take base strength below minimum of 3 */ + ATEMP(A_STR) = -1; /* temporary loss overrides Fixed_abil */ + /* defer context.botl status update until after hunger message */ + } else if (newhs < WEAK && u.uhs >= WEAK) { + /* this used to be losestr(-1) which could be abused by + becoming weak while wearing ring of sustain ability, + removing ring, eating to 'restore' strength which boosted + strength by a point each time the cycle was performed; + substituting "while polymorphed" for sustain ability and + "rehumanize" for ring removal might have done that too */ + ATEMP(A_STR) = 0; /* repair of loss also overrides Fixed_abil */ + /* defer context.botl status update until after hunger message */ + } + switch (newhs) { case HUNGRY: if (Hallucination) { diff --git a/src/potion.c b/src/potion.c index f167bf710..4925b27b0 100644 --- a/src/potion.c +++ b/src/potion.c @@ -565,8 +565,8 @@ register struct obj *otmp; i = rn2(A_MAX); /* start at a random point */ for (ii = 0; ii < A_MAX; ii++) { lim = AMAX(i); - if (i == A_STR && u.uhs >= 3) - --lim; /* WEAK */ + /* this used to adjust 'lim' for A_STR when u.uhs was + WEAK or worse, but that's handled via ATEMP(A_STR) now */ if (ABASE(i) < lim) { ABASE(i) = lim; context.botl = 1; diff --git a/src/pray.c b/src/pray.c index f9fe72083..51dfbb5bb 100644 --- a/src/pray.c +++ b/src/pray.c @@ -343,7 +343,7 @@ int trouble; u.utrap = 0; break; case TROUBLE_STARVING: - losestr(-1); + /* temporarily lost strength recovery now handled by init_uhunger() */ /*FALLTHRU*/ case TROUBLE_HUNGRY: Your("%s feels content.", body_part(STOMACH));