shop fixes

Try to fix multiple container-in-shop bugs; it seemed as if every time
I tried to investigate one I stumbled into another.  billable() (post-3.4.3
code, but already present in branch as well as trunk) didn't handle
containers properly.  It sometimes gave the wrong answer and it didn't
clear the no_charge flag of contained items as the old code in addtobill()
it replaced did.  stolen_value() didn't use the actual bill price for an
item already on the shop bill; it generated a new price which might be
different if the object was unID'd (3.4.3 had this one).  Throwing didn't
handle a container owned by the hero which contained items owned by the
shopkeeper.  I'm still not quite sure what's going on there, but throwing
the container out of the shop didn't give any feedback but did add to shop
charges which don't show up in ``I x'' (but do get revealed by ``$'' or
``I $'').  (This was intertwined with some of the other stuff and I don't
know how 3.4.3 behaved in this regard.  Now there's some shop feedback for
the throw and the contents show up for ``I x''.)  An unpaid container which
contained another nonempty unpaid container showed a different price when
picked up and in inventory display [k - a bag (unpaid, NNN zorkmids)]
compared to what was on the bill and showed by ``I u'' because the first
two included double billing of the nested container (just it, not its own
contents).  [There where a few recursive calls of the form
    x += func(x)
which should have been either
    x = func(x)
or  x += func(0).]  Purchasing used the right amount, I think.  I'm not
sure whether 3.4.3 had this particular bug or whether fixes for some of its
other container bugs inadvertently caused this one.

     This patch also changes stolen_container() to work like the other
recursive shop routines:  it just handles the contents, leaving the outer
container itself to be handled by its caller.  It seemed inconsistent, and
changing it simplified the fix for using bill price on stolen unpaid items.
This commit is contained in:
nethack.rankin
2006-10-31 07:03:37 +00:00
parent 4e25ab378b
commit 9d8f6fdc8e

View File

