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.56 by root, Mon Sep 29 10:20:49 2008 UTC vs.
Revision 1.89 by root, Sat Aug 13 23:22:46 2011 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,2011 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;
85 double diff;
86 84
87 approx_range = 0; 85 approx_range = 0;
88 86
89 no_bargain = flag & F_NO_BARGAIN; 87 no_bargain = flag & F_NO_BARGAIN;
90 identified = flag & F_IDENTIFIED; 88 identified = flag & F_IDENTIFIED;
91 not_cursed = flag & F_NOT_CURSED; 89 not_cursed = flag & F_NOT_CURSED;
92 approximate = flag & F_APPROX; 90 approximate = flag & F_APPROX;
93 shop = flag & F_SHOP; 91 shop = flag & F_SHOP;
94 flag &= ~(F_NO_BARGAIN | F_IDENTIFIED | F_NOT_CURSED | F_APPROX | F_SHOP); 92 flag &= ~(F_NO_BARGAIN | F_IDENTIFIED | F_NOT_CURSED | F_APPROX | F_SHOP);
95 93
94 int number = tmp->number_of ();
95
96 if (tmp->type == MONEY) 96 if (tmp->type == MONEY)
97 return tmp->nrof * tmp->value; 97 return number * tmp->value;
98 98
99 if (tmp->type == GEM) 99 if (tmp->type == GEM)
100 { 100 {
101 if (flag == F_TRUE) 101 if (flag == F_TRUE)
102 return (tmp->nrof * tmp->value); 102 return number * tmp->value;
103 103
104 if (flag == F_BUY) 104 if (flag == F_BUY)
105 return (sint64) (1.03 * tmp->nrof * tmp->value); 105 return 1.03 * number * tmp->value;
106 106
107 if (flag == F_SELL) 107 if (flag == F_SELL)
108 return (sint64) (0.97 * tmp->nrof * tmp->value); 108 return 0.97 * number * tmp->value;
109 109
110 LOG (llevError, "Query_cost: Gem type with unknown flag %d: %s\n", flag, tmp->debug_desc ()); 110 LOG (llevError, "Query_cost: Gem type with unknown flag %d: %s\n", flag, tmp->debug_desc ());
111 return 0; 111 return 0;
112 } 112 }
113 113
114 number = tmp->nrof;
115 if (number == 0)
116 number = 1;
117 if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified) 114 if (tmp->flag [FLAG_IDENTIFIED] || !tmp->need_identify () || identified)
118 { 115 {
119 if (!not_cursed && (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))) 116 if (!not_cursed && (tmp->flag [FLAG_CURSED] || tmp->flag [FLAG_DAMNED]))
120 return 0; 117 return 0;
121 else 118 else
122 val = tmp->value * number; 119 val = number * tmp->value;
123 } 120 }
124 /* This area deals with objects that are not identified, but can be */ 121 /* This area deals with objects that are not identified, but can be */
125 else 122 else
126 { 123 {
127 if (tmp->arch != NULL)
128 {
129 if (flag == F_BUY) 124 if (flag == F_BUY)
125 {
126 LOG (llevError | logBacktrace, "Asking for buy-value of unidentified object: %s\n", tmp->debug_desc ());
127 val = tmp->arch->value * 50 * number;
128 }
129 else
130 { /* Trying to sell something, or get true value */
131 if (tmp->type == POTION)
132 val = number * 40; /* Don't want to give anything away */
133 else
130 { 134 {
131 LOG (llevError | logBacktrace, "Asking for buy-value of unidentified object.\n"); 135 /* Get 2/3'rd value for applied objects, 1/3'rd for totally
132 val = tmp->arch->value * 50 * number; 136 * unknown objects
137 */
138 if (tmp->flag [FLAG_BEEN_APPLIED])
139 val = number * tmp->arch->value * 2 / 3;
140 else
141 val = number * tmp->arch->value / 3;
133 } 142 }
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 } 143 }
161 } 144 }
162 145
163 /* If the item has been applied or identifed or does not need to be 146 /* 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 147 * identified, AND the object is magical and the archetype is non
167 * tmp->arch->magic for any magic. The check for archetype 150 * tmp->arch->magic for any magic. The check for archetype
168 * magic is to not give extra money for archetypes that are by 151 * magic is to not give extra money for archetypes that are by
169 * default magical. This is because the archetype value should have 152 * default magical. This is because the archetype value should have
170 * already figured in that value. 153 * already figured in that value.
171 */ 154 */
172 if ((QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified || 155 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)) 156 && tmp->magic && (!tmp->arch || !tmp->arch->magic))
174 { 157 {
175 if (tmp->magic > 0) 158 if (tmp->magic > 0)
176 val *= (3 * tmp->magic * tmp->magic * tmp->magic); 159 val *= 3 * tmp->magic * tmp->magic * tmp->magic;
177 else 160 else
178 /* Note that tmp->magic is negative, so that this 161 /* Note that tmp->magic is negative, so that this
179 * will actually be something like val /=2, /=3, etc. 162 * will actually be something like val /=2, /=3, etc.
180 */ 163 */
181 val /= (1 - tmp->magic); 164 val /= 1 - tmp->magic;
182 } 165 }
183 166
184 if (tmp->type == WAND) 167 if (tmp->type == WAND)
185 { 168 {
186 /* Value of the wand is multiplied by the number of 169 /* Value of the wand is multiplied by the number of
187 * charges. the treasure code already sets up the value 170 * charges. the treasure code already sets up the value
188 * 50 charges is used as the baseline. 171 * 50 charges is used as the baseline.
189 */ 172 */
190 if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) || !need_identify (tmp) || identified) 173 if (tmp->flag [FLAG_IDENTIFIED] || !tmp->need_identify () || identified)
191 val = (val * tmp->stats.food) / 50; 174 val *= tmp->stats.food;
192 else /* if not identified, presume one charge */ 175 /* if not identified, presume one charge */
193 val /= 50; 176 val /= 50;
194 } 177 }
195 178
196 /* Limit amount of money you can get for really great items. */ 179 /* Limit amount of money you can get for really great items. */
197 if (flag == F_SELL) 180 if (flag == F_SELL)
198 val = value_limit ((sint64) val, number, who, shop); 181 val = value_limit (val, number, who, shop);
199 182
200 // use a nonlinear price adjustment. as my predecessor said, don't change 183 // 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. 184 // the archetypes, its work required for balancing, and we don't care.
202 //val = pow (val, 1.05); 185 //val = pow (val, 1.05);
203 186
206 * AND Cha = 30 will get optimal price. 189 * AND Cha = 30 will get optimal price.
207 * Thus charisma will never get useless. 190 * Thus charisma will never get useless.
208 * -b.e. edler@heydernet.de 191 * -b.e. edler@heydernet.de
209 */ 192 */
210 193
211 if (who && who->type == PLAYER) 194 if (who && who->is_player ())
212 { 195 {
213 int lev_bargain = 0; 196 int lev_bargain = 0;
214 int lev_identify = 0; 197 int lev_identify = 0;
215 198
216 if (find_skill_by_number (who, SK_BARGAINING)) 199 if (!no_bargain)
217 lev_bargain = find_skill_by_number (who, SK_BARGAINING)->level; 200 if (object *skill = find_skill_by_name (who, shstr_bargaining))
201 lev_bargain = skill->level;
218 202
219 if (const typedata *tmptype = get_typedata (tmp->type)) 203 if (const typedata *tmptype = get_typedata (tmp->type))
220 { 204 {
221 if (int idskill1 = tmptype->identifyskill) 205 if (int idskill1 = tmptype->identifyskill)
222 { 206 {
233 /* ratio determines how much of the price modification 217 /* ratio determines how much of the price modification
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 double bargaining = max (0., 1. - powf (double (lev_bargain) / MAXLEVEL_TREASURE, 0.25));
239 diff = no_bargain ? 1.0 : 1. - pow (lev_bargain / (double) settings.max_level, 0.25);
240 diff = (1. - cha_ratio) * diff + cha_ratio * (cha_bonus[who->stats.Cha] - 1.) / (cha_bonus[who->stats.Cha] + 1.); 223 double charisma = (cha_bonus[who->stats.Cha] - 1.) / (cha_bonus[who->stats.Cha] + 1.);
241 diff = .02 + (.80 - .02) * diff; 224
225 double factor = (1. - cha_ratio) * bargaining + cha_ratio * charisma;
226
227 // scale 0..1 to 2 .. 80%
228 factor = lerp (factor, 0., 1., 0.02, 0.80);
242 229
243 if (flag == F_BUY) 230 if (flag == F_BUY)
244 val += val * diff; 231 val += val * factor;
245 else if (flag == F_SELL) 232 else if (flag == F_SELL)
246 val -= val * diff; 233 val -= val * factor;
247 234
248 // now find a price range. the less good we can judge, the larger the range is 235 // 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 236 // then the range is adjusted randomly around the correct value
250 if (approximate) 237 if (approximate)
251 approx_range = sint64 (val / sqrt (lev_identify * 3 + 1)); 238 approx_range = val / sqrt (lev_identify * 3 + 1);
252 } 239 }
253 240
254 /* I don't think this should really happen - if it does, it indicates and 241 /* I don't think this should really happen - if it does, it indicates and
255 * overflow of diff above. That should only happen if 242 * overflow of diff above. That should only happen if
256 * we are selling objects - in that case, the person just 243 * we are selling objects - in that case, the person just
257 * gets no money. 244 * gets no money.
258 */ 245 */
259 if ((sint64) val < 0) 246 if ((sint64) val < 0)
260 val = 0; 247 val = 0;
261 248
262 /* Unidentified stuff won't sell for more than 60gp */ 249 /* Unidentified stuff won't sell for more than 10gp */
263 if (flag == F_SELL && !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && need_identify (tmp) && !identified) 250 if (flag == F_SELL && !tmp->flag [FLAG_IDENTIFIED] && tmp->need_identify () && !identified)
264 { 251 min_it (val, 1000);
265 val = (val > 600) ? 600 : val;
266 }
267 252
268 /* if we are in a shop, check how the type of shop should affect the price */ 253 /* if we are in a shop, check how the type of shop should affect the price */
269 if (shop && who) 254 if (shop && who)
270 { 255 {
271 if (flag == F_SELL) 256 if (flag == F_SELL)
272 val = (val * shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who) / shop_greed (who->map)); 257 val *= shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who) / shop_greed (who->map);
273 else if (flag == F_BUY) 258 else if (flag == F_BUY)
274 { 259 {
275 /* 260 /*
276 * when buying, if the item was sold by another player, it is ok to 261 * 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 262 * let the item be sold cheaper, according to the specialisation of
283 * be sold for (otherwise players could camp map resets to make money). 268 * 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 269 * 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 270 * value of the items they sell (much like how people sometimes find
286 * antiques in a junk shop in real life). 271 * antiques in a junk shop in real life).
287 */ 272 */
288 if (QUERY_FLAG (tmp, FLAG_PLAYER_SOLD)) 273 if (tmp->flag [FLAG_PLAYER_SOLD])
289 val = (val * shop_greed (who->map) * shop_specialisation_ratio (tmp, who->map) / shopkeeper_approval (who->map, who)); 274 val *= shop_specialisation_ratio (tmp, who->map);
290 else 275 else
291 val = (val * shop_greed (who->map) / (shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who))); 276 val /= shop_specialisation_ratio (tmp, who->map);
277
278 val *= shop_greed (who->map) / shopkeeper_approval (who->map, who);
292 } 279 }
293 280
294 /* we will also have an extra 0-5% variation between shops of the same type 281 /* 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 282 * for valuable items (below a value of 50 this effect wouldn't be very
296 * pointful, and could give fun with rounding. 283 * pointful, and could give fun with rounding.
297 */ 284 */
298 //TODO: why use cosf at all, just % and scale linearly, gives more even distribution 285 //TODO: why use cosf at all, just % and scale linearly, gives more even distribution
299 if (val > 50) 286 if (val > 50)
300 val += float (val) * .05f * cosf ((tmp->uuid.seq & 0xffff) * float (M_PI * 2. / 0x10000)); 287 val *= 1 + .05f * cosf ((tmp->uuid.seq & 0xffff) * M_PI * 2. / 0x10000);
301 } 288 }
302 289
303 return (sint64) val; 290 return val;
304} 291}
305 292
306/* Find the coin type that is worth more the 'c'. Starts at the 293/* Find the coin type that is worth more the 'c'. Starts at the
307 * cointype placement. 294 * cointype placement.
308 */ 295 */
312{ 299{
313 archetype *coin; 300 archetype *coin;
314 301
315 do 302 do
316 { 303 {
317 if (coins[*cointype] == NULL) 304 if (!coins [*cointype])
318 return NULL; 305 return 0;
306
319 coin = archetype::find (coins[*cointype]); 307 coin = archetype::find (coins [*cointype]);
308
320 if (coin == NULL) 309 if (!coin)
321 return NULL; 310 return 0;
311
322 *cointype += 1; 312 *cointype += 1;
323 } 313 }
324 while (coin->value > c); 314 while (coin->value > c);
325 315
326 return coin; 316 return coin;
337 * 10,000 silver or something) 327 * 10,000 silver or something)
338 */ 328 */
339const char * 329const char *
340cost_string_from_value (sint64 cost, int approx) 330cost_string_from_value (sint64 cost, int approx)
341{ 331{
342 static char buf[MAX_BUF];
343 archetype *coin, *next_coin; 332 archetype *coin, *next_coin;
344 int num, cointype = 0; 333 int num, cointype = 0;
345 334
346 coin = find_next_coin (cost, &cointype); 335 coin = find_next_coin (cost, &cointype);
347 if (coin == NULL) 336 if (!coin)
348 return "nothing"; 337 return "nothing";
349 338
350 num = cost / coin->value; 339 num = cost / coin->value;
351 /* so long as nrof is 32 bit, this is true. 340 /* so long as nrof is 32 bit, this is true.
352 * If it takes more coins than a person can possibly carry, this 341 * If it takes more coins than a person can possibly carry, this
353 * is basically true. 342 * is basically true.
354 */ 343 */
355 if ((cost / coin->value) > UINT32_MAX) 344 if (cost / coin->value > UINT32_MAX)
356 {
357 strcpy (buf, "an unimaginable sum of money"); 345 return "an unimaginable sum of money";
358 return buf;
359 }
360 346
361 cost -= num * (sint64)coin->value; 347 cost -= num * (sint64)coin->value;
362 348
363 sprintf (buf, "%d %s", num, num > 1 ? &coin->object::name_pl : &coin->object::name); 349 char *buf = format ("%d %s", num, num > 1 ? &coin->object::name_pl : &coin->object::name);
364 350
365 next_coin = find_next_coin (cost, &cointype); 351 next_coin = find_next_coin (cost, &cointype);
366 if (next_coin == NULL || approx) 352 if (!next_coin || approx)
367 return buf; 353 return buf;
368 354
369 coin = next_coin; 355 coin = next_coin;
370 num = cost / coin->value; 356 num = cost / coin->value;
371 cost -= num * (sint64)coin->value; 357 cost -= num * (sint64)coin->value;
372 358
373 sprintf (buf + strlen (buf), " and %d %s", num, num > 1 ? &coin->object::name_pl : &coin->object::name); 359 return format ("%s and %d %s", buf, num, num > 1 ? &coin->object::name_pl : &coin->object::name);
374
375 return buf;
376} 360}
377 361
378const char * 362const char *
379query_cost_string (const object *tmp, object *who, int flag) 363query_cost_string (const object *tmp, object *who, int flag)
380{ 364{
399 { 383 {
400 if (!idskill1 || !find_skill_by_number (who, idskill1)) 384 if (!idskill1 || !find_skill_by_number (who, idskill1))
401 { 385 {
402 if (!idskill2 || !find_skill_by_number (who, idskill2)) 386 if (!idskill2 || !find_skill_by_number (who, idskill2))
403 { 387 {
404 if (!find_skill_by_number (who, SK_BARGAINING)) 388 if (!find_skill_by_name (who, shstr_bargaining))
405 { 389 {
406 static char buf[MAX_BUF];
407 int num, cointype = 0; 390 int num, cointype = 0;
408 archetype *coin = find_next_coin (real_value, &cointype); 391 archetype *coin = find_next_coin (real_value, &cointype);
409 392
410 if (coin == NULL) 393 if (!coin)
411 return "nothing"; 394 return "nothing";
412 395
413 num = real_value / coin->value; 396 num = real_value / coin->value;
414 397
415 if (num == 1) 398 if (num == 1)
416 sprintf (buf, "about one %s", &coin->object::name); 399 return format ("about one %s", &coin->object::name);
417 else if (num < 5) 400 else if (num < 5)
418 sprintf (buf, "a few %s", &coin->object::name_pl); 401 return format ("a few %s", &coin->object::name_pl);
419 else if (num < 10) 402 else if (num < 10)
420 sprintf (buf, "several %s", &coin->object::name_pl); 403 return format ("several %s", &coin->object::name_pl);
421 else if (num < 25) 404 else if (num < 25)
422 sprintf (buf, "a moderate amount of %s", &coin->object::name_pl); 405 return format ("a moderate amount of %s", &coin->object::name_pl);
423 else if (num < 100) 406 else if (num < 100)
424 sprintf (buf, "lots of %s", &coin->object::name_pl); 407 return format ("lots of %s", &coin->object::name_pl);
425 else if (num < 1000) 408 else if (num < 1000)
426 sprintf (buf, "a great many %s", &coin->object::name_pl); 409 return format ("a great many %s", &coin->object::name_pl);
427 else 410 else
428 sprintf (buf, "a vast quantity of %s", &coin->object::name_pl); 411 return format ("a vast quantity of %s", &coin->object::name_pl);
429
430 return buf;
431 } 412 }
432 } 413 }
433 } 414 }
434 415
435 int hash = ((unsigned int) tmp->count * 174364621) & 1023;
436
437 if (approx_range) 416 if (approx_range)
438 { 417 {
418 int hash = tmp->random_seed () & 1023;
439 sint64 lo = (sint64) real_value - (approx_range * hash >> 10); 419 sint64 lo = real_value - (approx_range * hash >> 10);
440 static char buf[MAX_BUF];
441 420
442 sprintf (buf, "between %s", cost_string_from_value (lo, 1)); 421 return format ("between %s and %s",
443 sprintf (buf + strlen (buf), " and %s", cost_string_from_value (lo + approx_range, 1)); 422 cost_string_from_value (lo, 1),
444 423 cost_string_from_value (lo + approx_range, 1));
445 return buf;
446 } 424 }
447 } 425 }
448 426
449 return cost_string_from_value (real_value, 0); 427 return cost_string_from_value (real_value, 0);
450} 428}
465 } 443 }
466 444
467 for (tmp = op->inv; tmp; tmp = tmp->below) 445 for (tmp = op->inv; tmp; tmp = tmp->below)
468 if (tmp->type == MONEY) 446 if (tmp->type == MONEY)
469 total += tmp->nrof * (sint64)tmp->value; 447 total += tmp->nrof * (sint64)tmp->value;
470 else if (tmp->type == CONTAINER && QUERY_FLAG (tmp, FLAG_APPLIED) && (tmp->race == NULL || strstr (tmp->race, "gold"))) 448 else if (tmp->type == CONTAINER && tmp->flag [FLAG_APPLIED] && (!tmp->race || tmp->race.contains (shstr_gold)))
471 total += query_money (tmp); 449 total += query_money (tmp);
472 450
473 return total; 451 return total;
474} 452}
475 453
490 return 0; 468 return 0;
491 469
492 pay_from_container (pl, pl, to_pay); 470 pay_from_container (pl, pl, to_pay);
493 471
494 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 472 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"))) 473 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains (shstr_gold)))
496 pay_from_container (pl, pouch, to_pay); 474 pay_from_container (pl, pouch, to_pay);
497 475
498 pl->update_stats (); 476 pl->update_stats ();
499 return 1; 477 return 1;
500} 478}
522 * This determins the amount of exp (if any) gained for bargaining. 500 * This determins the amount of exp (if any) gained for bargaining.
523 */ 501 */
524 saved_money = query_cost (op, pl, F_BUY | F_NO_BARGAIN | F_SHOP) - to_pay; 502 saved_money = query_cost (op, pl, F_BUY | F_NO_BARGAIN | F_SHOP) - to_pay;
525 503
526 if (saved_money > 0) 504 if (saved_money > 0)
527 change_exp (pl, saved_money, "bargaining", SK_EXP_NONE); 505 change_exp (pl, saved_money, shstr_bargaining, SK_EXP_NONE);
528 506
529 pay_from_container (pl, pl, to_pay); 507 pay_from_container (pl, pl, to_pay);
530 508
531 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 509 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"))) 510 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains (shstr_gold)))
533 pay_from_container (pl, pouch, to_pay); 511 pay_from_container (pl, pouch, to_pay);
534 512
535 pl->update_stats (); 513 pl->update_stats ();
536 514
537 return 1; 515 return 1;
577 // This should not happen, but if it does, just merge the two. 555 // This should not happen, but if it does, just merge the two.
578 if (coin_objs [i]) 556 if (coin_objs [i])
579 { 557 {
580 LOG (llevError, "%s has two money entries of (%s)\n", &pouch->name, coins[NUM_COINS - 1 - i]); 558 LOG (llevError, "%s has two money entries of (%s)\n", &pouch->name, coins[NUM_COINS - 1 - i]);
581 coin_objs[i]->nrof += tmp->nrof; 559 coin_objs[i]->nrof += tmp->nrof;
582 tmp->destroy (true); 560 tmp->destroy ();
583 } 561 }
584 else 562 else
585 { 563 {
586 tmp->remove (); 564 tmp->remove ();
587 coin_objs[i] = tmp; 565 coin_objs[i] = tmp;
604 at = archetype::find (coins[NUM_COINS - 1 - i]); 582 at = archetype::find (coins[NUM_COINS - 1 - i]);
605 583
606 if (at == NULL) 584 if (at == NULL)
607 LOG (llevError, "Could not find %s archetype\n", coins[NUM_COINS - 1 - i]); 585 LOG (llevError, "Could not find %s archetype\n", coins[NUM_COINS - 1 - i]);
608 586
609 coin_objs[i] = arch_to_object (at); 587 coin_objs[i] = at->instance ();
610 coin_objs[i]->nrof = 0; 588 coin_objs[i]->nrof = 0;
611 } 589 }
612 590
613 for (i = 0; i < NUM_COINS; i++) 591 for (i = 0; i < NUM_COINS; i++)
614 { 592 {
615 object &coin = *coin_objs[i]; 593 object &coin = *coin_objs[i];
616 sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, coin.nrof); 594 sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, (sint64) coin.nrof);
617 to_pay -= num_coins * coin.value; 595 to_pay -= num_coins * coin.value;
618 596
619 coin.nrof -= num_coins; 597 coin.nrof -= num_coins;
620 /* Now start making change. Start at the coin value 598 /* Now start making change. Start at the coin value
621 * below the one we just did, and work down to 599 * below the one we just did, and work down to
634 612
635 for (i = 0; i < NUM_COINS; i++) 613 for (i = 0; i < NUM_COINS; i++)
636 if (coin_objs[i]->nrof) 614 if (coin_objs[i]->nrof)
637 insert_ob_in_ob (coin_objs [i], pouch); 615 insert_ob_in_ob (coin_objs [i], pouch);
638 else 616 else
639 coin_objs[i]->destroy (true); 617 coin_objs[i]->destroy ();
640} 618}
641 619
642/* Checks all unpaid items in op's inventory, adds up all the money they 620/* Checks all unpaid items in op's inventory, adds up all the money they
643 * have, and checks that they can actually afford what they want to buy. 621 * have, and checks that they can actually afford what they want to buy.
644 * Returns 1 if they can, and 0 if they can't. also prints an appropriate message 622 * Returns 1 if they can, and 0 if they can't. also prints an appropriate message
656 LOG (llevError, "can_pay(): called against something that isn't a player\n"); 634 LOG (llevError, "can_pay(): called against something that isn't a player\n");
657 return 0; 635 return 0;
658 } 636 }
659 637
660 for (object::depth_iterator item = pl->begin (); item != pl->end (); ++item) 638 for (object::depth_iterator item = pl->begin (); item != pl->end (); ++item)
661 if (QUERY_FLAG (item, FLAG_UNPAID)) 639 if (item->flag [FLAG_UNPAID])
662 { 640 {
663 unpaid_count++; 641 unpaid_count++;
664 unpaid_price += query_cost (item, pl, F_BUY | F_SHOP); 642 unpaid_price += query_cost (item, pl, F_BUY | F_SHOP);
665 } 643 }
666 644
667 if (unpaid_price > player_wealth) 645 if (unpaid_price > player_wealth)
668 { 646 {
669 dynbuf_text buf; 647 dynbuf_text &buf = msg_dynbuf; buf.clear ();
670 648
671 buf << "You have " << unpaid_count 649 buf << "You have " << unpaid_count
672 << " unpaid item(s) that would cost you " << cost_string_from_value (unpaid_price, 0) 650 << " 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) 651 << ". You need another " << cost_string_from_value (unpaid_price - player_wealth, 0)
674 << " to be able to afford that."; 652 << " to be able to afford that. "
653 "H<You cannot leave a shop without paying - drop unpaid items first to be able to leave.>";
675 654
676 pl->failmsg (buf); 655 pl->failmsg (buf);
677 656
678 return 0; 657 return 0;
679 } 658 }
694 { 673 {
695 next_item: 674 next_item:
696 675
697 for (object::depth_iterator op = pl->begin (); op != pl->end (); ++op) 676 for (object::depth_iterator op = pl->begin (); op != pl->end (); ++op)
698 { 677 {
699 if (QUERY_FLAG (op, FLAG_UNPAID)) 678 if (op->flag [FLAG_UNPAID])
700 { 679 {
701 char buf[MAX_BUF];
702 snprintf (buf, MAX_BUF, "%s", query_cost_string (op, pl, F_BUY | F_SHOP)); 680 const char *buf = query_cost_string (op, pl, F_BUY | F_SHOP);
703 681
704 if (!pay_for_item (op, pl)) 682 if (!pay_for_item (op, pl))
705 { 683 {
706 sint64 i = query_cost (op, pl, F_BUY | F_SHOP) - query_money (pl); 684 sint64 i = query_cost (op, pl, F_BUY | F_SHOP) - query_money (pl);
707 685
708 CLEAR_FLAG (op, FLAG_UNPAID); 686 op->clr_flag (FLAG_UNPAID);
709 new_draw_info_format (NDI_UNIQUE, 0, pl, "You lack %s to buy %s.", cost_string_from_value (i, 0), query_name (op)); 687 new_draw_info_format (NDI_UNIQUE, 0, pl, "You lack %s to buy %s.", cost_string_from_value (i, 0), query_name (op));
710 SET_FLAG (op, FLAG_UNPAID); 688 op->set_flag (FLAG_UNPAID);
711 return 0; 689 return 0;
712 } 690 }
713 else 691 else
714 { 692 {
715 CLEAR_FLAG (op, FLAG_UNPAID); 693 op->clr_flag (FLAG_UNPAID);
716 CLEAR_FLAG (op, FLAG_PLAYER_SOLD); 694 op->clr_flag (FLAG_PLAYER_SOLD);
717 new_draw_info_format (NDI_UNIQUE, 0, op, "You paid %s for %s.", buf, query_name (op)); 695 new_draw_info_format (NDI_UNIQUE, 0, pl, "You paid %s for %s.", buf, query_name (op));
718 696
719 if (!merge_ob (op, op->env->inv)) 697 if (!merge_ob (op, op->env->inv))
720 esrv_update_item (UPD_FLAGS, pl, op); 698 esrv_update_item (UPD_FLAGS, pl, op);
721 699
722 goto next_item; 700 goto next_item;
754 LOG (llevError, "Could not find %s archetype\n", coins[count]); 732 LOG (llevError, "Could not find %s archetype\n", coins[count]);
755 else if ((amount / at->value) > 0) 733 else if ((amount / at->value) > 0)
756 { 734 {
757 for (pouch = pl->inv; pouch; pouch = pouch->below) 735 for (pouch = pl->inv; pouch; pouch = pouch->below)
758 { 736 {
759 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && pouch->race && strstr (pouch->race, "gold")) 737 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && pouch->race.contains (shstr_gold))
760 { 738 {
761 int w = at->weight * (100 - pouch->stats.Str) / 100; 739 int w = at->weight * (100 - pouch->stats.Str) / 100;
762 int n = amount / at->value; 740 int n = amount / at->value;
763 741
764 if (w == 0) 742 if (w == 0)
767 if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit)) 745 if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit))
768 { 746 {
769 if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n) 747 if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n)
770 n = (pouch->weight_limit - pouch->carrying) / w; 748 n = (pouch->weight_limit - pouch->carrying) / w;
771 749
772 object *tmp = arch_to_object (at); 750 object *tmp = at->instance ();
773 tmp->nrof = n; 751 tmp->nrof = n;
774 amount -= tmp->nrof * tmp->value; 752 amount -= tmp->nrof * tmp->value;
775 pouch->insert (tmp); 753 pouch->insert (tmp);
776 } 754 }
777 } 755 }
778 } 756 }
779 757
780 if (amount / at->value > 0) 758 if (amount / at->value > 0)
781 { 759 {
782 object *tmp = arch_to_object (at); 760 object *tmp = at->instance ();
783 tmp->nrof = amount / tmp->value; 761 tmp->nrof = amount / tmp->value;
784 amount -= tmp->nrof * tmp->value; 762 amount -= tmp->nrof * tmp->value;
785 pl->insert (tmp); 763 pl->insert (tmp);
786 } 764 }
787 } 765 }
844 * exp/10 -> 1 for each gold coin 822 * exp/10 -> 1 for each gold coin
845 */ 823 */
846 extra_gain = amount - query_cost (op, pl, F_SELL | F_NO_BARGAIN | F_SHOP); 824 extra_gain = amount - query_cost (op, pl, F_SELL | F_NO_BARGAIN | F_SHOP);
847 825
848 if (extra_gain > 0) 826 if (extra_gain > 0)
849 change_exp (pl, extra_gain / 10, "bargaining", SK_EXP_NONE); 827 change_exp (pl, extra_gain / 10, shstr_bargaining, SK_EXP_NONE);
850 828
851 pay_player (pl, amount); 829 pay_player (pl, amount);
852 830
853 new_draw_info_format (NDI_UNIQUE, 0, pl, "You receive %s for %s.", 831 new_draw_info_format (NDI_UNIQUE, 0, pl, "You receive %s for %s.",
854 query_cost_string (op, pl, F_SELL | F_SHOP), query_name (op)); 832 query_cost_string (op, pl, F_SELL | F_SHOP), query_name (op));
855 pl->play_sound (sound_find ("shop_sell")); 833 pl->play_sound (sound_find ("shop_sell"));
856 834
857 SET_FLAG (op, FLAG_UNPAID); 835 op->set_flag (FLAG_UNPAID);
858 identify (op); 836 identify (op);
859 837
860 return true; 838 return true;
861} 839}
862 840
866 */ 844 */
867static double 845static double
868shop_specialisation_ratio (const object *item, const maptile *map) 846shop_specialisation_ratio (const object *item, const maptile *map)
869{ 847{
870 shopitems *items = map->shopitems; 848 shopitems *items = map->shopitems;
871 double likedness = 0.; 849 int likedness = 0;
872 int i; 850 int i;
873 851
874 if (item == NULL) 852 if (item == NULL)
875 { 853 {
876 LOG (llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", &map->path); 854 LOG (llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", &map->path);
877 return 0; 855 return 0;
878 } 856 }
879 857
880 if (!item->type) 858 if (!item->type)
881 { 859 {
882 LOG (llevError, "shop_specialisation_ratio: passed an item with an invalid type\n"); 860 LOG (llevError, "shop_specialisation_ratio: passed an item with an invalid type: %s\n", item->debug_desc ());
883 /* 861 /*
884 * I'm not really sure what the /right/ thing to do here is, these types of 862 * I'm not really sure what the /right/ thing to do here is, these types of
885 * item shouldn't exist anyway, but returning the ratio is probably the best bet.." 863 * item shouldn't exist anyway, but returning the ratio is probably the best bet.."
886 */ 864 */
887 return SPECIALISATION_EFFECT; 865 return SPECIALISATION_EFFECT;
888 } 866 }
889 867
890 if (map->shopitems) 868 if (map->shopitems)
891 {
892 for (i = 0; i < items[0].index; i++) 869 for (i = 0; i < items[0].index; i++)
893 if (items[i].typenum == item->type || (!items[i].typenum && likedness == 0.001)) 870 if (items[i].typenum == item->type || (!items[i].typenum && !likedness))
894 likedness = items[i].strength / 100.0; 871 likedness = items[i].strength;
895 }
896 872
897 if (likedness > 1.0) 873 if (likedness > 100)
898 { /* someone has been rather silly with the map headers. */ 874 { /* someone has been rather silly with the map headers. */
899 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, &map->path); 875 LOG (llevDebug, "shop_specialisation ratio: item %s on map %s is above 100%%\n", item->debug_desc (), &map->path);
900 likedness = 1.0; 876 likedness = 100;
901 } 877 }
902 878
903 if (likedness < -1.0) 879 if (likedness < -100)
904 { 880 {
905 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, &map->path); 881 LOG (llevDebug, "shop_specialisation ratio: item %s on map %s is below -100%%\n", item->debug_desc (), &map->path);
906 likedness = -1.0; 882 likedness = -100;
907 } 883 }
908 884
909 return lerp (likedness, -1., 1., SPECIALISATION_EFFECT, 1.); 885 return lerp (double (likedness), -100., 100., SPECIALISATION_EFFECT, 1.);
910} 886}
911 887
912/*returns the greed of the shop on map, or 1 if it isn't specified. */ 888/*returns the greed of the shop on map, or 1 if it isn't specified. */
913static double 889static double
914shop_greed (const maptile *map) 890shop_greed (const maptile *map)
964 tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default 940 tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default
965 941
966 if (map->shopmin && unit_price < map->shopmin) 942 if (map->shopmin && unit_price < map->shopmin)
967 return 0; 943 return 0;
968 else if (unit_price > tmpshopmax / 2) 944 else if (unit_price > tmpshopmax / 2)
969 newval = MIN ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax); 945 newval = min ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax);
970 else 946 else
971 newval = unit_price; 947 newval = unit_price;
972 } 948 }
973 949
974 newval *= quantity; 950 newval *= quantity;
978 954
979/* gives a desciption of the shop on their current map to the player op. */ 955/* gives a desciption of the shop on their current map to the player op. */
980int 956int
981describe_shop (const object *op) 957describe_shop (const object *op)
982{ 958{
959 dynbuf_text buf;
983 maptile *map = op->map; 960 maptile *map = op->map;
984 961
985 /*shopitems *items=map->shopitems; */ 962 /*shopitems *items=map->shopitems; */
986 int pos = 0, i; 963 int pos = 0, i;
987 double opinion = 0; 964 double opinion = 0;
988 char tmp[MAX_BUF] = "\0";
989 965
990 if (op->type != PLAYER) 966 if (op->type != PLAYER)
991 return 0; 967 return 0;
992 968
993 /*check if there is a shop specified for this map */ 969 /*check if there is a shop specified for this map */
994 if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax) 970 if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax)
995 { 971 {
996 new_draw_info (NDI_UNIQUE, 0, op, "From looking at the nearby shop you determine that it trades in:"); 972 buf << "From looking at the nearby shop you determine that it trades in ";
973 int lastcomma = 0, prevcomma = 0;
997 974
998 if (map->shopitems) 975 if (map->shopitems)
999 for (i = 0; i < map->shopitems[0].index; i++) 976 for (i = 0; i < map->shopitems[0].index; i++)
1000 if (map->shopitems[i].name && map->shopitems[i].strength > 10) 977 if (map->shopitems[i].name && map->shopitems[i].strength > 10)
1001 { 978 {
1002 snprintf (tmp + pos, sizeof (tmp) - pos, "%s, ", map->shopitems[i].name_pl); 979 buf << map->shopitems[i].name_pl;
1003 pos += strlen (tmp + pos); 980 prevcomma = lastcomma;
981 lastcomma = buf.size (); // remember offset
982 buf << ", ";
1004 } 983 }
1005 984
1006 if (!pos) 985 if (lastcomma)
986 {
987 buf.splice (lastcomma, 2);
988
989 if (prevcomma)
990 buf.splice (prevcomma, 2, " and ");
991 }
992 else
1007 strcat (tmp, "a little of everything."); 993 buf << "a little of everything.";
1008 994
1009 /* format the string into a list */ 995 buf << ".\n\n";
1010 make_list_like (tmp);
1011 new_draw_info_format (NDI_UNIQUE, 0, op, "%s", tmp);
1012 996
1013 if (map->shopmax) 997 if (map->shopmax)
1014 new_draw_info_format (NDI_UNIQUE, 0, op, "It won't trade for items above %s.", cost_string_from_value (map->shopmax, 0)); 998 buf << "It won't trade for items above " << cost_string_from_value (map->shopmax, 0) << ".\n\n";
1015 999
1016 if (map->shopmin) 1000 if (map->shopmin)
1017 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)); 1001 buf << "It won't trade in items worth less than " << cost_string_from_value (map->shopmin, 0) << ".\n\n";
1018 1002
1019 if (map->shopgreed) 1003 if (map->shopgreed)
1020 { 1004 {
1021 if (map->shopgreed > 2.0) 1005 if (map->shopgreed > 2.0)
1022 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge massively."); 1006 buf << "It tends to overcharge massively.\n\n";
1023 else if (map->shopgreed > 1.5) 1007 else if (map->shopgreed > 1.5)
1024 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge substantially."); 1008 buf << "It tends to overcharge substantially.\n\n";
1025 else if (map->shopgreed > 1.1) 1009 else if (map->shopgreed > 1.1)
1026 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge slightly."); 1010 buf << "It tends to overcharge slightly.\n\n";
1027 else if (map->shopgreed < 0.9) 1011 else if (map->shopgreed < 0.9)
1028 new_draw_info (NDI_UNIQUE, 0, op, "It tends to undercharge."); 1012 buf << "It tends to undercharge.\n\n";
1029 } 1013 }
1030 1014
1031 if (map->shoprace) 1015 if (map->shoprace)
1032 { 1016 {
1033 opinion = shopkeeper_approval (map, op); 1017 opinion = shopkeeper_approval (map, op);
1018
1034 if (opinion > 0.8) 1019 if (opinion > 0.8)
1035 new_draw_info (NDI_UNIQUE, 0, op, "You think the shopkeeper likes you."); 1020 buf << "You think the shopkeeper likes you.\n\n";
1036 else if (opinion > 0.5) 1021 else if (opinion > 0.5)
1037 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems unconcerned by you."); 1022 buf << "The shopkeeper seems unconcerned by you.\n\n";
1038 else 1023 else
1039 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems to have taken a dislike to you."); 1024 buf << "The shopkeeper seems to have taken a dislike to you.\n\n";
1040 } 1025 }
1041 } 1026 }
1042 else 1027 else
1043 new_draw_info (NDI_UNIQUE, 0, op, "There is no shop nearby."); 1028 buf << "There is no shop nearby.\n\n";
1029
1030 op->contr->infobox (MSG_CHANNEL ("shopinfo"), buf);
1044 1031
1045 return 1; 1032 return 1;
1046} 1033}
1047 1034
1048struct shopinv 1035struct shopinv
1049{ 1036{
1050 char *item_sort; 1037 char *item_sort;
1051 char *item_real; 1038 char *item_real;
1039 sint64 value;
1052 uint16 type; 1040 uint16 type;
1053 uint32 nrof; 1041 uint32 nrof;
1054}; 1042};
1055 1043
1056/* There are a lot fo extra casts in here just to suppress warnings - it 1044/* There are a lot fo extra casts in here just to suppress warnings - it
1076} 1064}
1077 1065
1078static void 1066static void
1079add_shop_item (object *tmp, shopinv * items, int *numitems, int *numallocated) 1067add_shop_item (object *tmp, shopinv * items, int *numitems, int *numallocated)
1080{ 1068{
1081#if 0
1082 char buf[MAX_BUF];
1083#endif
1084 /* clear unpaid flag so that doesn't come up in query 1069 /* clear unpaid flag so that doesn't come up in query
1085 * string. We clear nrof so that we can better sort 1070 * string. We clear nrof so that we can better sort
1086 * the object names. 1071 * the object names.
1087 */ 1072 */
1088 1073
1089 CLEAR_FLAG (tmp, FLAG_UNPAID); 1074 tmp->clr_flag (FLAG_UNPAID);
1090 items[*numitems].nrof = tmp->nrof; 1075 items[*numitems].nrof = tmp->nrof;
1091 /* Non mergable items have nrof of 0, but count them as one 1076 /* Non mergable items have nrof of 0, but count them as one
1092 * so the display is properly. 1077 * so the display is properly.
1093 */ 1078 */
1094 if (tmp->nrof == 0) 1079 if (tmp->nrof == 0)
1095 items[*numitems].nrof++; 1080 items[*numitems].nrof++;
1096 items[*numitems].type = tmp->type; 1081 items[*numitems].type = tmp->type;
1082
1083 items[*numitems].value = tmp->value;
1097 1084
1098 switch (tmp->type) 1085 switch (tmp->type)
1099 { 1086 {
1100#if 0 1087#if 0
1101 case BOOTS: 1088 case BOOTS:
1113#endif 1100#endif
1114 1101
1115 default: 1102 default:
1116 items[*numitems].item_sort = strdup (query_base_name (tmp, 0)); 1103 items[*numitems].item_sort = strdup (query_base_name (tmp, 0));
1117 items[*numitems].item_real = strdup (query_base_name (tmp, 1)); 1104 items[*numitems].item_real = strdup (query_base_name (tmp, 1));
1105 items[*numitems].value += tmp->value;
1118 (*numitems)++; 1106 (*numitems)++;
1119 break; 1107 break;
1120 } 1108 }
1121 SET_FLAG (tmp, FLAG_UNPAID); 1109
1110 tmp->set_flag (FLAG_UNPAID);
1122} 1111}
1123 1112
1124void 1113void
1125shop_listing (object *sign, object *op) 1114shop_listing (object *sign, object *op)
1126{ 1115{
1127 int i, j, numitems = 0, numallocated = 0, x1, x2, y1, y2; 1116 int i, j, x1, x2, y1, y2;
1128 const char *shop_coords = sign->kv (shstr_shop_coords); 1117 const char *shop_coords = sign->kv [shstr_shop_coords];
1129 object *stack; 1118 object *stack;
1130 shopinv *items; 1119 shopinv *items;
1131 1120
1132 /* Should never happen, but just in case a monster does apply a sign */ 1121 /* Should never happen, but just in case a monster does apply a sign */
1133 if (op->type != PLAYER) 1122 if (!op->is_player ())
1134 return; 1123 return;
1124
1125 dynbuf_text &buf = msg_dynbuf; buf.clear ();
1135 1126
1136 if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2))) 1127 if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2)))
1137 { 1128 {
1138 x1 = 0; 1129 x1 = 0;
1139 y1 = 0; 1130 y1 = 0;
1140 x2 = op->map->width - 1; 1131 x2 = op->map->width - 1;
1141 y2 = op->map->height - 1; 1132 y2 = op->map->height - 1;
1142 } 1133 }
1143 1134
1144 items = (shopinv *) malloc (40 * sizeof (shopinv));
1145 numallocated = 40; 1135 int numallocated = 40;
1136 int numitems = 0;
1137 items = (shopinv *)malloc (sizeof (shopinv) * numallocated);
1146 1138
1147 /* Find all the appropriate items */ 1139 /* Find all the appropriate items */
1148 for (i = x1; i <= x2; i++) 1140 for (i = x1; i <= x2; i++)
1149 {
1150 for (j = y1; j < y2; j++) 1141 for (j = y1; j < y2; j++)
1142 if (op->map->is_in_shop (i, j))
1151 { 1143 {
1152 if (is_in_shop (op->map, i, j)) 1144 stack = GET_MAP_OB (op->map, i, j);
1145
1146 while (stack)
1153 { 1147 {
1154 stack = GET_MAP_OB (op->map, i, j); 1148 if (stack->flag [FLAG_UNPAID])
1155
1156 while (stack)
1157 { 1149 {
1158 if (QUERY_FLAG (stack, FLAG_UNPAID))
1159 {
1160 if (numitems == numallocated) 1150 if (numitems == numallocated)
1161 {
1162 items = (shopinv *) realloc (items, sizeof (shopinv) * (numallocated + 10)); 1151 items = (shopinv *)realloc (items, sizeof (shopinv) * (numallocated *= 2));
1163 numallocated += 10;
1164 }
1165 1152
1166 add_shop_item (stack, items, &numitems, &numallocated); 1153 add_shop_item (stack, items, &numitems, &numallocated);
1167 }
1168
1169 stack = stack->above;
1170 } 1154 }
1155
1156 stack = stack->above;
1171 } 1157 }
1172 } 1158 }
1173 }
1174 1159
1175 if (numitems == 0) 1160 buf << (numitems ? "T<This shop contains:>\n\n"
1176 { 1161 : "T<This shop is currently empty.>");
1177 new_draw_info (NDI_UNIQUE, 0, op, "The shop is currently empty.\n");
1178 free (items);
1179 return;
1180 }
1181 1162
1182 qsort (items, numitems, sizeof (shopinv), (int (*)(const void *, const void *)) shop_sort); 1163 qsort (items, numitems, sizeof (shopinv), (int (*)(const void *, const void *)) shop_sort);
1183
1184 new_draw_info (NDI_UNIQUE, 0, op, "\nThe shop contains:");
1185 1164
1186 for (i = 0; i < numitems; i++) 1165 for (i = 0; i < numitems; i++)
1187 { 1166 {
1188 /* Collapse items of the same name together */ 1167 /* Collapse items of the same name together */
1189 if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real)) 1168 if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real))
1190 {
1191 items[i + 1].nrof += items[i].nrof; 1169 items[i + 1].nrof += items[i].nrof;
1192 free (items[i].item_sort);
1193 free (items[i].item_real);
1194 }
1195 else 1170 else
1196 { 1171 {
1197 new_draw_info_format (NDI_UNIQUE, 0, op, "%d %s", 1172 buf.printf (
1198 items[i].nrof ? items[i].nrof : 1, items[i].nrof == 1 ? items[i].item_sort : items[i].item_real); 1173 " %4d %s\n for %s\n",
1174 items[i].nrof ? items[i].nrof : 1,
1175 items[i].nrof == 1 ? items[i].item_sort : items[i].item_real,
1176 cost_string_from_value (items[i].value, op->flag [FLAG_WIZ] ? 0 : 1));
1177 }
1178
1199 free (items[i].item_sort); 1179 free (items[i].item_sort);
1200 free (items[i].item_real); 1180 free (items[i].item_real);
1201 }
1202 } 1181 }
1182
1183 op->contr->infobox (MSG_CHANNEL ("shopitems"), buf);
1203 1184
1204 free (items); 1185 free (items);
1205}
1206
1207/* elmex: this function checks whether the object is in a shop */
1208bool
1209is_in_shop (object *o)
1210{
1211 if (!o->is_on_map ())
1212 return false;
1213
1214 return is_in_shop (o->map, o->x, o->y);
1215} 1186}
1216 1187
1217/* elmex: this function checks whether we are in a shop or not 1188/* elmex: this function checks whether we are in a shop or not
1218 - change 2007-11-26: enhanced the O(n) case by stopping at the first 1189 - change 2007-11-26: enhanced the O(n) case by stopping at the first
1219 floor tile. this possibly will make map bugs where shopfloors are above 1190 floor tile. this possibly will make map bugs where shopfloors are above
1220 floors more obvious. 1191 floors more obvious.
1221*/ 1192*/
1222
1223bool 1193bool
1224is_in_shop (maptile *map, int x, int y) 1194maptile::is_in_shop (int x, int y) const
1225{ 1195{
1226 for (object *floor = GET_MAP_OB (map, x, y); floor; floor = floor->above) 1196 for (object *floor = at (x, y).bot; floor; floor = floor->above)
1227 if (QUERY_FLAG (floor, FLAG_IS_FLOOR)) 1197 if (floor->flag [FLAG_IS_FLOOR])
1228 return floor->type == SHOP_FLOOR; 1198 return floor->type == SHOP_FLOOR;
1229 1199
1230 return false; 1200 return false;
1231} 1201}
1232 1202

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines