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.65 by root, Sun Apr 26 19:42:45 2009 UTC vs.
Revision 1.81 by root, Wed Apr 28 19:20:48 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,2009 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.
90 not_cursed = flag & F_NOT_CURSED; 90 not_cursed = flag & F_NOT_CURSED;
91 approximate = flag & F_APPROX; 91 approximate = flag & F_APPROX;
92 shop = flag & F_SHOP; 92 shop = flag & F_SHOP;
93 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);
94 94
95 int number = tmp->number_of ();
96
95 if (tmp->type == MONEY) 97 if (tmp->type == MONEY)
96 return tmp->nrof * tmp->value; 98 return number * tmp->value;
97 99
98 if (tmp->type == GEM) 100 if (tmp->type == GEM)
99 { 101 {
100 if (flag == F_TRUE) 102 if (flag == F_TRUE)
101 return (tmp->nrof * tmp->value); 103 return number * tmp->value;
102 104
103 if (flag == F_BUY) 105 if (flag == F_BUY)
104 return (sint64) (1.03 * tmp->nrof * tmp->value); 106 return 1.03 * number * tmp->value;
105 107
106 if (flag == F_SELL) 108 if (flag == F_SELL)
107 return (sint64) (0.97 * tmp->nrof * tmp->value); 109 return 0.97 * number * tmp->value;
108 110
109 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 ());
110 return 0; 112 return 0;
111 } 113 }
112 114
113 int number = tmp->number_of ();
114
115 if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified) 115 if (tmp->flag [FLAG_IDENTIFIED] || !tmp->need_identify () || identified)
116 { 116 {
117 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]))
118 return 0; 118 return 0;
119 else 119 else
120 val = tmp->value * number; 120 val = number * tmp->value;
121 } 121 }
122 /* 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 */
123 else 123 else
124 { 124 {
125 if (flag == F_BUY) 125 if (flag == F_BUY)
134 else 134 else
135 { 135 {
136 /* Get 2/3'rd value for applied objects, 1/3'rd for totally 136 /* Get 2/3'rd value for applied objects, 1/3'rd for totally
137 * unknown objects 137 * unknown objects
138 */ 138 */
139 if (QUERY_FLAG (tmp, FLAG_BEEN_APPLIED)) 139 if (tmp->flag [FLAG_BEEN_APPLIED])
140 val = number * tmp->arch->value * 2 / 3; 140 val = number * tmp->arch->value * 2 / 3;
141 else 141 else
142 val = number * tmp->arch->value / 3; 142 val = number * tmp->arch->value / 3;
143 } 143 }
144 } 144 }
145 } 145 }
146 146
147 /* 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
151 * tmp->arch->magic for any magic. The check for archetype 151 * tmp->arch->magic for any magic. The check for archetype
152 * 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
153 * default magical. This is because the archetype value should have 153 * default magical. This is because the archetype value should have
154 * already figured in that value. 154 * already figured in that value.
155 */ 155 */
156 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])
157 QUERY_FLAG (tmp, FLAG_BEEN_APPLIED)) && tmp->magic && (tmp->arch == NULL || !tmp->arch->magic)) 157 && tmp->magic && (!tmp->arch || !tmp->arch->magic))
158 { 158 {
159 if (tmp->magic > 0) 159 if (tmp->magic > 0)
160 val *= (3 * tmp->magic * tmp->magic * tmp->magic); 160 val *= 3 * tmp->magic * tmp->magic * tmp->magic;
161 else 161 else
162 /* Note that tmp->magic is negative, so that this 162 /* Note that tmp->magic is negative, so that this
163 * will actually be something like val /=2, /=3, etc. 163 * will actually be something like val /=2, /=3, etc.
164 */ 164 */
165 val /= (1 - tmp->magic); 165 val /= 1 - tmp->magic;
166 } 166 }
167 167
168 if (tmp->type == WAND) 168 if (tmp->type == WAND)
169 { 169 {
170 /* Value of the wand is multiplied by the number of 170 /* Value of the wand is multiplied by the number of
171 * charges. the treasure code already sets up the value 171 * charges. the treasure code already sets up the value
172 * 50 charges is used as the baseline. 172 * 50 charges is used as the baseline.
173 */ 173 */
174 if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified) 174 if (tmp->flag [FLAG_IDENTIFIED] || !tmp->need_identify () || identified)
175 val = (val * tmp->stats.food) / 50; 175 val *= tmp->stats.food / 50;
176 else /* if not identified, presume one charge */ 176 else /* if not identified, presume one charge */
177 val /= 50; 177 val /= 50;
178 } 178 }
179 179
180 /* Limit amount of money you can get for really great items. */ 180 /* Limit amount of money you can get for really great items. */
181 if (flag == F_SELL) 181 if (flag == F_SELL)
182 val = value_limit ((sint64) val, number, who, shop); 182 val = value_limit (val, number, who, shop);
183 183
184 // 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
185 // 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.
186 //val = pow (val, 1.05); 186 //val = pow (val, 1.05);
187 187
218 * will come from the basic stat charisma 218 * will come from the basic stat charisma
219 * the rest will come from the level in bargaining skill 219 * the rest will come from the level in bargaining skill
220 */ 220 */
221 const double cha_ratio = 0.40; 221 const double cha_ratio = 0.40;
222 222
223 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);
224 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.);
225 diff = .02 + (.80 - .02) * diff; 225 diff = .02 + (.80 - .02) * diff;
226 226
227 if (flag == F_BUY) 227 if (flag == F_BUY)
228 val += val * diff; 228 val += val * diff;
230 val -= val * diff; 230 val -= val * diff;
231 231
232 // 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
233 // then the range is adjusted randomly around the correct value 233 // then the range is adjusted randomly around the correct value
234 if (approximate) 234 if (approximate)
235 approx_range = sint64 (val / sqrt (lev_identify * 3 + 1)); 235 approx_range = val / sqrt (lev_identify * 3 + 1);
236 } 236 }
237 237
238 /* 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
239 * overflow of diff above. That should only happen if 239 * overflow of diff above. That should only happen if
240 * we are selling objects - in that case, the person just 240 * we are selling objects - in that case, the person just
241 * gets no money. 241 * gets no money.
242 */ 242 */
243 if ((sint64) val < 0) 243 if ((sint64) val < 0)
244 val = 0; 244 val = 0;
245 245
246 /* Unidentified stuff won't sell for more than 60gp */ 246 /* Unidentified stuff won't sell for more than 10gp */
247 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)
248 { 248 min_it (val, 1000);
249 val = (val > 600) ? 600 : val;
250 }
251 249
252 /* 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 */
253 if (shop && who) 251 if (shop && who)
254 { 252 {
255 if (flag == F_SELL) 253 if (flag == F_SELL)
256 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);
257 else if (flag == F_BUY) 255 else if (flag == F_BUY)
258 { 256 {
259 /* 257 /*
260 * 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
261 * let the item be sold cheaper, according to the specialisation of 259 * let the item be sold cheaper, according to the specialisation of
267 * 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).
268 * 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
269 * 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
270 * antiques in a junk shop in real life). 268 * antiques in a junk shop in real life).
271 */ 269 */
272 if (QUERY_FLAG (tmp, FLAG_PLAYER_SOLD)) 270 if (tmp->flag [FLAG_PLAYER_SOLD])
273 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);
274 else 272 else
275 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);
276 } 276 }
277 277
278 /* 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
279 * 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
280 * pointful, and could give fun with rounding. 280 * pointful, and could give fun with rounding.
281 */ 281 */
282 //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
283 if (val > 50) 283 if (val > 50)
284 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);
285 } 285 }
286 286
287 return (sint64) val; 287 return val;
288} 288}
289 289
290/* 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
291 * cointype placement. 291 * cointype placement.
292 */ 292 */
296{ 296{
297 archetype *coin; 297 archetype *coin;
298 298
299 do 299 do
300 { 300 {
301 if (coins[*cointype] == NULL) 301 if (!coins [*cointype])
302 return NULL; 302 return 0;
303
303 coin = archetype::find (coins[*cointype]); 304 coin = archetype::find (coins [*cointype]);
305
304 if (coin == NULL) 306 if (!coin)
305 return NULL; 307 return 0;
308
306 *cointype += 1; 309 *cointype += 1;
307 } 310 }
308 while (coin->value > c); 311 while (coin->value > c);
309 312
310 return coin; 313 return coin;
321 * 10,000 silver or something) 324 * 10,000 silver or something)
322 */ 325 */
323const char * 326const char *
324cost_string_from_value (sint64 cost, int approx) 327cost_string_from_value (sint64 cost, int approx)
325{ 328{
326 static char buf[MAX_BUF];
327 archetype *coin, *next_coin; 329 archetype *coin, *next_coin;
328 int num, cointype = 0; 330 int num, cointype = 0;
329 331
330 coin = find_next_coin (cost, &cointype); 332 coin = find_next_coin (cost, &cointype);
331 if (coin == NULL) 333 if (!coin)
332 return "nothing"; 334 return "nothing";
333 335
334 num = cost / coin->value; 336 num = cost / coin->value;
335 /* so long as nrof is 32 bit, this is true. 337 /* so long as nrof is 32 bit, this is true.
336 * If it takes more coins than a person can possibly carry, this 338 * If it takes more coins than a person can possibly carry, this
337 * is basically true. 339 * is basically true.
338 */ 340 */
339 if ((cost / coin->value) > UINT32_MAX) 341 if (cost / coin->value > UINT32_MAX)
340 {
341 strcpy (buf, "an unimaginable sum of money"); 342 return "an unimaginable sum of money";
342 return buf;
343 }
344 343
345 cost -= num * (sint64)coin->value; 344 cost -= num * (sint64)coin->value;
346 345
347 sprintf (buf, "%d %s", num, num > 1 ? &coin->object::name_pl : &coin->object::name); 346 char *buf = format ("%d %s", num, num > 1 ? &coin->object::name_pl : &coin->object::name);
348 347
349 next_coin = find_next_coin (cost, &cointype); 348 next_coin = find_next_coin (cost, &cointype);
350 if (next_coin == NULL || approx) 349 if (!next_coin || approx)
351 return buf; 350 return buf;
352 351
353 coin = next_coin; 352 coin = next_coin;
354 num = cost / coin->value; 353 num = cost / coin->value;
355 cost -= num * (sint64)coin->value; 354 cost -= num * (sint64)coin->value;
356 355
357 sprintf (buf + strlen (buf), " and %d %s", num, num > 1 ? &coin->object::name_pl : &coin->object::name); 356 return format ("%s and %d %s", buf, num, num > 1 ? &coin->object::name_pl : &coin->object::name);
358
359 return buf;
360} 357}
361 358
362const char * 359const char *
363query_cost_string (const object *tmp, object *who, int flag) 360query_cost_string (const object *tmp, object *who, int flag)
364{ 361{
385 { 382 {
386 if (!idskill2 || !find_skill_by_number (who, idskill2)) 383 if (!idskill2 || !find_skill_by_number (who, idskill2))
387 { 384 {
388 if (!find_skill_by_number (who, SK_BARGAINING)) 385 if (!find_skill_by_number (who, SK_BARGAINING))
389 { 386 {
390 static char buf[MAX_BUF];
391 int num, cointype = 0; 387 int num, cointype = 0;
392 archetype *coin = find_next_coin (real_value, &cointype); 388 archetype *coin = find_next_coin (real_value, &cointype);
393 389
394 if (coin == NULL) 390 if (!coin)
395 return "nothing"; 391 return "nothing";
396 392
397 num = real_value / coin->value; 393 num = real_value / coin->value;
398 394
399 if (num == 1) 395 if (num == 1)
400 sprintf (buf, "about one %s", &coin->object::name); 396 return format ("about one %s", &coin->object::name);
401 else if (num < 5) 397 else if (num < 5)
402 sprintf (buf, "a few %s", &coin->object::name_pl); 398 return format ("a few %s", &coin->object::name_pl);
403 else if (num < 10) 399 else if (num < 10)
404 sprintf (buf, "several %s", &coin->object::name_pl); 400 return format ("several %s", &coin->object::name_pl);
405 else if (num < 25) 401 else if (num < 25)
406 sprintf (buf, "a moderate amount of %s", &coin->object::name_pl); 402 return format ("a moderate amount of %s", &coin->object::name_pl);
407 else if (num < 100) 403 else if (num < 100)
408 sprintf (buf, "lots of %s", &coin->object::name_pl); 404 return format ("lots of %s", &coin->object::name_pl);
409 else if (num < 1000) 405 else if (num < 1000)
410 sprintf (buf, "a great many %s", &coin->object::name_pl); 406 return format ("a great many %s", &coin->object::name_pl);
411 else 407 else
412 sprintf (buf, "a vast quantity of %s", &coin->object::name_pl); 408 return format ("a vast quantity of %s", &coin->object::name_pl);
413
414 return buf;
415 } 409 }
416 } 410 }
417 } 411 }
418 412
419 int hash = ((unsigned int) tmp->count * 174364621) & 1023;
420
421 if (approx_range) 413 if (approx_range)
422 { 414 {
415 int hash = tmp->random_seed () & 1023;
423 sint64 lo = (sint64) real_value - (approx_range * hash >> 10); 416 sint64 lo = real_value - (approx_range * hash >> 10);
424 static char buf[MAX_BUF];
425 417
426 sprintf (buf, "between %s", cost_string_from_value (lo, 1)); 418 return format ("between %s and %s",
427 sprintf (buf + strlen (buf), " and %s", cost_string_from_value (lo + approx_range, 1)); 419 cost_string_from_value (lo, 1),
428 420 cost_string_from_value (lo + approx_range, 1));
429 return buf;
430 } 421 }
431 } 422 }
432 423
433 return cost_string_from_value (real_value, 0); 424 return cost_string_from_value (real_value, 0);
434} 425}
449 } 440 }
450 441
451 for (tmp = op->inv; tmp; tmp = tmp->below) 442 for (tmp = op->inv; tmp; tmp = tmp->below)
452 if (tmp->type == MONEY) 443 if (tmp->type == MONEY)
453 total += tmp->nrof * (sint64)tmp->value; 444 total += tmp->nrof * (sint64)tmp->value;
454 else if (tmp->type == CONTAINER && QUERY_FLAG (tmp, FLAG_APPLIED) && (!tmp->race || tmp->race.contains ("gold"))) 445 else if (tmp->type == CONTAINER && tmp->flag [FLAG_APPLIED] && (!tmp->race || tmp->race.contains ("gold")))
455 total += query_money (tmp); 446 total += query_money (tmp);
456 447
457 return total; 448 return total;
458} 449}
459 450
474 return 0; 465 return 0;
475 466
476 pay_from_container (pl, pl, to_pay); 467 pay_from_container (pl, pl, to_pay);
477 468
478 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 469 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below)
479 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && (!pouch->race || pouch->race.contains ("gold"))) 470 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains ("gold")))
480 pay_from_container (pl, pouch, to_pay); 471 pay_from_container (pl, pouch, to_pay);
481 472
482 pl->update_stats (); 473 pl->update_stats ();
483 return 1; 474 return 1;
484} 475}
511 change_exp (pl, saved_money, "bargaining", SK_EXP_NONE); 502 change_exp (pl, saved_money, "bargaining", SK_EXP_NONE);
512 503
513 pay_from_container (pl, pl, to_pay); 504 pay_from_container (pl, pl, to_pay);
514 505
515 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 506 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below)
516 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && (!pouch->race || pouch->race.contains ("gold"))) 507 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains ("gold")))
517 pay_from_container (pl, pouch, to_pay); 508 pay_from_container (pl, pouch, to_pay);
518 509
519 pl->update_stats (); 510 pl->update_stats ();
520 511
521 return 1; 512 return 1;
588 at = archetype::find (coins[NUM_COINS - 1 - i]); 579 at = archetype::find (coins[NUM_COINS - 1 - i]);
589 580
590 if (at == NULL) 581 if (at == NULL)
591 LOG (llevError, "Could not find %s archetype\n", coins[NUM_COINS - 1 - i]); 582 LOG (llevError, "Could not find %s archetype\n", coins[NUM_COINS - 1 - i]);
592 583
593 coin_objs[i] = arch_to_object (at); 584 coin_objs[i] = at->instance ();
594 coin_objs[i]->nrof = 0; 585 coin_objs[i]->nrof = 0;
595 } 586 }
596 587
597 for (i = 0; i < NUM_COINS; i++) 588 for (i = 0; i < NUM_COINS; i++)
598 { 589 {
599 object &coin = *coin_objs[i]; 590 object &coin = *coin_objs[i];
600 sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, coin.nrof); 591 sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, (sint64) coin.nrof);
601 to_pay -= num_coins * coin.value; 592 to_pay -= num_coins * coin.value;
602 593
603 coin.nrof -= num_coins; 594 coin.nrof -= num_coins;
604 /* Now start making change. Start at the coin value 595 /* Now start making change. Start at the coin value
605 * below the one we just did, and work down to 596 * below the one we just did, and work down to
640 LOG (llevError, "can_pay(): called against something that isn't a player\n"); 631 LOG (llevError, "can_pay(): called against something that isn't a player\n");
641 return 0; 632 return 0;
642 } 633 }
643 634
644 for (object::depth_iterator item = pl->begin (); item != pl->end (); ++item) 635 for (object::depth_iterator item = pl->begin (); item != pl->end (); ++item)
645 if (QUERY_FLAG (item, FLAG_UNPAID)) 636 if (item->flag [FLAG_UNPAID])
646 { 637 {
647 unpaid_count++; 638 unpaid_count++;
648 unpaid_price += query_cost (item, pl, F_BUY | F_SHOP); 639 unpaid_price += query_cost (item, pl, F_BUY | F_SHOP);
649 } 640 }
650 641
651 if (unpaid_price > player_wealth) 642 if (unpaid_price > player_wealth)
652 { 643 {
653 dynbuf_text buf; 644 dynbuf_text &buf = msg_dynbuf; buf.clear ();
654 645
655 buf << "You have " << unpaid_count 646 buf << "You have " << unpaid_count
656 << " unpaid item(s) that would cost you " << cost_string_from_value (unpaid_price, 0) 647 << " unpaid item(s) that would cost you " << cost_string_from_value (unpaid_price, 0)
657 << ". You need another " << cost_string_from_value (unpaid_price - player_wealth, 0) 648 << ". You need another " << cost_string_from_value (unpaid_price - player_wealth, 0)
658 << " to be able to afford that. " 649 << " to be able to afford that. "
679 { 670 {
680 next_item: 671 next_item:
681 672
682 for (object::depth_iterator op = pl->begin (); op != pl->end (); ++op) 673 for (object::depth_iterator op = pl->begin (); op != pl->end (); ++op)
683 { 674 {
684 if (QUERY_FLAG (op, FLAG_UNPAID)) 675 if (op->flag [FLAG_UNPAID])
685 { 676 {
686 char buf[MAX_BUF];
687 snprintf (buf, MAX_BUF, "%s", query_cost_string (op, pl, F_BUY | F_SHOP)); 677 const char *buf = query_cost_string (op, pl, F_BUY | F_SHOP);
688 678
689 if (!pay_for_item (op, pl)) 679 if (!pay_for_item (op, pl))
690 { 680 {
691 sint64 i = query_cost (op, pl, F_BUY | F_SHOP) - query_money (pl); 681 sint64 i = query_cost (op, pl, F_BUY | F_SHOP) - query_money (pl);
692 682
693 CLEAR_FLAG (op, FLAG_UNPAID); 683 op->clr_flag (FLAG_UNPAID);
694 new_draw_info_format (NDI_UNIQUE, 0, pl, "You lack %s to buy %s.", cost_string_from_value (i, 0), query_name (op)); 684 new_draw_info_format (NDI_UNIQUE, 0, pl, "You lack %s to buy %s.", cost_string_from_value (i, 0), query_name (op));
695 SET_FLAG (op, FLAG_UNPAID); 685 op->set_flag (FLAG_UNPAID);
696 return 0; 686 return 0;
697 } 687 }
698 else 688 else
699 { 689 {
700 CLEAR_FLAG (op, FLAG_UNPAID); 690 op->clr_flag (FLAG_UNPAID);
701 CLEAR_FLAG (op, FLAG_PLAYER_SOLD); 691 op->clr_flag (FLAG_PLAYER_SOLD);
702 new_draw_info_format (NDI_UNIQUE, 0, op, "You paid %s for %s.", buf, query_name (op)); 692 new_draw_info_format (NDI_UNIQUE, 0, pl, "You paid %s for %s.", buf, query_name (op));
703 693
704 if (!merge_ob (op, op->env->inv)) 694 if (!merge_ob (op, op->env->inv))
705 esrv_update_item (UPD_FLAGS, pl, op); 695 esrv_update_item (UPD_FLAGS, pl, op);
706 696
707 goto next_item; 697 goto next_item;
739 LOG (llevError, "Could not find %s archetype\n", coins[count]); 729 LOG (llevError, "Could not find %s archetype\n", coins[count]);
740 else if ((amount / at->value) > 0) 730 else if ((amount / at->value) > 0)
741 { 731 {
742 for (pouch = pl->inv; pouch; pouch = pouch->below) 732 for (pouch = pl->inv; pouch; pouch = pouch->below)
743 { 733 {
744 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && pouch->race.contains ("gold")) 734 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && pouch->race.contains ("gold"))
745 { 735 {
746 int w = at->weight * (100 - pouch->stats.Str) / 100; 736 int w = at->weight * (100 - pouch->stats.Str) / 100;
747 int n = amount / at->value; 737 int n = amount / at->value;
748 738
749 if (w == 0) 739 if (w == 0)
752 if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit)) 742 if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit))
753 { 743 {
754 if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n) 744 if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n)
755 n = (pouch->weight_limit - pouch->carrying) / w; 745 n = (pouch->weight_limit - pouch->carrying) / w;
756 746
757 object *tmp = arch_to_object (at); 747 object *tmp = at->instance ();
758 tmp->nrof = n; 748 tmp->nrof = n;
759 amount -= tmp->nrof * tmp->value; 749 amount -= tmp->nrof * tmp->value;
760 pouch->insert (tmp); 750 pouch->insert (tmp);
761 } 751 }
762 } 752 }
763 } 753 }
764 754
765 if (amount / at->value > 0) 755 if (amount / at->value > 0)
766 { 756 {
767 object *tmp = arch_to_object (at); 757 object *tmp = at->instance ();
768 tmp->nrof = amount / tmp->value; 758 tmp->nrof = amount / tmp->value;
769 amount -= tmp->nrof * tmp->value; 759 amount -= tmp->nrof * tmp->value;
770 pl->insert (tmp); 760 pl->insert (tmp);
771 } 761 }
772 } 762 }
837 827
838 new_draw_info_format (NDI_UNIQUE, 0, pl, "You receive %s for %s.", 828 new_draw_info_format (NDI_UNIQUE, 0, pl, "You receive %s for %s.",
839 query_cost_string (op, pl, F_SELL | F_SHOP), query_name (op)); 829 query_cost_string (op, pl, F_SELL | F_SHOP), query_name (op));
840 pl->play_sound (sound_find ("shop_sell")); 830 pl->play_sound (sound_find ("shop_sell"));
841 831
842 SET_FLAG (op, FLAG_UNPAID); 832 op->set_flag (FLAG_UNPAID);
843 identify (op); 833 identify (op);
844 834
845 return true; 835 return true;
846} 836}
847 837
851 */ 841 */
852static double 842static double
853shop_specialisation_ratio (const object *item, const maptile *map) 843shop_specialisation_ratio (const object *item, const maptile *map)
854{ 844{
855 shopitems *items = map->shopitems; 845 shopitems *items = map->shopitems;
856 double likedness = 0.; 846 int likedness = 0;
857 int i; 847 int i;
858 848
859 if (item == NULL) 849 if (item == NULL)
860 { 850 {
861 LOG (llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", &map->path); 851 LOG (llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", &map->path);
871 */ 861 */
872 return SPECIALISATION_EFFECT; 862 return SPECIALISATION_EFFECT;
873 } 863 }
874 864
875 if (map->shopitems) 865 if (map->shopitems)
876 {
877 for (i = 0; i < items[0].index; i++) 866 for (i = 0; i < items[0].index; i++)
878 if (items[i].typenum == item->type || (!items[i].typenum && likedness == 0.001)) 867 if (items[i].typenum == item->type || (!items[i].typenum && !likedness))
879 likedness = items[i].strength / 100.0; 868 likedness = items[i].strength;
880 }
881 869
882 if (likedness > 1.0) 870 if (likedness > 100)
883 { /* someone has been rather silly with the map headers. */ 871 { /* someone has been rather silly with the map headers. */
884 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, &map->path); 872 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, &map->path);
885 likedness = 1.0; 873 likedness = 100;
886 } 874 }
887 875
888 if (likedness < -1.0) 876 if (likedness < -100)
889 { 877 {
890 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, &map->path); 878 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, &map->path);
891 likedness = -1.0; 879 likedness = -100;
892 } 880 }
893 881
894 return lerp (likedness, -1., 1., SPECIALISATION_EFFECT, 1.); 882 return lerp (double (likedness), -100., 100., SPECIALISATION_EFFECT, 1.);
895} 883}
896 884
897/*returns the greed of the shop on map, or 1 if it isn't specified. */ 885/*returns the greed of the shop on map, or 1 if it isn't specified. */
898static double 886static double
899shop_greed (const maptile *map) 887shop_greed (const maptile *map)
949 tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default 937 tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default
950 938
951 if (map->shopmin && unit_price < map->shopmin) 939 if (map->shopmin && unit_price < map->shopmin)
952 return 0; 940 return 0;
953 else if (unit_price > tmpshopmax / 2) 941 else if (unit_price > tmpshopmax / 2)
954 newval = MIN ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax); 942 newval = min ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax);
955 else 943 else
956 newval = unit_price; 944 newval = unit_price;
957 } 945 }
958 946
959 newval *= quantity; 947 newval *= quantity;
963 951
964/* gives a desciption of the shop on their current map to the player op. */ 952/* gives a desciption of the shop on their current map to the player op. */
965int 953int
966describe_shop (const object *op) 954describe_shop (const object *op)
967{ 955{
956 dynbuf_text buf;
968 maptile *map = op->map; 957 maptile *map = op->map;
969 958
970 /*shopitems *items=map->shopitems; */ 959 /*shopitems *items=map->shopitems; */
971 int pos = 0, i; 960 int pos = 0, i;
972 double opinion = 0; 961 double opinion = 0;
973 char tmp[MAX_BUF] = "\0";
974 962
975 if (op->type != PLAYER) 963 if (op->type != PLAYER)
976 return 0; 964 return 0;
977 965
978 /*check if there is a shop specified for this map */ 966 /*check if there is a shop specified for this map */
979 if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax) 967 if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax)
980 { 968 {
981 new_draw_info (NDI_UNIQUE, 0, op, "From looking at the nearby shop you determine that it trades in:"); 969 buf << "From looking at the nearby shop you determine that it trades in ";
970 int lastcomma = 0, prevcomma = 0;
982 971
983 if (map->shopitems) 972 if (map->shopitems)
984 for (i = 0; i < map->shopitems[0].index; i++) 973 for (i = 0; i < map->shopitems[0].index; i++)
985 if (map->shopitems[i].name && map->shopitems[i].strength > 10) 974 if (map->shopitems[i].name && map->shopitems[i].strength > 10)
986 { 975 {
987 snprintf (tmp + pos, sizeof (tmp) - pos, "%s, ", map->shopitems[i].name_pl); 976 buf << map->shopitems[i].name_pl;
988 pos += strlen (tmp + pos); 977 prevcomma = lastcomma;
978 lastcomma = buf.size (); // remember offset
979 buf << ", ";
989 } 980 }
990 981
991 if (!pos) 982 if (lastcomma)
983 {
984 buf.splice (lastcomma, 2);
985
986 if (prevcomma)
987 buf.splice (prevcomma, 2, " and ");
988 }
989 else
992 strcat (tmp, "a little of everything."); 990 buf << "a little of everything.";
993 991
994 /* format the string into a list */ 992 buf << ".\n\n";
995 make_list_like (tmp);
996 new_draw_info_format (NDI_UNIQUE, 0, op, "%s", tmp);
997 993
998 if (map->shopmax) 994 if (map->shopmax)
999 new_draw_info_format (NDI_UNIQUE, 0, op, "It won't trade for items above %s.", cost_string_from_value (map->shopmax, 0)); 995 buf << "It won't trade for items above " << cost_string_from_value (map->shopmax, 0) << ".\n\n";
1000 996
1001 if (map->shopmin) 997 if (map->shopmin)
1002 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)); 998 buf << "It won't trade in items worth less than " << cost_string_from_value (map->shopmin, 0) << ".\n\n";
1003 999
1004 if (map->shopgreed) 1000 if (map->shopgreed)
1005 { 1001 {
1006 if (map->shopgreed > 2.0) 1002 if (map->shopgreed > 2.0)
1007 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge massively."); 1003 buf << "It tends to overcharge massively.\n\n";
1008 else if (map->shopgreed > 1.5) 1004 else if (map->shopgreed > 1.5)
1009 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge substantially."); 1005 buf << "It tends to overcharge substantially.\n\n";
1010 else if (map->shopgreed > 1.1) 1006 else if (map->shopgreed > 1.1)
1011 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge slightly."); 1007 buf << "It tends to overcharge slightly.\n\n";
1012 else if (map->shopgreed < 0.9) 1008 else if (map->shopgreed < 0.9)
1013 new_draw_info (NDI_UNIQUE, 0, op, "It tends to undercharge."); 1009 buf << "It tends to undercharge.\n\n";
1014 } 1010 }
1015 1011
1016 if (map->shoprace) 1012 if (map->shoprace)
1017 { 1013 {
1018 opinion = shopkeeper_approval (map, op); 1014 opinion = shopkeeper_approval (map, op);
1015
1019 if (opinion > 0.8) 1016 if (opinion > 0.8)
1020 new_draw_info (NDI_UNIQUE, 0, op, "You think the shopkeeper likes you."); 1017 buf << "You think the shopkeeper likes you.\n\n";
1021 else if (opinion > 0.5) 1018 else if (opinion > 0.5)
1022 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems unconcerned by you."); 1019 buf << "The shopkeeper seems unconcerned by you.\n\n";
1023 else 1020 else
1024 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems to have taken a dislike to you."); 1021 buf << "The shopkeeper seems to have taken a dislike to you.\n\n";
1025 } 1022 }
1026 } 1023 }
1027 else 1024 else
1028 new_draw_info (NDI_UNIQUE, 0, op, "There is no shop nearby."); 1025 buf << "There is no shop nearby.\n\n";
1026
1027 op->contr->infobox (MSG_CHANNEL ("shopinfo"), buf);
1029 1028
1030 return 1; 1029 return 1;
1031} 1030}
1032 1031
1033struct shopinv 1032struct shopinv
1061} 1060}
1062 1061
1063static void 1062static void
1064add_shop_item (object *tmp, shopinv * items, int *numitems, int *numallocated) 1063add_shop_item (object *tmp, shopinv * items, int *numitems, int *numallocated)
1065{ 1064{
1066#if 0
1067 char buf[MAX_BUF];
1068#endif
1069 /* clear unpaid flag so that doesn't come up in query 1065 /* clear unpaid flag so that doesn't come up in query
1070 * string. We clear nrof so that we can better sort 1066 * string. We clear nrof so that we can better sort
1071 * the object names. 1067 * the object names.
1072 */ 1068 */
1073 1069
1074 CLEAR_FLAG (tmp, FLAG_UNPAID); 1070 tmp->clr_flag (FLAG_UNPAID);
1075 items[*numitems].nrof = tmp->nrof; 1071 items[*numitems].nrof = tmp->nrof;
1076 /* Non mergable items have nrof of 0, but count them as one 1072 /* Non mergable items have nrof of 0, but count them as one
1077 * so the display is properly. 1073 * so the display is properly.
1078 */ 1074 */
1079 if (tmp->nrof == 0) 1075 if (tmp->nrof == 0)
1101 items[*numitems].item_sort = strdup (query_base_name (tmp, 0)); 1097 items[*numitems].item_sort = strdup (query_base_name (tmp, 0));
1102 items[*numitems].item_real = strdup (query_base_name (tmp, 1)); 1098 items[*numitems].item_real = strdup (query_base_name (tmp, 1));
1103 (*numitems)++; 1099 (*numitems)++;
1104 break; 1100 break;
1105 } 1101 }
1106 SET_FLAG (tmp, FLAG_UNPAID); 1102
1103 tmp->set_flag (FLAG_UNPAID);
1107} 1104}
1108 1105
1109void 1106void
1110shop_listing (object *sign, object *op) 1107shop_listing (object *sign, object *op)
1111{ 1108{
1116 1113
1117 /* Should never happen, but just in case a monster does apply a sign */ 1114 /* Should never happen, but just in case a monster does apply a sign */
1118 if (!op->is_player ()) 1115 if (!op->is_player ())
1119 return; 1116 return;
1120 1117
1121 dynbuf_text buf (4096, 4096); 1118 dynbuf_text &buf = msg_dynbuf; buf.clear ();
1122 1119
1123 if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2))) 1120 if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2)))
1124 { 1121 {
1125 x1 = 0; 1122 x1 = 0;
1126 y1 = 0; 1123 y1 = 0;
1133 items = (shopinv *)malloc (sizeof (shopinv) * numallocated); 1130 items = (shopinv *)malloc (sizeof (shopinv) * numallocated);
1134 1131
1135 /* Find all the appropriate items */ 1132 /* Find all the appropriate items */
1136 for (i = x1; i <= x2; i++) 1133 for (i = x1; i <= x2; i++)
1137 for (j = y1; j < y2; j++) 1134 for (j = y1; j < y2; j++)
1138 if (is_in_shop (op->map, i, j)) 1135 if (op->map->is_in_shop (i, j))
1139 { 1136 {
1140 stack = GET_MAP_OB (op->map, i, j); 1137 stack = GET_MAP_OB (op->map, i, j);
1141 1138
1142 while (stack) 1139 while (stack)
1143 { 1140 {
1144 if (QUERY_FLAG (stack, FLAG_UNPAID)) 1141 if (stack->flag [FLAG_UNPAID])
1145 { 1142 {
1146 if (numitems == numallocated) 1143 if (numitems == numallocated)
1147 items = (shopinv *)realloc (items, sizeof (shopinv) * (numallocated *= 2)); 1144 items = (shopinv *)realloc (items, sizeof (shopinv) * (numallocated *= 2));
1148 1145
1149 add_shop_item (stack, items, &numitems, &numallocated); 1146 add_shop_item (stack, items, &numitems, &numallocated);
1162 { 1159 {
1163 /* Collapse items of the same name together */ 1160 /* Collapse items of the same name together */
1164 if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real)) 1161 if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real))
1165 items[i + 1].nrof += items[i].nrof; 1162 items[i + 1].nrof += items[i].nrof;
1166 else 1163 else
1167 buf.printf (" C<%4d %s>\n", items[i].nrof ? items[i].nrof : 1, items[i].nrof == 1 ? items[i].item_sort : items[i].item_real); 1164 buf.printf (" %4d %s\n", items[i].nrof ? items[i].nrof : 1, items[i].nrof == 1 ? items[i].item_sort : items[i].item_real);
1168 1165
1169 free (items[i].item_sort); 1166 free (items[i].item_sort);
1170 free (items[i].item_real); 1167 free (items[i].item_real);
1171 } 1168 }
1172 1169
1173 op->contr->infobox (MSG_CHANNEL ("shopitems"), buf); 1170 op->contr->infobox (MSG_CHANNEL ("shopitems"), buf);
1174 1171
1175 free (items); 1172 free (items);
1176}
1177
1178/* elmex: this function checks whether the object is in a shop */
1179bool
1180is_in_shop (object *o)
1181{
1182 if (!o->is_on_map ())
1183 return false;
1184
1185 return is_in_shop (o->map, o->x, o->y);
1186} 1173}
1187 1174
1188/* elmex: this function checks whether we are in a shop or not 1175/* elmex: this function checks whether we are in a shop or not
1189 - change 2007-11-26: enhanced the O(n) case by stopping at the first 1176 - change 2007-11-26: enhanced the O(n) case by stopping at the first
1190 floor tile. this possibly will make map bugs where shopfloors are above 1177 floor tile. this possibly will make map bugs where shopfloors are above
1191 floors more obvious. 1178 floors more obvious.
1192*/ 1179*/
1193
1194bool 1180bool
1195is_in_shop (maptile *map, int x, int y) 1181maptile::is_in_shop (int x, int y) const
1196{ 1182{
1197 for (object *floor = GET_MAP_OB (map, x, y); floor; floor = floor->above) 1183 for (object *floor = at (x, y).bot; floor; floor = floor->above)
1198 if (QUERY_FLAG (floor, FLAG_IS_FLOOR)) 1184 if (floor->flag [FLAG_IS_FLOOR])
1199 return floor->type == SHOP_FLOOR; 1185 return floor->type == SHOP_FLOOR;
1200 1186
1201 return false; 1187 return false;
1202} 1188}
1203 1189

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines