calculating shop price adjustments (trunk only)
authornethack.rankin <nethack.rankin>
Sat, 23 Jul 2011 03:57:09 +0000 (03:57 +0000)
committernethack.rankin <nethack.rankin>
Sat, 23 Jul 2011 03:57:09 +0000 (03:57 +0000)
     Fix the second of a couple of minor things I noticed when viewing
that guy's ttyrec about a hidden inventory item which turned out to be
scrolls of scare monster on the used-up items section of his shop bill.

     He had a lot of scroll prices which started as $X00 and were changed
to $Y99 due to integer division roundoff when being hit with a 1/3 price
increase for unID'd items followed by 1/2 price increase for low charisma:
  100  ->  133  ->  199
  200  ->  266  ->  399
Forcing things to round up instead of truncate would help in some cases
but yield $Z01 in others.  Rather than doing that, this accumulates the
adjustment factors and then uses them to make one calculation which gives
a better result:
  100  ->  200
  200  ->  400
Other values and/or other adjustments might not work out so well, but I
don't think they'll ever become prices which look worse than before.
For a single increase of 1/3, 100 still yields 133 but 200 now gives 267
(so ends up differing from the combined price for two 100->133 items).

doc/fixes35.0
src/shk.c

index cec8f59a2676d6101b8f345ce69dc6faf7c89de0..fd9801b0980b50ef34c8b4865f3ed6eec291ea46 100644 (file)
@@ -373,6 +373,7 @@ for poly'd hero hiding on ceiling, attack by sea monsters won't move them
        into hero's position unless it is over water or they're already on land
 for poly'd hero hiding on ceiling, attack by long worm might fill hero's
        destination with worm's tail, so double check and maybe choose again
+when shop prices are adjusted, handle roundoff (integer truncation) better
 
 
 Platform- and/or Interface-Specific Fixes
index d6992b6663ca4931727eec07b8492616b830651c..6d423b4400b7bc0d14750900b5fce1afd7c0ef33 100644 (file)
--- a/src/shk.c
+++ b/src/shk.c
@@ -1843,7 +1843,10 @@ get_cost(obj, shkp)
 register struct obj *obj;
 register struct monst *shkp;   /* if angry, impose a surcharge */
 {
-       register long tmp = getprice(obj, FALSE);
+       long tmp = getprice(obj, FALSE),
+            /* used to perform a single calculation even when multiple
+               adjustments (unID'd, dunce/tourist, charisma) are made */
+            multiplier = 1L, divisor = 1L;
 
        if (!tmp) tmp = 5L;
        /* shopkeeper may notice if the player isn't very knowledgeable -
@@ -1891,27 +1894,44 @@ register struct monst *shkp;    /* if angry, impose a surcharge */
                            break;
                    }
                    tmp = (long) objects[i].oc_cost;
-               } else if (!(obj->o_id % 4)) /* arbitrarily impose surcharge */
-                   tmp += tmp / 3L;
+               } else if (!(obj->o_id % 4)) {
+                   /* unid'd, arbitrarily impose surcharge: tmp *= 4/3 */
+                   multiplier *= 4L;
+                   divisor *= 3L;
+               }
        }
+       if (uarmh && uarmh->otyp == DUNCE_CAP)
+               multiplier *= 4L, divisor *= 3L;
 #ifdef TOURIST
-       if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2))
-           || (uarmu && !uarm && !uarmc))      /* touristy shirt visible */
-               tmp += tmp / 3L;
-       else
+       else if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2)) ||
+                   (uarmu && !uarm && !uarmc)) /* touristy shirt visible */
+               multiplier *= 4L, divisor *= 3L;
 #endif
-       if (uarmh && uarmh->otyp == DUNCE_CAP)
-               tmp += tmp / 3L;
-
-       if (ACURR(A_CHA) > 18)          tmp /= 2L;
-       else if (ACURR(A_CHA) > 17)     tmp -= tmp / 3L;
-       else if (ACURR(A_CHA) > 15)     tmp -= tmp / 4L;
-       else if (ACURR(A_CHA) < 6)      tmp *= 2L;
-       else if (ACURR(A_CHA) < 8)      tmp += tmp / 2L;
-       else if (ACURR(A_CHA) < 11)     tmp += tmp / 3L;
+
+       if      (ACURR(A_CHA) > 18)  divisor *= 2L;
+       else if (ACURR(A_CHA) == 18) multiplier *= 2L, divisor *= 3L;
+       else if (ACURR(A_CHA) >= 16) multiplier *= 3L, divisor *= 4L;
+       else if (ACURR(A_CHA) <= 5)  multiplier *= 2L;
+       else if (ACURR(A_CHA) <= 7)  multiplier *= 3L, divisor *= 2L;
+       else if (ACURR(A_CHA) <= 10) multiplier *= 4L, divisor *= 3L;
+
+       /* tmp = (tmp * multiplier) / divisor [with roundoff tweak] */
+       tmp *= multiplier;
+       if (divisor > 1L) {
+           /* tmp = (((tmp * 10) / divisor) + 5) / 10 */
+           tmp *= 10L;
+           tmp /= divisor;
+           tmp += 5L;
+           tmp /= 10L;
+       }
+
        if (tmp <= 0L) tmp = 1L;
-       else if (obj->oartifact) tmp *= 4L;
-       /* anger surcharge should match rile_shk's */
+       /* the artifact prices in artilist[] are also used as a score bonus;
+          inflate their shop price here without affecting score calculation */
+       if (obj->oartifact) tmp *= 4L;
+
+       /* anger surcharge should match rile_shk's, so we do it separately
+          from the multiplier/divisor calculation */
        if (shkp && ESHK(shkp)->surcharge) tmp += (tmp + 2L) / 3L;
        return tmp;
 }
@@ -2042,18 +2062,18 @@ set_cost(obj, shkp)
 register struct obj *obj;
 register struct monst *shkp;
 {
-       long tmp = getprice(obj, TRUE) * obj->quan;
+       long tmp = getprice(obj, TRUE) * obj->quan,
+            multiplier = 1L, divisor = 1L;
 
+       if (uarmh && uarmh->otyp == DUNCE_CAP)
+               divisor *= 3L;
 #ifdef TOURIST
-       if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2))
-           || (uarmu && !uarm && !uarmc))      /* touristy shirt visible */
-               tmp /= 3L;
-       else
+       else if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2)) ||
+                   (uarmu && !uarm && !uarmc)) /* touristy shirt visible */
+               divisor *= 3L;
 #endif
-       if (uarmh && uarmh->otyp == DUNCE_CAP)
-               tmp /= 3L;
        else
-               tmp /= 2L;
+               divisor *= 2L;
 
        /* shopkeeper may notice if the player isn't very knowledgeable -
           especially when gem prices are concerned */
@@ -2066,8 +2086,23 @@ register struct monst *shkp;
                                tmp = (tmp + 3) * obj->quan;
                        }
                } else if (tmp > 1L && !rn2(4))
-                       tmp -= tmp / 4L;
+                       multiplier *= 3L, divisor *= 4L;
        }
+
+       if (tmp >= 1L) {
+               /* [see get_cost()] */
+               tmp *= multiplier;
+               if (divisor > 1L) {
+                   tmp *= 10L;
+                   tmp /= divisor;
+                   tmp += 5L;
+                   tmp /= 10L;
+               }
+               /* avoid adjusting nonzero to zero */
+               if (tmp < 1L) tmp = 1L;
+       }
+
+       /* (no adjustment for angry shk here) */
        return tmp;
 }