]> granicus.if.org Git - nethack/commitdiff
fix some billing and pricing issues when globs coalesce
authornhmall <nhmall@nethack.org>
Fri, 17 May 2019 16:04:01 +0000 (12:04 -0400)
committernhmall <nhmall@nethack.org>
Fri, 17 May 2019 16:04:01 +0000 (12:04 -0400)
payment issue caused by glob coalescing
glob pricing did not consider coalesced weight

doc/fixes36.3
include/extern.h
src/invent.c
src/mkobj.c
src/objnam.c
src/shk.c

index 07ab11624b125abba61e0822601e7bfc4eabc7f5..77aac68957cf17250e594a4eb335941877085517 100644 (file)
@@ -13,6 +13,8 @@ when place_object() puts a non-boulder on the map at a spot which contains
        the top one got moved by means other than pushing
 when examining the map with '/' or ';', picking a symbol which is used for
        more than 4 things yielded a sentence lacking its terminating period
+billing and payment issue as a result of glob coalescing
+glob pricing did not consider weight properly
 
 
 Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository
index 6959e244898c45133f6546aa00caa5575d11d18b..890bb5f797e0c8d67464a87ac1a745e97026c6dc 100644 (file)
@@ -2268,6 +2268,8 @@ E boolean FDECL(block_door, (XCHAR_P, XCHAR_P));
 E boolean FDECL(block_entry, (XCHAR_P, XCHAR_P));
 E char *FDECL(shk_your, (char *, struct obj *));
 E char *FDECL(Shk_Your, (char *, struct obj *));
+E void FDECL(globby_bill_fixup, (struct obj *, struct obj *));
+E void FDECL(globby_donation, (struct obj *, struct obj *));
 
 /* ### shknam.c ### */
 
index ff69de77edbaa2e6dbdfd54c911159c90c2b131f..13c6eed676dabca2e670a853f8b12688b1679ee7 100644 (file)
@@ -720,7 +720,8 @@ struct obj **potmp, **pobj;
             otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan))
                         / (otmp->quan + obj->quan);
 
-        otmp->quan += obj->quan;
+        if (!otmp->globby)
+            otmp->quan += obj->quan;
         /* temporary special case for gold objects!!!! */
         if (otmp->oclass == COIN_CLASS)
             otmp->owt = weight(otmp), otmp->bknown = 0;
index b88bc25a203d9e5f4c72af40894da61ba2281cbc..00bbdebe9b0f707546c34d1b7be9010156177fca 100644 (file)
@@ -2755,6 +2755,10 @@ 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);
             if (otmp1->bknown != otmp2->bknown)
                 otmp1->bknown = otmp2->bknown = 0;
             if (otmp1->rknown != otmp2->rknown)
