From ed9647310a9a7f921a55f6ce9c7fa3988acbd5d1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 10 Jul 2021 19:41:55 -0400 Subject: [PATCH] deal with gold leaving shop via scatter() fixes #538 --- include/extern.h | 3 ++- src/dokick.c | 2 +- src/explode.c | 33 ++++++++++++++++++++++-- src/shk.c | 66 ++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 87 insertions(+), 17 deletions(-) diff --git a/include/extern.h b/include/extern.h index 3f0db893e..0a54e94dc 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2355,7 +2355,7 @@ extern void price_quote(struct obj *); extern void shk_chat(struct monst *); extern void check_unpaid_usage(struct obj *, boolean); extern void check_unpaid(struct obj *); -extern void costly_gold(xchar, xchar, long); +extern void costly_gold(xchar, xchar, long, boolean); extern long get_cost_of_shop_item(struct obj *, int *); extern int oid_price_adjustment(struct obj *, unsigned); extern boolean block_door(xchar, xchar); @@ -2364,6 +2364,7 @@ extern char *shk_your(char *, struct obj *); extern char *Shk_Your(char *, struct obj *); extern void globby_bill_fixup(struct obj *, struct obj *); extern void globby_donation(struct obj *, struct obj *); +extern void credit_report(struct monst *shkp, int idx, boolean silent); /* ### shknam.c ### */ diff --git a/src/dokick.c b/src/dokick.c index 387c7037a..6fa333553 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -689,7 +689,7 @@ really_kick_object(xchar x, xchar y) if (costly && (!costly_spot(g.bhitpos.x, g.bhitpos.y) || *in_rooms(x, y, SHOPBASE) != bhitroom)) { if (isgold) - costly_gold(x, y, g.kickedobj->quan); + costly_gold(x, y, g.kickedobj->quan, FALSE); else (void) stolen_value(g.kickedobj, x, y, (boolean) shkp->mpeaceful, FALSE); diff --git a/src/explode.c b/src/explode.c index f3d168b1d..f1a5e89ae 100644 --- a/src/explode.c +++ b/src/explode.c @@ -644,7 +644,8 @@ scatter(int sx, int sy, /* location of objects to scatter */ long qtmp; boolean used_up; boolean individual_object = obj ? TRUE : FALSE; - struct monst *mtmp; + boolean shop_origin, lostgoods = FALSE; + struct monst *mtmp, *shkp = 0; struct scatter_chain *stmp, *stmp2 = 0; struct scatter_chain *schain = (struct scatter_chain *) 0; long total = 0L; @@ -653,6 +654,11 @@ scatter(int sx, int sy, /* location of objects to scatter */ impossible("scattered object <%d,%d> not at scatter site <%d,%d>", obj->ox, obj->oy, sx, sy); + shop_origin = ((shkp = shop_keeper(*in_rooms(sx, sy, SHOPBASE))) != 0 + && costly_spot(sx, sy)); + if (shop_origin) + credit_report(shkp, 0, TRUE); /* establish baseline, without msgs */ + while ((otmp = (individual_object ? obj : g.level.objects[sx][sy])) != 0) { if (otmp == uball || otmp == uchain) { boolean waschain = (otmp == uchain); @@ -792,14 +798,35 @@ scatter(int sx, int sy, /* location of objects to scatter */ } for (stmp = schain; stmp; stmp = stmp2) { int x, y; + boolean obj_left_shop = FALSE; stmp2 = stmp->next; x = stmp->ox; y = stmp->oy; if (stmp->obj) { - if (x != sx || y != sy) + if (x != sx || y != sy) { total += stmp->obj->quan; + obj_left_shop = (shop_origin && !costly_spot(x, y)); + } if (!flooreffects(stmp->obj, x, y, "land")) { + if (obj_left_shop + && index(u.urooms, *in_rooms(u.ux, u.uy, SHOPBASE))) { + /* At the moment this only takes on gold. While it is + simple enough to call addtobill for other items that + leave the shop due to scatter(), by default the hero + will get billed for the full shopkeeper asking-price + on the object's way out of shop. That can leave the + hero in a pickle. Even if the hero then manages to + retrieve the item and drop it back inside the shop, + the owed charges will only be reduced at that point + by the lesser shopkeeper buying-price. + The non-gold situation will likely get adjusted further. + */ + if (stmp->obj->otyp == GOLD_PIECE) { + addtobill(stmp->obj, FALSE, FALSE, TRUE); + lostgoods = TRUE; + } + } place_object(stmp->obj, x, y); stackobj(stmp->obj); } @@ -811,6 +838,8 @@ scatter(int sx, int sy, /* location of objects to scatter */ if (sx == u.ux && sy == u.uy && u.uundetected && hides_under(g.youmonst.data)) (void) hideunder(&g.youmonst); + if (lostgoods) /* implies shop_origin and therefore shkp valid */ + credit_report(shkp, 1, FALSE); return total; } diff --git a/src/shk.c b/src/shk.c index b0cc791dc..e4ea7d019 100644 --- a/src/shk.c +++ b/src/shk.c @@ -432,6 +432,42 @@ u_left_shop(char* leavestring, boolean newlev) } } +void +credit_report(struct monst *shkp, int idx, boolean silent) +{ + struct eshk *eshkp = ESHK(shkp); + static long credit_snap[2][3] = {{0L, 0L, 0L}, {0L, 0L, 0L}}; + + if (!idx) { + credit_snap[BEFORE][0] = credit_snap[NOW][0] = 0L; + credit_snap[BEFORE][1] = credit_snap[NOW][1] = 0L; + credit_snap[BEFORE][2] = credit_snap[NOW][2] = 0L; + } else { + idx = 1; + } + + credit_snap[idx][0] = eshkp->credit; + credit_snap[idx][1] = eshkp->debit; + credit_snap[idx][2] = eshkp->loan; + + if (idx && !silent) { + long amt = 0L; + const char *msg = "debt has increased"; + + if (credit_snap[NOW][0] < credit_snap[BEFORE][0]) { + amt = credit_snap[BEFORE][0] - credit_snap[NOW][0]; + msg = "credit has been reduced"; + } else if (credit_snap[NOW][1] > credit_snap[BEFORE][1]) { + amt = credit_snap[NOW][1] - credit_snap[BEFORE][1]; + } else if (credit_snap[NOW][2] > credit_snap[BEFORE][2]) { + amt = credit_snap[NOW][2] - credit_snap[BEFORE][2]; + } + if (amt) + Your("%s by %ld %s.", msg, amt, currency(amt)); + + } +} + /* robbery from outside the shop via telekinesis or grappling hook */ void remote_burglary(xchar x, xchar y) @@ -2573,7 +2609,7 @@ addtobill( return; if (obj->oclass == COIN_CLASS) { - costly_gold(obj->ox, obj->oy, obj->quan); + costly_gold(obj->ox, obj->oy, obj->quan, silent); return; } else if (ESHK(shkp)->billct == BILLSZ) { if (!silent) @@ -2607,7 +2643,7 @@ addtobill( ltmp += cltmp; if (gltmp) { - costly_gold(obj->ox, obj->oy, gltmp); + costly_gold(obj->ox, obj->oy, gltmp, silent); if (!ltmp) return; } @@ -4574,7 +4610,7 @@ check_unpaid(struct obj* otmp) } void -costly_gold(register xchar x, register xchar y, register long amount) +costly_gold(xchar x, xchar y, long amount, boolean silent) { register long delta; register struct monst *shkp; @@ -4587,19 +4623,23 @@ costly_gold(register xchar x, register xchar y, register long amount) eshkp = ESHK(shkp); if (eshkp->credit >= amount) { - if (eshkp->credit > amount) - Your("credit is reduced by %ld %s.", amount, currency(amount)); - else - Your("credit is erased."); + if (!silent) { + if (eshkp->credit > amount) + Your("credit is reduced by %ld %s.", amount, currency(amount)); + else + Your("credit is erased."); + } eshkp->credit -= amount; } else { delta = amount - eshkp->credit; - if (eshkp->credit) - Your("credit is erased."); - if (eshkp->debit) - Your("debt increases by %ld %s.", delta, currency(delta)); - else - You("owe %s %ld %s.", shkname(shkp), delta, currency(delta)); + if (!silent) { + if (eshkp->credit) + Your("credit is erased."); + if (eshkp->debit) + Your("debt increases by %ld %s.", delta, currency(delta)); + else + You("owe %s %ld %s.", shkname(shkp), delta, currency(delta)); + } eshkp->debit += delta; eshkp->loan += delta; eshkp->credit = 0L;