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 | |
54 | static uint64 pay_from_container(object *pl, object *pouch, uint64 to_pay); |
51 | static uint64 pay_from_container(object *pl, object *pouch, uint64 to_pay); |
55 | static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop); |
52 | static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop); |
56 | static double shop_specialisation_ratio(const object *item, const mapstruct *map); |
53 | static double shop_specialisation_ratio(const object *item, const mapstruct *map); |
57 | static double shop_greed(const mapstruct *map); |
54 | static 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 */ |
60 | static const char* const coins[] = {"platinacoin", "goldcoin", "silvercoin", NULL}; |
57 | static 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 | |
|
|
84 | static uint64 approx_range; |
|
|
85 | |
86 | uint64 query_cost(const object *tmp, object *who, int flag) { |
86 | uint64 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 | */ |
335 | static const char *cost_string_from_value(uint64 cost) |
324 | static 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 | |
395 | const char *query_cost_string(const object *tmp,object *who,int flag) { |
360 | const 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; |
… | |
… | |
914 | static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop) { |
892 | static 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."); |