]> granicus.if.org Git - nethack/commitdiff
Fix paid object on bill when angering another shopkeeper
authorTung Nguyen <tungtn3@gmail.com>
Tue, 8 Mar 2016 13:48:52 +0000 (00:48 +1100)
committerTung Nguyen <tungtn3@gmail.com>
Fri, 11 Mar 2016 07:35:56 +0000 (18:35 +1100)
To test:

 1. Get a level layout with two shops facing each other, e.g. minetn-4.
 2. Sell a fragile object to one of the shops.
 3. Dig a pit in the other shop's door space so its shopkeeper stays out
    of the way.
 4. Pick up an object in that other shop so it appears on your bill.
 5. Zap a wand of striking at the first shop to break the fragile
    object.
 6. 'p'ay for the object picked up.

Expected result: Object gets the standard prompt to pay for it.

Actual result: "Paid object on bill??" followed by "Program in disorder
perhaps you'd better #quit." followed by the object being given to the
player for free.

The cause?  This comment going all the way back to 2002:

> /* FIXME: object handling should be limited to
>    items which are on this particular shk's bill */

Originally reported by PaRaD0xx in FreeNode's #NetHack IRC channel
whilst playing NAO343.

Based on DynaHack commit d995ed1 (Fix paid object on bill when angering
another shkp) by me.

src/shk.c

index addf8aac7ae1148ed5efd0adb15443be06bb90fd..4d683f500ad843def777c48ade9a8f46845d0bd9 100644 (file)
--- a/src/shk.c
+++ b/src/shk.c
@@ -38,7 +38,8 @@ STATIC_DCL struct monst *FDECL(next_shkp, (struct monst *, BOOLEAN_P));
 STATIC_DCL long FDECL(shop_debt, (struct eshk *));
 STATIC_DCL char *FDECL(shk_owns, (char *, struct obj *));
 STATIC_DCL char *FDECL(mon_owns, (char *, struct obj *));
-STATIC_DCL void FDECL(clear_unpaid, (struct obj *));
+STATIC_DCL void FDECL(clear_unpaid_obj, (struct monst *, struct obj *));
+STATIC_DCL void FDECL(clear_unpaid, (struct monst *, struct obj *));
 STATIC_DCL long FDECL(check_credit, (long, struct monst *));
 STATIC_DCL void FDECL(pay, (long, struct monst *));
 STATIC_DCL long FDECL(get_cost, (struct obj *, struct monst *));
@@ -260,15 +261,26 @@ boolean ghostly;
     }
 }
 
+/* Clear the unpaid bit on a single object and its contents. */
+STATIC_OVL void
+clear_unpaid_obj(shkp, otmp)
+struct monst *shkp;
+struct obj *otmp;
+{
+    if (Has_contents(otmp))
+        clear_unpaid(shkp, otmp->cobj);
+    if (onbill(otmp, shkp, TRUE))
+        otmp->unpaid = 0;
+}
+
 /* Clear the unpaid bit on all of the objects in the list. */
 STATIC_OVL void
-clear_unpaid(list)
-register struct obj *list;
+clear_unpaid(shkp, list)
+struct monst *shkp;
+struct obj *list;
 {
     while (list) {
-        if (Has_contents(list))
-            clear_unpaid(list->cobj);
-        list->unpaid = 0;
+        clear_unpaid_obj(shkp, list);
         list = list->nobj;
     }
 }
@@ -281,20 +293,17 @@ register struct monst *shkp;
     register struct obj *obj;
     register struct monst *mtmp;
 
-    /* FIXME: object handling should be limited to
-       items which are on this particular shk's bill */
-
-    clear_unpaid(invent);
-    clear_unpaid(fobj);
-    clear_unpaid(level.buriedobjlist);
+    clear_unpaid(shkp, invent);
+    clear_unpaid(shkp, fobj);
+    clear_unpaid(shkp, level.buriedobjlist);
     if (thrownobj)
-        thrownobj->unpaid = 0;
+        clear_unpaid_obj(shkp, thrownobj);
     if (kickedobj)
-        kickedobj->unpaid = 0;
+        clear_unpaid_obj(shkp, kickedobj);
     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
-        clear_unpaid(mtmp->minvent);
+        clear_unpaid(shkp, mtmp->minvent);
     for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
-        clear_unpaid(mtmp->minvent);
+        clear_unpaid(shkp, mtmp->minvent);
 
     while ((obj = billobjs) != 0) {
         obj_extract_self(obj);