From: Tung Nguyen Date: Tue, 8 Mar 2016 13:48:52 +0000 (+1100) Subject: Fix paid object on bill when angering another shopkeeper X-Git-Tag: NetHack-3.6.1_RC01~832^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e1d0faa5849c79741c29b962a51d356574ab3c06;p=nethack Fix paid object on bill when angering another shopkeeper 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. --- diff --git a/src/shk.c b/src/shk.c index addf8aac7..4d683f500 100644 --- 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);