]> granicus.if.org Git - nethack/commitdiff
further improve additional glob interaction scenarios within a shop
authornhmall <nhmall@nethack.org>
Sat, 18 May 2019 20:24:48 +0000 (16:24 -0400)
committernhmall <nhmall@nethack.org>
Sat, 18 May 2019 20:24:48 +0000 (16:24 -0400)
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

doc/fixes36.3
src/invent.c
src/mkobj.c
src/objnam.c
src/shk.c

index f935c3bdcf2db2c150b9b10c1835a80d65fb3f8c..d85086092eb042656e8e17d8443387f700aa7a1e 100644 (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
 ------------------------------------------------------------------
+glob shop interaction improved to handle more of the expected scenarios
 
 
 Platform- and/or Interface-Specific Fixes or Features
index 13c6eed676dabca2e670a853f8b12688b1679ee7..51c505375f9b569565e12170acad4bb3a06bfacd 100644 (file)
@@ -3581,11 +3581,7 @@ register struct obj *otmp, *obj;
     if (obj->oclass == COIN_CLASS)
         return TRUE;
 
-    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
-        || obj->bypass != otmp->bypass)
+    if (obj->bypass != otmp->bypass)
         return FALSE;
 
     if (obj->globby)
@@ -3594,6 +3590,12 @@ register struct obj *otmp, *obj;
      * 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
         && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
         return FALSE;
