]> granicus.if.org Git - nethack/commitdiff
extend sanity_check to shop items
authorPatR <rankin@nethack.org>
Mon, 21 Nov 2022 21:16:51 +0000 (13:16 -0800)
committerPatR <rankin@nethack.org>
Mon, 21 Nov 2022 21:16:51 +0000 (13:16 -0800)
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
src/shk.c

index 01a8a3419f48704cd27f985e20f219a03bfe03f2..886d16cf8c8b3b50037933738757a7b6d0e1117f 100644 (file)
@@ -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;
index b9c58c54dc0d251e692114d532fb0a347b652875..2d64a64f72cf4e28c23f6f1e0a46aca2b6e9028c 100644 (file)
--- a/src/shk.c
+++ b/src/shk.c
@@ -863,31 +863,32 @@ shop_keeper(char rmno)
 }
 
 boolean
-tended_shop(struct mkroomsroom)
+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;
 }