]> granicus.if.org Git - nethack/commitdiff
shrink_glob while away from level
authorPatR <rankin@nethack.org>
Sat, 13 Nov 2021 07:05:55 +0000 (23:05 -0800)
committerPatR <rankin@nethack.org>
Sat, 13 Nov 2021 07:05:55 +0000 (23:05 -0800)
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.

doc/fixes37.0
src/mkobj.c

index 6b9dcab1b1e000e88cd7992c2274a8a8ae7cee3e..ddcf7b334aab9a97d3395e57f333121a9388dcc3 100644 (file)
@@ -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
index 09c06eaa590f3a0d6388843c175b42e3e6d3420a..d8e7988a3ac53ed02eacf34793595879de620dc4 100644 (file)
@@ -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 */