From 1ceb9d2d91fe58b942a812f16aa9828e18d80823 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 9 Dec 2023 12:43:37 +0200 Subject: [PATCH] Show menu when paying items ... and have more than 1 billed item, and using non-traditional menustyle. I opted to add an extra field to the bill struct, because that made the code cleaner. Breaks saves and bones. --- doc/fixes3-7-0.txt | 1 + include/mextra.h | 1 + include/patchlevel.h | 2 +- src/shk.c | 76 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 9280ea463..4e4a690b8 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1321,6 +1321,7 @@ change vrock and hezrou from red to green, adjust vrock tile to have green change wolf and werewolf to grey, warg to black change [master] mind flayer, the Wizard, and the riders to bright magenta walking into a shopkeeper tries to pay the bill +show billed items in a menu when paying with non-traditional menustyle Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/mextra.h b/include/mextra.h index c88505916..13ba7f254 100644 --- a/include/mextra.h +++ b/include/mextra.h @@ -113,6 +113,7 @@ struct epri { struct bill_x { unsigned bo_id; boolean useup; + boolean queuedpay; long price; /* price per unit */ long bquan; /* amount used up */ }; diff --git a/include/patchlevel.h b/include/patchlevel.h index fca6e0958..79d5b0fd9 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -17,7 +17,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 93 +#define EDITLEVEL 94 /* * Development status possibilities. diff --git a/src/shk.c b/src/shk.c index 7968bcd02..7627449cf 100644 --- a/src/shk.c +++ b/src/shk.c @@ -45,6 +45,7 @@ static long set_cost(struct obj *, struct monst *); static const char *shk_embellish(struct obj *, long); static long cost_per_charge(struct monst *, struct obj *, boolean); static long cheapest_item(struct monst *); +static int menu_pick_pay_items(struct monst *); static int dopayobj(struct monst *, struct bill_x *, struct obj **, int, boolean); static long stolen_container(struct obj *, struct monst *, long, boolean); @@ -1382,6 +1383,56 @@ cheapest_item(struct monst *shkp) return gmin; } +/* show items on your bill in a menu, and ask which to pay. + returns the number of entries selected. */ +static int +menu_pick_pay_items(struct monst *shkp) +{ + struct eshk *eshkp = ESHK(shkp); + winid win; + anything any; + menu_item *pick_list = (menu_item *) 0; + int i, j, n, clr = NO_COLOR; + char buf[BUFSZ]; + + any = cg.zeroany; + win = create_nhwindow(NHW_MENU); + start_menu(win, MENU_BEHAVE_STANDARD); + + for (n = 0; n < eshkp->billct; n++) { + struct obj *otmp; + register struct bill_x *bp = &(eshkp->bill_p[n]); + + bp->queuedpay = FALSE; + + /* find the object on one of the lists */ + if ((otmp = bp_to_obj(bp)) != 0) { + /* if completely used up, object quantity is stale; + restoring it to its original value here avoids + making the partly-used-up code more complicated */ + if (bp->useup) + otmp->quan = bp->bquan; + Sprintf(buf, "%s%s", + bp->useup ? "(used up) " : "", + doname(otmp)); + any.a_int = n + 1; /* +1: avoid 0 */ + add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr, buf, + MENU_ITEMFLAGS_NONE); + } + } + + end_menu(win, "Pay which items?"); + n = select_menu(win, PICK_ANY, &pick_list); + destroy_nhwindow(win); + + for (j = 0; j < n; ++j) { + i = pick_list[j].item.a_int - 1; /* -1: reverse +1 above */ + eshkp->bill_p[i].queuedpay = TRUE; + } + free(pick_list); + return n; +} + /* the #pay command */ int dopay(void) @@ -1635,6 +1686,7 @@ dopay(void) /* now check items on bill */ if (eshkp->billct) { register boolean itemize; + boolean queuedpay = FALSE; int iprompt; umoney = money_cnt(gi.invent); @@ -1651,12 +1703,19 @@ dopay(void) return ECMD_OK; } - /* this isn't quite right; it itemizes without asking if the - * single item on the bill is partly used up and partly unpaid */ - iprompt = (eshkp->billct > 1 ? ynq("Itemized billing?") : 'y'); - itemize = (iprompt == 'y'); - if (iprompt == 'q') - goto thanks; + if (flags.menu_style != MENU_TRADITIONAL && eshkp->billct > 1) { + if (!menu_pick_pay_items(shkp)) + return ECMD_OK; + queuedpay = TRUE; + itemize = FALSE; + } else { + /* this isn't quite right; it itemizes without asking if the + * single item on the bill is partly used up and partly unpaid */ + iprompt = (eshkp->billct > 1 ? ynq("Itemized billing?") : 'y'); + itemize = (iprompt == 'y'); + if (iprompt == 'q') + goto thanks; + } for (pass = 0; pass <= 1; pass++) { tmp = 0; @@ -1664,6 +1723,11 @@ dopay(void) struct obj *otmp; register struct bill_x *bp = &(eshkp->bill_p[tmp]); + if (queuedpay && !bp->queuedpay) { + tmp++; + continue; + } + /* find the object on one of the lists */ if ((otmp = bp_to_obj(bp)) != 0) { /* if completely used up, object quantity is stale;