From 6bf42b8891b5f18751f286b8675eea6b25bdbf37 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 21 Nov 2022 13:16:51 -0800 Subject: [PATCH] extend sanity_check to shop items Make object sanity checks examine obj->unpaid and obj->no_charge. Shopping is complicated; there might be corner cases that aren't handled correctly. --- src/mkobj.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- src/shk.c | 19 ++++++++++--------- 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/src/mkobj.c b/src/mkobj.c index 01a8a3419..886d16cf8 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2722,7 +2722,10 @@ obj_sanity_check(void) static void objlist_sanity(struct obj *objlist, int wheretype, const char *mesg) { - struct obj *obj; + struct obj *obj, *otmp; + struct monst *shkp; + boolean costly; + const char *why; for (obj = objlist; obj; obj = obj->nobj) { if (obj->where != wheretype) @@ -2734,6 +2737,50 @@ objlist_sanity(struct obj *objlist, int wheretype, const char *mesg) mesg, (struct monst *) 0); check_contained(obj, mesg); } + why = (const char *) 0; + if (obj->no_charge && obj->unpaid) { + why = "%s obj both unpaid and no_charge! %s %s: %s"; + } else if (obj->unpaid) { + /* unpaid is only applicable for directly carried objects and + for objects inside carried containers */ + otmp = obj; + while (otmp->where == OBJ_CONTAINED) + otmp = otmp->ocontainer; + if (otmp != obj) + obj->ox = otmp->ox, obj->oy = otmp->oy; + + if (otmp->where != OBJ_INVENT) + why = "%s unpaid obj not carried! %s %s: %s"; + else if ((costly = costly_spot(obj->ox, obj->oy)) == FALSE) + why = "%s unpaid obj not inside shop! %s %s: %s"; + else if ((shkp = shop_keeper(*in_rooms(obj->ox, obj->oy, + SHOPBASE))) == 0) + why = "%s unpaid obj inside untended shop! %s %s: %s"; + else if (!onshopbill(obj, shkp, TRUE)) + why = "%s unpaid obj not on shop bill! %s %s: %s"; + } else if (obj->no_charge) { + /* no_charge is only applicable for floor objects in shops and + for objects inside floor containers in shops */ + otmp = obj; + while (otmp->where == OBJ_CONTAINED) + otmp = otmp->ocontainer; + if (otmp != obj) + (void) get_obj_location(otmp, &obj->ox, &obj->oy, BURIED_TOO); + + if (otmp->where != OBJ_FLOOR) + why = "%s no_charge obj not on floor! %s %s: %s"; + else if ((costly = costly_spot(obj->ox, obj->oy)) == FALSE) + why = "%s no_charge obj not inside shop! %s %s: %s"; + else if ((shkp = shop_keeper(*in_rooms(obj->ox, obj->oy, + SHOPBASE))) == 0) + why = "%s no_charge obj inside untended shop! %s %s: %s"; + else if (onshopbill(obj, shkp, TRUE)) + why = "%s no_charge obj on shop bill! %s %s: %s"; + if (why) + insane_object(obj, why, mesg, (struct monst *) 0); + } /* unpaid and/or no_charge */ + if (why) + insane_object(obj, why, mesg, (struct monst *) 0); if (obj->owornmask) { char maskbuf[40]; boolean bc_ok = FALSE; diff --git a/src/shk.c b/src/shk.c index b9c58c54d..2d64a64f7 100644 --- a/src/shk.c +++ b/src/shk.c @@ -863,31 +863,32 @@ shop_keeper(char rmno) } boolean -tended_shop(struct mkroom* sroom) +tended_shop(struct mkroom *sroom) { struct monst *mtmp = sroom->resident; return !mtmp ? FALSE : (boolean) inhishop(mtmp); } -struct bill_x * +static struct bill_x * onbill(struct obj *obj, struct monst *shkp, boolean silent) { if (shkp) { - register struct bill_x *bp = ESHK(shkp)->bill_p; - register int ct = ESHK(shkp)->billct; + struct bill_x *bp; + int ct; - while (--ct >= 0) + for (ct = ESHK(shkp)->billct, bp = ESHK(shkp)->bill_p; + ct > 0; --ct, ++bp) { if (bp->bo_id == obj->o_id) { if (!obj->unpaid) - pline("onbill: paid obj on bill?"); + impossible("onbill: paid obj on bill?"); return bp; - } else { - bp++; } + } } if (obj->unpaid && !silent) - pline("onbill: unpaid obj not on bill?"); + impossible("onbill: unpaid obj %s?", + shkp ? "without shopkeeper" : "not on shk's bill"); return (struct bill_x *) 0; }