diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 494e4c1b8..49d66b5a0 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -877,6 +877,9 @@ restoring while attached ball or chain is on floor in a breach of a shop wall might trigger an impossible about being positioned too far from hero don't try to catch up for lost time for shop damage repair in restdamage() called from getlev(); let normal shopkeeper movement take care of it +putting objects into a container with menustyle=traditional and then taking + them back out with #tip would result in complaints about obj bypass + bit being set if sanity_check was On Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/src/invent.c b/src/invent.c index be8fb8d73..2334cb3c5 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2051,15 +2051,16 @@ ggetobj(const char *word, int (*fn)(OBJ_P), int mx, * Walk through the chain starting at objchn and ask for all objects * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull) * whether the action in question (i.e., fn) has to be performed. - * If allflag then no questions are asked. Mx gives the max number - * of objects to be treated. Return the number of objects treated. */ int -askchain(struct obj **objchn, /* *objchn might change */ - const char *olets, /* olets is an Obj Class char array */ - int allflag, - int (*fn)(OBJ_P), int (*ckfn)(OBJ_P), - int mx, const char *word) +askchain( + struct obj **objchn, /* *objchn might change */ + const char *olets, /* olets is an Obj Class char array */ + int allflag, /* bypass prompting about individual items */ + int (*fn)(OBJ_P), /* action to perform on selected items */ + int (*ckfn)(OBJ_P), /* callback to decided if an item is selectable */ + int mx, /* if non-0, maximum number of objects to process */ + const char *word) /* name of the action */ { struct obj *otmp, *otmpo; char sym, ilet; @@ -2202,7 +2203,10 @@ askchain(struct obj **objchn, /* *objchn might change */ pline("No applicable objects."); ret: unsortloot(&sortedchn); - bypass_objlist(*objchn, FALSE); + /* can't just clear bypass bit of items in objchn because the action + applied to selected ones might move them to a different chain */ + /*bypass_objlist(*objchn, FALSE);*/ + clear_bypasses(); return cnt; } diff --git a/src/pickup.c b/src/pickup.c index b762e7d3d..759f0926d 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -2697,10 +2697,10 @@ stash_ok(struct obj *obj) } int -use_container(struct obj **objp, - int held, - boolean more_containers) /* True iff #loot multiple and this - isn't last one */ +use_container( + struct obj **objp, + int held, + boolean more_containers) /* True iff #loot multiple and this isn't last */ { struct obj *otmp, *obj = *objp; boolean quantum_cat, cursed_mbag, loot_out, loot_in, loot_in_first, @@ -2817,7 +2817,8 @@ use_container(struct obj **objp, } else { c = in_or_out_menu(qbuf, g.current_container, outmaybe, inokay, - (boolean) (used != ECMD_OK), more_containers); + (boolean) (used != ECMD_OK), + more_containers); } } else { /* TRADITIONAL or COMBINATION */ xbuf[0] = '\0'; /* list of extra acceptable responses */ diff --git a/src/worn.c b/src/worn.c index 1040715e4..74578fc90 100644 --- a/src/worn.c +++ b/src/worn.c @@ -6,6 +6,7 @@ #include "hack.h" static void m_lose_armor(struct monst *, struct obj *); +static void clear_bypass(struct obj *); static void m_dowear_type(struct monst *, long, boolean, boolean); static int extra_pref(struct monst *, struct obj *); @@ -786,11 +787,25 @@ m_lose_armor(struct monst *mon, struct obj *obj) newsym(mon->mx, mon->my); } -/* all objects with their bypass bit set should now be reset to normal */ +/* clear bypass bits for an object chain, plus contents if applicable */ +static void +clear_bypass(struct obj *objchn) +{ + struct obj *o; + + for (o = objchn; o; o = o->nobj) { + o->bypass = 0; + if (Has_contents(o)) + clear_bypass(o->cobj); + } +} + +/* all objects with their bypass bit set should now be reset to normal; + this can be a relatively expensive operation so is only called if + g.context.bypasses is set */ void clear_bypasses(void) { - struct obj *otmp, *nobj; struct monst *mtmp; /* @@ -800,41 +815,15 @@ clear_bypasses(void) * bypassed. */ - for (otmp = fobj; otmp; otmp = nobj) { - nobj = otmp->nobj; - if (otmp->bypass) { - otmp->bypass = 0; - - /* bypass will have inhibited any stacking, but since it's - * used for polymorph handling, the objects here probably - * have been transformed and won't be stacked in the usual - * manner afterwards; so don't bother with this. - * [Changing the fobj chain mid-traversal would also be risky.] - */ -#if 0 - if (objects[otmp->otyp].oc_merge) { - xchar ox, oy; - - (void) get_obj_location(otmp, &ox, &oy, 0); - stack_object(otmp); - newsym(ox, oy); - } -#endif /*0*/ - } - } - for (otmp = g.invent; otmp; otmp = otmp->nobj) - otmp->bypass = 0; - for (otmp = g.migrating_objs; otmp; otmp = otmp->nobj) - otmp->bypass = 0; - for (otmp = g.level.buriedobjlist; otmp; otmp = otmp->nobj) - otmp->bypass = 0; - for (otmp = g.billobjs; otmp; otmp = otmp->nobj) - otmp->bypass = 0; + clear_bypass(fobj); + clear_bypass(g.invent); + clear_bypass(g.migrating_objs); + clear_bypass(g.level.buriedobjlist); + clear_bypass(g.billobjs); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) - otmp->bypass = 0; + clear_bypass(mtmp->minvent); /* long worm created by polymorph has mon->mextra->mcorpsenm set to PM_LONG_WORM to flag it as not being subject to further polymorph (so polymorph zap won't hit monster to transform it @@ -844,22 +833,21 @@ clear_bypasses(void) MCORPSENM(mtmp) = NON_PM; } for (mtmp = g.migrating_mons; mtmp; mtmp = mtmp->nmon) { - for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) - otmp->bypass = 0; + clear_bypass(mtmp->minvent); /* no MCORPSENM(mtmp)==PM_LONG_WORM check here; long worms can't be just created by polymorph and migrating at the same time */ } /* this is a no-op since mydogs is only non-Null during level change or final ascension and we aren't called at those times, but be thorough */ for (mtmp = g.mydogs; mtmp; mtmp = mtmp->nmon) - for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) - otmp->bypass = 0; - - /* ball can be "floating", not on any chain */ + clear_bypass(mtmp->minvent); + /* ball and chain can be "floating", not on any object chain (when + hero is swallowed by an engulfing monster, for instance) */ if (uball) uball->bypass = 0; + if (uchain) + uchain->bypass = 0; - /* g.billobjs and g.mydogs chains don't matter here */ g.context.bypasses = FALSE; }