ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/shop.c
(Generate patch)

Comparing deliantra/server/server/shop.c (file contents):
Revision 1.1.1.2 by elmex, Wed Feb 22 18:03:24 2006 UTC vs.
Revision 1.17 by root, Tue Jul 11 10:35:20 2006 UTC

1/* 1/*
2 * static char *rcsid_shop_c = 2 * static char *rcsid_shop_c =
3 * "$Id: shop.c,v 1.1.1.2 2006/02/22 18:03:24 elmex Exp $"; 3 * "$Id: shop.c,v 1.17 2006/07/11 10:35:20 root Exp $";
4 */ 4 */
5 5
6/* 6/*
7 CrossFire, A Multiplayer game for X-windows 7 CrossFire, A Multiplayer game for X-windows
8 8
43 * setting this value above 1 or to a negative value would have interesting, 43 * setting this value above 1 or to a negative value would have interesting,
44 * (though not useful) effects. 44 * (though not useful) effects.
45 */ 45 */
46#define SPECIALISATION_EFFECT 0.5 46#define SPECIALISATION_EFFECT 0.5
47 47
48/* price a shopkeeper will give to someone they disapprove of.*/
49#define DISAPPROVAL_RATIO 0.2
50
51/* price a shopkeeper will give someone they neither like nor dislike */ 48/* price a shopkeeper will give someone they neither like nor dislike */
52#define NEUTRAL_RATIO 0.8 49#define NEUTRAL_RATIO 0.8
53 50
54static uint64 pay_from_container(object *pl, object *pouch, uint64 to_pay); 51static uint64 pay_from_container(object *pl, object *pouch, uint64 to_pay);
55static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop); 52static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop);
56static double shop_specialisation_ratio(const object *item, const mapstruct *map); 53static double shop_specialisation_ratio(const object *item, const mapstruct *map);
57static double shop_greed(const mapstruct *map); 54static double shop_greed(const mapstruct *map);
58 55
59#define NUM_COINS 3 /* number of coin types */ 56#define NUM_COINS 4 /* number of coin types */
60static const char* const coins[] = {"platinacoin", "goldcoin", "silvercoin", NULL}; 57static const char* const coins[] = {"royalty", "platinacoin", "goldcoin", "silvercoin", NULL};
61 58
62/* Added F_TRUE flag to define.h to mean that the price should not 59/* Added F_TRUE flag to define.h to mean that the price should not
63 * be adjusted by players charisma. With F_TRUE, it returns the amount 60 * be adjusted by players charisma. With F_TRUE, it returns the amount
64 * that the item is worth, if it was sold, but unadjusted by charisma. 61 * that the item is worth, if it was sold, but unadjusted by charisma.
65 * This is needed for alchemy, to to determine what value of gold nuggets 62 * This is needed for alchemy, to to determine what value of gold nuggets
81 * divisions took place, the value got rounded to 0 (Being an int), and 78 * divisions took place, the value got rounded to 0 (Being an int), and
82 * thus remained 0. 79 * thus remained 0.
83 * 80 *
84 * Mark Wedel (mwedel@pyramid.com) 81 * Mark Wedel (mwedel@pyramid.com)
85 */ 82 */
83
84static uint64 approx_range;
85
86uint64 query_cost(const object *tmp, object *who, int flag) { 86uint64 query_cost(const object *tmp, object *who, int flag) {
87 uint64 val; 87 uint64 val;
88 int number; /* used to better calculate value */ 88 int number; /* used to better calculate value */
89 int no_bargain; 89 int no_bargain;
90 int identified; 90 int identified;
91 int not_cursed; 91 int not_cursed;
92 int approximate; 92 int approximate;
93 int shop; 93 int shop;
94 float diff; 94 double diff;
95 float ratio; 95
96 approx_range = 0;
96 97
97 no_bargain = flag & F_NO_BARGAIN; 98 no_bargain = flag & F_NO_BARGAIN;
98 identified = flag & F_IDENTIFIED; 99 identified = flag & F_IDENTIFIED;
99 not_cursed = flag & F_NOT_CURSED; 100 not_cursed = flag & F_NOT_CURSED;
100 approximate = flag & F_APPROX; 101 approximate = flag & F_APPROX;
124 LOG(llevError, "Asking for buy-value of unidentified object.\n"); 125 LOG(llevError, "Asking for buy-value of unidentified object.\n");
125 val = tmp->arch->clone.value * 50 * number; 126 val = tmp->arch->clone.value * 50 * number;
126 } 127 }
127 else { /* Trying to sell something, or get true value */ 128 else { /* Trying to sell something, or get true value */
128 if (tmp->type == POTION) 129 if (tmp->type == POTION)
129 val = number * 1000; /* Don't want to give anything away */ 130 val = number * 40; /* Don't want to give anything away */
130 else { 131 else {
131 /* Get 2/3'rd value for applied objects, 1/3'rd for totally 132 /* Get 2/3'rd value for applied objects, 1/3'rd for totally
132 * unknown objects 133 * unknown objects
133 */ 134 */
134 if (QUERY_FLAG(tmp, FLAG_BEEN_APPLIED)) 135 if (QUERY_FLAG(tmp, FLAG_BEEN_APPLIED))
179 else /* if not identified, presume one charge */ 180 else /* if not identified, presume one charge */
180 val/=50; 181 val/=50;
181 } 182 }
182 183
183 /* Limit amount of money you can get for really great items. */ 184 /* Limit amount of money you can get for really great items. */
184 if (flag==F_TRUE || flag==F_SELL) 185 if (flag==F_SELL)
185 val=value_limit(val, number, who, shop); 186 val=value_limit(val, number, who, shop);
187
188 // use a nonlinear price adjustment. as my predecessor said, don't change
189 // the archetypes, its work required for balancing, and we don't care.
190 //val = pow (val, 1.05);
186 191
187 /* This modification is for bargaining skill. 192 /* This modification is for bargaining skill.
188 * Now only players with max level in bargaining 193 * Now only players with max level in bargaining
189 * AND Cha = 30 will get optimal price. 194 * AND Cha = 30 will get optimal price.
190 * Thus charisma will never get useless. 195 * Thus charisma will never get useless.
196 int lev_identify = 0; 201 int lev_identify = 0;
197 int idskill1=0; 202 int idskill1=0;
198 int idskill2=0; 203 int idskill2=0;
199 const typedata *tmptype; 204 const typedata *tmptype;
200 205
201 /* ratio determines how much of the price modification
202 * will come from the basic stat charisma
203 * the rest will come from the level in bargaining skill
204 */
205 ratio = 0.5;
206 tmptype=get_typedata(tmp->type); 206 tmptype=get_typedata(tmp->type);
207 207
208 if (find_skill_by_number(who,SK_BARGAINING)) { 208 if (find_skill_by_number(who,SK_BARGAINING)) {
209 lev_bargain = find_skill_by_number(who,SK_BARGAINING)->level; 209 lev_bargain = find_skill_by_number(who,SK_BARGAINING)->level;
210 } 210 }
219 lev_identify += find_skill_by_number(who,idskill2)->level; 219 lev_identify += find_skill_by_number(who,idskill2)->level;
220 } 220 }
221 } 221 }
222 } 222 }
223 else LOG(llevError, "Query_cost: item %s hasn't got a valid type\n", tmp->name); 223 else LOG(llevError, "Query_cost: item %s hasn't got a valid type\n", tmp->name);
224 if ( !no_bargain && (lev_bargain>0) ) 224
225 diff = (0.8 - 0.6*((lev_bargain+settings.max_level*0.05) 225 /* ratio determines how much of the price modification
226 /(settings.max_level*1.05))); 226 * will come from the basic stat charisma
227 else 227 * the rest will come from the level in bargaining skill
228 diff = 0.8; 228 */
229 const double cha_ratio = 0.40;
230
231 diff = no_bargain ? 1.0 : 1. - pow (lev_bargain / (double)settings.max_level, 0.25);
229 232
230 diff *= 1-ratio; 233 diff = (1. - cha_ratio) * diff
234 + cha_ratio * (cha_bonus[who->stats.Cha] - 1.) / (cha_bonus[who->stats.Cha] + 1.);
235
236 diff = .02 + (.80 - .02) * diff;
231 237
232 /* Diff is now a float between 0.2 and 0.8 */ 238 if (flag == F_BUY) val += val * diff;
233 diff+=(cha_bonus[who->stats.Cha]-1)/(1+cha_bonus[who->stats.Cha])*ratio; 239 else if (flag == F_SELL) val -= val * diff;
234 240
235 /* we need to multiply these by 4.0 to keep buy costs roughly the same 241 // now find a price range. the less good we can judge, the larger the range is
236 * (otherwise, you could buy a potion of charisma for around 400 pp. 242 // then the range is adjusted randomly around the correct value
237 * Arguable, the costs in the archetypes should be updated to better
238 * reflect values (potion charisma list for 1250 gold)
239 */
240 if(flag==F_BUY)
241 val=(4*val*(long)(1000*(1+diff)))/1000;
242 else if (flag==F_SELL)
243 val=(4*val*(long)(1000*(1-diff)))/1000;
244 else val *=4;
245
246 /* If we are approximating, then the value returned should be allowed to be wrong
247 * however merely using a random number each time will not be sufficiant, as then
248 * multiple examinations would give different answers, so we'll use the count
249 * instead. By taking the sine of the count, a value between -1 and 1 is
250 * generated, we then divide by the square root of the bargaining skill and the
251 * appropriate identification skills, so that higher level players get better estimates.
252 * (we need a +1 there in case we would otherwise be dividing by zero.
253 */
254 if (approximate) 243 if (approximate)
255 val = (sint64)val + (sint64)((sint64)val*(sin(tmp->count)/sqrt(lev_bargain+lev_identify*2+1.0))); 244 approx_range = val / sqrt (lev_identify * 3 + 1);
256 } 245 }
257 246
258 /* I don't think this should really happen - if it does, it indicates and 247 /* I don't think this should really happen - if it does, it indicates and
259 * overflow of diff above. That shoudl only happen if 248 * overflow of diff above. That shoudl only happen if
260 * we are selling objects - in that case, the person just 249 * we are selling objects - in that case, the person just
330 * have so much money that they have more than 2 billion platinum 319 * have so much money that they have more than 2 billion platinum
331 * coins, there are certainly issues - the easiest fix at that 320 * coins, there are certainly issues - the easiest fix at that
332 * time is to add a higher denomination (mithril piece with 321 * time is to add a higher denomination (mithril piece with
333 * 10,000 silver or something) 322 * 10,000 silver or something)
334 */ 323 */
335static const char *cost_string_from_value(uint64 cost) 324static const char *cost_string_from_value(uint64 cost, int approx)
336{ 325{
337 static char buf[MAX_BUF]; 326 static char buf[MAX_BUF];
338 archetype *coin, *next_coin; 327 archetype *coin, *next_coin;
339 char *endbuf;
340 int num, cointype = 0; 328 int num, cointype = 0;
341 329
342 coin = find_next_coin(cost, &cointype); 330 coin = find_next_coin(cost, &cointype);
343 if (coin == NULL) 331 if (coin == NULL)
344 return "nothing"; 332 return "nothing";
352 strcpy(buf,"an unimaginable sum of money."); 340 strcpy(buf,"an unimaginable sum of money.");
353 return buf; 341 return buf;
354 } 342 }
355 343
356 cost -= (uint64)num * (uint64)coin->clone.value; 344 cost -= (uint64)num * (uint64)coin->clone.value;
357 if (num == 1) 345 sprintf(buf, "%d %s", num, num > 1 ? coin->clone.name_pl : coin->clone.name);
358 sprintf(buf, "1 %s", coin->clone.name);
359 else
360 sprintf(buf, "%d %ss", num, coin->clone.name);
361 346
362 next_coin = find_next_coin(cost, &cointype); 347 next_coin = find_next_coin(cost, &cointype);
363 if (next_coin == NULL) 348 if (next_coin == NULL || approx)
364 return buf; 349 return buf;
365 350
366 do {
367 endbuf = buf + strlen(buf);
368
369 coin = next_coin; 351 coin = next_coin;
370 num = cost / coin->clone.value; 352 num = cost / coin->clone.value;
371 cost -= (uint64)num * (uint64)coin->clone.value; 353 cost -= (uint64)num * (uint64)coin->clone.value;
372 354
373 if (cost == 0) 355 sprintf (buf + strlen (buf), " and %d %s", num, num > 1 ? coin->clone.name_pl : coin->clone.name);
374 next_coin = NULL; 356
375 else
376 next_coin = find_next_coin(cost, &cointype);
377
378 if (next_coin) {
379 /* There will be at least one more string to add to the list,
380 * use a comma.
381 */
382 strcat(endbuf, ", "); endbuf += 2;
383 } else {
384 strcat(endbuf, " and "); endbuf += 5;
385 }
386 if (num == 1)
387 sprintf(endbuf, "1 %s", coin->clone.name);
388 else
389 sprintf(endbuf, "%d %ss", num, coin->clone.name);
390 } while (next_coin);
391
392 return buf; 357 return buf;
393} 358}
394 359
395const char *query_cost_string(const object *tmp,object *who,int flag) { 360const char *query_cost_string(const object *tmp,object *who,int flag) {
396 uint64 real_value = query_cost(tmp,who,flag); 361 uint64 real_value = query_cost(tmp,who,flag);
436 sprintf(buf, "a vast quantity of %s", coin->clone.name_pl); 401 sprintf(buf, "a vast quantity of %s", coin->clone.name_pl);
437 return buf; 402 return buf;
438 } 403 }
439 } 404 }
440 } 405 }
406
407 int hash = ((unsigned int)tmp->count * 174364621) & 1023;
408
409 if (approx_range)
410 {
411 uint64 lo = (sint64)real_value - (approx_range * hash >> 10);
412 static char buf[MAX_BUF];
413
414 sprintf (buf, "between %s", cost_string_from_value (lo, 1));
415 sprintf (buf + strlen (buf), " and %s", cost_string_from_value (lo + approx_range, 1));
416
417 return buf;
418 }
441 } 419 }
420
442 return cost_string_from_value(real_value); 421 return cost_string_from_value (real_value, 0);
443} 422}
444 423
445/* This function finds out how much money the player is carrying, 424/* This function finds out how much money the player is carrying,
446 * including what is in containers. 425 * including what is in containers.
447 */ 426 */
667 else item = NULL; 646 else item = NULL;
668 } 647 }
669 if (unpaid_price > player_wealth) { 648 if (unpaid_price > player_wealth) {
670 char buf[MAX_BUF], coinbuf[MAX_BUF]; 649 char buf[MAX_BUF], coinbuf[MAX_BUF];
671 int denominations = 0; 650 int denominations = 0;
672 sprintf(buf, "You have %d unpaid items that would cost you %s, but you only have", 651 int has_coins = NUM_COINS;
652 char cost[MAX_BUF];
653 char missing[MAX_BUF];
654
673 unpaid_count, cost_string_from_value(unpaid_price)); 655 sprintf(cost, "%s", cost_string_from_value (unpaid_price, 0));
674 for (i=0; i< NUM_COINS; i++) { 656 sprintf(missing, "%s", cost_string_from_value (unpaid_price - player_wealth, 0));
675 if (coincount[i] > 0 && coins[i]) { 657
676 denominations++; 658 sprintf(buf, "You have %d unpaid items that would cost you %s. You need another %s to be able to afford that.",
677 sprintf(coinbuf, " %d %s,", coincount[i], find_archetype(coins[i])->clone.name_pl); 659 unpaid_count, cost, missing);
678 strcat (buf, coinbuf);
679 }
680 }
681 if (denominations > 1) make_list_like(buf);
682 new_draw_info(NDI_UNIQUE, 0, pl, buf); 660 new_draw_info(NDI_UNIQUE, 0, pl, buf);
683 return 0; 661 return 0;
684 } 662 }
685 else return 1; 663 else return 1;
686} 664}
716 buf[MAX_BUF-1] = '\0'; 694 buf[MAX_BUF-1] = '\0';
717 if(!pay_for_item(op,pl)) { 695 if(!pay_for_item(op,pl)) {
718 uint64 i=query_cost(op,pl,F_BUY | F_SHOP) - query_money(pl); 696 uint64 i=query_cost(op,pl,F_BUY | F_SHOP) - query_money(pl);
719 CLEAR_FLAG(op, FLAG_UNPAID); 697 CLEAR_FLAG(op, FLAG_UNPAID);
720 new_draw_info_format(NDI_UNIQUE, 0, pl, 698 new_draw_info_format(NDI_UNIQUE, 0, pl,
721 "You lack %s to buy %s.", cost_string_from_value(i), 699 "You lack %s to buy %s.", cost_string_from_value (i, 0),
722 query_name(op)); 700 query_name(op));
723 SET_FLAG(op, FLAG_UNPAID); 701 SET_FLAG(op, FLAG_UNPAID);
724 return 0; 702 return 0;
725 } else { 703 } else {
726 object *tmp; 704 object *tmp;
914static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop) { 892static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop) {
915 uint64 newval, unit_price; 893 uint64 newval, unit_price;
916 mapstruct *map; 894 mapstruct *map;
917 unit_price=val/quantity; 895 unit_price=val/quantity;
918 if (!isshop || !who) { 896 if (!isshop || !who) {
919 if (unit_price > 10000) 897 if (unit_price > 250000)
920 newval=8000+isqrt(unit_price)*20; 898 newval = 250000. - pow (250000., .75) * 65. + pow (unit_price, .75) * 65.;
921 else 899 else
922 newval=unit_price; 900 newval=unit_price;
923 } else { 901 } else {
924 if (!who->map) { 902 if (!who->map) {
925 LOG(llevError, "value_limit: asked shop price for ob %s on NULL map\n", who->name); 903 LOG(llevError, "value_limit: asked shop price for ob %s on NULL map\n", who->name);
927 } 905 }
928 map=who->map; 906 map=who->map;
929 if (map->shopmin && unit_price < map->shopmin) return 0; 907 if (map->shopmin && unit_price < map->shopmin) return 0;
930 else if (map->shopmax && unit_price > map->shopmax/2) 908 else if (map->shopmax && unit_price > map->shopmax/2)
931 newval=MIN((map->shopmax/2)+isqrt(unit_price-map->shopmax/2), map->shopmax); 909 newval=MIN((map->shopmax/2)+isqrt(unit_price-map->shopmax/2), map->shopmax);
932 else if (unit_price>10000) 910 else if (unit_price > 250000)
933 newval=8000+isqrt(unit_price)*20; 911 newval = 250000. - pow (250000., .75) * 65. + pow (unit_price, .75) * 65.;
934 else 912 else
935 newval=unit_price; 913 newval=unit_price;
936 } 914 }
937 newval *= quantity; 915 newval *= quantity;
938 return newval; 916 return newval;
964 make_list_like(tmp); 942 make_list_like(tmp);
965 new_draw_info_format(NDI_UNIQUE, 0, op, "%s", tmp); 943 new_draw_info_format(NDI_UNIQUE, 0, op, "%s", tmp);
966 944
967 if (map->shopmax) 945 if (map->shopmax)
968 new_draw_info_format(NDI_UNIQUE,0,op,"It won't trade for items above %s.", 946 new_draw_info_format(NDI_UNIQUE,0,op,"It won't trade for items above %s.",
969 cost_string_from_value(map->shopmax)); 947 cost_string_from_value(map->shopmax, 0));
970 if (map->shopmin) 948 if (map->shopmin)
971 new_draw_info_format(NDI_UNIQUE,0,op,"It won't trade in items worth less than %s.", 949 new_draw_info_format(NDI_UNIQUE,0,op,"It won't trade in items worth less than %s.",
972 cost_string_from_value(map->shopmin)); 950 cost_string_from_value(map->shopmin, 0));
973 if (map->shopgreed) { 951 if (map->shopgreed) {
974 if (map->shopgreed >2.0) 952 if (map->shopgreed >2.0)
975 new_draw_info(NDI_UNIQUE,0,op,"It tends to overcharge massively."); 953 new_draw_info(NDI_UNIQUE,0,op,"It tends to overcharge massively.");
976 else if (map->shopgreed >1.5) 954 else if (map->shopgreed >1.5)
977 new_draw_info(NDI_UNIQUE,0,op,"It tends to overcharge substantially."); 955 new_draw_info(NDI_UNIQUE,0,op,"It tends to overcharge substantially.");

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines