redo itemized shop billing for containers

Finish shop changes begun in 2674a9904d.

Fix the longstanding bug where shop paying with itemized buying would
reveal container contents if any unpaid items were inside containers,
regardless of whether the containers' contents were known yet, even
when the container was a locked box/chest or a cursed bag of holding.
Paying by menu made that be more noticeable but it has been present
ever since itemized paying was introduced.  I can't find any old bug
reports for it though.  I did find an old message of mine that claims
it's in bugzilla with a "#Hnnnn" tag.

This changes how buying containers and their contained items behaves.
It's now an all or nothing operation.  Itemized billing will list
the container but not contents, and to buy what is inside you need
to pay for the whole thing as a single unit.  If the container itself
is unpaid then its price is part of that item's total cost.  If it is
hero-owned than it is listed as an item to buy but doesn't increase
the cost derived from its unpaid contents.  (If you decline to pay,
hero will still own the container and still owe for unpaid contents.)
This commit is contained in:
PatR
2024-07-02 14:52:49 -07:00
parent 14d0e48e73
commit 7fa328fda3
3 changed files with 329 additions and 162 deletions

View File

@@ -2279,18 +2279,31 @@ paydoname(struct obj *obj)
{
static const char and_contents[] = " and its contents";
char *p;
unsigned save_cknown = obj->cknown;
boolean save_wizweight = iflags.wizweight;
if (Has_contents(obj))
obj->cknown = 0;
/* avoid showing item weights to unclutter billing's pay-menu a bit */
iflags.wizweight = FALSE;
/* suppress invent-style price; caller will add billing-style price */
iflags.suppress_price++;
p = doname_base(obj, 0U);
iflags.suppress_price--;
iflags.wizweight = save_wizweight;
if (Has_contents(obj)) {
if (!strncmp(p, "a ", 2))
p += 2;
else if (!strncmp(p, "an ", 3))
p += 3;
p = strprepend(p, obj->unpaid ? "an unpaid " : "your ");
/* buy_container() sets no_charge for a container that has just
been purchased so that when paydoname() is called by
shk_names_obj(), we'll provide "a/an <container>" instead of
"your <container>" */
if (!obj->no_charge) {
if (!strncmp(p, "a ", 2))
p += 2;
else if (!strncmp(p, "an ", 3))
p += 3;
p = strprepend(p, obj->unpaid ? "an unpaid " : "your ");
}
if (!obj->cknown) {
if (obj->unpaid) {
@@ -2298,10 +2311,11 @@ paydoname(struct obj *obj)
< BUFSZ - PREFIX)
Strcat(p, and_contents);
} else {
p = strprepend(p, "contents of ");
p = strprepend(p, "the contents of ");
}
}
}
obj->cknown = save_cknown;
return p;
}