further improve additional glob interaction scenarios within a shop

Scenarios:
1. shop_owned glob merging into shop_owned glob
2. player_owned glob merging into shop_owned glob
3. shop_owned glob merging into player_owned glob
4. player_owned glob merging into player_owned glob
This commit is contained in:
nhmall
2019-05-18 16:24:48 -04:00
parent a19e64e470
commit 670fc9ca34
5 changed files with 117 additions and 68 deletions
+1
View File
@@ -19,6 +19,7 @@ glob pricing did not consider weight properly
Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository
------------------------------------------------------------------ ------------------------------------------------------------------
glob shop interaction improved to handle more of the expected scenarios
Platform- and/or Interface-Specific Fixes or Features Platform- and/or Interface-Specific Fixes or Features
+7 -5
View File
@@ -3581,11 +3581,7 @@ register struct obj *otmp, *obj;
if (obj->oclass == COIN_CLASS) if (obj->oclass == COIN_CLASS)
return TRUE; return TRUE;
if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe if (obj->bypass != otmp->bypass)
|| obj->cursed != otmp->cursed || obj->blessed != otmp->blessed
|| obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
|| obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit
|| obj->bypass != otmp->bypass)
return FALSE; return FALSE;
if (obj->globby) if (obj->globby)
@@ -3594,6 +3590,12 @@ register struct obj *otmp, *obj;
* or don't inhibit their merger. * or don't inhibit their merger.
*/ */
if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe
|| obj->cursed != otmp->cursed || obj->blessed != otmp->blessed
|| obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
|| obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit)
return FALSE;
if (obj->oclass == FOOD_CLASS if (obj->oclass == FOOD_CLASS
&& (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten)) && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
return FALSE; return FALSE;
+8 -7
View File
@@ -2786,10 +2786,7 @@ struct obj **obj1, **obj2;
otmp1 = *obj1; otmp1 = *obj1;
otmp2 = *obj2; otmp2 = *obj2;
if (otmp1 && otmp2 && otmp1 != otmp2) { if (otmp1 && otmp2 && otmp1 != otmp2) {
if (otmp1->unpaid || otmp2->unpaid) globby_bill_fixup(otmp1, otmp2);
globby_bill_fixup(otmp1, otmp2);
else if (costly_spot(otmp1->ox, otmp1->oy))
globby_donation(otmp1, otmp2);
if (otmp1->bknown != otmp2->bknown) if (otmp1->bknown != otmp2->bknown)
otmp1->bknown = otmp2->bknown = 0; otmp1->bknown = otmp2->bknown = 0;
if (otmp1->rknown != otmp2->rknown) if (otmp1->rknown != otmp2->rknown)
@@ -2823,7 +2820,10 @@ struct obj **obj1, **obj2;
} }
/* /*
* Causes the heavier object to absorb the lighter object; * Causes the heavier object to absorb the lighter object in
* most cases, but if one object is OBJ_FREE and the other is
* on the floor, the floor object goes first.
*
* wrapper for obj_absorb so that floor_effects works more * wrapper for obj_absorb so that floor_effects works more
* cleanly (since we don't know which we want to stay around) * cleanly (since we don't know which we want to stay around)
*/ */
@@ -2837,8 +2837,9 @@ struct obj **obj1, **obj2;
otmp1 = *obj1; otmp1 = *obj1;
otmp2 = *obj2; otmp2 = *obj2;
if (otmp1 && otmp2 && otmp1 != otmp2) { if (otmp1 && otmp2 && otmp1 != otmp2) {
if (otmp1->owt > otmp2->owt if (!(otmp2->where == OBJ_FLOOR && otmp1->where == OBJ_FREE) &&
|| (otmp1->owt == otmp2->owt && rn2(2))) { (otmp1->owt > otmp2->owt
|| (otmp1->owt == otmp2->owt && rn2(2)))) {
return obj_absorb(obj1, obj2); return obj_absorb(obj1, obj2);
} }
return obj_absorb(obj2, obj1); return obj_absorb(obj2, obj1);
+3 -2
View File
@@ -1228,7 +1228,7 @@ unsigned doname_flags;
nochrg ? "contents" : "for sale", nochrg ? "contents" : "for sale",
globwt(obj, globbuf), price, currency(price)); globwt(obj, globbuf), price, currency(price));
else if (nochrg > 0) else if (nochrg > 0)
Strcat(bp, " (no charge)"); Sprintf(eos(bp), " (%sno charge)", globwt(obj, globbuf));
} }
if (!strncmp(prefix, "a ", 2)) { if (!strncmp(prefix, "a ", 2)) {
/* save current prefix, without "a "; might be empty */ /* save current prefix, without "a "; might be empty */
@@ -1242,7 +1242,8 @@ unsigned doname_flags;
/* show weight for items (debug tourist info) /* show weight for items (debug tourist info)
* aum is stolen from Crawl's "Arbitrary Unit of Measure" */ * aum is stolen from Crawl's "Arbitrary Unit of Measure" */
if (wizard && iflags.wizweight) { if (wizard && iflags.wizweight) {
Sprintf(eos(bp), " (%d aum)", obj->owt); if (!obj->globby) /* aum already apparent for globs */
Sprintf(eos(bp), " (%d aum)", obj->owt);
} }
bp = strprepend(bp, prefix); bp = strprepend(bp, prefix);
return bp; return bp;
+98 -54
View File
@@ -4801,91 +4801,108 @@ sasc_bug(struct obj *op, unsigned x)
#endif #endif
/* /*
* When one glob is absorbed by another glob, the two become * The caller is about to make obj_absorbed go away.
* indistinguishable and the remaining glob grows in mass,
* the product of both.
* *
* The original billed item is lost to the absorption and the * There's no way for you (or a shopkeeper) to prevent globs
* original billed amount for the object being absorbed gets * from merging with each other on the floor due to the
* added to the cost owing for the absorber, and the separate * inherent nature of globs so it irretrievably becomes part
* cost for the absorbed object goes away. * of the floor glob mass. When one glob is absorbed by another
* glob, the two become indistinguishable and the remaining
* glob object grows in mass, the product of both.
*
* billing admin, player compensation, shopkeeper compensation
* all need to be considered.
*
* Any original billed item is lost to the absorption so the
* original billed amount for the object being absorbed must
* get added to the cost owing for the absorber, and the
* separate cost for the object being absorbed goes away.
*
* There are four scenarios to deal with:
* 1. shop_owned glob merging into shop_owned glob
* 2. player_owned glob merging into shop_owned glob
* 3. shop_owned glob merging into player_owned glob
* 4. player_owned glob merging into player_owned glob
*/ */
void void
globby_bill_fixup(obj_absorber, obj_absorbed) globby_bill_fixup(obj_absorber, obj_absorbed)
struct obj *obj_absorber, *obj_absorbed; struct obj *obj_absorber, *obj_absorbed;
{ {
int x, y;
struct bill_x *bp, *bp_absorber = (struct bill_x *) 0; struct bill_x *bp, *bp_absorber = (struct bill_x *) 0;
struct monst *shkp = 0; struct monst *shkp = 0;
struct eshk *eshkp;
long amount, per_unit_cost = set_cost(obj_absorbed, shkp);
boolean floor_absorber = (obj_absorber->where == OBJ_FLOOR);
if (!obj_absorber->globby) if (!obj_absorber->globby)
impossible("globby_bill_fixup called for non-globby object"); impossible("globby_bill_fixup called for non-globby object");
if (floor_absorber) {
x = obj_absorber->ox, y = obj_absorber->oy;
}
if (obj_absorber->unpaid) { if (obj_absorber->unpaid) {
/* look for a shopkeeper who owns this object */ /* look for a shopkeeper who owns this object */
for (shkp = next_shkp(fmon, TRUE); shkp; for (shkp = next_shkp(fmon, TRUE); shkp;
shkp = next_shkp(shkp->nmon, TRUE)) shkp = next_shkp(shkp->nmon, TRUE))
if (onbill(obj_absorber, shkp, TRUE)) if (onbill(obj_absorber, shkp, TRUE))
break; break;
} else if (obj_absorbed->unpaid) {
if (obj_absorbed->where == OBJ_FREE
&& floor_absorber && costly_spot(x, y)) {
shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
}
} }
/* sanity check, in case obj is on bill but not marked 'unpaid' */ /* sanity check, in case obj is on bill but not marked 'unpaid' */
if (!shkp) if (!shkp)
shkp = shop_keeper(*u.ushops); shkp = shop_keeper(*u.ushops);
if (!shkp)
return;
bp_absorber = onbill(obj_absorber, shkp, FALSE);
bp = onbill(obj_absorbed, shkp, FALSE);
eshkp = ESHK(shkp);
if ((bp_absorber = onbill(obj_absorber, shkp, FALSE)) != 0) { /**************************************************************
bp = onbill(obj_absorbed, shkp, FALSE); * Scenario 1. Shop-owned glob absorbing into shop-owned glob
if (bp) { **************************************************************/
bp_absorber->price += bp->price; if (bp && (!obj_absorber->no_charge
ESHK(shkp)->billct--; || billable(&shkp, obj_absorber, eshkp->shoproom, FALSE))) {
/* the glob being absorbed has a billing record */
amount = bp->price;
eshkp->billct--;
#ifdef DUMB #ifdef DUMB
{ {
/* DRS/NS 2.2.6 messes up -- Peter Kendell */ /* DRS/NS 2.2.6 messes up -- Peter Kendell */
int indx = ESHK(shkp)->billct; int indx = eshkp->billct;
*bp = ESHK(shkp)->bill_p[indx]; *bp = eshkp->bill_p[indx];
}
#else
*bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
#endif
clear_unpaid_obj(shkp, obj_absorbed);
} else {
/* should never happen */
bp_absorber->price += get_cost(obj_absorbed, shkp)
* get_pricing_units(obj_absorbed);
} }
#else
*bp = eshkp->bill_p[eshkp->billct];
#endif
clear_unpaid_obj(shkp, obj_absorbed);
if (bp_absorber) {
/* the absorber has a billing record */
bp_absorber->price += amount;
} else {
/* the absorber has no billing record */
;
}
return;
} }
} /**************************************************************
* Scenario 2. Player-owned glob absorbing into shop-owned glob
/* **************************************************************/
* The caller is about to make obj_absorbed go away. if (!bp_absorber && !bp && !obj_absorber->no_charge) {
* /* there are no billing records */
* There's no way for you (or a shopkeeper) to prevent globs amount = get_pricing_units(obj_absorbed) * per_unit_cost;
* from merging with each other on the floor due to the
* inherent nature of globs so it irretrievably becomes part
* of the floor glob mass.
*
* globby_donation() needs to handle whether/how to
* compensate you for that.
*
* unpaid globs don't end up here.
*/
void
globby_donation(obj_absorber, obj_absorbed)
struct obj *obj_absorber, *obj_absorbed;
{
if (obj_absorber->where == OBJ_FLOOR
&& costly_spot(obj_absorber->ox, obj_absorber->oy)) {
int x = obj_absorber->ox, y = obj_absorber->oy;
struct monst *shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
struct eshk *eshkp = ESHK(shkp);
long amount, per_unit_cost = get_cost(obj_absorbed, shkp);
if (saleable(shkp, obj_absorbed)) { if (saleable(shkp, obj_absorbed)) {
amount = get_pricing_units(obj_absorbed) * per_unit_cost;
if (eshkp->debit >= amount) { if (eshkp->debit >= amount) {
if (eshkp->loan) { /* you carry shop's gold */ if (eshkp->loan) { /* you carry shop's gold */
if (eshkp->loan >= amount) if (eshkp->loan >= amount)
eshkp->loan -= amount; eshkp->loan -= amount;
else else
eshkp->loan = 0L; eshkp->loan = 0L;
} }
eshkp->debit -= amount; eshkp->debit -= amount;
@@ -4913,7 +4930,34 @@ struct obj *obj_absorber, *obj_absorbed;
eshkp->credit, currency(eshkp->credit)); eshkp->credit, currency(eshkp->credit));
} }
} }
return;
} else if (bp_absorber) {
/* absorber has a billing record */
bp_absorber->price += per_unit_cost * get_pricing_units(obj_absorbed);
return;
} }
/**************************************************************
* Scenario 3. shop_owned glob merging into player_owned glob
**************************************************************/
if (bp &&
(obj_absorber->no_charge
|| (floor_absorber && !costly_spot(x, y)))) {
amount = bp->price;
bill_dummy_object(obj_absorbed);
verbalize(
"You owe me %ld %s for my %s that %s with your%s",
amount, currency(amount), obj_typename(obj_absorbed->otyp),
ANGRY(shkp) ? "had the audacity to mix" :
"just mixed",
ANGRY(shkp) ? " stinking batch!" :
"s.");
return;
}
/**************************************************************
* Scenario 4. player_owned glob merging into player_owned glob
**************************************************************/
return;
} }
/*shk.c*/ /*shk.c*/