Don't attempt to cache encumber_msg result

There was only one point in the code at which this caching was
being done, and it was incorrect: it's possible for the result of
near_capacity to change during a monster turn because monster
actions can change either inventory weight or carry capacity.

The bug was particularly relevant in cases where a character
polymorphed into a slow weak monster gets attacked by a monster
that moves at normal speed: due to the polyform being slow, the
normal-speed monster gets in a lot of attacks and causes a
rehumanization, but due to the polyform being weak, it was
burdened at the start of the monster turn, and so when that
penalty is (due to the bug) applied to the next turn it can
mean that the character misses the next turn too, and may end up
dying as a result.
This commit is contained in:
Alex Smith
2025-11-24 02:07:23 +00:00
parent ae516ddc67
commit fce66245ca
20 changed files with 50 additions and 46 deletions
+2
View File
@@ -1535,6 +1535,8 @@ some messages by amorous demons and mail daemon were delivered as verbal ones
travel couldn't find the vibrating square if it was covered by an object or travel couldn't find the vibrating square if it was covered by an object or
a monster; it isn't really a trap so treat it as special terrain a monster; it isn't really a trap so treat it as special terrain
travel would stop one step in front of known vibrating square like other traps travel would stop one step in front of known vibrating square like other traps
fix bug which delayed burden changes due to monster actions (e.g. reverting to
natural form due to damage, changing carry capacity) for one turn
Fixes to 3.7.0-x General Problems Exposed Via git Repository Fixes to 3.7.0-x General Problems Exposed Via git Repository
+1 -1
View File
@@ -2405,7 +2405,7 @@ extern int query_category(const char *, struct obj *, int, menu_item **, int) NO
extern int query_objlist(const char *, struct obj **, int, menu_item **, int, extern int query_objlist(const char *, struct obj **, int, menu_item **, int,
boolean(*)(struct obj *)) NONNULLARG24; boolean(*)(struct obj *)) NONNULLARG24;
extern struct obj *pick_obj(struct obj *) NONNULLARG1; extern struct obj *pick_obj(struct obj *) NONNULLARG1;
extern int encumber_msg(void); extern void encumber_msg(void);
extern int container_at(coordxy, coordxy, boolean); extern int container_at(coordxy, coordxy, boolean);
extern int doloot(void); extern int doloot(void);
extern void observe_quantum_cat(struct obj *, boolean, boolean) NONNULLARG1; extern void observe_quantum_cat(struct obj *, boolean, boolean) NONNULLARG1;
+7 -3
View File
@@ -90,7 +90,7 @@ moveloop_preamble(boolean resuming)
fix_shop_damage(); fix_shop_damage();
} }
(void) encumber_msg(); /* in case they auto-picked up something */ encumber_msg(); /* in case they auto-picked up something */
if (gd.defer_see_monsters) { if (gd.defer_see_monsters) {
gd.defer_see_monsters = FALSE; gd.defer_see_monsters = FALSE;
see_monsters(); see_monsters();
@@ -197,7 +197,7 @@ moveloop_core(void)
u.umovement -= NORMAL_SPEED; u.umovement -= NORMAL_SPEED;
do { /* hero can't move this turn loop */ do { /* hero can't move this turn loop */
mvl_wtcap = encumber_msg(); encumber_msg();
svc.context.mon_moving = TRUE; svc.context.mon_moving = TRUE;
do { do {
@@ -207,6 +207,10 @@ moveloop_core(void)
} while (monscanmove); } while (monscanmove);
svc.context.mon_moving = FALSE; svc.context.mon_moving = FALSE;
/* this needs to be after the monster movement loop in
case monster actions affected burden, e.g. rehumanize */
mvl_wtcap = near_capacity();
if (!monscanmove && u.umovement < NORMAL_SPEED) { if (!monscanmove && u.umovement < NORMAL_SPEED) {
/* both hero and monsters are out of steam this round */ /* both hero and monsters are out of steam this round */
struct monst *mtmp; struct monst *mtmp;
@@ -392,7 +396,7 @@ moveloop_core(void)
inventory may have changed in, e.g., nh_timeout(); we do inventory may have changed in, e.g., nh_timeout(); we do
need two checks here so that the player gets feedback need two checks here so that the player gets feedback
immediately if their own action encumbered them */ immediately if their own action encumbered them */
(void) encumber_msg(); encumber_msg();
#ifdef STATUS_HILITES #ifdef STATUS_HILITES
if (iflags.hilite_delta) if (iflags.hilite_delta)
+5 -5
View File
@@ -191,7 +191,7 @@ adjattrib(
if (msgflg <= 0) if (msgflg <= 0)
You_feel("%s%s!", (incr > 1 || incr < -1) ? "very " : "", attrstr); You_feel("%s%s!", (incr > 1 || incr < -1) ? "very " : "", attrstr);
if (program_state.in_moveloop && (ndx == A_STR || ndx == A_CON)) if (program_state.in_moveloop && (ndx == A_STR || ndx == A_CON))
(void) encumber_msg(); encumber_msg();
return TRUE; return TRUE;
} }
@@ -401,7 +401,7 @@ poisoned(
/* "Poisoned by a poisoned ___" is redundant */ /* "Poisoned by a poisoned ___" is redundant */
done(strstri(pkiller, "poison") ? DIED : POISONING); done(strstri(pkiller, "poison") ? DIED : POISONING);
} }
(void) encumber_msg(); encumber_msg();
} }
void void
@@ -477,7 +477,7 @@ restore_attrib(void)
} }
} }
if (disp.botl) if (disp.botl)
(void) encumber_msg(); encumber_msg();
} }
#define AVAL 50 /* tune value for exercise gains */ #define AVAL 50 /* tune value for exercise gains */
@@ -511,7 +511,7 @@ exercise(int i, boolean inc_or_dec)
(inc_or_dec) ? "inc" : "dec", AEXE(i)); (inc_or_dec) ? "inc" : "dec", AEXE(i));
} }
if (svm.moves > 0 && (i == A_STR || i == A_CON)) if (svm.moves > 0 && (i == A_STR || i == A_CON))
(void) encumber_msg(); encumber_msg();
} }
staticfn void staticfn void
@@ -753,7 +753,7 @@ redist_attr(void)
if (ABASE(i) < ATTRMIN(i)) if (ABASE(i) < ATTRMIN(i))
ABASE(i) = ATTRMIN(i); ABASE(i) = ATTRMIN(i);
} }
/* (void) encumber_msg(); -- caller needs to do this */ /* encumber_msg(); -- caller needs to do this */
} }
/* apply minor variation to attributes */ /* apply minor variation to attributes */
+1 -1
View File
@@ -34,7 +34,7 @@ ballrelease(boolean showmsg)
/* [this used to test 'if (uwep != uball)' but that always passes /* [this used to test 'if (uwep != uball)' but that always passes
after the setuwep() above] */ after the setuwep() above] */
freeinv(uball); /* remove from inventory but don't place on floor */ freeinv(uball); /* remove from inventory but don't place on floor */
(void) encumber_msg(); encumber_msg();
} }
} }
+3 -3
View File
@@ -839,7 +839,7 @@ dropz(struct obj *obj, boolean with_impact)
map_object(obj, 0); map_object(obj, 0);
newsym(u.ux, u.uy); /* remap location under self */ newsym(u.ux, u.uy); /* remap location under self */
} }
(void) encumber_msg(); encumber_msg();
} }
/* when swallowed, move dropped object from OBJ_FREE to u.ustuck's inventory; /* when swallowed, move dropped object from OBJ_FREE to u.ustuck's inventory;
@@ -2431,7 +2431,7 @@ set_wounded_legs(long side, int timex)
direct assignment instead of bitwise-OR so getting wounded in direct assignment instead of bitwise-OR so getting wounded in
one leg mysteriously healed the other */ one leg mysteriously healed the other */
EWounded_legs |= side; EWounded_legs |= side;
(void) encumber_msg(); encumber_msg();
} }
void void
@@ -2470,7 +2470,7 @@ heal_legs(
more when steed becomes healthy, then possible floor more when steed becomes healthy, then possible floor
feedback, then able to carry less when back on foot]. */ feedback, then able to carry less when back on foot]. */
if (how == 0) if (how == 0)
(void) encumber_msg(); encumber_msg();
} }
} }
+1 -1
View File
@@ -671,7 +671,7 @@ Gloves_off(void)
} }
setworn((struct obj *) 0, W_ARMG); setworn((struct obj *) 0, W_ARMG);
svc.context.takeoff.cancelled_don = FALSE; svc.context.takeoff.cancelled_don = FALSE;
(void) encumber_msg(); /* immediate feedback for GoP */ encumber_msg(); /* immediate feedback for GoP */
/* usually can't remove gloves when they're slippery but it can /* usually can't remove gloves when they're slippery but it can
be done by having them fall off (polymorph), stolen, or be done by having them fall off (polymorph), stolen, or
+4 -4
View File
@@ -268,7 +268,7 @@ throw_obj(struct obj *obj, int shotlimit)
} }
freeinv(otmp); freeinv(otmp);
throwit(otmp, wep_mask, twoweap, oldslot); throwit(otmp, wep_mask, twoweap, oldslot);
(void) encumber_msg(); encumber_msg();
} }
gm.m_shot.n = gm.m_shot.i = 0; gm.m_shot.n = gm.m_shot.i = 0;
gm.m_shot.o = STRANGE_OBJECT; gm.m_shot.o = STRANGE_OBJECT;
@@ -1699,7 +1699,7 @@ throwit(
if (!impaired && rn2(100)) { if (!impaired && rn2(100)) {
pline("%s to your hand!", Tobjnam(obj, "return")); pline("%s to your hand!", Tobjnam(obj, "return"));
obj = addinv_before(obj, oldslot); obj = addinv_before(obj, oldslot);
(void) encumber_msg(); encumber_msg();
/* addinv autoquivers an aklys if quiver is empty; /* addinv autoquivers an aklys if quiver is empty;
if obj is quivered, remove it before wielding */ if obj is quivered, remove it before wielding */
if (obj->owornmask & W_QUIVER) if (obj->owornmask & W_QUIVER)
@@ -1886,7 +1886,7 @@ return_throw_to_inv(
set_twoweap(TRUE); /* u.twoweap = TRUE */ set_twoweap(TRUE); /* u.twoweap = TRUE */
} }
(void) encumber_msg(); encumber_msg();
return obj; return obj;
} }
@@ -2124,7 +2124,7 @@ thitmonst(
sho_obj_return_to_u(obj); sho_obj_return_to_u(obj);
obj = addinv(obj); /* back into your inventory */ obj = addinv(obj); /* back into your inventory */
nhUse(obj); nhUse(obj);
(void) encumber_msg(); encumber_msg();
} }
return 1; /* caller doesn't need to place it */ return 1; /* caller doesn't need to place it */
} }
+1 -1
View File
@@ -130,7 +130,7 @@ init_uhunger(void)
u.uhs = NOT_HUNGRY; u.uhs = NOT_HUNGRY;
if (ATEMP(A_STR) < 0) { if (ATEMP(A_STR) < 0) {
ATEMP(A_STR) = 0; ATEMP(A_STR) = 0;
(void) encumber_msg(); encumber_msg();
} }
} }
+1 -1
View File
@@ -1269,7 +1269,7 @@ hold_another_object(
prinv(hold_msg, obj, oquan); prinv(hold_msg, obj, oquan);
/* obj made it into inventory and is staying there */ /* obj made it into inventory and is staying there */
update_inventory(); update_inventory();
(void) encumber_msg(); encumber_msg();
} }
} }
return obj; return obj;
+2 -2
View File
@@ -1657,7 +1657,7 @@ shrink_glob(
} }
if (updinv) { if (updinv) {
update_inventory(); update_inventory();
(void) encumber_msg(); encumber_msg();
} }
} }
@@ -2892,7 +2892,7 @@ hornoplenty(
/* item still in magic horn was weightless; when it's now in /* item still in magic horn was weightless; when it's now in
a carried container, hero's encumbrance could change */ a carried container, hero's encumbrance could change */
if (carried(targetbox)) { if (carried(targetbox)) {
(void) encumber_msg(); encumber_msg();
update_inventory(); /* for contents count or wizweight */ update_inventory(); /* for contents count or wizweight */
} }
} else { } else {
+3 -5
View File
@@ -1972,10 +1972,9 @@ pickup_prinv(
} }
/* /*
* prints a message if encumbrance changed since the last check and * prints a message if encumbrance changed since the last check
* returns the new encumbrance value (from near_capacity()).
*/ */
int void
encumber_msg(void) encumber_msg(void)
{ {
int newcap = near_capacity(); int newcap = near_capacity();
@@ -2018,7 +2017,6 @@ encumber_msg(void)
} }
go.oldcap = newcap; go.oldcap = newcap;
return newcap;
} }
/* Is there a container at x,y. Optional: return count of containers at x,y */ /* Is there a container at x,y. Optional: return count of containers at x,y */
@@ -3821,7 +3819,7 @@ tipcontainer(struct obj *box) /* or bag */
if (targetbox) if (targetbox)
targetbox->owt = weight(targetbox); targetbox->owt = weight(targetbox);
if (srcheld || dstheld) if (srcheld || dstheld)
(void) encumber_msg(); encumber_msg();
} }
if (srcheld || dstheld) if (srcheld || dstheld)
+4 -4
View File
@@ -425,7 +425,7 @@ newman(void)
done(DIED); done(DIED);
/* must have been life-saved to get here */ /* must have been life-saved to get here */
newuhs(FALSE); newuhs(FALSE);
(void) encumber_msg(); /* used to be done by redist_attr() */ encumber_msg(); /* used to be done by redist_attr() */
return; /* lifesaved */ return; /* lifesaved */
} }
} }
@@ -454,7 +454,7 @@ newman(void)
disp.botl = TRUE; disp.botl = TRUE;
see_monsters(); see_monsters();
(void) encumber_msg(); encumber_msg();
retouch_equipment(2); retouch_equipment(2);
if (!uarmg) if (!uarmg)
@@ -1012,7 +1012,7 @@ polymon(int mntmp)
disp.botl = TRUE; disp.botl = TRUE;
gv.vision_full_recalc = 1; gv.vision_full_recalc = 1;
see_monsters(); see_monsters();
(void) encumber_msg(); encumber_msg();
retouch_equipment(2); retouch_equipment(2);
/* this might trigger a recursive call to polymon() [stone golem /* this might trigger a recursive call to polymon() [stone golem
@@ -1398,7 +1398,7 @@ rehumanize(void)
disp.botl = TRUE; disp.botl = TRUE;
gv.vision_full_recalc = 1; gv.vision_full_recalc = 1;
(void) encumber_msg(); encumber_msg();
if (was_flying && !Flying && u.usteed) if (was_flying && !Flying && u.usteed)
You("and %s return gently to the %s.", You("and %s return gently to the %s.",
mon_nam(u.usteed), surface(u.ux, u.uy)); mon_nam(u.usteed), surface(u.ux, u.uy));
+2 -2
View File
@@ -550,7 +550,7 @@ fix_worst_trouble(int trouble)
disp.botl = TRUE; disp.botl = TRUE;
} }
} }
(void) encumber_msg(); encumber_msg();
break; break;
case TROUBLE_BLIND: { /* handles deafness as well as blindness */ case TROUBLE_BLIND: { /* handles deafness as well as blindness */
char msgbuf[BUFSZ]; char msgbuf[BUFSZ];
@@ -1263,7 +1263,7 @@ pleased(aligntyp g_align)
if (ABASE(A_STR) < AMAX(A_STR)) { if (ABASE(A_STR) < AMAX(A_STR)) {
ABASE(A_STR) = AMAX(A_STR); ABASE(A_STR) = AMAX(A_STR);
disp.botl = TRUE; /* before potential message */ disp.botl = TRUE; /* before potential message */
(void) encumber_msg(); encumber_msg();
} }
if (u.uhunger < 900) if (u.uhunger < 900)
init_uhunger(); init_uhunger();
+3 -3
View File
@@ -601,7 +601,7 @@ steal(struct monst *mtmp, char *objnambuf)
&& mtmp->data->mlet == S_NYMPH) && mtmp->data->mlet == S_NYMPH)
++named; ++named;
urgent_pline("%s stole %s.", named ? "She" : Monnambuf, doname(otmp)); urgent_pline("%s stole %s.", named ? "She" : Monnambuf, doname(otmp));
(void) encumber_msg(); encumber_msg();
could_petrify = (otmp->otyp == CORPSE could_petrify = (otmp->otyp == CORPSE
&& touch_petrifies(&mons[otmp->corpsenm])); && touch_petrifies(&mons[otmp->corpsenm]));
otmp->how_lost = LOST_STOLEN; otmp->how_lost = LOST_STOLEN;
@@ -762,7 +762,7 @@ stealamulet(struct monst *mtmp)
pline("%s steals %s!", Some_Monnam(mtmp), buf); pline("%s steals %s!", Some_Monnam(mtmp), buf);
if (can_teleport(mtmp->data) && !tele_restrict(mtmp)) if (can_teleport(mtmp->data) && !tele_restrict(mtmp))
(void) rloc(mtmp, RLOC_MSG); (void) rloc(mtmp, RLOC_MSG);
(void) encumber_msg(); encumber_msg();
} }
} }
@@ -799,7 +799,7 @@ maybe_absorb_item(
otense(obj, "are"), hand_s); otense(obj, "are"), hand_s);
} }
freeinv(obj); freeinv(obj);
(void) encumber_msg(); encumber_msg();
} else { } else {
/* not carried; presumably thrown or kicked */ /* not carried; presumably thrown or kicked */
if (canspotmon(mon)) if (canspotmon(mon))
+1 -1
View File
@@ -811,7 +811,7 @@ dismount_steed(
(void) float_down(0L, W_SADDLE); (void) float_down(0L, W_SADDLE);
gi.in_steed_dismounting = FALSE; gi.in_steed_dismounting = FALSE;
disp.botl = TRUE; disp.botl = TRUE;
(void) encumber_msg(); encumber_msg();
gv.vision_full_recalc = 1; gv.vision_full_recalc = 1;
} else } else
disp.botl = TRUE; disp.botl = TRUE;
+5 -5
View File
@@ -3907,7 +3907,7 @@ float_up(void)
float_vs_flight(); /* set BFlying, also BLevitation if still trapped */ float_vs_flight(); /* set BFlying, also BLevitation if still trapped */
/* levitation gives maximum carrying capacity, so encumbrance /* levitation gives maximum carrying capacity, so encumbrance
state might be reduced */ state might be reduced */
(void) encumber_msg(); encumber_msg();
return; return;
} }
@@ -3954,7 +3954,7 @@ float_down(
: (u.utraptype == TT_BURIEDBALL) ? "chain" : (u.utraptype == TT_BURIEDBALL) ? "chain"
: (u.utraptype == TT_LAVA) ? "lava" : (u.utraptype == TT_LAVA) ? "lava"
: "ground"); /* TT_INFLOOR */ : "ground"); /* TT_INFLOOR */
(void) encumber_msg(); /* carrying capacity might have changed */ encumber_msg(); /* carrying capacity might have changed */
return 0; return 0;
} }
disp.botl = TRUE; disp.botl = TRUE;
@@ -3965,14 +3965,14 @@ float_down(
* unless hero is stuck in floor */ * unless hero is stuck in floor */
if (Flying) { if (Flying) {
You("have stopped levitating and are now flying."); You("have stopped levitating and are now flying.");
(void) encumber_msg(); /* carrying capacity might have changed */ encumber_msg(); /* carrying capacity might have changed */
return 1; return 1;
} }
} }
if (u.uswallow) { if (u.uswallow) {
You("float down, but you are still %s.", You("float down, but you are still %s.",
digests(u.ustuck->data) ? "swallowed" : "engulfed"); digests(u.ustuck->data) ? "swallowed" : "engulfed");
(void) encumber_msg(); encumber_msg();
return 1; return 1;
} }
@@ -4056,7 +4056,7 @@ float_down(
/* levitation gives maximum carrying capacity, so having it end /* levitation gives maximum carrying capacity, so having it end
potentially triggers greater encumbrance; do this after potentially triggers greater encumbrance; do this after
'come down' messages, before trap activation or autopickup */ 'come down' messages, before trap activation or autopickup */
(void) encumber_msg(); encumber_msg();
/* can't rely on u.uz0 for detecting trap door-induced level change; /* can't rely on u.uz0 for detecting trap door-induced level change;
it gets changed to reflect the new level before we can check it */ it gets changed to reflect the new level before we can check it */
+2 -2
View File
@@ -958,7 +958,7 @@ chwepon(struct obj *otmp, int amount)
if (otyp != STRANGE_OBJECT) if (otyp != STRANGE_OBJECT)
makeknown(otyp); makeknown(otyp);
if (multiple) if (multiple)
(void) encumber_msg(); encumber_msg();
return 1; return 1;
} else if (uwep->otyp == CRYSKNIFE && amount < 0) { } else if (uwep->otyp == CRYSKNIFE && amount < 0) {
multiple = (uwep->quan > 1L); multiple = (uwep->quan > 1L);
@@ -975,7 +975,7 @@ chwepon(struct obj *otmp, int amount)
if (otyp != STRANGE_OBJECT && otmp->bknown) if (otyp != STRANGE_OBJECT && otmp->bknown)
makeknown(otyp); makeknown(otyp);
if (multiple) if (multiple)
(void) encumber_msg(); encumber_msg();
return 1; return 1;
} }
+1 -1
View File
@@ -37,7 +37,7 @@ wiz_wish(void) /* Unlimited wishes for debug mode by Paul Polderman */
flags.verbose = FALSE; flags.verbose = FALSE;
makewish(); makewish();
flags.verbose = save_verbose; flags.verbose = save_verbose;
(void) encumber_msg(); encumber_msg();
} else } else
pline(unavailcmd, ecname_from_fn(wiz_wish)); pline(unavailcmd, ecname_from_fn(wiz_wish));
return ECMD_OK; return ECMD_OK;
+1 -1
View File
@@ -1214,7 +1214,7 @@ unturn_dead(struct monst *mon)
} }
} }
if (is_u && res) if (is_u && res)
(void) encumber_msg(); encumber_msg();
return res; return res;
} }