From e25f8ec6e3b320daeba7049f204b0d74a15216df Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 11 Dec 2021 18:39:36 -0800 Subject: [PATCH] endless shrink_glob... A shrink_glob timer keeps running for a glob on the migrating objects list so shink_glob() needs to be aware of that. --- src/mkobj.c | 60 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/src/mkobj.c b/src/mkobj.c index 86be3b0e6..2737ae6eb 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -8,6 +8,7 @@ static void mkbox_cnts(struct obj *); static unsigned nextoid(struct obj *, struct obj *); static int item_on_ice(struct obj *); +static void shrinking_glob_gone(struct obj *); static void obj_timer_checks(struct obj *, xchar, xchar, int); static void container_weight(struct obj *); static struct obj *save_mtraits(struct obj *, struct monst *); @@ -282,6 +283,7 @@ mkbox_cnts(struct obj *box) if (otmp->timed) { (void) stop_timer(ROT_CORPSE, obj_to_any(otmp)); (void) stop_timer(REVIVE_MON, obj_to_any(otmp)); + (void) stop_timer(SHRINK_GLOB, obj_to_any(otmp)); } } else { register int tprob; @@ -1328,7 +1330,9 @@ start_glob_timeout( /* globs have quantity 1 and size which varies by multiples of 20 in owt; they don't become tainted with age, but every 25 turns this timer runs and reduces owt by 1; when it hits 0, destroy the glob (if some other - part of the program destroys it, the timer will be cancelled) */ + part of the program destroys it, the timer will be cancelled); + note: timer keeps going if an object gets buried or scheduled to + migrate to another level and can delete the glob in those states */ void shrink_glob( anything *arg, /* glob (in arg->a_obj) */ @@ -1361,18 +1365,15 @@ shrink_glob( /* 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); + moddelta = 25L - (delta % 25L); if (globloc == SET_ON_ICE) delta = (delta + 2L) / 3L; if (delta >= (long) obj->owt) { /* gone; no newsym() or message here--forthcoming map update for - level arrival is all that's needed; no owornmask handling is - necessary (obj is not in invent, monsters never wield globs) */ - obj_extract_self(obj); /* if contained, also updates container's - * weight (recursively when nested) */ - obfree(obj, (struct obj *) 0); + level arrival is all that's needed */ + shrinking_glob_gone(obj); } else { /* shrank but not gone; reduce remaining weight */ obj->owt -= (unsigned) delta; @@ -1488,21 +1489,7 @@ shrink_glob( && cansee(ox, oy)); /* weight has been reduced to 0 so destroy the glob */ - if (ininv) { - if (obj->owornmask) { - remove_worn_item(obj, FALSE); - stop_occupation(); - } - useupall(obj); /* freeinv()+obfree() */ - } else { - /* no owornmask handling necessary (when not in hero's invent, - can't be worn: monsters don't wield globs and shrink timer - can't fire for migrating objects); if glob was contained, it - has already been removed from its container and is now free */ - if (obj->where != OBJ_FREE) - obj_extract_self(obj); - obfree(obj, (struct obj *) 0); - } + shrinking_glob_gone(obj); if (seeit) { newsym(ox, oy); @@ -1522,6 +1509,35 @@ shrink_glob( } } +/* a glob has shrunk away to nothing; handle owornmask, then delete glob */ +static void +shrinking_glob_gone(struct obj *obj) +{ + if (obj->where == OBJ_INVENT) { + if (obj->owornmask) { + remove_worn_item(obj, FALSE); + stop_occupation(); + } + useupall(obj); /* freeinv()+obfree() */ + } else { + if (obj->where == OBJ_MIGRATING) { + /* clear destination flag so that obfree()'s check for freeing + a worn object doesn't get a false hit */ + obj->owornmask = 0L; + } else if (obj->where == OBJ_MINVENT) { + /* monsters don't wield globs so this isn't strictly needed */ + if (obj->owornmask && obj == MON_WEP(obj->ocarry)) + setmnotwielded(obj->ocarry, obj); /* clears owornmask */ + } + /* glob might already be free if shrink_glob() has removed it from + a container; otherwise, free it now */ + if (obj->where != OBJ_FREE) + obj_extract_self(obj); + /* delete it */ + obfree(obj, (struct obj *) 0); + } +} + void maybe_adjust_light(struct obj *obj, int old_range) {