From: PatR Date: Wed, 29 Jun 2022 18:46:31 +0000 (-0700) Subject: fix 'D' vs obj->bypass X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=46652d3cef8645f99147d684848de0a95c77eb47;p=nethack fix 'D' vs obj->bypass Reported by entrez: dropping items with the 'D' command sets obj->bypass which prevents an otherwise compatible item from merging with non-bypass floor stack. 'D' sets the bypass bit to avoid trouble if a dropped item triggers an explosion that destroys some of inventory (making straightforward invent traversal be unreliable). Having bypass set prevented merging with a floor stack that had that flag bit clear. That was very noticeable if a subset of a stack was picked up and then 'D' used to drop it again, resulting in two stacks instead of recombining into the original. Change the test for mergability to ignore bypass so items will merge when one has it set and other doesn't. And when successfully merging set bypass on the combined stack if either part had that set. --- diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index ca4ef5a93..791ecbe43 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -942,6 +942,8 @@ a migrating long worm that couldn't arrive could be placed at <0,0> while setting up another migration attempt to the level, triggering impossible "trying to place long worm tail at <0,0> mstate:8 on level" (message is confused; it should say "long worm" without tail) +dropping things with 'D' wouldn't merge them with compatible items already at + that floor spot because use of obj->bypass made them seem incompatible Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/invent.c b/src/invent.c index 4ed9a1d84..9db3c1d98 100644 --- a/src/invent.c +++ b/src/invent.c @@ -770,6 +770,17 @@ merged(struct obj **potmp, struct obj **pobj) #endif /*0*/ } + /* mergable() no longer requires 'bypass' to match; if 'obj' has + the bypass bit set, force the combined stack to have that too; + primarily in case this merge is occurring because stackobj() + is operating on an object just dropped by a monster that was + zapped with polymorph, we want bypass set in order to inhibit + the same zap from affecting the new combined stack when it hits + objects at the monster's spot (but also in case we're called by + code that's using obj->bypass to track 'already processed') */ + if (obj->bypass) + otmp->bypass = 1; + /* handle puddings a bit differently; absorption will free the other object automatically so we can just return out from here */ if (obj->globby) { @@ -4273,6 +4284,8 @@ feel_cockatrice(struct obj *otmp, boolean force_touch) } } +/* 'obj' is being placed on the floor; if it can merge with something that + is already there, combine them and discard obj as a separate object */ void stackobj(struct obj *obj) { @@ -4286,7 +4299,9 @@ stackobj(struct obj *obj) /* returns TRUE if obj & otmp can be merged; used in invent.c and mkobj.c */ boolean -mergable(register struct obj *otmp, register struct obj *obj) +mergable( + register struct obj *otmp, /* potential 'into' stack */ + register struct obj *obj) /* 'combine' stack */ { size_t objnamelth = 0, otmpnamelth = 0; @@ -4300,9 +4315,14 @@ mergable(register struct obj *otmp, register struct obj *obj) if (obj->oclass == COIN_CLASS) return TRUE; - if (obj->bypass != otmp->bypass - || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed) + if (obj->cursed != otmp->cursed || obj->blessed != otmp->blessed) + return FALSE; +#if 0 /* don't require 'bypass' to match; that results in items dropped + * via 'D' not stacking with compatible items already on the floor; + * caller who wants that behavior should use 'nomerge' instead */ + if (obj->bypass != otmp->bypass) return FALSE; +#endif if (obj->globby) return TRUE;