1 | /* |
1 | /* |
2 | * static char *rcsid_shop_c = |
2 | * static char *rcsid_shop_c = |
3 | * "$Id: shop.c,v 1.7 2006/06/25 22:19:42 root 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 | |
… | |
… | |
78 | * 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 |
79 | * thus remained 0. |
79 | * thus remained 0. |
80 | * |
80 | * |
81 | * Mark Wedel (mwedel@pyramid.com) |
81 | * Mark Wedel (mwedel@pyramid.com) |
82 | */ |
82 | */ |
|
|
83 | |
|
|
84 | static uint64 approx_range; |
|
|
85 | |
83 | uint64 query_cost(const object *tmp, object *who, int flag) { |
86 | uint64 query_cost(const object *tmp, object *who, int flag) { |
84 | uint64 val; |
87 | uint64 val; |
85 | int number; /* used to better calculate value */ |
88 | int number; /* used to better calculate value */ |
86 | int no_bargain; |
89 | int no_bargain; |
87 | int identified; |
90 | int identified; |
88 | int not_cursed; |
91 | int not_cursed; |
89 | int approximate; |
92 | int approximate; |
90 | int shop; |
93 | int shop; |
91 | double diff; |
94 | double diff; |
|
|
95 | |
|
|
96 | approx_range = 0; |
92 | |
97 | |
93 | no_bargain = flag & F_NO_BARGAIN; |
98 | no_bargain = flag & F_NO_BARGAIN; |
94 | identified = flag & F_IDENTIFIED; |
99 | identified = flag & F_IDENTIFIED; |
95 | not_cursed = flag & F_NOT_CURSED; |
100 | not_cursed = flag & F_NOT_CURSED; |
96 | approximate = flag & F_APPROX; |
101 | approximate = flag & F_APPROX; |
… | |
… | |
120 | LOG(llevError, "Asking for buy-value of unidentified object.\n"); |
125 | LOG(llevError, "Asking for buy-value of unidentified object.\n"); |
121 | val = tmp->arch->clone.value * 50 * number; |
126 | val = tmp->arch->clone.value * 50 * number; |
122 | } |
127 | } |
123 | else { /* Trying to sell something, or get true value */ |
128 | else { /* Trying to sell something, or get true value */ |
124 | if (tmp->type == POTION) |
129 | if (tmp->type == POTION) |
125 | val = number * 1000; /* Don't want to give anything away */ |
130 | val = number * 40; /* Don't want to give anything away */ |
126 | else { |
131 | else { |
127 | /* 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 |
128 | * unknown objects |
133 | * unknown objects |
129 | */ |
134 | */ |
130 | if (QUERY_FLAG(tmp, FLAG_BEEN_APPLIED)) |
135 | if (QUERY_FLAG(tmp, FLAG_BEEN_APPLIED)) |
… | |
… | |
175 | else /* if not identified, presume one charge */ |
180 | else /* if not identified, presume one charge */ |
176 | val/=50; |
181 | val/=50; |
177 | } |
182 | } |
178 | |
183 | |
179 | /* Limit amount of money you can get for really great items. */ |
184 | /* Limit amount of money you can get for really great items. */ |
180 | if (flag==F_TRUE || flag==F_SELL) |
185 | if (flag==F_SELL) |
181 | val=value_limit(val, number, who, shop); |
186 | val=value_limit(val, number, who, shop); |
182 | |
187 | |
183 | // use a nonlinear price adjustment. as my predecessor said, don't change |
188 | // use a nonlinear price adjustment. as my predecessor said, don't change |
184 | // the archetypes, its work required for balancing, and we don't care. |
189 | // the archetypes, its work required for balancing, and we don't care. |
185 | val = pow (val / 128., 1.4) * 128.; |
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. |
… | |
… | |
219 | |
224 | |
220 | /* ratio determines how much of the price modification |
225 | /* ratio determines how much of the price modification |
221 | * will come from the basic stat charisma |
226 | * will come from the basic stat charisma |
222 | * the rest will come from the level in bargaining skill |
227 | * the rest will come from the level in bargaining skill |
223 | */ |
228 | */ |
224 | const double cha_ratio = 0.35; |
229 | const double cha_ratio = 0.40; |
225 | |
230 | |
226 | diff = no_bargain ? 1.0 : 1. - pow (lev_bargain / (double)settings.max_level, 0.25); |
231 | diff = no_bargain ? 1.0 : 1. - pow (lev_bargain / (double)settings.max_level, 0.25); |
227 | |
232 | |
228 | diff = (1. - cha_ratio) * diff |
233 | diff = (1. - cha_ratio) * diff |
229 | + cha_ratio * (cha_bonus[who->stats.Cha] - 1.) / (cha_bonus[who->stats.Cha] + 1.); |
234 | + cha_ratio * (cha_bonus[who->stats.Cha] - 1.) / (cha_bonus[who->stats.Cha] + 1.); |
230 | |
235 | |
231 | diff = .02 + (1. - .02) * diff; |
236 | diff = .02 + (.80 - .02) * diff; |
232 | |
237 | |
233 | if (flag == F_BUY) val = val * (1. + diff); |
238 | if (flag == F_BUY) val += val * diff; |
234 | else if (flag == F_SELL) val = val * (1. - diff); |
239 | else if (flag == F_SELL) val -= val * diff; |
235 | |
240 | |
236 | /* If we are approximating, then the value returned should be |
241 | // now find a price range. the less good we can judge, the larger the range is |
237 | * allowed to be wrong however merely using a random number each |
242 | // then the range is adjusted randomly around the correct value |
238 | * time will not be sufficiant, as then multiple examinations |
|
|
239 | * would give different answers, so we'll use the count |
|
|
240 | * instead. Using the count, generate a value between -1 |
|
|
241 | * and 1, we then divide by the square root of the |
|
|
242 | * appropriate identification skills, so that higher level players |
|
|
243 | * get better estimates. |
|
|
244 | */ |
|
|
245 | |
|
|
246 | if (approximate) |
243 | if (approximate) |
247 | val += val * ((((int)(tmp->count & 1023) - 512) / 512.) / sqrt (lev_identify * 0.6 + 0.3)); |
244 | approx_range = val / sqrt (lev_identify * 3 + 1); |
248 | } |
245 | } |
249 | |
246 | |
250 | /* 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 |
251 | * overflow of diff above. That shoudl only happen if |
248 | * overflow of diff above. That shoudl only happen if |
252 | * we are selling objects - in that case, the person just |
249 | * we are selling objects - in that case, the person just |
… | |
… | |
322 | * 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 |
323 | * coins, there are certainly issues - the easiest fix at that |
320 | * coins, there are certainly issues - the easiest fix at that |
324 | * time is to add a higher denomination (mithril piece with |
321 | * time is to add a higher denomination (mithril piece with |
325 | * 10,000 silver or something) |
322 | * 10,000 silver or something) |
326 | */ |
323 | */ |
327 | static const char *cost_string_from_value(uint64 cost) |
324 | static const char *cost_string_from_value(uint64 cost, int approx) |
328 | { |
325 | { |
329 | static char buf[MAX_BUF]; |
326 | static char buf[MAX_BUF]; |
330 | archetype *coin, *next_coin; |
327 | archetype *coin, *next_coin; |
331 | char *endbuf; |
|
|
332 | int num, cointype = 0; |
328 | int num, cointype = 0; |
333 | |
329 | |
334 | coin = find_next_coin(cost, &cointype); |
330 | coin = find_next_coin(cost, &cointype); |
335 | if (coin == NULL) |
331 | if (coin == NULL) |
336 | return "nothing"; |
332 | return "nothing"; |
… | |
… | |
344 | strcpy(buf,"an unimaginable sum of money."); |
340 | strcpy(buf,"an unimaginable sum of money."); |
345 | return buf; |
341 | return buf; |
346 | } |
342 | } |
347 | |
343 | |
348 | cost -= (uint64)num * (uint64)coin->clone.value; |
344 | cost -= (uint64)num * (uint64)coin->clone.value; |
349 | if (num == 1) |
345 | sprintf(buf, "%d %s", num, num > 1 ? coin->clone.name_pl : coin->clone.name); |
350 | sprintf(buf, "1 %s", coin->clone.name); |
|
|
351 | else |
|
|
352 | sprintf(buf, "%d %s", num, coin->clone.name_pl); |
|
|
353 | |
346 | |
354 | next_coin = find_next_coin(cost, &cointype); |
347 | next_coin = find_next_coin(cost, &cointype); |
355 | if (next_coin == NULL) |
348 | if (next_coin == NULL || approx) |
356 | return buf; |
349 | return buf; |
357 | |
|
|
358 | endbuf = buf + strlen(buf); |
|
|
359 | |
350 | |
360 | coin = next_coin; |
351 | coin = next_coin; |
361 | num = cost / coin->clone.value; |
352 | num = cost / coin->clone.value; |
362 | cost -= (uint64)num * (uint64)coin->clone.value; |
353 | cost -= (uint64)num * (uint64)coin->clone.value; |
363 | |
354 | |
364 | strcat(endbuf, " and "); endbuf += 5; |
355 | sprintf (buf + strlen (buf), " and %d %s", num, num > 1 ? coin->clone.name_pl : coin->clone.name); |
365 | if (num == 1) |
|
|
366 | sprintf(endbuf, "1 %s", coin->clone.name); |
|
|
367 | else |
|
|
368 | sprintf(endbuf, "%d %s", num, coin->clone.name_pl); |
|
|
369 | |
356 | |
370 | return buf; |
357 | return buf; |
371 | } |
358 | } |
372 | |
359 | |
373 | 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) { |
… | |
… | |
414 | sprintf(buf, "a vast quantity of %s", coin->clone.name_pl); |
401 | sprintf(buf, "a vast quantity of %s", coin->clone.name_pl); |
415 | return buf; |
402 | return buf; |
416 | } |
403 | } |
417 | } |
404 | } |
418 | } |
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 | } |
419 | } |
419 | } |
|
|
420 | |
420 | return cost_string_from_value(real_value); |
421 | return cost_string_from_value (real_value, 0); |
421 | } |
422 | } |
422 | |
423 | |
423 | /* This function finds out how much money the player is carrying, |
424 | /* This function finds out how much money the player is carrying, |
424 | * including what is in containers. |
425 | * including what is in containers. |
425 | */ |
426 | */ |
… | |
… | |
649 | int denominations = 0; |
650 | int denominations = 0; |
650 | int has_coins = NUM_COINS; |
651 | int has_coins = NUM_COINS; |
651 | char cost[MAX_BUF]; |
652 | char cost[MAX_BUF]; |
652 | char missing[MAX_BUF]; |
653 | char missing[MAX_BUF]; |
653 | |
654 | |
654 | sprintf(cost, "%s", cost_string_from_value(unpaid_price)); |
655 | sprintf(cost, "%s", cost_string_from_value (unpaid_price, 0)); |
655 | sprintf(missing, "%s", cost_string_from_value(unpaid_price - player_wealth)); |
656 | sprintf(missing, "%s", cost_string_from_value (unpaid_price - player_wealth, 0)); |
656 | |
657 | |
657 | sprintf(buf, "You have %d unpaid items that would cost you %s. You need another %s to be able to afford that.", |
658 | sprintf(buf, "You have %d unpaid items that would cost you %s. You need another %s to be able to afford that.", |
658 | unpaid_count, cost, missing); |
659 | unpaid_count, cost, missing); |
659 | new_draw_info(NDI_UNIQUE, 0, pl, buf); |
660 | new_draw_info(NDI_UNIQUE, 0, pl, buf); |
660 | return 0; |
661 | return 0; |
… | |
… | |
693 | buf[MAX_BUF-1] = '\0'; |
694 | buf[MAX_BUF-1] = '\0'; |
694 | if(!pay_for_item(op,pl)) { |
695 | if(!pay_for_item(op,pl)) { |
695 | 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); |
696 | CLEAR_FLAG(op, FLAG_UNPAID); |
697 | CLEAR_FLAG(op, FLAG_UNPAID); |
697 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
698 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
698 | "You lack %s to buy %s.", cost_string_from_value(i), |
699 | "You lack %s to buy %s.", cost_string_from_value (i, 0), |
699 | query_name(op)); |
700 | query_name(op)); |
700 | SET_FLAG(op, FLAG_UNPAID); |
701 | SET_FLAG(op, FLAG_UNPAID); |
701 | return 0; |
702 | return 0; |
702 | } else { |
703 | } else { |
703 | object *tmp; |
704 | object *tmp; |
… | |
… | |
891 | 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) { |
892 | uint64 newval, unit_price; |
893 | uint64 newval, unit_price; |
893 | mapstruct *map; |
894 | mapstruct *map; |
894 | unit_price=val/quantity; |
895 | unit_price=val/quantity; |
895 | if (!isshop || !who) { |
896 | if (!isshop || !who) { |
896 | if (unit_price > 10000) |
897 | if (unit_price > 250000) |
897 | newval=8000+isqrt(unit_price)*20; |
898 | newval = 250000. - pow (250000., .75) * 65. + pow (unit_price, .75) * 65.; |
898 | else |
899 | else |
899 | newval=unit_price; |
900 | newval=unit_price; |
900 | } else { |
901 | } else { |
901 | if (!who->map) { |
902 | if (!who->map) { |
902 | 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); |
… | |
… | |
904 | } |
905 | } |
905 | map=who->map; |
906 | map=who->map; |
906 | if (map->shopmin && unit_price < map->shopmin) return 0; |
907 | if (map->shopmin && unit_price < map->shopmin) return 0; |
907 | else if (map->shopmax && unit_price > map->shopmax/2) |
908 | else if (map->shopmax && unit_price > map->shopmax/2) |
908 | 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); |
909 | else if (unit_price>10000) |
910 | else if (unit_price > 250000) |
910 | newval=8000+isqrt(unit_price)*20; |
911 | newval = 250000. - pow (250000., .75) * 65. + pow (unit_price, .75) * 65.; |
911 | else |
912 | else |
912 | newval=unit_price; |
913 | newval=unit_price; |
913 | } |
914 | } |
914 | newval *= quantity; |
915 | newval *= quantity; |
915 | return newval; |
916 | return newval; |
… | |
… | |
941 | make_list_like(tmp); |
942 | make_list_like(tmp); |
942 | new_draw_info_format(NDI_UNIQUE, 0, op, "%s", tmp); |
943 | new_draw_info_format(NDI_UNIQUE, 0, op, "%s", tmp); |
943 | |
944 | |
944 | if (map->shopmax) |
945 | if (map->shopmax) |
945 | 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.", |
946 | cost_string_from_value(map->shopmax)); |
947 | cost_string_from_value(map->shopmax, 0)); |
947 | if (map->shopmin) |
948 | if (map->shopmin) |
948 | 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.", |
949 | cost_string_from_value(map->shopmin)); |
950 | cost_string_from_value(map->shopmin, 0)); |
950 | if (map->shopgreed) { |
951 | if (map->shopgreed) { |
951 | if (map->shopgreed >2.0) |
952 | if (map->shopgreed >2.0) |
952 | 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."); |
953 | else if (map->shopgreed >1.5) |
954 | else if (map->shopgreed >1.5) |
954 | 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."); |