@@ -1856,18 +1856,18 @@ register struct monst *shkp; /* if angry, impose a surcharge */
*/
long
contained_cost(obj, shkp, price, usell, unpaid_only)
register struct obj *obj;
register struct monst *shkp;
struct obj *obj;
struct monst *shkp;
long price;
register boolean usell;
register boolean unpaid_only;
boolean usell;
boolean unpaid_only;
{
register struct obj *otmp;
/* the price of contained objects */
/* price of contained objects; "top" container handled by caller */
for (otmp = obj->cobj; otmp; otmp = otmp->nobj) {
if (otmp->oclass == COIN_CLASS) continue;
/* the "top" container is evaluated by caller */
if (usell) {
if (saleable(shkp, otmp) &&
!otmp->unpaid && otmp->oclass != BALL_CLASS &&
@@ -1875,13 +1875,12 @@ register boolean unpaid_only;
!(Is_candle(otmp) && otmp->age <
20L * (long)objects[otmp->otyp].oc_cost))
price += set_cost(otmp, shkp);
} else if (!otmp->no_charge &&
(!unpaid_only || (unpaid_only && otmp->unpaid))) {
price += get_cost(otmp, shkp) * otmp->quan;
} else if (!otmp->no_charge && (otmp->unpaid || !unpaid_only)) {
price += get_cost(otmp, shkp) * otmp->quan;
}
if (Has_contents(otmp))
price += contained_cost(otmp, shkp, price, usell, unpaid_only);
price = contained_cost(otmp, shkp, price, usell, unpaid_only);
}
return(price);
@@ -2178,10 +2177,12 @@ boolean reset_nocharge;
if (obj->no_charge) {
if (!Has_contents(obj) ||
(contained_gold(obj) == 0L &&
contained_cost(obj, shkp, 0L, FALSE, TRUE) == 0L))
contained_cost(obj, shkp, 0L, FALSE, !reset_nocharge) == 0L))
shkp = 0; /* not billable */
if (reset_nocharge && !shkp && obj->oclass != COIN_CLASS)
if (reset_nocharge && !shkp && obj->oclass != COIN_CLASS) {
obj->no_charge = 0;
if (Has_contents(obj)) picked_container(obj); /* clear no_charge */
}
}
return shkp ? TRUE : FALSE;
}
@@ -2402,30 +2403,31 @@ long price;
boolean ininv;
{
struct obj *otmp;
struct bill_x *bp;
long billamt;
if (ininv ? obj->unpaid : !obj->no_charge)
price += get_cost(obj, shkp); /* container itself (quan 1) */
else
obj->no_charge = 0;
/* the price of contained objects, if any */
/* the price of contained objects; caller handles top container */
for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
if (otmp->oclass == COIN_CLASS) continue;
billamt = 0L;
if (!billable(&shkp, otmp, ESHK(shkp)->shoproom, TRUE)) {
/* billable() returns false for objects already on bill */
if (!onbill(obj, shkp, FALSE)) continue;
if ((bp = onbill(otmp, shkp, FALSE)) == 0) continue;
/* this assumes that we're being called by stolen_value()
(or by a recursive call to self on behalf of it) where
the cost of this object is about to be added to shop
debt in place of having it remain on the current bill */
subfrombill(obj, shkp); /* avoid double billing */
billamt = bp->bquan * bp->price;
sub_one_frombill(otmp, shkp); /* avoid double billing */
}
if (!Has_contents(otmp)) {
if (otmp->unpaid || !ininv)
price += otmp->quan * get_cost(otmp, shkp);
} else
price += stolen_container(otmp, shkp, price, ininv);
if (billamt)
price += billamt;
else if (ininv ? otmp->unpaid : !otmp->no_charge)
price += otmp->quan * get_cost(otmp, shkp);
if (Has_contents(otmp))
price = stolen_container(otmp, shkp, price, ininv);
}
return(price);
@@ -2437,27 +2439,35 @@ struct obj *obj;
xchar x, y;
boolean peaceful, silent;
{
long value = 0L, gvalue = 0L;
long value = 0L, gvalue = 0L, billamt = 0L;
char roomno = *in_rooms(x, y, SHOPBASE);
struct bill_x *bp;
struct monst *shkp = 0;
if (!billable(&shkp, obj, roomno, FALSE)) {
/* things already on the bill yield a not-billable result, so
we need to check bill before deciding that shk doesn't care */
if (!onbill(obj, shkp, FALSE)) return 0L;
if ((bp = onbill(obj, shkp, FALSE)) == 0) return 0L;
/* shk does care; take obj off bill to avoid double billing */
subfrombill(obj, shkp);
billamt = bp->bquan * bp->price;
sub_one_frombill(obj, shkp);
}
if(obj->oclass == COIN_CLASS) {
gvalue += obj->quan;
} else if (Has_contents(obj)) {
boolean ininv = !!count_unpaid(obj->cobj);
} else {
if (billamt)
value += billamt;
else if (!obj->no_charge)
value += obj->quan * get_cost(obj, shkp);
value += stolen_container(obj, shkp, value, ininv);
if(!ininv) gvalue += contained_gold(obj);
} else if (!obj->no_charge) {
value += obj->quan * get_cost(obj, shkp);
if (Has_contents(obj)) {
boolean ininv = (obj->where == OBJ_INVENT ||
obj->where == OBJ_FREE);
value += stolen_container(obj, shkp, 0L, ininv);
if(!ininv) gvalue += contained_gold(obj);
}
}
if(gvalue + value == 0L) return(0L);
@@ -2557,7 +2567,7 @@ xchar x, y;
}
if(container) {
/* find the price of content before subfrombill */
cltmp += contained_cost(obj, shkp, cltmp, TRUE, FALSE);
cltmp = contained_cost(obj, shkp, cltmp, TRUE, FALSE);
/* find the value of contained gold */
gltmp += contained_gold(obj);
cgold = (gltmp > 0L);