1 | /* |
1 | /* |
2 | * static char *rcsid_shop_c = |
2 | * static char *rcsid_shop_c = |
3 | * "$Id: shop.c,v 1.1 2006/02/03 07:14:37 root Exp $"; |
3 | * "$Id: shop.c,v 1.13 2006/07/05 21:02:50 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, object *who, int isshop); |
52 | static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop); |
|
|
53 | static double shop_specialisation_ratio(const object *item, const mapstruct *map); |
|
|
54 | static double shop_greed(const mapstruct *map); |
56 | |
55 | |
57 | #define NUM_COINS 3 /* number of coin types */ |
56 | #define NUM_COINS 4 /* number of coin types */ |
58 | static char *coins[] = {"platinacoin", "goldcoin", "silvercoin", NULL}; |
57 | static const char* const coins[] = {"royalty", "platinacoin", "goldcoin", "silvercoin", NULL}; |
59 | |
58 | |
60 | /* 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 |
61 | * 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 |
62 | * 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. |
63 | * 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 |
… | |
… | |
79 | * 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 |
80 | * thus remained 0. |
79 | * thus remained 0. |
81 | * |
80 | * |
82 | * Mark Wedel (mwedel@pyramid.com) |
81 | * Mark Wedel (mwedel@pyramid.com) |
83 | */ |
82 | */ |
|
|
83 | |
|
|
84 | static uint64 approx_range; |
|
|
85 | |
84 | uint64 query_cost(object *tmp, object *who, int flag) { |
86 | uint64 query_cost(const object *tmp, object *who, int flag) { |
85 | uint64 val; |
87 | uint64 val; |
86 | int number; /* used to better calculate value */ |
88 | int number; /* used to better calculate value */ |
87 | int no_bargain; |
89 | int no_bargain; |
88 | int identified; |
90 | int identified; |
89 | int not_cursed; |
91 | int not_cursed; |
90 | int approximate; |
92 | int approximate; |
91 | int shop; |
93 | int shop; |
92 | float diff; |
94 | double diff; |
93 | float ratio; |
95 | |
|
|
96 | approx_range = 0; |
94 | |
97 | |
95 | no_bargain = flag & F_NO_BARGAIN; |
98 | no_bargain = flag & F_NO_BARGAIN; |
96 | identified = flag & F_IDENTIFIED; |
99 | identified = flag & F_IDENTIFIED; |
97 | not_cursed = flag & F_NOT_CURSED; |
100 | not_cursed = flag & F_NOT_CURSED; |
98 | approximate = flag & F_APPROX; |
101 | approximate = flag & F_APPROX; |
… | |
… | |
177 | else /* if not identified, presume one charge */ |
180 | else /* if not identified, presume one charge */ |
178 | val/=50; |
181 | val/=50; |
179 | } |
182 | } |
180 | |
183 | |
181 | /* Limit amount of money you can get for really great items. */ |
184 | /* Limit amount of money you can get for really great items. */ |
182 | if (flag==F_TRUE || flag==F_SELL) |
185 | if (flag==F_SELL) |
183 | 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.2); |
184 | |
191 | |
185 | /* This modification is for bargaining skill. |
192 | /* This modification is for bargaining skill. |
186 | * Now only players with max level in bargaining |
193 | * Now only players with max level in bargaining |
187 | * AND Cha = 30 will get optimal price. |
194 | * AND Cha = 30 will get optimal price. |
188 | * Thus charisma will never get useless. |
195 | * Thus charisma will never get useless. |
… | |
… | |
194 | int lev_identify = 0; |
201 | int lev_identify = 0; |
195 | int idskill1=0; |
202 | int idskill1=0; |
196 | int idskill2=0; |
203 | int idskill2=0; |
197 | const typedata *tmptype; |
204 | const typedata *tmptype; |
198 | |
205 | |
199 | /* ratio determines how much of the price modification |
|
|
200 | * will come from the basic stat charisma |
|
|
201 | * the rest will come from the level in bargaining skill |
|
|
202 | */ |
|
|
203 | ratio = 0.5; |
|
|
204 | tmptype=get_typedata(tmp->type); |
206 | tmptype=get_typedata(tmp->type); |
205 | |
207 | |
206 | if (find_skill_by_number(who,SK_BARGAINING)) { |
208 | if (find_skill_by_number(who,SK_BARGAINING)) { |
207 | lev_bargain = find_skill_by_number(who,SK_BARGAINING)->level; |
209 | lev_bargain = find_skill_by_number(who,SK_BARGAINING)->level; |
208 | } |
210 | } |
… | |
… | |
217 | lev_identify += find_skill_by_number(who,idskill2)->level; |
219 | lev_identify += find_skill_by_number(who,idskill2)->level; |
218 | } |
220 | } |
219 | } |
221 | } |
220 | } |
222 | } |
221 | 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); |
222 | if ( !no_bargain && (lev_bargain>0) ) |
224 | |
223 | diff = (0.8 - 0.6*((lev_bargain+settings.max_level*0.05) |
225 | /* ratio determines how much of the price modification |
224 | /(settings.max_level*1.05))); |
226 | * will come from the basic stat charisma |
225 | else |
227 | * the rest will come from the level in bargaining skill |
226 | diff = 0.8; |
228 | */ |
|
|
229 | const double cha_ratio = 0.45; |
|
|
230 | |
|
|
231 | diff = no_bargain ? 1.0 : 1. - pow (lev_bargain / (double)settings.max_level, 0.25); |
227 | |
232 | |
228 | 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 + (0.80. - .02) * diff; |
229 | |
237 | |
230 | /* Diff is now a float between 0.2 and 0.8 */ |
238 | if (flag == F_BUY) val += val * diff; |
231 | diff+=(cha_bonus[who->stats.Cha]-1)/(1+cha_bonus[who->stats.Cha])*ratio; |
239 | else if (flag == F_SELL) val -= val * diff; |
232 | |
240 | |
233 | /* 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 |
234 | * (otherwise, you could buy a potion of charisma for around 400 pp. |
242 | // then the range is adjusted randomly around the correct value |
235 | * Arguable, the costs in the archetypes should be updated to better |
|
|
236 | * reflect values (potion charisma list for 1250 gold) |
|
|
237 | */ |
|
|
238 | if(flag==F_BUY) |
|
|
239 | val=(4*val*(long)(1000*(1+diff)))/1000; |
|
|
240 | else if (flag==F_SELL) |
|
|
241 | val=(4*val*(long)(1000*(1-diff)))/1000; |
|
|
242 | else val *=4; |
|
|
243 | |
|
|
244 | /* If we are approximating, then the value returned should be allowed to be wrong |
|
|
245 | * however merely using a random number each time will not be sufficiant, as then |
|
|
246 | * multiple examinations would give different answers, so we'll use the count |
|
|
247 | * instead. By taking the sine of the count, a value between -1 and 1 is |
|
|
248 | * generated, we then divide by the square root of the bargaining skill and the |
|
|
249 | * appropriate identification skills, so that higher level players get better estimates. |
|
|
250 | * (we need a +1 there in case we would otherwise be dividing by zero. |
|
|
251 | */ |
|
|
252 | if (approximate) |
243 | if (approximate) |
253 | 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); |
254 | } |
245 | } |
255 | |
246 | |
256 | /* 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 |
257 | * overflow of diff above. That shoudl only happen if |
248 | * overflow of diff above. That shoudl only happen if |
258 | * we are selling objects - in that case, the person just |
249 | * we are selling objects - in that case, the person just |
… | |
… | |
328 | * 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 |
329 | * coins, there are certainly issues - the easiest fix at that |
320 | * coins, there are certainly issues - the easiest fix at that |
330 | * time is to add a higher denomination (mithril piece with |
321 | * time is to add a higher denomination (mithril piece with |
331 | * 10,000 silver or something) |
322 | * 10,000 silver or something) |
332 | */ |
323 | */ |
333 | const char *cost_string_from_value(uint64 cost) |
324 | static const char *cost_string_from_value(uint64 cost, int approx) |
334 | { |
325 | { |
335 | static char buf[MAX_BUF]; |
326 | static char buf[MAX_BUF]; |
336 | archetype *coin, *next_coin; |
327 | archetype *coin, *next_coin; |
337 | char *endbuf; |
|
|
338 | int num, cointype = 0; |
328 | int num, cointype = 0; |
339 | |
329 | |
340 | coin = find_next_coin(cost, &cointype); |
330 | coin = find_next_coin(cost, &cointype); |
341 | if (coin == NULL) |
331 | if (coin == NULL) |
342 | return "nothing"; |
332 | return "nothing"; |
… | |
… | |
350 | strcpy(buf,"an unimaginable sum of money."); |
340 | strcpy(buf,"an unimaginable sum of money."); |
351 | return buf; |
341 | return buf; |
352 | } |
342 | } |
353 | |
343 | |
354 | cost -= (uint64)num * (uint64)coin->clone.value; |
344 | cost -= (uint64)num * (uint64)coin->clone.value; |
355 | if (num == 1) |
345 | sprintf(buf, "%d %s", num, num > 1 ? coin->clone.name_pl : coin->clone.name); |
356 | sprintf(buf, "1 %s", coin->clone.name); |
|
|
357 | else |
|
|
358 | sprintf(buf, "%d %ss", num, coin->clone.name); |
|
|
359 | |
346 | |
360 | next_coin = find_next_coin(cost, &cointype); |
347 | next_coin = find_next_coin(cost, &cointype); |
361 | if (next_coin == NULL) |
348 | if (next_coin == NULL || approx) |
362 | return buf; |
349 | return buf; |
363 | |
350 | |
364 | do { |
|
|
365 | endbuf = buf + strlen(buf); |
|
|
366 | |
|
|
367 | coin = next_coin; |
351 | coin = next_coin; |
368 | num = cost / coin->clone.value; |
352 | num = cost / coin->clone.value; |
369 | cost -= (uint64)num * (uint64)coin->clone.value; |
353 | cost -= (uint64)num * (uint64)coin->clone.value; |
370 | |
354 | |
371 | if (cost == 0) |
355 | sprintf (buf + strlen (buf), " and %d %s", num, num > 1 ? coin->clone.name_pl : coin->clone.name); |
372 | next_coin = NULL; |
356 | |
373 | else |
|
|
374 | next_coin = find_next_coin(cost, &cointype); |
|
|
375 | |
|
|
376 | if (next_coin) { |
|
|
377 | /* There will be at least one more string to add to the list, |
|
|
378 | * use a comma. |
|
|
379 | */ |
|
|
380 | strcat(endbuf, ", "); endbuf += 2; |
|
|
381 | } else { |
|
|
382 | strcat(endbuf, " and "); endbuf += 5; |
|
|
383 | } |
|
|
384 | if (num == 1) |
|
|
385 | sprintf(endbuf, "1 %s", coin->clone.name); |
|
|
386 | else |
|
|
387 | sprintf(endbuf, "%d %ss", num, coin->clone.name); |
|
|
388 | } while (next_coin); |
|
|
389 | |
|
|
390 | return buf; |
357 | return buf; |
391 | } |
358 | } |
392 | |
359 | |
393 | const char *query_cost_string(object *tmp,object *who,int flag) { |
360 | const char *query_cost_string(const object *tmp,object *who,int flag) { |
394 | uint64 real_value = query_cost(tmp,who,flag); |
361 | uint64 real_value = query_cost(tmp,who,flag); |
395 | int idskill1=0; |
362 | int idskill1=0; |
396 | int idskill2=0; |
363 | int idskill2=0; |
397 | const typedata *tmptype; |
364 | const typedata *tmptype; |
398 | |
365 | |
… | |
… | |
434 | sprintf(buf, "a vast quantity of %s", coin->clone.name_pl); |
401 | sprintf(buf, "a vast quantity of %s", coin->clone.name_pl); |
435 | return buf; |
402 | return buf; |
436 | } |
403 | } |
437 | } |
404 | } |
438 | } |
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 | } |
439 | } |
419 | } |
|
|
420 | |
440 | return cost_string_from_value(real_value); |
421 | return cost_string_from_value (real_value, 0); |
441 | } |
422 | } |
442 | |
423 | |
443 | /* This function finds out how much money the player is carrying, |
424 | /* This function finds out how much money the player is carrying, |
444 | * including what is in containers. |
425 | * including what is in containers. |
445 | */ |
426 | */ |
446 | uint64 query_money(object *op) { |
427 | uint64 query_money(const object *op) { |
447 | object *tmp; |
428 | object *tmp; |
448 | uint64 total=0; |
429 | uint64 total=0; |
449 | |
430 | |
450 | if (op->type!=PLAYER && op->type!=CONTAINER) { |
431 | if (op->type!=PLAYER && op->type!=CONTAINER) { |
451 | LOG(llevError, "Query money called with non player/container\n"); |
432 | LOG(llevError, "Query money called with non player/container\n"); |
… | |
… | |
642 | uint64 unpaid_price = 0; |
623 | uint64 unpaid_price = 0; |
643 | uint64 player_wealth = query_money(pl); |
624 | uint64 player_wealth = query_money(pl); |
644 | object *item; |
625 | object *item; |
645 | uint32 coincount[NUM_COINS]; |
626 | uint32 coincount[NUM_COINS]; |
646 | if (!pl || pl->type != PLAYER) { |
627 | if (!pl || pl->type != PLAYER) { |
647 | LOG(llevError, "can_pay(): called against something that isn't a player"); |
628 | LOG(llevError, "can_pay(): called against something that isn't a player\n"); |
648 | return 0; |
629 | return 0; |
649 | } |
630 | } |
650 | for (i=0; i< NUM_COINS; i++) coincount[i] = 0; |
631 | for (i=0; i< NUM_COINS; i++) coincount[i] = 0; |
651 | for (item = pl->inv;item;) { |
632 | for (item = pl->inv;item;) { |
652 | if QUERY_FLAG(item, FLAG_UNPAID) { |
633 | if QUERY_FLAG(item, FLAG_UNPAID) { |
… | |
… | |
665 | else item = NULL; |
646 | else item = NULL; |
666 | } |
647 | } |
667 | if (unpaid_price > player_wealth) { |
648 | if (unpaid_price > player_wealth) { |
668 | char buf[MAX_BUF], coinbuf[MAX_BUF]; |
649 | char buf[MAX_BUF], coinbuf[MAX_BUF]; |
669 | int denominations = 0; |
650 | int denominations = 0; |
670 | 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 | |
671 | unpaid_count, cost_string_from_value(unpaid_price)); |
655 | sprintf(cost, "%s", cost_string_from_value (unpaid_price, 0)); |
672 | for (i=0; i< NUM_COINS; i++) { |
656 | sprintf(missing, "%s", cost_string_from_value (unpaid_price - player_wealth, 0)); |
673 | if (coincount[i] > 0 && coins[i]) { |
657 | |
674 | denominations++; |
658 | sprintf(buf, "You have %d unpaid items that would cost you %s. You need another %s to be able to afford that.", |
675 | sprintf(coinbuf, " %d %s,", coincount[i], find_archetype(coins[i])->clone.name_pl); |
659 | unpaid_count, cost, missing); |
676 | strcat (buf, coinbuf); |
|
|
677 | } |
|
|
678 | } |
|
|
679 | if (denominations > 1) make_list_like(buf); |
|
|
680 | new_draw_info(NDI_UNIQUE, 0, pl, buf); |
660 | new_draw_info(NDI_UNIQUE, 0, pl, buf); |
681 | return 0; |
661 | return 0; |
682 | } |
662 | } |
683 | else return 1; |
663 | else return 1; |
684 | } |
664 | } |
… | |
… | |
714 | buf[MAX_BUF-1] = '\0'; |
694 | buf[MAX_BUF-1] = '\0'; |
715 | if(!pay_for_item(op,pl)) { |
695 | if(!pay_for_item(op,pl)) { |
716 | 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); |
717 | CLEAR_FLAG(op, FLAG_UNPAID); |
697 | CLEAR_FLAG(op, FLAG_UNPAID); |
718 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
698 | new_draw_info_format(NDI_UNIQUE, 0, pl, |
719 | "You lack %s to buy %s.", cost_string_from_value(i), |
699 | "You lack %s to buy %s.", cost_string_from_value (i, 0), |
720 | query_name(op)); |
700 | query_name(op)); |
721 | SET_FLAG(op, FLAG_UNPAID); |
701 | SET_FLAG(op, FLAG_UNPAID); |
722 | return 0; |
702 | return 0; |
723 | } else { |
703 | } else { |
724 | object *tmp; |
704 | object *tmp; |
… | |
… | |
842 | /* returns a double that is the ratio of the price that a shop will offer for |
822 | /* returns a double that is the ratio of the price that a shop will offer for |
843 | * item based on the shops specialisation. Does not take account of greed, |
823 | * item based on the shops specialisation. Does not take account of greed, |
844 | * returned value is between (2*SPECIALISATION_EFFECT-1) and 1 and in any |
824 | * returned value is between (2*SPECIALISATION_EFFECT-1) and 1 and in any |
845 | * event is never less than 0.1 (calling functions divide by it) |
825 | * event is never less than 0.1 (calling functions divide by it) |
846 | */ |
826 | */ |
847 | double shop_specialisation_ratio(object *item, mapstruct *map) { |
827 | static double shop_specialisation_ratio(const object *item, const mapstruct *map) { |
848 | shopitems *items=map->shopitems; |
828 | shopitems *items=map->shopitems; |
849 | double ratio = SPECIALISATION_EFFECT, likedness=0.001; |
829 | double ratio = SPECIALISATION_EFFECT, likedness=0.001; |
850 | int i; |
830 | int i; |
851 | |
831 | |
852 | if (item==NULL) { |
832 | if (item==NULL) { |
853 | LOG(llevError, "shop_specialisation_ratio: passed a NULL item for map %s", map->path); |
833 | LOG(llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", map->path); |
854 | return 0; |
834 | return 0; |
855 | } |
835 | } |
856 | if (!item->type) { |
836 | if (!item->type) { |
857 | LOG(llevError, "shop_specialisation_ratio: passed an item with an invalid type"); |
837 | LOG(llevError, "shop_specialisation_ratio: passed an item with an invalid type\n"); |
858 | /* |
838 | /* |
859 | * I'm not really sure what the /right/ thing to do here is, these types of |
839 | * I'm not really sure what the /right/ thing to do here is, these types of |
860 | * item shouldn't exist anyway, but returning the ratio is probably the best bet.." |
840 | * item shouldn't exist anyway, but returning the ratio is probably the best bet.." |
861 | */ |
841 | */ |
862 | return ratio; |
842 | return ratio; |
… | |
… | |
880 | if (ratio <= 0.1) ratio=0.1; /* if the ratio were much lower than this, we would get silly prices */ |
860 | if (ratio <= 0.1) ratio=0.1; /* if the ratio were much lower than this, we would get silly prices */ |
881 | return ratio; |
861 | return ratio; |
882 | } |
862 | } |
883 | |
863 | |
884 | /*returns the greed of the shop on map, or 1 if it isn't specified. */ |
864 | /*returns the greed of the shop on map, or 1 if it isn't specified. */ |
885 | double shop_greed(mapstruct *map) { |
865 | static double shop_greed(const mapstruct *map) { |
886 | double greed=1.0; |
866 | double greed=1.0; |
887 | if (map->shopgreed) |
867 | if (map->shopgreed) |
888 | return map->shopgreed; |
868 | return map->shopgreed; |
889 | return greed; |
869 | return greed; |
890 | } |
870 | } |
891 | |
871 | |
892 | /* Returns a double based on how much the shopkeeper approves of the player. |
872 | /* Returns a double based on how much the shopkeeper approves of the player. |
893 | * this is based on the race of the shopkeeper and that of the player. |
873 | * this is based on the race of the shopkeeper and that of the player. |
894 | */ |
874 | */ |
895 | double shopkeeper_approval(mapstruct *map, object *player) { |
875 | double shopkeeper_approval(const mapstruct *map, const object *player) { |
896 | double approval=1.0; |
876 | double approval=1.0; |
897 | |
877 | |
898 | if (map->shoprace) { |
878 | if (map->shoprace) { |
899 | approval=NEUTRAL_RATIO; |
879 | approval=NEUTRAL_RATIO; |
900 | if (player->race && !strcmp(player->race, map->shoprace)) approval = 1.0; |
880 | if (player->race && !strcmp(player->race, map->shoprace)) approval = 1.0; |
… | |
… | |
907 | * below the minimum value the shop is prepared to trade in, then we don't |
887 | * below the minimum value the shop is prepared to trade in, then we don't |
908 | * want it and offer nothing. If it isn't a shop, check whether we should do generic |
888 | * want it and offer nothing. If it isn't a shop, check whether we should do generic |
909 | * value reduction. |
889 | * value reduction. |
910 | * |
890 | * |
911 | */ |
891 | */ |
912 | static uint64 value_limit(uint64 val, int quantity, object *who, int isshop) { |
892 | static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop) { |
913 | uint64 newval, unit_price; |
893 | uint64 newval, unit_price; |
914 | mapstruct *map; |
894 | mapstruct *map; |
915 | unit_price=val/quantity; |
895 | unit_price=val/quantity; |
916 | if (!isshop || !who) { |
896 | if (!isshop || !who) { |
917 | if (unit_price > 10000) |
897 | if (unit_price > 250000) |
918 | newval=8000+isqrt(unit_price)*20; |
898 | newval = 250000. - pow (250000., .75) * 65. + pow (unit_price, .75) * 65.; |
919 | else |
899 | else |
920 | newval=unit_price; |
900 | newval=unit_price; |
921 | } else { |
901 | } else { |
922 | if (!who->map) { |
902 | if (!who->map) { |
923 | LOG(llevError, "value_limit: asked shop price for ob %s on NULL map", who->name); |
903 | LOG(llevError, "value_limit: asked shop price for ob %s on NULL map\n", who->name); |
924 | return val; |
904 | return val; |
925 | } |
905 | } |
926 | map=who->map; |
906 | map=who->map; |
927 | if (map->shopmin && unit_price < map->shopmin) return 0; |
907 | if (map->shopmin && unit_price < map->shopmin) return 0; |
928 | else if (map->shopmax && unit_price > map->shopmax/2) |
908 | else if (map->shopmax && unit_price > map->shopmax/2) |
929 | 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); |
930 | else if (unit_price>10000) |
910 | else if (unit_price > 250000) |
931 | newval=8000+isqrt(unit_price)*20; |
911 | newval = 250000. - pow (250000., .75) * 65. + pow (unit_price, .75) * 65.; |
932 | else |
912 | else |
933 | newval=unit_price; |
913 | newval=unit_price; |
934 | } |
914 | } |
935 | newval *= quantity; |
915 | newval *= quantity; |
936 | return newval; |
916 | return newval; |
937 | } |
917 | } |
938 | |
918 | |
939 | /* gives a desciption of the shop on their current map to the player op. */ |
919 | /* gives a desciption of the shop on their current map to the player op. */ |
940 | int describe_shop(object *op) { |
920 | int describe_shop(const object *op) { |
941 | mapstruct *map = op->map; |
921 | mapstruct *map = op->map; |
942 | /*shopitems *items=map->shopitems;*/ |
922 | /*shopitems *items=map->shopitems;*/ |
943 | int pos=0, i; |
923 | int pos=0, i; |
944 | double opinion=0; |
924 | double opinion=0; |
945 | char tmp[MAX_BUF]="\0"; |
925 | char tmp[MAX_BUF]="\0"; |
… | |
… | |
962 | make_list_like(tmp); |
942 | make_list_like(tmp); |
963 | new_draw_info_format(NDI_UNIQUE, 0, op, "%s", tmp); |
943 | new_draw_info_format(NDI_UNIQUE, 0, op, "%s", tmp); |
964 | |
944 | |
965 | if (map->shopmax) |
945 | if (map->shopmax) |
966 | 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.", |
967 | cost_string_from_value(map->shopmax)); |
947 | cost_string_from_value(map->shopmax, 0)); |
968 | if (map->shopmin) |
948 | if (map->shopmin) |
969 | 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.", |
970 | cost_string_from_value(map->shopmin)); |
950 | cost_string_from_value(map->shopmin, 0)); |
971 | if (map->shopgreed) { |
951 | if (map->shopgreed) { |
972 | if (map->shopgreed >2.0) |
952 | if (map->shopgreed >2.0) |
973 | 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."); |
974 | else if (map->shopgreed >1.5) |
954 | else if (map->shopgreed >1.5) |
975 | 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."); |