index 2428aec4973bb3c34e5ed793631c254f6dc34812..94370c96da5d625d395f78b19b48b1d6cd88d297 100644 (file)
@@ -2786,10 +2786,7 @@ struct obj **obj1, **obj2;
         otmp1 = *obj1;
         otmp2 = *obj2;
         if (otmp1 && otmp2 && otmp1 != otmp2) {
-            if (otmp1->unpaid || otmp2->unpaid)
-                globby_bill_fixup(otmp1, otmp2);
-            else if (costly_spot(otmp1->ox, otmp1->oy))
-                globby_donation(otmp1, otmp2);
+            globby_bill_fixup(otmp1, otmp2);
             if (otmp1->bknown != otmp2->bknown)
                 otmp1->bknown = otmp2->bknown = 0;
             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
  * cleanly (since we don't know which we want to stay around)
  */
@@ -2837,8 +2837,9 @@ struct obj **obj1, **obj2;
         otmp1 = *obj1;
         otmp2 = *obj2;
         if (otmp1 && otmp2 && otmp1 != otmp2) {
-            if (otmp1->owt > otmp2->owt
-                || (otmp1->owt == otmp2->owt && rn2(2))) {
+            if (!(otmp2->where == OBJ_FLOOR && otmp1->where == OBJ_FREE) &&
+                (otmp1->owt > otmp2->owt
+                 || (otmp1->owt == otmp2->owt && rn2(2)))) {
                 return obj_absorb(obj1, obj2);
             }
             return obj_absorb(obj2, obj1);
index a684f163ce69a7cc25b4f84bd273f8ae452899e1..e8bb71c14f266add0a3aab47003d3ba15fa4494c 100644 (file)
@@ -1228,7 +1228,7 @@ unsigned doname_flags;
                     nochrg ? "contents" : "for sale",
                     globwt(obj, globbuf), price, currency(price));
         else if (nochrg > 0)
-            Strcat(bp, " (no charge)");
+            Sprintf(eos(bp), " (%sno charge)", globwt(obj, globbuf));
     }
     if (!strncmp(prefix, "a ", 2)) {
         /* save current prefix, without "a "; might be empty */
@@ -1242,7 +1242,8 @@ unsigned doname_flags;
     /* show weight for items (debug tourist info)
      * aum is stolen from Crawl's "Arbitrary Unit of Measure" */
     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);
     return bp;
index 18a2599e03bf1bde754651b91175c1817d17c11b..470253570a0a41a27e612d001ead6c137c02fc82 100644 (file)
--- a/src/shk.c
+++ b/src/shk.c
@@ -4801,91 +4801,108 @@ sasc_bug(struct obj *op, unsigned x)
 #endif
 
 /*
- * When one glob is absorbed by another glob, the two become
- * indistinguishable and the remaining glob grows in mass,
- * the product of both.
+ * The caller is about to make obj_absorbed go away.
+ *
+ * There's no way for you (or a shopkeeper) to prevent globs
+ * 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. 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.
  *
- * The original billed item is lost to the absorption and the
- * original billed amount for the object being absorbed gets
- * added to the cost owing for the absorber, and the separate
- * cost for the absorbed object goes away.
+ * 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
 globby_bill_fixup(obj_absorber, obj_absorbed)
 struct obj *obj_absorber, *obj_absorbed;
 {
+    int x, y;
     struct bill_x *bp, *bp_absorber = (struct bill_x *) 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)
         impossible("globby_bill_fixup called for non-globby object");
 
+    if (floor_absorber) {
+        x = obj_absorber->ox, y = obj_absorber->oy;
+    }
     if (obj_absorber->unpaid) {
         /* look for a shopkeeper who owns this object */
         for (shkp = next_shkp(fmon, TRUE); shkp;
              shkp = next_shkp(shkp->nmon, TRUE))
             if (onbill(obj_absorber, shkp, TRUE))
                 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' */
     if (!shkp)
         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);
-        if (bp) {
-            bp_absorber->price += bp->price;
-            ESHK(shkp)->billct--;
+    /**************************************************************
+     * Scenario 1. Shop-owned glob absorbing into shop-owned glob
+     **************************************************************/
+    if (bp && (!obj_absorber->no_charge
+                || billable(&shkp, obj_absorber, eshkp->shoproom, FALSE))) {
+        /* the glob being absorbed has a billing record */
+        amount = bp->price;
+        eshkp->billct--;
 #ifdef DUMB
-            {
-                /* DRS/NS 2.2.6 messes up -- Peter Kendell */
-                int indx = ESHK(shkp)->billct;
+        {
+            /* DRS/NS 2.2.6 messes up -- Peter Kendell */
+            int indx = eshkp->billct;
 
-                *bp = ESHK(shkp)->bill_p[indx];
-            }
+            *bp = eshkp->bill_p[indx];
+        }
 #else
-            *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
+        *bp = eshkp->bill_p[eshkp->billct];
 #endif
-            clear_unpaid_obj(shkp, obj_absorbed);
+        clear_unpaid_obj(shkp, obj_absorbed);
+
+        if (bp_absorber) {
+            /* the absorber has a billing record */
+            bp_absorber->price += amount;           
         } else {
-            /* should never happen */
-            bp_absorber->price += get_cost(obj_absorbed, shkp)
-                                    * get_pricing_units(obj_absorbed);
+            /* the absorber has no billing record */
+            ;
         }
+        return;
     }
-}
-
-/*
- * The caller is about to make obj_absorbed go away.
- *
- * There's no way for you (or a shopkeeper) to prevent globs
- * 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);
-
+    /**************************************************************
+     * Scenario 2. Player-owned glob absorbing into shop-owned glob 
+     **************************************************************/
+    if (!bp_absorber && !bp && !obj_absorber->no_charge) {
+        /* there are no billing records */
+        amount = get_pricing_units(obj_absorbed) * per_unit_cost;
         if (saleable(shkp, obj_absorbed)) {
-            amount = get_pricing_units(obj_absorbed) * per_unit_cost;
             if (eshkp->debit >= amount) {
                 if (eshkp->loan) { /* you carry shop's gold */
-                    if (eshkp->loan >= amount)
+                   if (eshkp->loan >= amount)
                         eshkp->loan -= amount;
-                    else
+                   else
                         eshkp->loan = 0L;
                 }
                 eshkp->debit -= amount;
@@ -4913,7 +4930,34 @@ struct obj *obj_absorber, *obj_absorbed;
                               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*/