From: PatR Date: Sat, 13 Nov 2021 07:05:55 +0000 (-0800) Subject: shrink_glob while away from level X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=05a843826d0514b1b9a54db079e69622e7551237;p=nethack shrink_glob while away from level If the hero left a level that had globs on the floor or in floor containers or being carried by monsters and stayed away for a while, returning to the level only shrunk them by one unit of weight. Account for all the time away. The complexity of this has steadily grown; I hope its peak has been reached. --- diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 6b9dcab1b..ddcf7b334 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -883,6 +883,7 @@ misaligned potion colors due to lack of reset_glyphmap() following obj shuffle; this issue only impacted a new game closed doors were described as "horizontal closed door" or "vertical closed door" instead of just "closed door" +glob shrinkage while hero was away from glob's level wasn't handled properly curses: 'msg_window' option wasn't functional for curses unless the binary also included tty support diff --git a/src/mkobj.c b/src/mkobj.c index 09c06eaa5..d8e7988a3 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1331,12 +1331,14 @@ start_glob_timeout( part of the program destroys it, the timer will be cancelled) */ void shrink_glob( - anything *arg, /* glob (in arg->a_obj) */ - long expire_time UNUSED) /* timer callback data, not referenced here */ + anything *arg, /* glob (in arg->a_obj) */ + long expire_time) /* turn the timer should have gone off; if less than + * current 'moves', we're making up for lost time + * after leaving and then returning to this level */ { char globnambuf[BUFSZ]; - int globloc; struct obj *obj = arg->a_obj; + int globloc = item_on_ice(obj); boolean ininv = (obj->where == OBJ_INVENT), shrink = FALSE, gone = FALSE, updinv = FALSE; struct obj *contnr = (obj->where == OBJ_CONTAINED) ? obj->ocontainer : 0, @@ -1352,6 +1354,35 @@ shrink_glob( will be replaced in the feedback with info about this glob */ check_glob(obj, "shrink obj "); + /* + * If shrinkage occurred while we were on another level, catch up now. + */ + if (expire_time < g.moves && globloc != BURIED_UNDER_ICE) { + /* number of units of weight to remove */ + long delta = (g.moves - expire_time + 24L) / 25L, + /* leftover amount to use for new timer */ + moddelta = 25L - (delta % 25L); + + if (globloc == SET_ON_ICE) + delta = (delta + 2L) / 3L; + + if (delta >= (long) obj->owt) { + /* no newsym() or message here; forthcoming map update for + level arrival is all that's needed */ + obj_extract_self(obj); + obfree(obj, (struct obj *) 0); + + /* won't be a container carried by hero but might be a floor + one or one carried by a monster */ + if (contnr) + container_weight(contnr); + } else { + obj->owt -= (unsigned) delta; + start_glob_timeout(obj, moddelta); + } + return; + } + /* * When on ice, only shrink every third try. If buried under ice, * don't shrink at all, similar to being contained in an ice box @@ -1363,7 +1394,7 @@ shrink_glob( * monster, timer won't have a chance to run before meal is finished). */ if (eating_glob(obj) - || (globloc = item_on_ice(obj)) == BURIED_UNDER_ICE + || globloc == BURIED_UNDER_ICE || (globloc == SET_ON_ICE && (g.moves % 3L) == 1L)) { /* schedule next shrink attempt; for the being eaten case, the glob and its timer might be deleted before this kicks in */