index 06efd9bda8f26108430d8d0d0ad77c017bd1d30c..58f2573037b659c7d92fd0d120727f495d8cd626 100644 (file)
@@ -25,6 +25,7 @@ STATIC_DCL boolean FDECL(singplur_lookup, (char *, char *, BOOLEAN_P,
 STATIC_DCL char *FDECL(singplur_compound, (char *));
 STATIC_DCL char *FDECL(xname_flags, (struct obj *, unsigned));
 STATIC_DCL boolean FDECL(badman, (const char *, BOOLEAN_P));
+STATIC_DCL char *FDECL(globwt, (struct obj *, char *));
 
 struct Jitem {
     int item;
@@ -1219,11 +1220,12 @@ unsigned doname_flags;
     } else if (with_price) { /* on floor or in container on floor */
         int nochrg = 0;
         long price = get_cost_of_shop_item(obj, &nochrg);
+        char globbuf[BUFSZ];
 
         if (price > 0L)
-            Sprintf(eos(bp), " (%s, %ld %s)",
+            Sprintf(eos(bp), " (%s, %s%ld %s)",
                     nochrg ? "contents" : "for sale",
-                    price, currency(price));
+                    globwt(obj, globbuf), price, currency(price));
         else if (nochrg > 0)
             Strcat(bp, " (no charge)");
     }
@@ -4200,4 +4202,16 @@ const char *lastR;
     return qbuf;
 }
 
+STATIC_OVL char *
+globwt(otmp, buf)
+struct obj *otmp;
+char *buf;
+{
+    if (otmp && buf && otmp->globby && otmp->quan == 1L) {
+        Sprintf(buf, "%ld aum, ", otmp->owt);
+        return buf;
+    }
+    return "";
+}
+
 /*objnam.c*/
index fb63a0ae992072f940bc3ea5cb71a009a8278264..89bb147cf68e19788049c6a7afc5b6ae12982f9f 100644 (file)
--- a/src/shk.c
+++ b/src/shk.c
@@ -75,6 +75,7 @@ STATIC_DCL void FDECL(deserted_shop, (char *));
 STATIC_DCL boolean FDECL(special_stock, (struct obj *, struct monst *,
                                          BOOLEAN_P));
 STATIC_DCL const char *FDECL(cad, (BOOLEAN_P));
+STATIC_DCL long FDECL(get_pricing_units, (struct obj *obj));
 
 /*
         invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
@@ -2015,14 +2016,34 @@ int *nochrg; /* alternate return value: 1: no charge, 0: shop owned,        */
            items on freespot are implicitly 'no charge' */
         *nochrg = (top->where == OBJ_FLOOR && (obj->no_charge || freespot));
 
-        if (carried(top) ? (int) obj->unpaid : !*nochrg)
-            cost = obj->quan * get_cost(obj, shkp);
+        if (carried(top) ? (int) obj->unpaid : !*nochrg) {
+            long per_unit_cost = get_cost(obj, shkp);
+
+            cost = get_pricing_units(obj) * per_unit_cost;
+        }
         if (Has_contents(obj) && !freespot)
             cost += contained_cost(obj, shkp, 0L, FALSE, TRUE);
     }
     return cost;
 }
 
+STATIC_OVL long
+get_pricing_units(obj)
+struct obj *obj;
+{
+    long units = obj->quan;
+
+    if (obj->globby) {
+        /* globs must be sold by weight not by volume */
+        int unit_weight = (int) objects[obj->otyp].oc_weight,
+            wt = (obj->owt > 0) ? obj->owt : weight(obj);
+
+        if (unit_weight)
+            units = wt / unit_weight;
+    }
+    return units;
+}
+
 /* decide whether to apply a surcharge (or hypothetically, a discount) to obj
    if it had ID number 'oid'; returns 1: increase, 0: normal, -1: decrease */
 int
@@ -2191,7 +2212,7 @@ boolean unpaid_only;
                items on freespot are implicitly 'no charge' */
             if (on_floor ? (!otmp->no_charge && !freespot)
                          : (otmp->unpaid || !unpaid_only))
-                price += get_cost(otmp, shkp) * otmp->quan;
+                price += get_cost(otmp, shkp) * get_pricing_units(otmp);
         }
 
         if (Has_contents(otmp))
@@ -2304,7 +2325,9 @@ set_cost(obj, shkp)
 register struct obj *obj;
 register struct monst *shkp;
 {
-    long tmp = getprice(obj, TRUE) * obj->quan, multiplier = 1L, divisor = 1L;
+    long tmp, unit_price = getprice(obj, TRUE), multiplier = 1L, divisor = 1L;
+
+    tmp = get_pricing_units(obj) * unit_price;
 
     if (uarmh && uarmh->otyp == DUNCE_CAP)
         divisor *= 3L;
@@ -2480,6 +2503,9 @@ struct monst *shkp;
     } else
         bp->useup = 0;
     bp->price = get_cost(obj, shkp);
+    if (obj->globby)
+        /* for globs, the amt charged for quan 1 depends on owt */
+        bp->price *= get_pricing_units(obj);
     eshkp->billct++;
     obj->unpaid = 1;
 }
