]> granicus.if.org Git - nethack/commitdiff
fix #6144 - strength loss from severe hunger
authorPatR <rankin@nethack.org>
Mon, 9 Oct 2017 01:12:08 +0000 (18:12 -0700)
committerPatR <rankin@nethack.org>
Mon, 9 Oct 2017 01:12:08 +0000 (18:12 -0700)
It was possible to arbitrarily boost strength (up to its race-specific
limit) by wearing a ring of sustain ability, becoming weak from hunger
(but not actually losing strength due to Fixed_abil), removing the ring,
eating enough to stop being Weak, then repeat as desired.  I think you
could substitute polymorph for wearing ring, and rehumanize for removing
ring and get similar results, although that would be more tedious.

My first attempt to fix this was a lot more complicated.  This one puts
the temporary strength loss in ATEMP(A_STR) where it carries over from
normal form to polymophed form and back.  Fixed_abil doesn't prevent the
loss any more, nor its recovery.

One side-effect of the change is that the possibility of dying when
becoming weak from hunger (if Str gets down to 3, further attempts to
lower it take away HP instead of Str) no longer exists.  Using ATEMP()
instead of directly manipulating ABASE() means that current strength is
less but underlying base strength does not actually drop any more.

doc/fixes36.1
src/apply.c
src/attrib.c
src/eat.c
src/potion.c
src/pray.c

index e6f3e7c783f0e7614f7fa8229bc661f2ada35c4c..19c92f722fdc0d8a604ea1beca065fb6f42b6276 100644 (file)
@@ -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 <method>" 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
index e5df1b904a0067ee62a43e61d74a7eb142423b67..c477a4fb81c4a38bbe0fba7d28d0dae9b716ac8a 100644 (file)
@@ -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 */
index e0021632fdd86d40bdd30d6135bd449923fbe700..a3812d54bccb80268c22d15d185f60f8ce82e89d 100644 (file)
@@ -366,20 +366,27 @@ set_moreluck()
 void
 restore_attrib()
 {
-    int i;
+    int i, equilibrium;;
 
-    for (i = 0; i < A_MAX; i++) { /* all temporary losses/gains */
+    /*
+     * 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.
+     */
 
-        if (ATEMP(i) && ATIME(i)) {
+    for (i = 0; i < A_MAX; i++) { /* all temporary losses/gains */
+        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 */
index 9bd6346b006b908a54fb41d0d4f5fa3fbdc92499..6bbc1836b8099d6100a55202b40e75357cc2bd04 100644 (file)
--- 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) {
index f167bf710524ef0ad7df1de4daef3e7f5fa7784a..4925b27b05e62c07bf607a7deec2b6549ea28fd4 100644 (file)
@@ -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;
index f9fe72083ec9f72ddd399346cbc655edad295a2b..51dfbb5bb36b010b7a170ecfad6913793a03836e 100644 (file)
@@ -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));