Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_shop_c = 00003 * "$Id: shop.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The authors can be reached via e-mail at crossfire-devel@real-time.com 00027 */ 00028 00036 #include <assert.h> 00037 #include <global.h> 00038 #include <spells.h> 00039 #include <skills.h> 00040 #include <living.h> 00041 #include <newclient.h> 00042 #ifndef __CEXTRACT__ 00043 #include <sproto.h> 00044 #endif 00045 #include <math.h> 00046 00055 #define SPECIALISATION_EFFECT 0.5 00056 00058 #define DISAPPROVAL_RATIO 0.2 00059 00061 #define NEUTRAL_RATIO 0.8 00062 00063 static uint64 pay_from_container(object *pl, object *pouch, uint64 to_pay); 00064 static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop); 00065 static double shop_specialisation_ratio(const object *item, const mapstruct *map); 00066 static double shop_greed(const mapstruct *map); 00067 00068 #define NUM_COINS 5 00070 #define LARGEST_COIN_GIVEN 2 00073 static const char *const coins[] = { 00074 "ambercoin", 00075 "jadecoin", 00076 "platinacoin", 00077 "goldcoin", 00078 "silvercoin", 00079 NULL 00080 }; 00081 00121 uint64 query_cost(const object *tmp, object *who, int flag) { 00122 uint64 val; 00123 int number; /* used to better calculate value */ 00124 int no_bargain; 00125 int identified; 00126 int not_cursed; 00127 int approximate; 00128 int shop; 00129 float diff; 00130 float ratio; 00131 const char *key; 00132 00133 no_bargain = flag&F_NO_BARGAIN; 00134 identified = flag&F_IDENTIFIED; 00135 not_cursed = flag&F_NOT_CURSED; 00136 approximate = flag&F_APPROX; 00137 shop = flag&F_SHOP; 00138 flag &= ~(F_NO_BARGAIN|F_IDENTIFIED|F_NOT_CURSED|F_APPROX|F_SHOP); 00139 00140 number = tmp->nrof; 00141 if (number == 0) 00142 number = 1; 00143 00144 if ((key = get_ob_key_value(tmp, "price_adjustment")) != NULL) { 00145 ratio = atof(key); 00146 return tmp->value*number*ratio; 00147 } 00148 if ((flag == F_BUY) && ((key = get_ob_key_value(tmp, "price_adjustment_buy")) != NULL)) { 00149 ratio = atof(key); 00150 return tmp->value*number*ratio; 00151 } 00152 if ((flag == F_SELL) && ((key = get_ob_key_value(tmp, "price_adjustment_sell")) != NULL)) { 00153 ratio = atof(key); 00154 return tmp->value*number*ratio; 00155 } 00156 00157 if (tmp->type == MONEY) 00158 return (tmp->nrof*tmp->value); 00159 if (tmp->type == GEM) { 00160 if (flag == F_TRUE) 00161 return number*tmp->value; 00162 if (flag == F_BUY) 00163 return (1.03*tmp->nrof*tmp->value); 00164 if (flag == F_SELL) 00165 return (0.97*tmp->nrof*tmp->value); 00166 LOG(llevError, "Query_cost: Gem type with unknown flag : %d\n", flag); 00167 return 0; 00168 } 00169 if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) 00170 || !need_identify(tmp) 00171 || identified) { 00172 if (!not_cursed 00173 && (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))) 00174 return 0; 00175 else 00176 val = tmp->value*number; 00177 /* This area deals with objects that are not identified, but can be */ 00178 } else { 00179 if (tmp->arch != NULL) { 00180 if (flag == F_BUY) { 00181 LOG(llevError, "Asking for buy-value of unidentified object.\n"); 00182 val = tmp->arch->clone.value*50*number; 00183 } else { /* Trying to sell something, or get true value */ 00184 if (tmp->type == POTION) 00185 val = number*1000; /* Don't want to give anything away */ 00186 else { 00187 /* Get 2/3 value for applied objects, 1/3 for totally 00188 * unknown objects 00189 */ 00190 if (QUERY_FLAG(tmp, FLAG_BEEN_APPLIED)) 00191 val = number*tmp->arch->clone.value*2/3; 00192 else 00193 val = number*tmp->arch->clone.value/3; 00194 } 00195 } 00196 } else { /* No archetype with this object */ 00197 LOG(llevDebug, "In sell item: Have object with no archetype: %s\n", tmp->name); 00198 if (flag == F_BUY) { 00199 LOG(llevError, "Asking for buy-value of unidentified object without arch.\n"); 00200 val = number*tmp->value*10; 00201 } else 00202 val = number*tmp->value/5; 00203 } 00204 } 00205 00206 /* If the item has been applied or identifed or does not need to be 00207 * identified, AND the object is magical and the archetype is non 00208 * magical, then change values accordingly. The tmp->arch==NULL is 00209 * really just a check to prevent core dumps for when it checks 00210 * tmp->arch->clone.magic for any magic. The check for archetype 00211 * magic is to not give extra money for archetypes that are by 00212 * default magical. This is because the archetype value should have 00213 * already figured in that value. 00214 */ 00215 if ((QUERY_FLAG(tmp, FLAG_IDENTIFIED) || !need_identify(tmp) || identified || QUERY_FLAG(tmp, FLAG_BEEN_APPLIED)) 00216 && tmp->magic 00217 && (tmp->arch == NULL || !tmp->arch->clone.magic)) { 00218 if (tmp->magic > 0) 00219 val *= (3*tmp->magic*tmp->magic*tmp->magic); 00220 else 00221 /* Note that tmp->magic is negative, so that this 00222 * will actually be something like val /=2, /=3, etc. 00223 */ 00224 val /= (1-tmp->magic); 00225 } 00226 00227 if (tmp->type == WAND) { 00228 /* Value of the wand is multiplied by the number of 00229 * charges. the treasure code already sets up the value 00230 * 50 charges is used as the baseline. 00231 */ 00232 if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) 00233 || !need_identify(tmp) 00234 || identified) 00235 val = (val*tmp->stats.food)/50; 00236 else /* if not identified, presume one charge */ 00237 val /= 50; 00238 } 00239 00240 /* Limit amount of money you can get for really great items. */ 00241 if (flag == F_TRUE || flag == F_SELL) 00242 val = value_limit(val, number, who, shop); 00243 00244 /* we need to multiply these by 4.0 to keep buy costs roughly the same 00245 * (otherwise, you could buy a potion of charisma for around 400 pp. 00246 * Arguable, the costs in the archetypes should be updated to better 00247 * reflect values (potion charisma list for 1250 gold) 00248 */ 00249 val *= 4; 00250 00251 /* This modification is for bargaining skill. 00252 * Now only players with max level in bargaining 00253 * AND Cha = 30 will get optimal price. 00254 * Thus charisma will never get useless. 00255 * -b.e. edler@heydernet.de 00256 */ 00257 00258 if (who != NULL && who->type == PLAYER) { 00259 int lev_bargain = 0; 00260 int lev_identify = 0; 00261 int idskill1 = 0; 00262 int idskill2 = 0; 00263 const typedata *tmptype; 00264 00265 /* ratio determines how much of the price modification 00266 * will come from the basic stat charisma 00267 * the rest will come from the level in bargaining skill 00268 */ 00269 ratio = 0.5; 00270 tmptype = get_typedata(tmp->type); 00271 00272 if (find_skill_by_number(who, SK_BARGAINING)) { 00273 lev_bargain = find_skill_by_number(who, SK_BARGAINING)->level; 00274 } 00275 if (tmptype) { 00276 idskill1 = tmptype->identifyskill; 00277 if (idskill1) { 00278 idskill2 = tmptype->identifyskill2; 00279 if (find_skill_by_number(who, idskill1)) { 00280 lev_identify = find_skill_by_number(who, idskill1)->level; 00281 } 00282 if (idskill2 && find_skill_by_number(who, idskill2)) { 00283 lev_identify += find_skill_by_number(who, idskill2)->level; 00284 } 00285 } 00286 } else 00287 LOG(llevError, "Query_cost: item %s hasn't got a valid type\n", tmp->name); 00288 if (!no_bargain && (lev_bargain > 0)) 00289 diff = (0.8-0.6*((lev_bargain+settings.max_level*0.05)/(settings.max_level*1.05))); 00290 else 00291 diff = 0.8; 00292 00293 diff *= 1-ratio; 00294 00295 /* Diff is now a float between 0.2 and 0.8 */ 00296 diff += (cha_bonus[who->stats.Cha]-1)/(1+cha_bonus[who->stats.Cha])*ratio; 00297 00298 if (flag == F_BUY) 00299 val = (val*(long)(1000*(1+diff)))/1000; 00300 else if (flag == F_SELL) 00301 val = (val*(long)(1000*(1-diff)))/1000; 00302 00303 /* If we are approximating, then the value returned should 00304 * be allowed to be wrong however merely using a random number 00305 * each time will not be sufficient, as then multiple examinations 00306 * would give different answers, so we'll use the count instead. 00307 * By taking the sine of the count, a value between -1 and 1 is 00308 * generated, we then divide by the square root of the bargaining 00309 * skill and the appropriate identification skills, so that higher 00310 * level players get better estimates. (We need a +1 there to 00311 * prevent dividing by zero.) 00312 */ 00313 if (approximate) 00314 val = (sint64)val+(sint64)((sint64)val*(sin(tmp->count)/sqrt(lev_bargain+lev_identify*2+1.0))); 00315 } 00316 00317 /* I don't think this should really happen - if it does, 00318 * it indicates an overflow of diff above. That should only 00319 * happen if we are selling objects - in that case, the person 00320 * just gets no money. 00321 */ 00322 if ((sint64)val < 0) 00323 val = 0; 00324 00325 /* Unidentified stuff won't sell for more than 60gp */ 00326 if (flag == F_SELL 00327 && !QUERY_FLAG(tmp, FLAG_IDENTIFIED) 00328 && need_identify(tmp) 00329 && !identified) { 00330 val = MIN(val, 600); 00331 } 00332 00333 /* if in a shop, check how the type of shop should affect the price */ 00334 if (shop && who) { 00335 if (flag == F_SELL) 00336 val = (sint64)val*shop_specialisation_ratio(tmp, who->map) 00337 *shopkeeper_approval(who->map, who)/shop_greed(who->map); 00338 else if (flag == F_BUY) { 00339 /* 00340 * When buying, if the item was sold by another player, it is 00341 * ok to let the item be sold cheaper, according to the 00342 * specialisation of the shop. If a player sold an item here, 00343 * then his sale price was multiplied by the specialisation 00344 * ratio, to do the same to the buy price will not generate 00345 * extra money. However, the same is not true of generated 00346 * items, these have to /divide/ by the specialisation, so 00347 * that the price is never less than what they could 00348 * be sold for (otherwise players could camp map resets to 00349 * make money). 00350 * In game terms, a non-specialist shop might not recognise 00351 * the true value of the items it sells (much like how people 00352 * sometimes find antiques in a junk shop in real life). 00353 */ 00354 if (QUERY_FLAG(tmp, FLAG_PLAYER_SOLD)) 00355 val = (sint64)val*shop_greed(who->map) 00356 *shop_specialisation_ratio(tmp, who->map) 00357 /shopkeeper_approval(who->map, who); 00358 else 00359 val = (sint64)val*shop_greed(who->map) 00360 /(shop_specialisation_ratio(tmp, who->map) 00361 *shopkeeper_approval(who->map, who)); 00362 } 00363 /* We will also have an extra 0-5% variation between shops of 00364 * the same type for valuable items (below a value of 50 this 00365 * effect wouldn't be very meaningful, and could give fun with 00366 * rounding. 00367 */ 00368 if (who->map->path != NULL && val > 50) 00369 val = (sint64)val+0.05*(sint64)val*cos(tmp->count+strlen(who->map->path)); 00370 } 00371 return val; 00372 } 00373 00385 static archetype *find_next_coin(uint64 c, int *cointype) { 00386 archetype *coin; 00387 00388 do { 00389 if (coins[*cointype] == NULL) 00390 return NULL; 00391 coin = find_archetype(coins[*cointype]); 00392 if (coin == NULL) 00393 return NULL; 00394 *cointype += 1; 00395 } while (coin->clone.value > c); 00396 00397 return coin; 00398 } 00399 00417 static StringBuffer *cost_string_from_value(uint64 cost, StringBuffer *buf) { 00418 archetype *coin, *next_coin; 00419 uint32 num; 00420 int cointype = LARGEST_COIN_GIVEN; 00421 00422 if (!buf) 00423 buf = stringbuffer_new(); 00424 00425 coin = find_next_coin(cost, &cointype); 00426 if (coin == NULL) { 00427 stringbuffer_append_string(buf, "nothing"); 00428 return buf; 00429 } 00430 00431 num = cost/coin->clone.value; 00432 /* so long as nrof is 32 bit, this is true. 00433 * If it takes more coins than a person can possibly carry, this 00434 * is basically true. 00435 */ 00436 if ((cost/coin->clone.value) > UINT32_MAX) { 00437 stringbuffer_append_string(buf, "an unimaginable sum of money."); 00438 return buf; 00439 } 00440 00441 cost -= (uint64)num*(uint64)coin->clone.value; 00442 if (num == 1) 00443 stringbuffer_append_printf(buf, "1 %s", coin->clone.name); 00444 else 00445 stringbuffer_append_printf(buf, "%u %ss", num, coin->clone.name); 00446 00447 next_coin = find_next_coin(cost, &cointype); 00448 if (next_coin == NULL) 00449 return buf; 00450 00451 do { 00452 coin = next_coin; 00453 num = cost/coin->clone.value; 00454 cost -= (uint64)num*(uint64)coin->clone.value; 00455 00456 if (cost == 0) 00457 next_coin = NULL; 00458 else 00459 next_coin = find_next_coin(cost, &cointype); 00460 00461 if (next_coin) { 00462 /* There will be at least one more string to add to the list, 00463 * use a comma. 00464 */ 00465 stringbuffer_append_string(buf, ", "); 00466 } else { 00467 stringbuffer_append_string(buf, " and "); 00468 } 00469 if (num == 1) 00470 stringbuffer_append_printf(buf, "1 %s", coin->clone.name); 00471 else 00472 stringbuffer_append_printf(buf, "%u %ss", num, coin->clone.name); 00473 } while (next_coin); 00474 00475 return buf; 00476 } 00477 00488 static StringBuffer *real_money_value(const object *coin, StringBuffer *buf) { 00489 assert(coin->type == MONEY); 00490 assert(buf); 00491 00492 stringbuffer_append_printf(buf, "%ld %s", coin->nrof, coin->nrof == 1 ? coin->name : coin->name_pl); 00493 return buf; 00494 } 00495 00511 StringBuffer *query_cost_string(const object *tmp, object *who, int flag, StringBuffer *buf) { 00512 uint64 real_value = query_cost(tmp, who, flag); 00513 int idskill1 = 0; 00514 int idskill2 = 0; 00515 const typedata *tmptype; 00516 00517 if (!buf) 00518 buf = stringbuffer_new(); 00519 00520 /* money it's pretty hard to not give the exact price, so skip all logic and just return the real value. */ 00521 if (tmp->type == MONEY) { 00522 return real_money_value(tmp, buf); 00523 } 00524 00525 tmptype = get_typedata(tmp->type); 00526 if (tmptype) { 00527 idskill1 = tmptype->identifyskill; 00528 idskill2 = tmptype->identifyskill2; 00529 } 00530 00531 /* we show an approximate price if 00532 * 1) we are approximating 00533 * 2) there either is no id skill(s) for the item, or we don't have them 00534 * 3) we don't have bargaining skill either 00535 */ 00536 if (flag&F_APPROX) { 00537 if (!idskill1 || !find_skill_by_number(who, idskill1)) { 00538 if (!idskill2 || !find_skill_by_number(who, idskill2)) { 00539 if (!find_skill_by_number(who, SK_BARGAINING)) { 00540 int num; 00541 int cointype = LARGEST_COIN_GIVEN; 00542 archetype *coin = find_next_coin(real_value, &cointype); 00543 00544 if (coin == NULL) { 00545 stringbuffer_append_string(buf, "nothing"); 00546 return buf; 00547 } 00548 00549 num = real_value/coin->clone.value; 00550 if (num == 1) 00551 stringbuffer_append_printf(buf, "about one %s", coin->clone.name); 00552 else if (num < 5) 00553 stringbuffer_append_printf(buf, "a few %s", coin->clone.name_pl); 00554 else if (num < 10) 00555 stringbuffer_append_printf(buf, "several %s", coin->clone.name_pl); 00556 else if (num < 25) 00557 stringbuffer_append_printf(buf, "a moderate amount of %s", coin->clone.name_pl); 00558 else if (num < 100) 00559 stringbuffer_append_printf(buf, "lots of %s", coin->clone.name_pl); 00560 else if (num < 1000) 00561 stringbuffer_append_printf(buf, "a great many %s", coin->clone.name_pl); 00562 else 00563 stringbuffer_append_printf(buf, "a vast quantity of %s", coin->clone.name_pl); 00564 return buf; 00565 } 00566 } 00567 } 00568 } 00569 return cost_string_from_value(real_value, buf); 00570 } 00571 00581 uint64 query_money(const object *op) { 00582 object *tmp; 00583 uint64 total = 0; 00584 00585 if (op->type != PLAYER && op->type != CONTAINER) { 00586 LOG(llevError, "Query money called with non player/container\n"); 00587 return 0; 00588 } 00589 for (tmp = op->inv; tmp; tmp = tmp->below) { 00590 if (tmp->type == MONEY) { 00591 total += (uint64)tmp->nrof*(uint64)tmp->value; 00592 } else if (tmp->type == CONTAINER 00593 && QUERY_FLAG(tmp, FLAG_APPLIED) 00594 && (tmp->race == NULL || strstr(tmp->race, "gold"))) { 00595 total += query_money(tmp); 00596 } 00597 } 00598 return total; 00599 } 00600 00613 int pay_for_amount(uint64 to_pay, object *pl) { 00614 object *pouch; 00615 00616 if (to_pay == 0) 00617 return 1; 00618 if (to_pay > query_money(pl)) 00619 return 0; 00620 00621 to_pay = pay_from_container(pl, pl, to_pay); 00622 00623 for (pouch = pl->inv; (pouch != NULL) && (to_pay > 0); pouch = pouch->below) { 00624 if (pouch->type == CONTAINER 00625 && QUERY_FLAG(pouch, FLAG_APPLIED) 00626 && (pouch->race == NULL || strstr(pouch->race, "gold"))) { 00627 to_pay = pay_from_container(pl, pouch, to_pay); 00628 } 00629 } 00630 if (to_pay > 0) { 00631 LOG(llevError, "pay_for_amount: Cannot remove enough money -- %"FMT64U" remains\n", to_pay); 00632 } 00633 00634 fix_object(pl); 00635 return 1; 00636 } 00637 00652 int pay_for_item(object *op, object *pl) { 00653 uint64 to_pay = query_cost(op, pl, F_BUY|F_SHOP); 00654 object *pouch; 00655 uint64 saved_money; 00656 00657 if (to_pay == 0) 00658 return 1; 00659 if (to_pay > query_money(pl)) 00660 return 0; 00661 00662 /* We compare the paid price with the one for a player 00663 * without bargaining skill. 00664 * This determins the amount of exp (if any) gained for bargaining. 00665 */ 00666 saved_money = query_cost(op, pl, F_BUY|F_NO_BARGAIN|F_SHOP)-to_pay; 00667 00668 if (saved_money > 0) 00669 change_exp(pl, saved_money, "bargaining", SK_EXP_NONE); 00670 00671 to_pay = pay_from_container(pl, pl, to_pay); 00672 00673 for (pouch = pl->inv; (pouch != NULL) && (to_pay > 0); pouch = pouch->below) { 00674 if (pouch->type == CONTAINER 00675 && QUERY_FLAG(pouch, FLAG_APPLIED) 00676 && (pouch->race == NULL || strstr(pouch->race, "gold"))) { 00677 to_pay = pay_from_container(pl, pouch, to_pay); 00678 } 00679 } 00680 if (to_pay > 0) { 00681 LOG(llevError, "pay_for_item: Cannot remove enough money -- %"FMT64U" remains\n", to_pay); 00682 } 00683 if (settings.real_wiz == FALSE && QUERY_FLAG(pl, FLAG_WAS_WIZ)) 00684 SET_FLAG(op, FLAG_WAS_WIZ); 00685 fix_object(pl); 00686 return 1; 00687 } 00688 00700 static sint64 remove_value(object *coin_objs[], sint64 remain) { 00701 int i; 00702 00703 for (i = 0; i < NUM_COINS; i++) { 00704 int count; 00705 sint64 num_coins; 00706 00707 if (coin_objs[i]->nrof*coin_objs[i]->value > remain) { 00708 num_coins = remain/coin_objs[i]->value; 00709 if ((uint64)num_coins*(uint64)coin_objs[i]->value < remain) { 00710 num_coins++; 00711 } 00712 } else { 00713 num_coins = coin_objs[i]->nrof; 00714 } 00715 remain -= (sint64)num_coins*(sint64)coin_objs[i]->value; 00716 coin_objs[i]->nrof -= num_coins; 00717 /* Now start making change. Start at the coin value 00718 * below the one we just did, and work down to 00719 * the lowest value. 00720 */ 00721 count = i-1; 00722 while (remain < 0 && count >= 0) { 00723 num_coins = -remain/coin_objs[count]->value; 00724 coin_objs[count]->nrof += num_coins; 00725 remain += num_coins*coin_objs[count]->value; 00726 count--; 00727 } 00728 } 00729 00730 return remain; 00731 } 00732 00741 static void add_value(object *coin_objs[], sint64 value) { 00742 int i; 00743 00744 for (i = NUM_COINS-LARGEST_COIN_GIVEN-1; i >= 0; i--) { 00745 uint32 nrof; 00746 00747 nrof = (uint32)(value/coin_objs[i]->value); 00748 value -= nrof*coin_objs[i]->value; 00749 coin_objs[i]->nrof += nrof; 00750 } 00751 } 00752 00765 static void insert_objects(object *pl, object *container, object *objects[], int objects_len) { 00766 int i, one = 0; 00767 00768 for (i = 0; i < objects_len; i++) { 00769 if (objects[i]->nrof > 0) { 00770 insert_ob_in_ob(objects[i], container); 00771 one = 1; 00772 } else { 00773 free_object(objects[i]); 00774 } 00775 } 00776 if (one) 00777 esrv_update_item(UPD_WEIGHT, pl, container); 00778 } 00779 00796 static uint64 pay_from_container(object *pl, object *pouch, uint64 to_pay) { 00797 int i; 00798 sint64 remain; 00799 object *tmp, *coin_objs[NUM_COINS], *next; 00800 object *other_money[16]; /* collects MONEY objects not matching coins[] */ 00801 size_t other_money_len; /* number of allocated entries in other_money[] */ 00802 archetype *at; 00803 00804 if (pouch->type != PLAYER && pouch->type != CONTAINER) 00805 return to_pay; 00806 00807 remain = to_pay; 00808 for (i = 0; i < NUM_COINS; i++) 00809 coin_objs[i] = NULL; 00810 00811 /* This hunk should remove all the money objects from the player/container */ 00812 other_money_len = 0; 00813 for (tmp = pouch->inv; tmp; tmp = next) { 00814 next = tmp->below; 00815 if (tmp->type == MONEY) { 00816 for (i = 0; i < NUM_COINS; i++) { 00817 if (!strcmp(coins[NUM_COINS-1-i], tmp->arch->name) 00818 && (tmp->value == tmp->arch->clone.value)) { 00819 00820 /* This should not happen, but if it does, just 00821 * merge the two. 00822 */ 00823 if (coin_objs[i] != NULL) { 00824 LOG(llevError, "%s has two money entries of (%s)\n", pouch->name, coins[NUM_COINS-1-i]); 00825 remove_ob(tmp); 00826 coin_objs[i]->nrof += tmp->nrof; 00827 free_object(tmp); 00828 } else { 00829 remove_ob(tmp); 00830 coin_objs[i] = tmp; 00831 } 00832 break; 00833 } 00834 } 00835 if (i == NUM_COINS) { 00836 if (other_money_len >= sizeof(other_money)/sizeof(*other_money)) { 00837 LOG(llevError, "pay_for_item: Cannot store non-standard money object %s\n", tmp->arch->name); 00838 } else { 00839 remove_ob(tmp); 00840 other_money[other_money_len++] = tmp; 00841 } 00842 } 00843 } 00844 } 00845 00846 /* Fill in any gaps in the coin_objs array - needed to make change. */ 00847 /* Note that the coin_objs array goes from least value to greatest value */ 00848 for (i = 0; i < NUM_COINS; i++) 00849 if (coin_objs[i] == NULL) { 00850 at = find_archetype(coins[NUM_COINS-1-i]); 00851 if (at == NULL) 00852 LOG(llevError, "Could not find %s archetype\n", coins[NUM_COINS-1-i]); 00853 coin_objs[i] = get_object(); 00854 copy_object(&at->clone, coin_objs[i]); 00855 coin_objs[i]->nrof = 0; 00856 } 00857 00858 /* Try to pay from standard coins first. */ 00859 remain = remove_value(coin_objs, remain); 00860 00861 /* Now pay from non-standard coins until all is paid. */ 00862 for (i = 0; i < other_money_len && remain > 0; i++) { 00863 uint32 nrof; 00864 object *coin; 00865 00866 coin = other_money[i]; 00867 00868 /* Find the minimal number of coins to use. This prevents converting 00869 * excess non-standard coins to standard money. 00870 */ 00871 nrof = (remain+coin->value-1)/coin->value; 00872 if (nrof > coin->nrof) { 00873 nrof = coin->nrof; 00874 } 00875 coin->nrof -= nrof; 00876 add_value(coin_objs, nrof*coin->value); 00877 00878 remain = remove_value(coin_objs, remain); 00879 } 00880 00881 /* re-insert remaining coins into player */ 00882 insert_objects(pl, pouch, coin_objs, NUM_COINS); 00883 insert_objects(pl, pouch, other_money, other_money_len); 00884 00885 return(remain); 00886 } 00887 00904 static void count_unpaid(object *pl, object *item, int *unpaid_count, uint64 *unpaid_price, uint32 *coincount) { 00905 int i; 00906 00907 for (; item; item = item->below) { 00908 if QUERY_FLAG(item, FLAG_UNPAID) { 00909 (*unpaid_count)++; 00910 (*unpaid_price) += query_cost(item, pl, F_BUY|F_SHOP); 00911 } 00912 /* Merely converting the player's monetary wealth won't do. 00913 * If we did that, we could print the wrong numbers for the 00914 * coins, so we count the money instead. 00915 */ 00916 for (i = 0; i < NUM_COINS; i++) 00917 if (!strcmp(coins[i], item->arch->name)) { 00918 coincount[i] += item->nrof; 00919 break; 00920 } 00921 if (item->inv) 00922 count_unpaid(pl, item->inv, unpaid_count, unpaid_price, coincount); 00923 } 00924 } 00925 00938 int can_pay(object *pl) { 00939 int unpaid_count = 0, i; 00940 uint64 unpaid_price = 0; 00941 uint64 player_wealth = query_money(pl); 00942 uint32 coincount[NUM_COINS]; 00943 00944 if (!pl || pl->type != PLAYER) { 00945 LOG(llevError, "can_pay(): called against something that isn't a player\n"); 00946 return 0; 00947 } 00948 00949 for (i = 0; i < NUM_COINS; i++) 00950 coincount[i] = 0; 00951 00952 count_unpaid(pl, pl->inv, &unpaid_count, &unpaid_price, coincount); 00953 00954 if (unpaid_price > player_wealth) { 00955 char buf[MAX_BUF], coinbuf[MAX_BUF]; 00956 int denominations = 0; 00957 char *value = stringbuffer_finish(cost_string_from_value(unpaid_price, NULL)); 00958 00959 snprintf(buf, sizeof(buf), "You have %d unpaid items that would cost you %s, ", unpaid_count, value); 00960 free(value); 00961 for (i = 0; i < NUM_COINS; i++) { 00962 if (coincount[i] > 0 && coins[i]) { 00963 if (denominations == 0) 00964 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "but you only have"); 00965 denominations++; 00966 snprintf(coinbuf, sizeof(coinbuf), " %u %s,", coincount[i], find_archetype(coins[i])->clone.name_pl); 00967 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s", coinbuf); 00968 } 00969 } 00970 if (denominations == 0) 00971 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "but you don't have any money."); 00972 else if (denominations > 1) 00973 make_list_like(buf); 00974 draw_ext_info(NDI_UNIQUE, 0, pl, MSG_TYPE_SHOP, 00975 MSG_TYPE_SHOP_PAYMENT, buf, NULL); 00976 return 0; 00977 } else 00978 return 1; 00979 } 00980 00992 int get_payment(object *pl, object *op) { 00993 char name_op[MAX_BUF]; 00994 int ret = 1; 00995 00996 if (op != NULL && op->inv) 00997 ret = get_payment(pl, op->inv); 00998 00999 if (!ret) 01000 return 0; 01001 01002 if (op != NULL && op->below) 01003 ret = get_payment(pl, op->below); 01004 01005 if (!ret) 01006 return 0; 01007 01008 if (op != NULL && QUERY_FLAG(op, FLAG_UNPAID)) { 01009 if (!pay_for_item(op, pl)) { 01010 uint64 i = query_cost(op, pl, F_BUY|F_SHOP)-query_money(pl); 01011 char *missing = stringbuffer_finish(cost_string_from_value(i, NULL)); 01012 01013 CLEAR_FLAG(op, FLAG_UNPAID); 01014 query_name(op, name_op, MAX_BUF); 01015 draw_ext_info_format(NDI_UNIQUE, 0, pl, 01016 MSG_TYPE_SHOP, MSG_TYPE_SHOP_PAYMENT, 01017 "You lack %s to buy %s.", 01018 "You lack %s to buy %s.", 01019 missing, name_op); 01020 free(missing); 01021 SET_FLAG(op, FLAG_UNPAID); 01022 return 0; 01023 } else { 01024 object *tmp; 01025 char *value = stringbuffer_finish(query_cost_string(op, pl, F_BUY|F_SHOP, NULL)); 01026 01027 CLEAR_FLAG(op, FLAG_UNPAID); 01028 CLEAR_FLAG(op, FLAG_PLAYER_SOLD); 01029 query_name(op, name_op, MAX_BUF); 01030 draw_ext_info_format(NDI_UNIQUE, 0, pl, 01031 MSG_TYPE_SHOP, MSG_TYPE_SHOP_PAYMENT, 01032 "You paid %s for %s.", 01033 "You paid %s for %s.", 01034 value, name_op); 01035 free(value); 01036 tmp = merge_ob(op, NULL); 01037 if (pl->type == PLAYER && !tmp) { 01038 /* If item wasn't merged we update it. If merged, merge_ob handled everything for us. */ 01039 esrv_update_item(UPD_FLAGS|UPD_NAME, pl, op); 01040 } 01041 } 01042 } 01043 return 1; 01044 } 01045 01059 void sell_item(object *op, object *pl) { 01060 uint64 i = query_cost(op, pl, F_SELL|F_SHOP), extra_gain; 01061 int count; 01062 object *tmp, *pouch; 01063 archetype *at; 01064 char name_op[MAX_BUF], *value; 01065 01066 if (pl == NULL || pl->type != PLAYER) { 01067 LOG(llevDebug, "Object other than player tried to sell something.\n"); 01068 return; 01069 } 01070 01071 if (op->custom_name) 01072 FREE_AND_CLEAR_STR(op->custom_name); 01073 01074 if (!i) { 01075 query_name(op, name_op, MAX_BUF); 01076 draw_ext_info_format(NDI_UNIQUE, 0, pl, 01077 MSG_TYPE_SHOP, MSG_TYPE_SHOP_SELL, 01078 "We're not interested in %s.", 01079 "We're not interested in %s.", 01080 name_op); 01081 01082 /* Even if the character doesn't get anything for it, it may still be 01083 * worth something. If so, make it unpaid 01084 */ 01085 if (op->value) { 01086 SET_FLAG(op, FLAG_UNPAID); 01087 SET_FLAG(op, FLAG_PLAYER_SOLD); 01088 } 01089 identify(op); 01090 return; 01091 } 01092 01093 /* We compare the price with the one for a player 01094 * without bargaining skill. 01095 * This determins the amount of exp (if any) gained for bargaining. 01096 * exp/10 -> 1 for each gold coin 01097 */ 01098 extra_gain = i-query_cost(op, pl, F_SELL|F_NO_BARGAIN|F_SHOP); 01099 01100 if (extra_gain > 0) 01101 change_exp(pl, extra_gain/10, "bargaining", SK_EXP_NONE); 01102 01103 for (count = LARGEST_COIN_GIVEN; coins[count] != NULL; count++) { 01104 at = find_archetype(coins[count]); 01105 if (at == NULL) 01106 LOG(llevError, "Could not find %s archetype\n", coins[count]); 01107 else if ((i/at->clone.value) > 0) { 01108 for (pouch = pl->inv; pouch; pouch = pouch->below) { 01109 if (pouch->type == CONTAINER 01110 && QUERY_FLAG(pouch, FLAG_APPLIED) 01111 && pouch->race 01112 && strstr(pouch->race, "gold")) { 01113 int w = at->clone.weight*(100-pouch->stats.Str)/100; 01114 int n = i/at->clone.value; 01115 01116 if (w == 0) 01117 w = 1; /* Prevent divide by zero */ 01118 if (n > 0 01119 && (!pouch->weight_limit || pouch->carrying+w <= pouch->weight_limit)) { 01120 if (pouch->weight_limit 01121 && (pouch->weight_limit-pouch->carrying)/w < n) 01122 n = (pouch->weight_limit-pouch->carrying)/w; 01123 01124 tmp = get_object(); 01125 copy_object(&at->clone, tmp); 01126 tmp->nrof = n; 01127 i -= (uint64)tmp->nrof*(uint64)tmp->value; 01128 tmp = insert_ob_in_ob(tmp, pouch); 01129 esrv_update_item(UPD_WEIGHT, pl, pl); 01130 } 01131 } 01132 } 01133 if (i/at->clone.value > 0) { 01134 tmp = get_object(); 01135 copy_object(&at->clone, tmp); 01136 tmp->nrof = i/tmp->value; 01137 i -= (uint64)tmp->nrof*(uint64)tmp->value; 01138 tmp = insert_ob_in_ob(tmp, pl); 01139 esrv_update_item(UPD_WEIGHT, pl, pl); 01140 } 01141 } 01142 } 01143 01144 if (i != 0) 01145 #ifndef WIN32 01146 LOG(llevError, "Warning - payment not zero: %llu\n", i); 01147 #else 01148 LOG(llevError, "Warning - payment not zero: %I64u\n", i); 01149 #endif 01150 01151 query_name(op, name_op, MAX_BUF); 01152 value = stringbuffer_finish(query_cost_string(op, pl, F_SELL|F_SHOP, NULL)); 01153 01154 draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_SHOP, MSG_TYPE_SHOP_SELL, 01155 "You receive %s for %s.", 01156 "You receive %s for %s.", 01157 value, 01158 name_op); 01159 01160 free(value); 01161 01162 SET_FLAG(op, FLAG_UNPAID); 01163 identify(op); 01164 } 01165 01179 static double shop_specialisation_ratio(const object *item, const mapstruct *map) { 01180 shopitems *items = map->shopitems; 01181 double ratio = SPECIALISATION_EFFECT, likedness = 0.001; 01182 int i; 01183 01184 if (item == NULL) { 01185 LOG(llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", map->path); 01186 return 0; 01187 } 01188 if (!item->type) { 01189 LOG(llevError, "shop_specialisation_ratio: passed an item with an invalid type\n"); 01190 /* 01191 * I'm not really sure what the /right/ thing to do here is, 01192 * these types of item shouldn't exist anyway, but returning 01193 * the ratio is probably the best bet.." 01194 */ 01195 return ratio; 01196 } 01197 if (map->shopitems) { 01198 for (i = 0; i < items[0].index; i++) 01199 if (items[i].typenum == item->type || (!items[i].typenum && likedness == 0.001)) 01200 likedness = items[i].strength/100.0; 01201 } 01202 if (likedness > 1.0) { /* someone has been rather silly with the map headers. */ 01203 LOG(llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, map->path); 01204 likedness = 1.0; 01205 } 01206 if (likedness < -1.0) { 01207 LOG(llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, map->path); 01208 likedness = -1.0; 01209 } 01210 ratio = ratio+(1.0-ratio)*likedness; 01211 if (ratio <= 0.1) 01212 ratio = 0.1; /* if the ratio were much lower than this, we would get silly prices */ 01213 return ratio; 01214 } 01215 01224 static double shop_greed(const mapstruct *map) { 01225 double greed = 1.0; 01226 01227 if (map->shopgreed) 01228 return map->shopgreed; 01229 return greed; 01230 } 01231 01243 double shopkeeper_approval(const mapstruct *map, const object *player) { 01244 double approval = 1.0; 01245 01246 if (map->shoprace) { 01247 approval = NEUTRAL_RATIO; 01248 if (player->race && !strcmp(player->race, map->shoprace)) 01249 approval = 1.0; 01250 } 01251 return approval; 01252 } 01253 01273 static uint64 value_limit(uint64 val, int quantity, const object *who, int isshop) { 01274 uint64 newval, unit_price; 01275 mapstruct *map; 01276 01277 unit_price = val/quantity; 01278 if (!isshop || !who) { 01279 if (unit_price > 10000) 01280 newval = 8000+isqrt(unit_price)*20; 01281 else 01282 newval = unit_price; 01283 } else { 01284 if (!who->map) { 01285 LOG(llevError, "value_limit: asked shop price for ob %s on NULL map\n", who->name); 01286 return val; 01287 } 01288 map = who->map; 01289 if (map->shopmin && unit_price < map->shopmin) 01290 return 0; 01291 else if (map->shopmax && unit_price > map->shopmax/2) 01292 newval = MIN((map->shopmax/2)+isqrt(unit_price-map->shopmax/2), map->shopmax); 01293 else if (unit_price > 10000) 01294 newval = 8000+isqrt(unit_price)*20; 01295 else 01296 newval = unit_price; 01297 } 01298 newval *= quantity; 01299 return newval; 01300 } 01301 01311 int describe_shop(const object *op) { 01312 mapstruct *map = op->map; 01313 /*shopitems *items=map->shopitems;*/ 01314 int pos = 0, i; 01315 double opinion = 0; 01316 char tmp[MAX_BUF] = "\0", *value; 01317 01318 if (op->type != PLAYER) 01319 return 0; 01320 01321 /*check if there is a shop specified for this map */ 01322 if (map->shopitems 01323 || map->shopgreed 01324 || map->shoprace 01325 || map->shopmin 01326 || map->shopmax) { 01327 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SHOP, MSG_TYPE_SHOP_LISTING, 01328 "From looking at the nearby shop you determine that it trades in:", 01329 NULL); 01330 01331 if (map->shopitems) { 01332 for (i = 0; i < map->shopitems[0].index; i++) { 01333 if (map->shopitems[i].name && map->shopitems[i].strength > 10) { 01334 snprintf(tmp+pos, sizeof(tmp)-pos, "%s, ", map->shopitems[i].name_pl); 01335 pos += strlen(tmp+pos); 01336 } 01337 } 01338 } 01339 if (!pos) 01340 strcpy(tmp, "a little of everything."); 01341 01342 /* format the string into a list */ 01343 make_list_like(tmp); 01344 draw_ext_info(NDI_UNIQUE, 0, op, 01345 MSG_TYPE_SHOP, MSG_TYPE_SHOP_LISTING, tmp, NULL); 01346 01347 if (map->shopmax) { 01348 value = stringbuffer_finish(cost_string_from_value(map->shopmax, NULL)); 01349 draw_ext_info_format(NDI_UNIQUE, 0, op, 01350 MSG_TYPE_SHOP, MSG_TYPE_SHOP_MISC, 01351 "It won't trade for items above %s.", 01352 "It won't trade for items above %s.", 01353 value); 01354 free(value); 01355 } 01356 01357 if (map->shopmin) { 01358 value = stringbuffer_finish(cost_string_from_value(map->shopmin, NULL)); 01359 draw_ext_info_format(NDI_UNIQUE, 0, op, 01360 MSG_TYPE_SHOP, MSG_TYPE_SHOP_MISC, 01361 "It won't trade in items worth less than %s.", 01362 "It won't trade in items worth less than %s.", 01363 value); 01364 free(value); 01365 } 01366 01367 if (map->shopgreed) { 01368 if (map->shopgreed > 2.0) 01369 draw_ext_info(NDI_UNIQUE, 0, op, 01370 MSG_TYPE_SHOP, MSG_TYPE_SHOP_MISC, 01371 "It tends to overcharge massively.", NULL); 01372 else if (map->shopgreed > 1.5) 01373 draw_ext_info(NDI_UNIQUE, 0, op, 01374 MSG_TYPE_SHOP, MSG_TYPE_SHOP_MISC, 01375 "It tends to overcharge substantially.", NULL); 01376 else if (map->shopgreed > 1.1) 01377 draw_ext_info(NDI_UNIQUE, 0, op, 01378 MSG_TYPE_SHOP, MSG_TYPE_SHOP_MISC, 01379 "It tends to overcharge slightly.", NULL); 01380 else if (map->shopgreed < 0.9) 01381 draw_ext_info(NDI_UNIQUE, 0, op, 01382 MSG_TYPE_SHOP, MSG_TYPE_SHOP_MISC, 01383 "It tends to undercharge.", NULL); 01384 } 01385 if (map->shoprace) { 01386 opinion = shopkeeper_approval(map, op); 01387 if (opinion > 0.8) 01388 draw_ext_info(NDI_UNIQUE, 0, op, 01389 MSG_TYPE_SHOP, MSG_TYPE_SHOP_MISC, 01390 "You think the shopkeeper likes you.", NULL); 01391 else if (opinion > 0.5) 01392 draw_ext_info(NDI_UNIQUE, 0, op, 01393 MSG_TYPE_SHOP, MSG_TYPE_SHOP_MISC, 01394 "The shopkeeper seems unconcerned by you.", NULL); 01395 else 01396 draw_ext_info(NDI_UNIQUE, 0, op, 01397 MSG_TYPE_SHOP, MSG_TYPE_SHOP_MISC, 01398 "The shopkeeper seems to have taken a dislike to you.", NULL); 01399 } 01400 } else draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SHOP, MSG_TYPE_SHOP_MISC, 01401 "There is no shop nearby.", NULL); 01402 01403 return 1; 01404 } 01405 01414 int is_in_shop(object *ob) { 01415 if (!ob->map) 01416 return 0; 01417 return coords_in_shop(ob->map, ob->x, ob->y); 01418 } 01419 01429 int coords_in_shop(mapstruct *map, int x, int y) { 01430 object *floor; 01431 01432 for (floor = GET_MAP_OB(map, x, y); floor; floor = floor->above) 01433 if (floor->type == SHOP_FLOOR) 01434 return 1; 01435 return 0; 01436 }