@@ -2621,9 +2647,11 @@ boolean ininv, dummy, silent;
     ltmp = cltmp = gltmp = 0L;
     container = Has_contents(obj);
 
-    if (!obj->no_charge)
+    if (!obj->no_charge) {
         ltmp = get_cost(obj, shkp);
-
+        if (obj->globby)
+            ltmp *= get_pricing_units(obj);
+    }
     if (obj->no_charge && !container) {
         obj->no_charge = 0;
         return;
@@ -2851,7 +2879,7 @@ boolean ininv;
         if (billamt)
             price += billamt;
         else if (ininv ? otmp->unpaid : !otmp->no_charge)
-            price += otmp->quan * get_cost(otmp, shkp);
+            price += get_pricing_units(otmp) * get_cost(otmp, shkp);
 
         if (Has_contents(otmp))
             price = stolen_container(otmp, shkp, price, ininv);
@@ -2898,7 +2926,7 @@ boolean peaceful, silent;
         if (billamt)
             value += billamt;
         else if (!obj->no_charge)
-            value += obj->quan * get_cost(obj, shkp);
+            value += get_pricing_units(obj) * get_cost(obj, shkp);
 
         if (Has_contents(obj)) {
             boolean ininv =
@@ -4277,6 +4305,8 @@ register struct obj *first_obj;
         contentsonly = !cost;
         if (Has_contents(otmp))
             cost += contained_cost(otmp, shkp, 0L, FALSE, FALSE);
+        if (otmp->globby)
+            cost *= get_pricing_units(otmp);  /* always quan 1, vary by wt */
         if (!cost) {
             Strcpy(price, "no charge");
             contentsonly = FALSE;
@@ -4770,4 +4800,121 @@ sasc_bug(struct obj *op, unsigned x)
 }
 #endif
 
+/*
+ * When one glob is absorbed by another glob, the two become
+ * become indistinguishable and the remaining glob grows in
+ * mass, the product of both.
+ *
+ * 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.
+ */
+void
+globby_bill_fixup(obj_absorber, obj_absorbed)
+struct obj *obj_absorber, *obj_absorbed;
+{
+    struct bill_x *bp, *bp_absorber = (struct bill_x *) 0;
+    struct monst *shkp = 0;
+
+    if (!obj_absorber->globby)
+        impossible("globby_bill_fixup called for non-globby object");
+
+    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;
+    }
+    /* sanity check, in case obj is on bill but not marked 'unpaid' */
+    if (!shkp)
+        shkp = shop_keeper(*u.ushops);
+
+    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--;
+#ifdef DUMB
+            {
+                /* DRS/NS 2.2.6 messes up -- Peter Kendell */
+                int indx = ESHK(shkp)->billct;
+
+                *bp = ESHK(shkp)->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);
+        }
+    }
+}
+
+/*
+ * 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;
+        char *o_shop = in_rooms(x, y, SHOPBASE);
+        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)) {
+            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)
+                        eshkp->loan -= amount;
+                    else
+                        eshkp->loan = 0L;
+                }
+                eshkp->debit -= amount;
+                pline_The("donated %s %spays off your debt.",
+                          obj_typename(obj_absorbed->otyp),
+                          eshkp->debit ? "partially " : "");
+            } else {
+                long delta = amount - eshkp->debit;
+
+                eshkp->credit += delta;
+                if (eshkp->debit) {
+                    eshkp->debit = 0L;
+                    eshkp->loan = 0L;
+                    Your("debt is paid off.");
+                }
+                if (eshkp->credit == delta)
+                    pline_The("%s established %ld %s credit.",
+                              obj_typename(obj_absorbed->otyp),
+                              delta, currency(delta));
+                else
+                    pline_The("%s added %ld %s %s %ld %s.",
+                              obj_typename(obj_absorbed->otyp),
+                              delta, currency(delta),
+                              "to your credit; total is now",
+                              eshkp->credit, currency(eshkp->credit));
+            }
+        }
+    }
+}
+
 /*shk.c*/