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

Comparing deliantra/server/server/shop.C (file contents):
Revision 1.58 by root, Tue Dec 16 23:25:25 2008 UTC vs.
Revision 1.80 by root, Wed Apr 28 19:01:01 2010 UTC

1/* 1/*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG. 2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 * 3 *
4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 4 * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team 5 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen 6 * Copyright (©) 1992 Frank Tore Johansen
7 * 7 *
8 * Deliantra is free software: you can redistribute it and/or modify 8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * it under the terms of the GNU General Public License as published by 9 * the terms of the Affero GNU General Public License as published by the
10 * the Free Software Foundation, either version 3 of the License, or 10 * Free Software Foundation, either version 3 of the License, or (at your
11 * (at your option) any later version. 11 * option) any later version.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 16 * GNU General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the Affero GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
20 * 21 *
21 * The authors can be reached via e-mail to <support@deliantra.net> 22 * The authors can be reached via e-mail to <support@deliantra.net>
22 */ 23 */
23 24
24#include <global.h> 25#include <global.h>
25#include <spells.h> 26#include <spells.h>
26#include <skills.h> 27#include <skills.h>
27#include <living.h> 28#include <living.h>
28#include <sproto.h> 29#include <sproto.h>
29#include <math.h>
30 30
31/* this is a measure of how effective store specialisation is. A general store 31/* this is a measure of how effective store specialisation is. A general store
32 * will offer this proportion of the 'maximum' price, a specialised store will 32 * will offer this proportion of the 'maximum' price, a specialised store will
33 * offer a range of prices around it such that the maximum price is always one 33 * offer a range of prices around it such that the maximum price is always one
34 * therefore making this number higher, makes specialisation less effective. 34 * therefore making this number higher, makes specialisation less effective.
74 74
75sint64 75sint64
76query_cost (const object *tmp, object *who, int flag) 76query_cost (const object *tmp, object *who, int flag)
77{ 77{
78 double val; 78 double val;
79 int number; /* used to better calculate value */
80 int no_bargain; 79 int no_bargain;
81 int identified; 80 int identified;
82 int not_cursed; 81 int not_cursed;
83 int approximate; 82 int approximate;
84 int shop; 83 int shop;
91 not_cursed = flag & F_NOT_CURSED; 90 not_cursed = flag & F_NOT_CURSED;
92 approximate = flag & F_APPROX; 91 approximate = flag & F_APPROX;
93 shop = flag & F_SHOP; 92 shop = flag & F_SHOP;
94 flag &= ~(F_NO_BARGAIN | F_IDENTIFIED | F_NOT_CURSED | F_APPROX | F_SHOP); 93 flag &= ~(F_NO_BARGAIN | F_IDENTIFIED | F_NOT_CURSED | F_APPROX | F_SHOP);
95 94
95 int number = tmp->number_of ();
96
96 if (tmp->type == MONEY) 97 if (tmp->type == MONEY)
97 return tmp->nrof * tmp->value; 98 return number * tmp->value;
98 99
99 if (tmp->type == GEM) 100 if (tmp->type == GEM)
100 { 101 {
101 if (flag == F_TRUE) 102 if (flag == F_TRUE)
102 return (tmp->nrof * tmp->value); 103 return number * tmp->value;
103 104
104 if (flag == F_BUY) 105 if (flag == F_BUY)
105 return (sint64) (1.03 * tmp->nrof * tmp->value); 106 return 1.03 * number * tmp->value;
106 107
107 if (flag == F_SELL) 108 if (flag == F_SELL)
108 return (sint64) (0.97 * tmp->nrof * tmp->value); 109 return 0.97 * number * tmp->value;
109 110
110 LOG (llevError, "Query_cost: Gem type with unknown flag %d: %s\n", flag, tmp->debug_desc ()); 111 LOG (llevError, "Query_cost: Gem type with unknown flag %d: %s\n", flag, tmp->debug_desc ());
111 return 0; 112 return 0;
112 } 113 }
113 114
114 number = tmp->nrof;
115 if (number == 0)
116 number = 1;
117 if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified) 115 if (tmp->flag [FLAG_IDENTIFIED] || !tmp->need_identify () || identified)
118 { 116 {
119 if (!not_cursed && (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))) 117 if (!not_cursed && (tmp->flag [FLAG_CURSED] || tmp->flag [FLAG_DAMNED]))
120 return 0; 118 return 0;
121 else 119 else
122 val = tmp->value * number; 120 val = number * tmp->value;
123 } 121 }
124 /* This area deals with objects that are not identified, but can be */ 122 /* This area deals with objects that are not identified, but can be */
125 else 123 else
126 { 124 {
127 if (tmp->arch != NULL)
128 {
129 if (flag == F_BUY) 125 if (flag == F_BUY)
126 {
127 LOG (llevError | logBacktrace, "Asking for buy-value of unidentified object: %s\n", tmp->debug_desc ());
128 val = tmp->arch->value * 50 * number;
129 }
130 else
131 { /* Trying to sell something, or get true value */
132 if (tmp->type == POTION)
133 val = number * 40; /* Don't want to give anything away */
134 else
130 { 135 {
131 LOG (llevError | logBacktrace, "Asking for buy-value of unidentified object.\n"); 136 /* Get 2/3'rd value for applied objects, 1/3'rd for totally
132 val = tmp->arch->value * 50 * number; 137 * unknown objects
138 */
139 if (tmp->flag [FLAG_BEEN_APPLIED])
140 val = number * tmp->arch->value * 2 / 3;
141 else
142 val = number * tmp->arch->value / 3;
133 } 143 }
134 else
135 { /* Trying to sell something, or get true value */
136 if (tmp->type == POTION)
137 val = number * 40; /* Don't want to give anything away */
138 else
139 {
140 /* Get 2/3'rd value for applied objects, 1/3'rd for totally
141 * unknown objects
142 */
143 if (QUERY_FLAG (tmp, FLAG_BEEN_APPLIED))
144 val = number * tmp->arch->value * 2 / 3;
145 else
146 val = number * tmp->arch->value / 3;
147 }
148 }
149 }
150 else
151 { /* No archetype with this object */
152 LOG (llevDebug, "In sell item: Have object with no archetype: %s\n", &tmp->name);
153 if (flag == F_BUY)
154 {
155 LOG (llevError | logBacktrace, "Asking for buy-value of unidentified object without arch.\n");
156 val = number * tmp->value * 10;
157 }
158 else
159 val = number * tmp->value / 5;
160 } 144 }
161 } 145 }
162 146
163 /* If the item has been applied or identifed or does not need to be 147 /* If the item has been applied or identifed or does not need to be
164 * identified, AND the object is magical and the archetype is non 148 * identified, AND the object is magical and the archetype is non
167 * tmp->arch->magic for any magic. The check for archetype 151 * tmp->arch->magic for any magic. The check for archetype
168 * magic is to not give extra money for archetypes that are by 152 * magic is to not give extra money for archetypes that are by
169 * default magical. This is because the archetype value should have 153 * default magical. This is because the archetype value should have
170 * already figured in that value. 154 * already figured in that value.
171 */ 155 */
172 if ((QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified || 156 if ((tmp->flag [FLAG_IDENTIFIED] || !tmp->need_identify () || identified || tmp->flag [FLAG_BEEN_APPLIED])
173 QUERY_FLAG (tmp, FLAG_BEEN_APPLIED)) && tmp->magic && (tmp->arch == NULL || !tmp->arch->magic)) 157 && tmp->magic && (!tmp->arch || !tmp->arch->magic))
174 { 158 {
175 if (tmp->magic > 0) 159 if (tmp->magic > 0)
176 val *= (3 * tmp->magic * tmp->magic * tmp->magic); 160 val *= 3 * tmp->magic * tmp->magic * tmp->magic;
177 else 161 else
178 /* Note that tmp->magic is negative, so that this 162 /* Note that tmp->magic is negative, so that this
179 * will actually be something like val /=2, /=3, etc. 163 * will actually be something like val /=2, /=3, etc.
180 */ 164 */
181 val /= (1 - tmp->magic); 165 val /= 1 - tmp->magic;
182 } 166 }
183 167
184 if (tmp->type == WAND) 168 if (tmp->type == WAND)
185 { 169 {
186 /* Value of the wand is multiplied by the number of 170 /* Value of the wand is multiplied by the number of
187 * charges. the treasure code already sets up the value 171 * charges. the treasure code already sets up the value
188 * 50 charges is used as the baseline. 172 * 50 charges is used as the baseline.
189 */ 173 */
190 if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified) 174 if (tmp->flag [FLAG_IDENTIFIED] || !tmp->need_identify () || identified)
191 val = (val * tmp->stats.food) / 50; 175 val *= tmp->stats.food / 50;
192 else /* if not identified, presume one charge */ 176 else /* if not identified, presume one charge */
193 val /= 50; 177 val /= 50;
194 } 178 }
195 179
196 /* Limit amount of money you can get for really great items. */ 180 /* Limit amount of money you can get for really great items. */
197 if (flag == F_SELL) 181 if (flag == F_SELL)
198 val = value_limit ((sint64) val, number, who, shop); 182 val = value_limit (val, number, who, shop);
199 183
200 // use a nonlinear price adjustment. as my predecessor said, don't change 184 // use a nonlinear price adjustment. as my predecessor said, don't change
201 // the archetypes, its work required for balancing, and we don't care. 185 // the archetypes, its work required for balancing, and we don't care.
202 //val = pow (val, 1.05); 186 //val = pow (val, 1.05);
203 187
234 * will come from the basic stat charisma 218 * will come from the basic stat charisma
235 * the rest will come from the level in bargaining skill 219 * the rest will come from the level in bargaining skill
236 */ 220 */
237 const double cha_ratio = 0.40; 221 const double cha_ratio = 0.40;
238 222
239 diff = no_bargain ? 1.0 : 1. - pow (lev_bargain / (double) settings.max_level, 0.25); 223 diff = no_bargain ? 1.0 : 1. - pow (lev_bargain / MAXLEVEL_TREASURE, 0.25);
240 diff = (1. - cha_ratio) * diff + cha_ratio * (cha_bonus[who->stats.Cha] - 1.) / (cha_bonus[who->stats.Cha] + 1.); 224 diff = (1. - cha_ratio) * diff + cha_ratio * (cha_bonus[who->stats.Cha] - 1.) / (cha_bonus[who->stats.Cha] + 1.);
241 diff = .02 + (.80 - .02) * diff; 225 diff = .02 + (.80 - .02) * diff;
242 226
243 if (flag == F_BUY) 227 if (flag == F_BUY)
244 val += val * diff; 228 val += val * diff;
246 val -= val * diff; 230 val -= val * diff;
247 231
248 // now find a price range. the less good we can judge, the larger the range is 232 // now find a price range. the less good we can judge, the larger the range is
249 // then the range is adjusted randomly around the correct value 233 // then the range is adjusted randomly around the correct value
250 if (approximate) 234 if (approximate)
251 approx_range = sint64 (val / sqrt (lev_identify * 3 + 1)); 235 approx_range = val / sqrt (lev_identify * 3 + 1);
252 } 236 }
253 237
254 /* I don't think this should really happen - if it does, it indicates and 238 /* I don't think this should really happen - if it does, it indicates and
255 * overflow of diff above. That should only happen if 239 * overflow of diff above. That should only happen if
256 * we are selling objects - in that case, the person just 240 * we are selling objects - in that case, the person just
257 * gets no money. 241 * gets no money.
258 */ 242 */
259 if ((sint64) val < 0) 243 if ((sint64) val < 0)
260 val = 0; 244 val = 0;
261 245
262 /* Unidentified stuff won't sell for more than 60gp */ 246 /* Unidentified stuff won't sell for more than 10gp */
263 if (flag == F_SELL && !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && need_identify (tmp) && !identified) 247 if (flag == F_SELL && !tmp->flag [FLAG_IDENTIFIED] && tmp->need_identify () && !identified)
264 { 248 min_it (val, 1000);
265 val = (val > 600) ? 600 : val;
266 }
267 249
268 /* if we are in a shop, check how the type of shop should affect the price */ 250 /* if we are in a shop, check how the type of shop should affect the price */
269 if (shop && who) 251 if (shop && who)
270 { 252 {
271 if (flag == F_SELL) 253 if (flag == F_SELL)
272 val = (val * shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who) / shop_greed (who->map)); 254 val *= shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who) / shop_greed (who->map);
273 else if (flag == F_BUY) 255 else if (flag == F_BUY)
274 { 256 {
275 /* 257 /*
276 * when buying, if the item was sold by another player, it is ok to 258 * when buying, if the item was sold by another player, it is ok to
277 * let the item be sold cheaper, according to the specialisation of 259 * let the item be sold cheaper, according to the specialisation of
283 * be sold for (otherwise players could camp map resets to make money). 265 * be sold for (otherwise players could camp map resets to make money).
284 * In game terms, a non-specialist shop, might not recognise the true 266 * In game terms, a non-specialist shop, might not recognise the true
285 * value of the items they sell (much like how people sometimes find 267 * value of the items they sell (much like how people sometimes find
286 * antiques in a junk shop in real life). 268 * antiques in a junk shop in real life).
287 */ 269 */
288 if (QUERY_FLAG (tmp, FLAG_PLAYER_SOLD)) 270 if (tmp->flag [FLAG_PLAYER_SOLD])
289 val = (val * shop_greed (who->map) * shop_specialisation_ratio (tmp, who->map) / shopkeeper_approval (who->map, who)); 271 val *= shop_specialisation_ratio (tmp, who->map);
290 else 272 else
291 val = (val * shop_greed (who->map) / (shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who))); 273 val /= shop_specialisation_ratio (tmp, who->map);
274
275 val *= shop_greed (who->map) / shopkeeper_approval (who->map, who);
292 } 276 }
293 277
294 /* we will also have an extra 0-5% variation between shops of the same type 278 /* we will also have an extra 0-5% variation between shops of the same type
295 * for valuable items (below a value of 50 this effect wouldn't be very 279 * for valuable items (below a value of 50 this effect wouldn't be very
296 * pointful, and could give fun with rounding. 280 * pointful, and could give fun with rounding.
297 */ 281 */
298 //TODO: why use cosf at all, just % and scale linearly, gives more even distribution 282 //TODO: why use cosf at all, just % and scale linearly, gives more even distribution
299 if (val > 50) 283 if (val > 50)
300 val += float (val) * .05f * cosf ((tmp->uuid.seq & 0xffff) * float (M_PI * 2. / 0x10000)); 284 val *= 1 + .05f * cosf ((tmp->uuid.seq & 0xffff) * M_PI * 2. / 0x10000);
301 } 285 }
302 286
303 return (sint64) val; 287 return val;
304} 288}
305 289
306/* Find the coin type that is worth more the 'c'. Starts at the 290/* Find the coin type that is worth more the 'c'. Starts at the
307 * cointype placement. 291 * cointype placement.
308 */ 292 */
312{ 296{
313 archetype *coin; 297 archetype *coin;
314 298
315 do 299 do
316 { 300 {
317 if (coins[*cointype] == NULL) 301 if (!coins [*cointype])
318 return NULL; 302 return 0;
303
319 coin = archetype::find (coins[*cointype]); 304 coin = archetype::find (coins [*cointype]);
305
320 if (coin == NULL) 306 if (!coin)
321 return NULL; 307 return 0;
308
322 *cointype += 1; 309 *cointype += 1;
323 } 310 }
324 while (coin->value > c); 311 while (coin->value > c);
325 312
326 return coin; 313 return coin;
465 } 452 }
466 453
467 for (tmp = op->inv; tmp; tmp = tmp->below) 454 for (tmp = op->inv; tmp; tmp = tmp->below)
468 if (tmp->type == MONEY) 455 if (tmp->type == MONEY)
469 total += tmp->nrof * (sint64)tmp->value; 456 total += tmp->nrof * (sint64)tmp->value;
470 else if (tmp->type == CONTAINER && QUERY_FLAG (tmp, FLAG_APPLIED) && (tmp->race == NULL || strstr (tmp->race, "gold"))) 457 else if (tmp->type == CONTAINER && tmp->flag [FLAG_APPLIED] && (!tmp->race || tmp->race.contains ("gold")))
471 total += query_money (tmp); 458 total += query_money (tmp);
472 459
473 return total; 460 return total;
474} 461}
475 462
490 return 0; 477 return 0;
491 478
492 pay_from_container (pl, pl, to_pay); 479 pay_from_container (pl, pl, to_pay);
493 480
494 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 481 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below)
495 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && (pouch->race == NULL || strstr (pouch->race, "gold"))) 482 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains ("gold")))
496 pay_from_container (pl, pouch, to_pay); 483 pay_from_container (pl, pouch, to_pay);
497 484
498 pl->update_stats (); 485 pl->update_stats ();
499 return 1; 486 return 1;
500} 487}
527 change_exp (pl, saved_money, "bargaining", SK_EXP_NONE); 514 change_exp (pl, saved_money, "bargaining", SK_EXP_NONE);
528 515
529 pay_from_container (pl, pl, to_pay); 516 pay_from_container (pl, pl, to_pay);
530 517
531 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 518 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below)
532 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && (pouch->race == NULL || strstr (pouch->race, "gold"))) 519 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains ("gold")))
533 pay_from_container (pl, pouch, to_pay); 520 pay_from_container (pl, pouch, to_pay);
534 521
535 pl->update_stats (); 522 pl->update_stats ();
536 523
537 return 1; 524 return 1;
604 at = archetype::find (coins[NUM_COINS - 1 - i]); 591 at = archetype::find (coins[NUM_COINS - 1 - i]);
605 592
606 if (at == NULL) 593 if (at == NULL)
607 LOG (llevError, "Could not find %s archetype\n", coins[NUM_COINS - 1 - i]); 594 LOG (llevError, "Could not find %s archetype\n", coins[NUM_COINS - 1 - i]);
608 595
609 coin_objs[i] = arch_to_object (at); 596 coin_objs[i] = at->instance ();
610 coin_objs[i]->nrof = 0; 597 coin_objs[i]->nrof = 0;
611 } 598 }
612 599
613 for (i = 0; i < NUM_COINS; i++) 600 for (i = 0; i < NUM_COINS; i++)
614 { 601 {
615 object &coin = *coin_objs[i]; 602 object &coin = *coin_objs[i];
616 sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, coin.nrof); 603 sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, (sint64) coin.nrof);
617 to_pay -= num_coins * coin.value; 604 to_pay -= num_coins * coin.value;
618 605
619 coin.nrof -= num_coins; 606 coin.nrof -= num_coins;
620 /* Now start making change. Start at the coin value 607 /* Now start making change. Start at the coin value
621 * below the one we just did, and work down to 608 * below the one we just did, and work down to
656 LOG (llevError, "can_pay(): called against something that isn't a player\n"); 643 LOG (llevError, "can_pay(): called against something that isn't a player\n");
657 return 0; 644 return 0;
658 } 645 }
659 646
660 for (object::depth_iterator item = pl->begin (); item != pl->end (); ++item) 647 for (object::depth_iterator item = pl->begin (); item != pl->end (); ++item)
661 if (QUERY_FLAG (item, FLAG_UNPAID)) 648 if (item->flag [FLAG_UNPAID])
662 { 649 {
663 unpaid_count++; 650 unpaid_count++;
664 unpaid_price += query_cost (item, pl, F_BUY | F_SHOP); 651 unpaid_price += query_cost (item, pl, F_BUY | F_SHOP);
665 } 652 }
666 653
667 if (unpaid_price > player_wealth) 654 if (unpaid_price > player_wealth)
668 { 655 {
669 dynbuf_text buf; 656 dynbuf_text &buf = msg_dynbuf; buf.clear ();
670 657
671 buf << "You have " << unpaid_count 658 buf << "You have " << unpaid_count
672 << " unpaid item(s) that would cost you " << cost_string_from_value (unpaid_price, 0) 659 << " unpaid item(s) that would cost you " << cost_string_from_value (unpaid_price, 0)
673 << ". You need another " << cost_string_from_value (unpaid_price - player_wealth, 0) 660 << ". You need another " << cost_string_from_value (unpaid_price - player_wealth, 0)
674 << " to be able to afford that. " 661 << " to be able to afford that. "
675 "H<You cannot leave a shop with items you cannot pay - drop those unpaid items first.>"; 662 "H<You cannot leave a shop without paying - drop unpaid items first to be able to leave.>";
676 663
677 pl->failmsg (buf); 664 pl->failmsg (buf);
678 665
679 return 0; 666 return 0;
680 } 667 }
695 { 682 {
696 next_item: 683 next_item:
697 684
698 for (object::depth_iterator op = pl->begin (); op != pl->end (); ++op) 685 for (object::depth_iterator op = pl->begin (); op != pl->end (); ++op)
699 { 686 {
700 if (QUERY_FLAG (op, FLAG_UNPAID)) 687 if (op->flag [FLAG_UNPAID])
701 { 688 {
702 char buf[MAX_BUF]; 689 char buf[MAX_BUF];
703 snprintf (buf, MAX_BUF, "%s", query_cost_string (op, pl, F_BUY | F_SHOP)); 690 snprintf (buf, MAX_BUF, "%s", query_cost_string (op, pl, F_BUY | F_SHOP));
704 691
705 if (!pay_for_item (op, pl)) 692 if (!pay_for_item (op, pl))
706 { 693 {
707 sint64 i = query_cost (op, pl, F_BUY | F_SHOP) - query_money (pl); 694 sint64 i = query_cost (op, pl, F_BUY | F_SHOP) - query_money (pl);
708 695
709 CLEAR_FLAG (op, FLAG_UNPAID); 696 op->clr_flag (FLAG_UNPAID);
710 new_draw_info_format (NDI_UNIQUE, 0, pl, "You lack %s to buy %s.", cost_string_from_value (i, 0), query_name (op)); 697 new_draw_info_format (NDI_UNIQUE, 0, pl, "You lack %s to buy %s.", cost_string_from_value (i, 0), query_name (op));
711 SET_FLAG (op, FLAG_UNPAID); 698 op->set_flag (FLAG_UNPAID);
712 return 0; 699 return 0;
713 } 700 }
714 else 701 else
715 { 702 {
716 CLEAR_FLAG (op, FLAG_UNPAID); 703 op->clr_flag (FLAG_UNPAID);
717 CLEAR_FLAG (op, FLAG_PLAYER_SOLD); 704 op->clr_flag (FLAG_PLAYER_SOLD);
718 new_draw_info_format (NDI_UNIQUE, 0, op, "You paid %s for %s.", buf, query_name (op)); 705 new_draw_info_format (NDI_UNIQUE, 0, op, "You paid %s for %s.", buf, query_name (op));
719 706
720 if (!merge_ob (op, op->env->inv)) 707 if (!merge_ob (op, op->env->inv))
721 esrv_update_item (UPD_FLAGS, pl, op); 708 esrv_update_item (UPD_FLAGS, pl, op);
722 709
755 LOG (llevError, "Could not find %s archetype\n", coins[count]); 742 LOG (llevError, "Could not find %s archetype\n", coins[count]);
756 else if ((amount / at->value) > 0) 743 else if ((amount / at->value) > 0)
757 { 744 {
758 for (pouch = pl->inv; pouch; pouch = pouch->below) 745 for (pouch = pl->inv; pouch; pouch = pouch->below)
759 { 746 {
760 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && pouch->race && strstr (pouch->race, "gold")) 747 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && pouch->race.contains ("gold"))
761 { 748 {
762 int w = at->weight * (100 - pouch->stats.Str) / 100; 749 int w = at->weight * (100 - pouch->stats.Str) / 100;
763 int n = amount / at->value; 750 int n = amount / at->value;
764 751
765 if (w == 0) 752 if (w == 0)
768 if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit)) 755 if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit))
769 { 756 {
770 if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n) 757 if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n)
771 n = (pouch->weight_limit - pouch->carrying) / w; 758 n = (pouch->weight_limit - pouch->carrying) / w;
772 759
773 object *tmp = arch_to_object (at); 760 object *tmp = at->instance ();
774 tmp->nrof = n; 761 tmp->nrof = n;
775 amount -= tmp->nrof * tmp->value; 762 amount -= tmp->nrof * tmp->value;
776 pouch->insert (tmp); 763 pouch->insert (tmp);
777 } 764 }
778 } 765 }
779 } 766 }
780 767
781 if (amount / at->value > 0) 768 if (amount / at->value > 0)
782 { 769 {
783 object *tmp = arch_to_object (at); 770 object *tmp = at->instance ();
784 tmp->nrof = amount / tmp->value; 771 tmp->nrof = amount / tmp->value;
785 amount -= tmp->nrof * tmp->value; 772 amount -= tmp->nrof * tmp->value;
786 pl->insert (tmp); 773 pl->insert (tmp);
787 } 774 }
788 } 775 }
853 840
854 new_draw_info_format (NDI_UNIQUE, 0, pl, "You receive %s for %s.", 841 new_draw_info_format (NDI_UNIQUE, 0, pl, "You receive %s for %s.",
855 query_cost_string (op, pl, F_SELL | F_SHOP), query_name (op)); 842 query_cost_string (op, pl, F_SELL | F_SHOP), query_name (op));
856 pl->play_sound (sound_find ("shop_sell")); 843 pl->play_sound (sound_find ("shop_sell"));
857 844
858 SET_FLAG (op, FLAG_UNPAID); 845 op->set_flag (FLAG_UNPAID);
859 identify (op); 846 identify (op);
860 847
861 return true; 848 return true;
862} 849}
863 850
867 */ 854 */
868static double 855static double
869shop_specialisation_ratio (const object *item, const maptile *map) 856shop_specialisation_ratio (const object *item, const maptile *map)
870{ 857{
871 shopitems *items = map->shopitems; 858 shopitems *items = map->shopitems;
872 double likedness = 0.; 859 int likedness = 0;
873 int i; 860 int i;
874 861
875 if (item == NULL) 862 if (item == NULL)
876 { 863 {
877 LOG (llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", &map->path); 864 LOG (llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", &map->path);
887 */ 874 */
888 return SPECIALISATION_EFFECT; 875 return SPECIALISATION_EFFECT;
889 } 876 }
890 877
891 if (map->shopitems) 878 if (map->shopitems)
892 {
893 for (i = 0; i < items[0].index; i++) 879 for (i = 0; i < items[0].index; i++)
894 if (items[i].typenum == item->type || (!items[i].typenum && likedness == 0.001)) 880 if (items[i].typenum == item->type || (!items[i].typenum && !likedness))
895 likedness = items[i].strength / 100.0; 881 likedness = items[i].strength;
896 }
897 882
898 if (likedness > 1.0) 883 if (likedness > 100)
899 { /* someone has been rather silly with the map headers. */ 884 { /* someone has been rather silly with the map headers. */
900 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, &map->path); 885 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, &map->path);
901 likedness = 1.0; 886 likedness = 100;
902 } 887 }
903 888
904 if (likedness < -1.0) 889 if (likedness < -100)
905 { 890 {
906 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, &map->path); 891 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, &map->path);
907 likedness = -1.0; 892 likedness = -100;
908 } 893 }
909 894
910 return lerp (likedness, -1., 1., SPECIALISATION_EFFECT, 1.); 895 return lerp (double (likedness), -100., 100., SPECIALISATION_EFFECT, 1.);
911} 896}
912 897
913/*returns the greed of the shop on map, or 1 if it isn't specified. */ 898/*returns the greed of the shop on map, or 1 if it isn't specified. */
914static double 899static double
915shop_greed (const maptile *map) 900shop_greed (const maptile *map)
965 tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default 950 tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default
966 951
967 if (map->shopmin && unit_price < map->shopmin) 952 if (map->shopmin && unit_price < map->shopmin)
968 return 0; 953 return 0;
969 else if (unit_price > tmpshopmax / 2) 954 else if (unit_price > tmpshopmax / 2)
970 newval = MIN ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax); 955 newval = min ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax);
971 else 956 else
972 newval = unit_price; 957 newval = unit_price;
973 } 958 }
974 959
975 newval *= quantity; 960 newval *= quantity;
979 964
980/* gives a desciption of the shop on their current map to the player op. */ 965/* gives a desciption of the shop on their current map to the player op. */
981int 966int
982describe_shop (const object *op) 967describe_shop (const object *op)
983{ 968{
969 dynbuf_text buf;
984 maptile *map = op->map; 970 maptile *map = op->map;
985 971
986 /*shopitems *items=map->shopitems; */ 972 /*shopitems *items=map->shopitems; */
987 int pos = 0, i; 973 int pos = 0, i;
988 double opinion = 0; 974 double opinion = 0;
989 char tmp[MAX_BUF] = "\0";
990 975
991 if (op->type != PLAYER) 976 if (op->type != PLAYER)
992 return 0; 977 return 0;
993 978
994 /*check if there is a shop specified for this map */ 979 /*check if there is a shop specified for this map */
995 if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax) 980 if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax)
996 { 981 {
997 new_draw_info (NDI_UNIQUE, 0, op, "From looking at the nearby shop you determine that it trades in:"); 982 buf << "From looking at the nearby shop you determine that it trades in ";
983 int lastcomma = 0, prevcomma = 0;
998 984
999 if (map->shopitems) 985 if (map->shopitems)
1000 for (i = 0; i < map->shopitems[0].index; i++) 986 for (i = 0; i < map->shopitems[0].index; i++)
1001 if (map->shopitems[i].name && map->shopitems[i].strength > 10) 987 if (map->shopitems[i].name && map->shopitems[i].strength > 10)
1002 { 988 {
1003 snprintf (tmp + pos, sizeof (tmp) - pos, "%s, ", map->shopitems[i].name_pl); 989 buf << map->shopitems[i].name_pl;
1004 pos += strlen (tmp + pos); 990 prevcomma = lastcomma;
991 lastcomma = buf.size (); // remember offset
992 buf << ", ";
1005 } 993 }
1006 994
1007 if (!pos) 995 if (lastcomma)
996 {
997 buf.splice (lastcomma, 2);
998
999 if (prevcomma)
1000 buf.splice (prevcomma, 2, " and ");
1001 }
1002 else
1008 strcat (tmp, "a little of everything."); 1003 buf << "a little of everything.";
1009 1004
1010 /* format the string into a list */ 1005 buf << ".\n\n";
1011 make_list_like (tmp);
1012 new_draw_info_format (NDI_UNIQUE, 0, op, "%s", tmp);
1013 1006
1014 if (map->shopmax) 1007 if (map->shopmax)
1015 new_draw_info_format (NDI_UNIQUE, 0, op, "It won't trade for items above %s.", cost_string_from_value (map->shopmax, 0)); 1008 buf << "It won't trade for items above " << cost_string_from_value (map->shopmax, 0) << ".\n\n";
1016 1009
1017 if (map->shopmin) 1010 if (map->shopmin)
1018 new_draw_info_format (NDI_UNIQUE, 0, op, "It won't trade in items worth less than %s.", cost_string_from_value (map->shopmin, 0)); 1011 buf << "It won't trade in items worth less than " << cost_string_from_value (map->shopmin, 0) << ".\n\n";
1019 1012
1020 if (map->shopgreed) 1013 if (map->shopgreed)
1021 { 1014 {
1022 if (map->shopgreed > 2.0) 1015 if (map->shopgreed > 2.0)
1023 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge massively."); 1016 buf << "It tends to overcharge massively.\n\n";
1024 else if (map->shopgreed > 1.5) 1017 else if (map->shopgreed > 1.5)
1025 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge substantially."); 1018 buf << "It tends to overcharge substantially.\n\n";
1026 else if (map->shopgreed > 1.1) 1019 else if (map->shopgreed > 1.1)
1027 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge slightly."); 1020 buf << "It tends to overcharge slightly.\n\n";
1028 else if (map->shopgreed < 0.9) 1021 else if (map->shopgreed < 0.9)
1029 new_draw_info (NDI_UNIQUE, 0, op, "It tends to undercharge."); 1022 buf << "It tends to undercharge.\n\n";
1030 } 1023 }
1031 1024
1032 if (map->shoprace) 1025 if (map->shoprace)
1033 { 1026 {
1034 opinion = shopkeeper_approval (map, op); 1027 opinion = shopkeeper_approval (map, op);
1028
1035 if (opinion > 0.8) 1029 if (opinion > 0.8)
1036 new_draw_info (NDI_UNIQUE, 0, op, "You think the shopkeeper likes you."); 1030 buf << "You think the shopkeeper likes you.\n\n";
1037 else if (opinion > 0.5) 1031 else if (opinion > 0.5)
1038 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems unconcerned by you."); 1032 buf << "The shopkeeper seems unconcerned by you.\n\n";
1039 else 1033 else
1040 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems to have taken a dislike to you."); 1034 buf << "The shopkeeper seems to have taken a dislike to you.\n\n";
1041 } 1035 }
1042 } 1036 }
1043 else 1037 else
1044 new_draw_info (NDI_UNIQUE, 0, op, "There is no shop nearby."); 1038 buf << "There is no shop nearby.\n\n";
1039
1040 op->contr->infobox (MSG_CHANNEL ("shopinfo"), buf);
1045 1041
1046 return 1; 1042 return 1;
1047} 1043}
1048 1044
1049struct shopinv 1045struct shopinv
1085 /* clear unpaid flag so that doesn't come up in query 1081 /* clear unpaid flag so that doesn't come up in query
1086 * string. We clear nrof so that we can better sort 1082 * string. We clear nrof so that we can better sort
1087 * the object names. 1083 * the object names.
1088 */ 1084 */
1089 1085
1090 CLEAR_FLAG (tmp, FLAG_UNPAID); 1086 tmp->clr_flag (FLAG_UNPAID);
1091 items[*numitems].nrof = tmp->nrof; 1087 items[*numitems].nrof = tmp->nrof;
1092 /* Non mergable items have nrof of 0, but count them as one 1088 /* Non mergable items have nrof of 0, but count them as one
1093 * so the display is properly. 1089 * so the display is properly.
1094 */ 1090 */
1095 if (tmp->nrof == 0) 1091 if (tmp->nrof == 0)
1117 items[*numitems].item_sort = strdup (query_base_name (tmp, 0)); 1113 items[*numitems].item_sort = strdup (query_base_name (tmp, 0));
1118 items[*numitems].item_real = strdup (query_base_name (tmp, 1)); 1114 items[*numitems].item_real = strdup (query_base_name (tmp, 1));
1119 (*numitems)++; 1115 (*numitems)++;
1120 break; 1116 break;
1121 } 1117 }
1122 SET_FLAG (tmp, FLAG_UNPAID); 1118
1119 tmp->set_flag (FLAG_UNPAID);
1123} 1120}
1124 1121
1125void 1122void
1126shop_listing (object *sign, object *op) 1123shop_listing (object *sign, object *op)
1127{ 1124{
1128 int i, j, numitems = 0, numallocated = 0, x1, x2, y1, y2; 1125 int i, j, x1, x2, y1, y2;
1129 const char *shop_coords = sign->kv (shstr_shop_coords); 1126 const char *shop_coords = sign->kv (shstr_shop_coords);
1130 object *stack; 1127 object *stack;
1131 shopinv *items; 1128 shopinv *items;
1132 1129
1133 /* Should never happen, but just in case a monster does apply a sign */ 1130 /* Should never happen, but just in case a monster does apply a sign */
1134 if (op->type != PLAYER) 1131 if (!op->is_player ())
1135 return; 1132 return;
1133
1134 dynbuf_text &buf = msg_dynbuf; buf.clear ();
1136 1135
1137 if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2))) 1136 if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2)))
1138 { 1137 {
1139 x1 = 0; 1138 x1 = 0;
1140 y1 = 0; 1139 y1 = 0;
1141 x2 = op->map->width - 1; 1140 x2 = op->map->width - 1;
1142 y2 = op->map->height - 1; 1141 y2 = op->map->height - 1;
1143 } 1142 }
1144 1143
1145 items = (shopinv *) malloc (40 * sizeof (shopinv));
1146 numallocated = 40; 1144 int numallocated = 40;
1145 int numitems = 0;
1146 items = (shopinv *)malloc (sizeof (shopinv) * numallocated);
1147 1147
1148 /* Find all the appropriate items */ 1148 /* Find all the appropriate items */
1149 for (i = x1; i <= x2; i++) 1149 for (i = x1; i <= x2; i++)
1150 {
1151 for (j = y1; j < y2; j++) 1150 for (j = y1; j < y2; j++)
1151 if (op->map->is_in_shop (i, j))
1152 { 1152 {
1153 if (is_in_shop (op->map, i, j)) 1153 stack = GET_MAP_OB (op->map, i, j);
1154
1155 while (stack)
1154 { 1156 {
1155 stack = GET_MAP_OB (op->map, i, j); 1157 if (stack->flag [FLAG_UNPAID])
1156
1157 while (stack)
1158 { 1158 {
1159 if (QUERY_FLAG (stack, FLAG_UNPAID))
1160 {
1161 if (numitems == numallocated) 1159 if (numitems == numallocated)
1162 {
1163 items = (shopinv *) realloc (items, sizeof (shopinv) * (numallocated + 10)); 1160 items = (shopinv *)realloc (items, sizeof (shopinv) * (numallocated *= 2));
1164 numallocated += 10;
1165 }
1166 1161
1167 add_shop_item (stack, items, &numitems, &numallocated); 1162 add_shop_item (stack, items, &numitems, &numallocated);
1168 }
1169
1170 stack = stack->above;
1171 } 1163 }
1164
1165 stack = stack->above;
1172 } 1166 }
1173 } 1167 }
1174 }
1175 1168
1176 if (numitems == 0) 1169 buf << (numitems ? "T<This shop contains:>\n\n"
1177 { 1170 : "T<This shop is currently empty.>");
1178 new_draw_info (NDI_UNIQUE, 0, op, "The shop is currently empty.\n");
1179 free (items);
1180 return;
1181 }
1182 1171
1183 qsort (items, numitems, sizeof (shopinv), (int (*)(const void *, const void *)) shop_sort); 1172 qsort (items, numitems, sizeof (shopinv), (int (*)(const void *, const void *)) shop_sort);
1184
1185 new_draw_info (NDI_UNIQUE, 0, op, "\nThe shop contains:");
1186 1173
1187 for (i = 0; i < numitems; i++) 1174 for (i = 0; i < numitems; i++)
1188 { 1175 {
1189 /* Collapse items of the same name together */ 1176 /* Collapse items of the same name together */
1190 if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real)) 1177 if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real))
1191 {
1192 items[i + 1].nrof += items[i].nrof; 1178 items[i + 1].nrof += items[i].nrof;
1193 free (items[i].item_sort);
1194 free (items[i].item_real);
1195 }
1196 else 1179 else
1197 {
1198 new_draw_info_format (NDI_UNIQUE, 0, op, "%d %s",
1199 items[i].nrof ? items[i].nrof : 1, items[i].nrof == 1 ? items[i].item_sort : items[i].item_real); 1180 buf.printf (" %4d %s\n", items[i].nrof ? items[i].nrof : 1, items[i].nrof == 1 ? items[i].item_sort : items[i].item_real);
1181
1200 free (items[i].item_sort); 1182 free (items[i].item_sort);
1201 free (items[i].item_real); 1183 free (items[i].item_real);
1202 }
1203 } 1184 }
1185
1186 op->contr->infobox (MSG_CHANNEL ("shopitems"), buf);
1204 1187
1205 free (items); 1188 free (items);
1206}
1207
1208/* elmex: this function checks whether the object is in a shop */
1209bool
1210is_in_shop (object *o)
1211{
1212 if (!o->is_on_map ())
1213 return false;
1214
1215 return is_in_shop (o->map, o->x, o->y);
1216} 1189}
1217 1190
1218/* elmex: this function checks whether we are in a shop or not 1191/* elmex: this function checks whether we are in a shop or not
1219 - change 2007-11-26: enhanced the O(n) case by stopping at the first 1192 - change 2007-11-26: enhanced the O(n) case by stopping at the first
1220 floor tile. this possibly will make map bugs where shopfloors are above 1193 floor tile. this possibly will make map bugs where shopfloors are above
1221 floors more obvious. 1194 floors more obvious.
1222*/ 1195*/
1223
1224bool 1196bool
1225is_in_shop (maptile *map, int x, int y) 1197maptile::is_in_shop (int x, int y) const
1226{ 1198{
1227 for (object *floor = GET_MAP_OB (map, x, y); floor; floor = floor->above) 1199 for (object *floor = at (x, y).bot; floor; floor = floor->above)
1228 if (QUERY_FLAG (floor, FLAG_IS_FLOOR)) 1200 if (floor->flag [FLAG_IS_FLOOR])
1229 return floor->type == SHOP_FLOOR; 1201 return floor->type == SHOP_FLOOR;
1230 1202
1231 return false; 1203 return false;
1232} 1204}
1233 1205

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines