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.54 by root, Sat Aug 30 02:26:46 2008 UTC vs.
Revision 1.95 by root, Sat Nov 17 23:40:04 2018 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 (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 5 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team 6 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen 7 * Copyright (©) 1992 Frank Tore Johansen
7 * 8 *
8 * Deliantra is free software: you can redistribute it and/or modify 9 * 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 10 * 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 11 * Free Software Foundation, either version 3 of the License, or (at your
11 * (at your option) any later version. 12 * option) any later version.
12 * 13 *
13 * This program is distributed in the hope that it will be useful, 14 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 17 * GNU General Public License for more details.
17 * 18 *
18 * You should have received a copy of the GNU General Public License 19 * 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/>. 20 * and the GNU General Public License along with this program. If not, see
21 * <http://www.gnu.org/licenses/>.
20 * 22 *
21 * The authors can be reached via e-mail to <support@deliantra.net> 23 * The authors can be reached via e-mail to <support@deliantra.net>
22 */ 24 */
23 25
24#include <global.h> 26#include <global.h>
25#include <spells.h> 27#include <spells.h>
26#include <skills.h> 28#include <skills.h>
27#include <living.h> 29#include <living.h>
28#include <sproto.h> 30#include <sproto.h>
29#include <math.h>
30 31
31/* this is a measure of how effective store specialisation is. A general store 32/* 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 33 * 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 34 * 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. 35 * therefore making this number higher, makes specialisation less effective.
35 * setting this value above 1 or to a negative value would have interesting, 36 * setting this value above 1 or to a negative value would have interesting,
36 * (though not useful) effects. 37 * (though not useful) effects.
37 */ 38 */
38#define SPECIALISATION_EFFECT .5 39#define SPECIALISATION_EFFECT .5
39 40
55 * would not be done. 56 * would not be done.
56 * 57 *
57 * Added F_APPROX flag, which means that the price returned should be wrong by 58 * Added F_APPROX flag, which means that the price returned should be wrong by
58 * an amount related to the player's bargaining skill. 59 * an amount related to the player's bargaining skill.
59 * 60 *
60 * Added F_SHOP flag to mean that the specialisation of the shop on the player's 61 * Added F_SHOP flag to mean that the specialisation of the shop on the player's
61 * current map should be taken into account when determining the price. Shops that 62 * current map should be taken into account when determining the price. Shops that
62 * specialise in what is being traded will give better prices than those that do not. 63 * specialise in what is being traded will give better prices than those that do not.
63 * 64 *
64 * CF 0.91.4 - This function got changed around a bit. Now the 65 * CF 0.91.4 - This function got changed around a bit. Now the
65 * number of object is multiplied by the value early on. This fixes problems 66 * number of object is multiplied by the value early on. This fixes problems
66 * with items worth very little. What happened before is that various 67 * with items worth very little. What happened before is that various
67 * divisions took place, the value got rounded to 0 (Being an int), and 68 * divisions took place, the value got rounded to 0 (Being an int), and
74 75
75sint64 76sint64
76query_cost (const object *tmp, object *who, int flag) 77query_cost (const object *tmp, object *who, int flag)
77{ 78{
78 double val; 79 double val;
79 int number; /* used to better calculate value */
80 int no_bargain; 80 int no_bargain;
81 int identified; 81 int identified;
82 int not_cursed; 82 int not_cursed;
83 int approximate; 83 int approximate;
84 int shop; 84 int shop;
85 double diff;
86 85
87 approx_range = 0; 86 approx_range = 0;
88 87
89 no_bargain = flag & F_NO_BARGAIN; 88 no_bargain = flag & F_NO_BARGAIN;
90 identified = flag & F_IDENTIFIED; 89 identified = flag & F_IDENTIFIED;
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, "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, "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;
192 else /* if not identified, presume one charge */ 176 /* 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
206 * AND Cha = 30 will get optimal price. 190 * AND Cha = 30 will get optimal price.
207 * Thus charisma will never get useless. 191 * Thus charisma will never get useless.
208 * -b.e. edler@heydernet.de 192 * -b.e. edler@heydernet.de
209 */ 193 */
210 194
211 if (who && who->type == PLAYER) 195 if (who && who->is_player ())
212 { 196 {
213 int lev_bargain = 0; 197 int lev_bargain = 0;
214 int lev_identify = 0; 198 int lev_identify = 0;
215 199
216 if (find_skill_by_number (who, SK_BARGAINING)) 200 if (!no_bargain)
217 lev_bargain = find_skill_by_number (who, SK_BARGAINING)->level; 201 if (object *skill = find_skill_by_name (who, shstr_bargaining))
202 lev_bargain = skill->level;
218 203
219 if (const typedata *tmptype = get_typedata (tmp->type)) 204 if (const typedata *tmptype = get_typedata (tmp->type))
220 { 205 {
221 if (int idskill1 = tmptype->identifyskill) 206 if (int idskill1 = tmptype->identifyskill)
222 { 207 {
233 /* ratio determines how much of the price modification 218 /* ratio determines how much of the price modification
234 * will come from the basic stat charisma 219 * will come from the basic stat charisma
235 * the rest will come from the level in bargaining skill 220 * the rest will come from the level in bargaining skill
236 */ 221 */
237 const double cha_ratio = 0.40; 222 const double cha_ratio = 0.40;
238 223 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.); 224 double charisma = (cha_bonus[who->stats.Cha] - 1.) / (cha_bonus[who->stats.Cha] + 1.);
241 diff = .02 + (.80 - .02) * diff; 225
226 double factor = (1. - cha_ratio) * bargaining + cha_ratio * charisma;
227
228 // scale 0..1 to 2 .. 80%
229 factor = lerp (factor, 0., 1., 0.02, 0.80);
242 230
243 if (flag == F_BUY) 231 if (flag == F_BUY)
244 val += val * diff; 232 val += val * factor;
245 else if (flag == F_SELL) 233 else if (flag == F_SELL)
246 val -= val * diff; 234 val -= val * factor;
247 235
248 // now find a price range. the less good we can judge, the larger the range is 236 // 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 237 // then the range is adjusted randomly around the correct value
250 if (approximate) 238 if (approximate)
251 approx_range = sint64 (val / sqrt (lev_identify * 3 + 1)); 239 approx_range = val / sqrt (lev_identify * 3 + 1);
252 } 240 }
253 241
254 /* I don't think this should really happen - if it does, it indicates and 242 /* I don't think this should really happen - if it does, it indicates and
255 * overflow of diff above. That should only happen if 243 * overflow of diff above. That should only happen if
256 * we are selling objects - in that case, the person just 244 * we are selling objects - in that case, the person just
257 * gets no money. 245 * gets no money.
258 */ 246 */
259 if ((sint64) val < 0) 247 if ((sint64) val < 0)
260 val = 0; 248 val = 0;
261 249
262 /* Unidentified stuff won't sell for more than 60gp */ 250 /* Unidentified stuff won't sell for more than 10gp */
263 if (flag == F_SELL && !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && need_identify (tmp) && !identified) 251 if (flag == F_SELL && !tmp->flag [FLAG_IDENTIFIED] && tmp->need_identify () && !identified)
264 { 252 min_it (val, 1000);
265 val = (val > 600) ? 600 : val;
266 }
267 253
268 /* if we are in a shop, check how the type of shop should affect the price */ 254 /* if we are in a shop, check how the type of shop should affect the price */
269 if (shop && who) 255 if (shop && who)
270 { 256 {
271 if (flag == F_SELL) 257 if (flag == F_SELL)
272 val = (val * shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who) / shop_greed (who->map)); 258 val *= shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who) / shop_greed (who->map);
273 else if (flag == F_BUY) 259 else if (flag == F_BUY)
274 { 260 {
275 /* 261 /*
276 * when buying, if the item was sold by another player, it is ok to 262 * 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 263 * let the item be sold cheaper, according to the specialisation of
278 * the shop. If a player sold an item here, then his sale price was 264 * the shop. If a player sold an item here, then his sale price was
279 * multiplied by the specialisation ratio, to do the same to the buy 265 * multiplied by the specialisation ratio, to do the same to the buy
280 * price will not generate extra money. However, the 266 * price will not generate extra money. However, the
281 * same is not true of generated items, these have to /divide/ by the 267 * same is not true of generated items, these have to /divide/ by the
282 * specialisation, so that the price is never less than what they could 268 * specialisation, so that the price is never less than what they could
283 * be sold for (otherwise players could camp map resets to make money). 269 * 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 270 * 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 271 * value of the items they sell (much like how people sometimes find
286 * antiques in a junk shop in real life). 272 * antiques in a junk shop in real life).
287 */ 273 */
288 if (QUERY_FLAG (tmp, FLAG_PLAYER_SOLD)) 274 if (tmp->flag [FLAG_PLAYER_SOLD])
289 val = (val * shop_greed (who->map) * shop_specialisation_ratio (tmp, who->map) / shopkeeper_approval (who->map, who)); 275 val *= shop_specialisation_ratio (tmp, who->map);
290 else 276 else
291 val = (val * shop_greed (who->map) / (shop_specialisation_ratio (tmp, who->map) * shopkeeper_approval (who->map, who))); 277 val /= shop_specialisation_ratio (tmp, who->map);
292 }
293 278
279 val *= shop_greed (who->map) / shopkeeper_approval (who->map, who);
280 }
281
294 /* we will also have an extra 0-5% variation between shops of the same type 282 /* 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 283 * for valuable items (below a value of 50 this effect wouldn't be very
296 * pointful, and could give fun with rounding. 284 * pointful, and could give fun with rounding.
297 */ 285 */
298 //TODO: why use cosf at all, just % and scale linearly, gives more even distribution 286 //TODO: why use cosf at all, just % and scale linearly, gives more even distribution
299 if (val > 50) 287 if (val > 50)
300 val += float (val) * .05f * cosf ((tmp->uuid.seq & 0xffff) * float (M_PI * 2. / 0x10000)); 288 val *= 1 + .05f * cosf ((tmp->uuid.seq & 0xffff) * M_PI * 2. / 0x10000);
301 } 289 }
302 290
303 return (sint64) val; 291 return val;
304} 292}
305 293
306/* Find the coin type that is worth more the 'c'. Starts at the 294/* Find the coin type that is worth more the 'c'. Starts at the
307 * cointype placement. 295 * cointype placement.
308 */ 296 */
312{ 300{
313 archetype *coin; 301 archetype *coin;
314 302
315 do 303 do
316 { 304 {
317 if (coins[*cointype] == NULL) 305 if (!coins [*cointype])
318 return NULL; 306 return 0;
307
319 coin = archetype::find (coins[*cointype]); 308 coin = archetype::find (coins [*cointype]);
309
320 if (coin == NULL) 310 if (!coin)
321 return NULL; 311 return 0;
312
322 *cointype += 1; 313 *cointype += 1;
323 } 314 }
324 while (coin->value > c); 315 while (coin->value > c);
325 316
326 return coin; 317 return coin;
337 * 10,000 silver or something) 328 * 10,000 silver or something)
338 */ 329 */
339const char * 330const char *
340cost_string_from_value (sint64 cost, int approx) 331cost_string_from_value (sint64 cost, int approx)
341{ 332{
342 static char buf[MAX_BUF];
343 archetype *coin, *next_coin; 333 archetype *coin, *next_coin;
344 int num, cointype = 0; 334 int num, cointype = 0;
345 335
346 coin = find_next_coin (cost, &cointype); 336 coin = find_next_coin (cost, &cointype);
347 if (coin == NULL) 337 if (!coin)
348 return "nothing"; 338 return "nothing";
349 339
350 num = cost / coin->value; 340 num = cost / coin->value;
351 /* so long as nrof is 32 bit, this is true. 341 /* so long as nrof is 32 bit, this is true.
352 * If it takes more coins than a person can possibly carry, this 342 * If it takes more coins than a person can possibly carry, this
353 * is basically true. 343 * is basically true.
354 */ 344 */
355 if ((cost / coin->value) > UINT32_MAX) 345 if (cost / coin->value > UINT32_MAX)
356 {
357 strcpy (buf, "an unimaginable sum of money"); 346 return "an unimaginable sum of money";
358 return buf;
359 }
360 347
361 cost -= num * (sint64)coin->value; 348 cost -= num * (sint64)coin->value;
362 349
363 sprintf (buf, "%d %s", num, num > 1 ? &coin->object::name_pl : &coin->object::name); 350 char *buf = format ("%d %s", num, num > 1 ? &coin->object::name_pl : &coin->object::name);
364 351
365 next_coin = find_next_coin (cost, &cointype); 352 next_coin = find_next_coin (cost, &cointype);
366 if (next_coin == NULL || approx) 353 if (!next_coin || approx)
367 return buf; 354 return buf;
368 355
369 coin = next_coin; 356 coin = next_coin;
370 num = cost / coin->value; 357 num = cost / coin->value;
371 cost -= num * (sint64)coin->value; 358 cost -= num * (sint64)coin->value;
372 359
373 sprintf (buf + strlen (buf), " and %d %s", num, num > 1 ? &coin->object::name_pl : &coin->object::name); 360 return format ("%s and %d %s", buf, num, num > 1 ? &coin->object::name_pl : &coin->object::name);
374
375 return buf;
376} 361}
377 362
378const char * 363const char *
379query_cost_string (const object *tmp, object *who, int flag) 364query_cost_string (const object *tmp, object *who, int flag)
380{ 365{
399 { 384 {
400 if (!idskill1 || !find_skill_by_number (who, idskill1)) 385 if (!idskill1 || !find_skill_by_number (who, idskill1))
401 { 386 {
402 if (!idskill2 || !find_skill_by_number (who, idskill2)) 387 if (!idskill2 || !find_skill_by_number (who, idskill2))
403 { 388 {
404 if (!find_skill_by_number (who, SK_BARGAINING)) 389 if (!find_skill_by_name (who, shstr_bargaining))
405 { 390 {
406 static char buf[MAX_BUF];
407 int num, cointype = 0; 391 int num, cointype = 0;
408 archetype *coin = find_next_coin (real_value, &cointype); 392 archetype *coin = find_next_coin (real_value, &cointype);
409 393
410 if (coin == NULL) 394 if (!coin)
411 return "nothing"; 395 return "nothing";
412 396
413 num = real_value / coin->value; 397 num = real_value / coin->value;
414 398
415 if (num == 1) 399 if (num == 1)
416 sprintf (buf, "about one %s", &coin->object::name); 400 return format ("about one %s", &coin->object::name);
417 else if (num < 5) 401 else if (num < 5)
418 sprintf (buf, "a few %s", &coin->object::name_pl); 402 return format ("a few %s", &coin->object::name_pl);
419 else if (num < 10) 403 else if (num < 10)
420 sprintf (buf, "several %s", &coin->object::name_pl); 404 return format ("several %s", &coin->object::name_pl);
421 else if (num < 25) 405 else if (num < 25)
422 sprintf (buf, "a moderate amount of %s", &coin->object::name_pl); 406 return format ("a moderate amount of %s", &coin->object::name_pl);
423 else if (num < 100) 407 else if (num < 100)
424 sprintf (buf, "lots of %s", &coin->object::name_pl); 408 return format ("lots of %s", &coin->object::name_pl);
425 else if (num < 1000) 409 else if (num < 1000)
426 sprintf (buf, "a great many %s", &coin->object::name_pl); 410 return format ("a great many %s", &coin->object::name_pl);
427 else 411 else
428 sprintf (buf, "a vast quantity of %s", &coin->object::name_pl); 412 return format ("a vast quantity of %s", &coin->object::name_pl);
429
430 return buf;
431 } 413 }
432 } 414 }
433 } 415 }
434 416
435 int hash = ((unsigned int) tmp->count * 174364621) & 1023;
436
437 if (approx_range) 417 if (approx_range)
438 { 418 {
419 int hash = tmp->random_seed () & 1023;
439 sint64 lo = (sint64) real_value - (approx_range * hash >> 10); 420 sint64 lo = real_value - (approx_range * hash >> 10);
440 static char buf[MAX_BUF];
441 421
442 sprintf (buf, "between %s", cost_string_from_value (lo, 1)); 422 return format ("between %s and %s",
443 sprintf (buf + strlen (buf), " and %s", cost_string_from_value (lo + approx_range, 1)); 423 cost_string_from_value (lo, 1),
444 424 cost_string_from_value (lo + approx_range, 1));
445 return buf;
446 } 425 }
447 } 426 }
448 427
449 return cost_string_from_value (real_value, 0); 428 return cost_string_from_value (real_value, 0);
450} 429}
465 } 444 }
466 445
467 for (tmp = op->inv; tmp; tmp = tmp->below) 446 for (tmp = op->inv; tmp; tmp = tmp->below)
468 if (tmp->type == MONEY) 447 if (tmp->type == MONEY)
469 total += tmp->nrof * (sint64)tmp->value; 448 total += tmp->nrof * (sint64)tmp->value;
470 else if (tmp->type == CONTAINER && QUERY_FLAG (tmp, FLAG_APPLIED) && (tmp->race == NULL || strstr (tmp->race, "gold"))) 449 else if (tmp->type == CONTAINER && tmp->flag [FLAG_APPLIED] && (!tmp->race || tmp->race.contains (shstr_gold)))
471 total += query_money (tmp); 450 total += query_money (tmp);
472 451
473 return total; 452 return total;
474} 453}
475 454
490 return 0; 469 return 0;
491 470
492 pay_from_container (pl, pl, to_pay); 471 pay_from_container (pl, pl, to_pay);
493 472
494 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 473 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"))) 474 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains (shstr_gold)))
496 pay_from_container (pl, pouch, to_pay); 475 pay_from_container (pl, pouch, to_pay);
497 476
498 pl->update_stats (); 477 pl->update_stats ();
499 return 1; 478 return 1;
500} 479}
522 * This determins the amount of exp (if any) gained for bargaining. 501 * This determins the amount of exp (if any) gained for bargaining.
523 */ 502 */
524 saved_money = query_cost (op, pl, F_BUY | F_NO_BARGAIN | F_SHOP) - to_pay; 503 saved_money = query_cost (op, pl, F_BUY | F_NO_BARGAIN | F_SHOP) - to_pay;
525 504
526 if (saved_money > 0) 505 if (saved_money > 0)
527 change_exp (pl, saved_money, "bargaining", SK_EXP_NONE); 506 change_exp (pl, saved_money, shstr_bargaining, SK_EXP_NONE);
528 507
529 pay_from_container (pl, pl, to_pay); 508 pay_from_container (pl, pl, to_pay);
530 509
531 for (pouch = pl->inv; pouch && to_pay; pouch = pouch->below) 510 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"))) 511 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && (!pouch->race || pouch->race.contains (shstr_gold)))
533 pay_from_container (pl, pouch, to_pay); 512 pay_from_container (pl, pouch, to_pay);
534 513
535 pl->update_stats (); 514 pl->update_stats ();
536 515
537 return 1; 516 return 1;
604 at = archetype::find (coins[NUM_COINS - 1 - i]); 583 at = archetype::find (coins[NUM_COINS - 1 - i]);
605 584
606 if (at == NULL) 585 if (at == NULL)
607 LOG (llevError, "Could not find %s archetype\n", coins[NUM_COINS - 1 - i]); 586 LOG (llevError, "Could not find %s archetype\n", coins[NUM_COINS - 1 - i]);
608 587
609 coin_objs[i] = arch_to_object (at); 588 coin_objs[i] = at->instance ();
610 coin_objs[i]->nrof = 0; 589 coin_objs[i]->nrof = 0;
611 } 590 }
612 591
613 for (i = 0; i < NUM_COINS; i++) 592 for (i = 0; i < NUM_COINS; i++)
614 { 593 {
615 object &coin = *coin_objs[i]; 594 object &coin = *coin_objs[i];
616 sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, coin.nrof); 595 sint64 num_coins = min ((to_pay + coin.value - 1) / coin.value, (sint64) coin.nrof);
617 to_pay -= num_coins * coin.value; 596 to_pay -= num_coins * coin.value;
618 597
619 coin.nrof -= num_coins; 598 coin.nrof -= num_coins;
620 /* Now start making change. Start at the coin value 599 /* Now start making change. Start at the coin value
621 * below the one we just did, and work down to 600 * below the one we just did, and work down to
631 count--; 610 count--;
632 } 611 }
633 } 612 }
634 613
635 for (i = 0; i < NUM_COINS; i++) 614 for (i = 0; i < NUM_COINS; i++)
636 {
637 if (coin_objs[i]->nrof) 615 if (coin_objs[i]->nrof)
638 insert_ob_in_ob (coin_objs [i], pouch); 616 insert_ob_in_ob (coin_objs [i], pouch);
639 else 617 else
640 coin_objs[i]->destroy (); 618 coin_objs[i]->destroy ();
641 }
642} 619}
643 620
644/* Checks all unpaid items in op's inventory, adds up all the money they 621/* Checks all unpaid items in op's inventory, adds up all the money they
645 * have, and checks that they can actually afford what they want to buy. 622 * have, and checks that they can actually afford what they want to buy.
646 * Returns 1 if they can, and 0 if they can't. also prints an appropriate message 623 * Returns 1 if they can, and 0 if they can't. also prints an appropriate message
647 * to the player 624 * to the player
648 */ 625 */
649int 626int
650can_pay (object *pl) 627can_pay (object *pl)
651{ 628{
658 LOG (llevError, "can_pay(): called against something that isn't a player\n"); 635 LOG (llevError, "can_pay(): called against something that isn't a player\n");
659 return 0; 636 return 0;
660 } 637 }
661 638
662 for (object::depth_iterator item = pl->begin (); item != pl->end (); ++item) 639 for (object::depth_iterator item = pl->begin (); item != pl->end (); ++item)
663 if (QUERY_FLAG (item, FLAG_UNPAID)) 640 if (item->flag [FLAG_UNPAID])
664 { 641 {
665 unpaid_count++; 642 unpaid_count++;
666 unpaid_price += query_cost (item, pl, F_BUY | F_SHOP); 643 unpaid_price += query_cost (item, pl, F_BUY | F_SHOP);
667 } 644 }
668 645
669 if (unpaid_price > player_wealth) 646 if (unpaid_price > player_wealth)
670 { 647 {
671 dynbuf_text buf; 648 dynbuf_text &buf = msg_dynbuf; buf.clear ();
672 649
673 buf << "You have " << unpaid_count 650 buf << "You have " << unpaid_count
674 << " unpaid item(s) that would cost you " << cost_string_from_value (unpaid_price, 0) 651 << " unpaid item(s) that would cost you " << cost_string_from_value (unpaid_price, 0)
675 << ". You need another " << cost_string_from_value (unpaid_price - player_wealth, 0) 652 << ". You need another " << cost_string_from_value (unpaid_price - player_wealth, 0)
676 << " to be able to afford that."; 653 << " to be able to afford that. "
654 "H<You cannot leave a shop without paying - drop unpaid items first to be able to leave.>";
677 655
678 pl->failmsg (buf); 656 pl->failmsg (buf);
679 657
680 return 0; 658 return 0;
681 } 659 }
696 { 674 {
697 next_item: 675 next_item:
698 676
699 for (object::depth_iterator op = pl->begin (); op != pl->end (); ++op) 677 for (object::depth_iterator op = pl->begin (); op != pl->end (); ++op)
700 { 678 {
701 if (QUERY_FLAG (op, FLAG_UNPAID)) 679 if (op->flag [FLAG_UNPAID])
702 { 680 {
703 char buf[MAX_BUF];
704 snprintf (buf, MAX_BUF, "%s", query_cost_string (op, pl, F_BUY | F_SHOP)); 681 const char *buf = query_cost_string (op, pl, F_BUY | F_SHOP);
705 682
706 if (!pay_for_item (op, pl)) 683 if (!pay_for_item (op, pl))
707 { 684 {
708 sint64 i = query_cost (op, pl, F_BUY | F_SHOP) - query_money (pl); 685 sint64 i = query_cost (op, pl, F_BUY | F_SHOP) - query_money (pl);
709 686
710 CLEAR_FLAG (op, FLAG_UNPAID); 687 op->clr_flag (FLAG_UNPAID);
711 new_draw_info_format (NDI_UNIQUE, 0, pl, "You lack %s to buy %s.", cost_string_from_value (i, 0), query_name (op)); 688 new_draw_info_format (NDI_UNIQUE, 0, pl, "You lack %s to buy %s.", cost_string_from_value (i, 0), query_name (op));
712 SET_FLAG (op, FLAG_UNPAID); 689 op->set_flag (FLAG_UNPAID);
713 return 0; 690 return 0;
714 } 691 }
715 else 692 else
716 { 693 {
717 CLEAR_FLAG (op, FLAG_UNPAID); 694 op->clr_flag (FLAG_UNPAID);
718 CLEAR_FLAG (op, FLAG_PLAYER_SOLD); 695 op->clr_flag (FLAG_PLAYER_SOLD);
719 new_draw_info_format (NDI_UNIQUE, 0, op, "You paid %s for %s.", buf, query_name (op)); 696 new_draw_info_format (NDI_UNIQUE, 0, pl, "You paid %s for %s.", buf, query_name (op));
720 697
721 if (!merge_ob (op, op->env->inv)) 698 if (!merge_ob (op, op->env->inv))
722 esrv_update_item (UPD_FLAGS, pl, op); 699 esrv_update_item (UPD_FLAGS, pl, op);
723 700
724 goto next_item; 701 goto next_item;
744void 721void
745pay_player (object *pl, sint64 amount) 722pay_player (object *pl, sint64 amount)
746{ 723{
747 int count = 0; 724 int count = 0;
748 archetype *at = 0; 725 archetype *at = 0;
749 object *pouch = 0, *tmp = 0; 726 object *pouch = 0;
750 727
751 for (count = 0; coins[count]; count++) 728 for (count = 0; coins[count]; count++)
752 { 729 {
753 at = archetype::find (coins[count]); 730 at = archetype::find (coins[count]);
754 731
756 LOG (llevError, "Could not find %s archetype\n", coins[count]); 733 LOG (llevError, "Could not find %s archetype\n", coins[count]);
757 else if ((amount / at->value) > 0) 734 else if ((amount / at->value) > 0)
758 { 735 {
759 for (pouch = pl->inv; pouch; pouch = pouch->below) 736 for (pouch = pl->inv; pouch; pouch = pouch->below)
760 { 737 {
761 if (pouch->type == CONTAINER && QUERY_FLAG (pouch, FLAG_APPLIED) && pouch->race && strstr (pouch->race, "gold")) 738 if (pouch->type == CONTAINER && pouch->flag [FLAG_APPLIED] && pouch->race.contains (shstr_gold))
762 { 739 {
763 int w = at->weight * (100 - pouch->stats.Str) / 100; 740 int w = at->weight * (100 - pouch->stats.Str) / 100;
764 int n = amount / at->value; 741 int n = amount / at->value;
765 742
766 if (w == 0) 743 if (w == 0)
769 if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit)) 746 if (n > 0 && (!pouch->weight_limit || pouch->carrying + w <= pouch->weight_limit))
770 { 747 {
771 if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n) 748 if (pouch->weight_limit && (pouch->weight_limit - pouch->carrying) / w < n)
772 n = (pouch->weight_limit - pouch->carrying) / w; 749 n = (pouch->weight_limit - pouch->carrying) / w;
773 750
774 object *tmp = arch_to_object (at); 751 object *tmp = at->instance ();
775 tmp->nrof = n; 752 tmp->nrof = n;
776 amount -= tmp->nrof * tmp->value; 753 amount -= tmp->nrof * tmp->value;
777 pouch->insert (tmp); 754 pouch->insert (tmp);
778 } 755 }
779 } 756 }
780 } 757 }
781 758
782 if (amount / at->value > 0) 759 if (amount / at->value > 0)
783 { 760 {
784 object *tmp = arch_to_object (at); 761 object *tmp = at->instance ();
785 tmp->nrof = amount / tmp->value; 762 tmp->nrof = amount / tmp->value;
786 amount -= tmp->nrof * tmp->value; 763 amount -= tmp->nrof * tmp->value;
787 pl->insert (tmp); 764 pl->insert (tmp);
788 } 765 }
789 } 766 }
846 * exp/10 -> 1 for each gold coin 823 * exp/10 -> 1 for each gold coin
847 */ 824 */
848 extra_gain = amount - query_cost (op, pl, F_SELL | F_NO_BARGAIN | F_SHOP); 825 extra_gain = amount - query_cost (op, pl, F_SELL | F_NO_BARGAIN | F_SHOP);
849 826
850 if (extra_gain > 0) 827 if (extra_gain > 0)
851 change_exp (pl, extra_gain / 10, "bargaining", SK_EXP_NONE); 828 change_exp (pl, extra_gain / 10, shstr_bargaining, SK_EXP_NONE);
852 829
853 pay_player (pl, amount); 830 pay_player (pl, amount);
854 831
855 new_draw_info_format (NDI_UNIQUE, 0, pl, "You receive %s for %s.", 832 new_draw_info_format (NDI_UNIQUE, 0, pl, "You receive %s for %s.",
856 query_cost_string (op, pl, F_SELL | F_SHOP), query_name (op)); 833 query_cost_string (op, pl, F_SELL | F_SHOP), query_name (op));
857 pl->play_sound (sound_find ("shop_sell")); 834 pl->play_sound (sound_find ("shop_sell"));
858 835
859 SET_FLAG (op, FLAG_UNPAID); 836 op->set_flag (FLAG_UNPAID);
860 identify (op); 837 identify (op);
861 838
862 return true; 839 return true;
863} 840}
864 841
865/* returns a double that is the ratio of the price that a shop will offer for 842/* returns a double that is the ratio of the price that a shop will offer for
866 * item based on the shops specialisation. Does not take account of greed, 843 * item based on the shops specialisation. Does not take account of greed,
867 * returned value is between SPECIALISATION_EFFECT and 1. 844 * returned value is between SPECIALISATION_EFFECT and 1.
868 */ 845 */
869static double 846static double
870shop_specialisation_ratio (const object *item, const maptile *map) 847shop_specialisation_ratio (const object *item, const maptile *map)
871{ 848{
872 shopitems *items = map->shopitems; 849 shopitems *items = map->shopitems;
873 double likedness = 0.; 850 int likedness = 0;
874 int i; 851 int i;
875 852
876 if (item == NULL) 853 if (item == NULL)
877 { 854 {
878 LOG (llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", &map->path); 855 LOG (llevError, "shop_specialisation_ratio: passed a NULL item for map %s\n", &map->path);
879 return 0; 856 return 0;
880 } 857 }
881 858
882 if (!item->type) 859 if (!item->type)
883 { 860 {
884 LOG (llevError, "shop_specialisation_ratio: passed an item with an invalid type\n"); 861 LOG (llevError, "shop_specialisation_ratio: passed an item with an invalid type: %s\n", item->debug_desc ());
885 /* 862 /*
886 * I'm not really sure what the /right/ thing to do here is, these types of 863 * I'm not really sure what the /right/ thing to do here is, these types of
887 * item shouldn't exist anyway, but returning the ratio is probably the best bet.." 864 * item shouldn't exist anyway, but returning the ratio is probably the best bet.."
888 */ 865 */
889 return SPECIALISATION_EFFECT; 866 return SPECIALISATION_EFFECT;
890 } 867 }
891 868
892 if (map->shopitems) 869 if (map->shopitems)
893 {
894 for (i = 0; i < items[0].index; i++) 870 for (i = 0; i < items[0].index; i++)
895 if (items[i].typenum == item->type || (!items[i].typenum && likedness == 0.001)) 871 if (items[i].typenum == item->type || (!items[i].typenum && !likedness))
896 likedness = items[i].strength / 100.0; 872 likedness = items[i].strength;
897 }
898 873
899 if (likedness > 1.0) 874 if (likedness > 100)
900 { /* someone has been rather silly with the map headers. */ 875 { /* someone has been rather silly with the map headers. */
901 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is above 100%%\n", item->type, &map->path); 876 LOG (llevDebug, "shop_specialisation ratio: item %s on map %s is above 100%%\n", item->debug_desc (), &map->path);
902 likedness = 1.0; 877 likedness = 100;
903 } 878 }
904 879
905 if (likedness < -1.0) 880 if (likedness < -100)
906 { 881 {
907 LOG (llevDebug, "shop_specialisation ratio: item type %d on map %s is below -100%%\n", item->type, &map->path); 882 LOG (llevDebug, "shop_specialisation ratio: item %s on map %s is below -100%%\n", item->debug_desc (), &map->path);
908 likedness = -1.0; 883 likedness = -100;
909 } 884 }
910 885
911 return lerp (likedness, -1., 1., SPECIALISATION_EFFECT, 1.); 886 return lerp (double (likedness), -100., 100., SPECIALISATION_EFFECT, 1.);
912} 887}
913 888
914/*returns the greed of the shop on map, or 1 if it isn't specified. */ 889/*returns the greed of the shop on map, or 1 if it isn't specified. */
915static double 890static double
916shop_greed (const maptile *map) 891shop_greed (const maptile *map)
930 ? DISLIKE_RATIO 905 ? DISLIKE_RATIO
931 : 1.; 906 : 1.;
932} 907}
933 908
934/* limit the value of items based on the wealth of the shop. If the item is close 909/* limit the value of items based on the wealth of the shop. If the item is close
935 * to the maximum value a shop will offer, we start to reduce it, if the item is 910 * to the maximum value a shop will offer, we start to reduce it, if the item is
936 * below the minimum value the shop is prepared to trade in, then we don't 911 * below the minimum value the shop is prepared to trade in, then we don't
937 * want it and offer nothing. If it isn't a shop, check whether we should do generic 912 * want it and offer nothing. If it isn't a shop, check whether we should do generic
938 * value reduction. 913 * value reduction.
939 * 914 *
940 */ 915 */
941static sint64 916static sint64
942value_limit (sint64 val, int quantity, const object *who, int isshop) 917value_limit (sint64 val, int quantity, const object *who, int isshop)
943{ 918{
944 sint64 newval, unit_price, tmpshopmax; 919 sint64 newval, unit_price, tmpshopmax;
966 tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default 941 tmpshopmax = map->shopmax ? map->shopmax : 100000; // 20 royalties default
967 942
968 if (map->shopmin && unit_price < map->shopmin) 943 if (map->shopmin && unit_price < map->shopmin)
969 return 0; 944 return 0;
970 else if (unit_price > tmpshopmax / 2) 945 else if (unit_price > tmpshopmax / 2)
971 newval = MIN ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax); 946 newval = min ((tmpshopmax / 2) + isqrt (unit_price - tmpshopmax / 2), tmpshopmax);
972 else 947 else
973 newval = unit_price; 948 newval = unit_price;
974 } 949 }
975 950
976 newval *= quantity; 951 newval *= quantity;
980 955
981/* gives a desciption of the shop on their current map to the player op. */ 956/* gives a desciption of the shop on their current map to the player op. */
982int 957int
983describe_shop (const object *op) 958describe_shop (const object *op)
984{ 959{
960 dynbuf_text buf;
985 maptile *map = op->map; 961 maptile *map = op->map;
986 962
987 /*shopitems *items=map->shopitems; */ 963 /*shopitems *items=map->shopitems; */
988 int pos = 0, i; 964 int i;
989 double opinion = 0; 965 double opinion = 0;
990 char tmp[MAX_BUF] = "\0";
991 966
992 if (op->type != PLAYER) 967 if (op->type != PLAYER)
993 return 0; 968 return 0;
994 969
995 /*check if there is a shop specified for this map */ 970 /*check if there is a shop specified for this map */
996 if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax) 971 if (map->shopitems || map->shopgreed || map->shoprace || map->shopmin || map->shopmax)
997 { 972 {
998 new_draw_info (NDI_UNIQUE, 0, op, "From looking at the nearby shop you determine that it trades in:"); 973 buf << "From looking at the nearby shop you determine that it trades in ";
974 int lastcomma = 0, prevcomma = 0;
999 975
1000 if (map->shopitems) 976 if (map->shopitems)
1001 for (i = 0; i < map->shopitems[0].index; i++) 977 for (i = 0; i < map->shopitems[0].index; i++)
1002 if (map->shopitems[i].name && map->shopitems[i].strength > 10) 978 if (map->shopitems[i].name && map->shopitems[i].strength > 10)
1003 { 979 {
1004 snprintf (tmp + pos, sizeof (tmp) - pos, "%s, ", map->shopitems[i].name_pl); 980 buf << map->shopitems[i].name_pl;
1005 pos += strlen (tmp + pos); 981 prevcomma = lastcomma;
982 lastcomma = buf.size (); // remember offset
983 buf << ", ";
1006 } 984 }
1007 985
1008 if (!pos) 986 if (lastcomma)
987 {
988 buf.splice (lastcomma, 2);
989
990 if (prevcomma)
991 buf.splice (prevcomma, 2, " and ");
992 }
993 else
1009 strcat (tmp, "a little of everything."); 994 buf << "a little of everything.";
1010 995
1011 /* format the string into a list */ 996 buf << ".\n\n";
1012 make_list_like (tmp);
1013 new_draw_info_format (NDI_UNIQUE, 0, op, "%s", tmp);
1014 997
1015 if (map->shopmax) 998 if (map->shopmax)
1016 new_draw_info_format (NDI_UNIQUE, 0, op, "It won't trade for items above %s.", cost_string_from_value (map->shopmax, 0)); 999 buf << "It won't trade for items above " << cost_string_from_value (map->shopmax, 0) << ".\n\n";
1017 1000
1018 if (map->shopmin) 1001 if (map->shopmin)
1019 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)); 1002 buf << "It won't trade in items worth less than " << cost_string_from_value (map->shopmin, 0) << ".\n\n";
1020 1003
1021 if (map->shopgreed) 1004 if (map->shopgreed)
1022 { 1005 {
1023 if (map->shopgreed > 2.0) 1006 if (map->shopgreed > 2.0)
1024 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge massively."); 1007 buf << "It tends to overcharge massively.\n\n";
1025 else if (map->shopgreed > 1.5) 1008 else if (map->shopgreed > 1.5)
1026 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge substantially."); 1009 buf << "It tends to overcharge substantially.\n\n";
1027 else if (map->shopgreed > 1.1) 1010 else if (map->shopgreed > 1.1)
1028 new_draw_info (NDI_UNIQUE, 0, op, "It tends to overcharge slightly."); 1011 buf << "It tends to overcharge slightly.\n\n";
1029 else if (map->shopgreed < 0.9) 1012 else if (map->shopgreed < 0.9)
1030 new_draw_info (NDI_UNIQUE, 0, op, "It tends to undercharge."); 1013 buf << "It tends to undercharge.\n\n";
1031 } 1014 }
1032 1015
1033 if (map->shoprace) 1016 if (map->shoprace)
1034 { 1017 {
1035 opinion = shopkeeper_approval (map, op); 1018 opinion = shopkeeper_approval (map, op);
1019
1036 if (opinion > 0.8) 1020 if (opinion > 0.8)
1037 new_draw_info (NDI_UNIQUE, 0, op, "You think the shopkeeper likes you."); 1021 buf << "You think the shopkeeper likes you.\n\n";
1038 else if (opinion > 0.5) 1022 else if (opinion > 0.5)
1039 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems unconcerned by you."); 1023 buf << "The shopkeeper seems unconcerned by you.\n\n";
1040 else 1024 else
1041 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper seems to have taken a dislike to you."); 1025 buf << "The shopkeeper seems to have taken a dislike to you.\n\n";
1042 } 1026 }
1043 } 1027 }
1044 else 1028 else
1045 new_draw_info (NDI_UNIQUE, 0, op, "There is no shop nearby."); 1029 buf << "There is no shop nearby.\n\n";
1030
1031 op->contr->infobox (MSG_CHANNEL ("shopinfo"), buf);
1046 1032
1047 return 1; 1033 return 1;
1048} 1034}
1049 1035
1050struct shopinv 1036struct shopinv
1051{ 1037{
1052 char *item_sort; 1038 char *item_sort;
1053 char *item_real; 1039 char *item_real;
1040 sint64 value;
1054 uint16 type; 1041 uint16 type;
1055 uint32 nrof; 1042 uint32 nrof;
1056}; 1043};
1057 1044
1058/* There are a lot fo extra casts in here just to suppress warnings - it 1045/* There are a lot fo extra casts in here just to suppress warnings - it
1078} 1065}
1079 1066
1080static void 1067static void
1081add_shop_item (object *tmp, shopinv * items, int *numitems, int *numallocated) 1068add_shop_item (object *tmp, shopinv * items, int *numitems, int *numallocated)
1082{ 1069{
1083#if 0
1084 char buf[MAX_BUF];
1085#endif
1086 /* clear unpaid flag so that doesn't come up in query 1070 /* clear unpaid flag so that doesn't come up in query
1087 * string. We clear nrof so that we can better sort 1071 * string. We clear nrof so that we can better sort
1088 * the object names. 1072 * the object names.
1089 */ 1073 */
1090 1074
1091 CLEAR_FLAG (tmp, FLAG_UNPAID); 1075 tmp->clr_flag (FLAG_UNPAID);
1092 items[*numitems].nrof = tmp->nrof; 1076 items[*numitems].nrof = tmp->nrof;
1093 /* Non mergable items have nrof of 0, but count them as one 1077 /* Non mergable items have nrof of 0, but count them as one
1094 * so the display is properly. 1078 * so the display is properly.
1095 */ 1079 */
1096 if (tmp->nrof == 0) 1080 if (tmp->nrof == 0)
1097 items[*numitems].nrof++; 1081 items[*numitems].nrof++;
1098 items[*numitems].type = tmp->type; 1082 items[*numitems].type = tmp->type;
1083
1084 items[*numitems].value = tmp->value;
1099 1085
1100 switch (tmp->type) 1086 switch (tmp->type)
1101 { 1087 {
1102#if 0 1088#if 0
1103 case BOOTS: 1089 case BOOTS:
1115#endif 1101#endif
1116 1102
1117 default: 1103 default:
1118 items[*numitems].item_sort = strdup (query_base_name (tmp, 0)); 1104 items[*numitems].item_sort = strdup (query_base_name (tmp, 0));
1119 items[*numitems].item_real = strdup (query_base_name (tmp, 1)); 1105 items[*numitems].item_real = strdup (query_base_name (tmp, 1));
1106 items[*numitems].value += tmp->value;
1120 (*numitems)++; 1107 (*numitems)++;
1121 break; 1108 break;
1122 } 1109 }
1123 SET_FLAG (tmp, FLAG_UNPAID); 1110
1111 tmp->set_flag (FLAG_UNPAID);
1124} 1112}
1125 1113
1126void 1114void
1127shop_listing (object *sign, object *op) 1115shop_listing (object *sign, object *op)
1128{ 1116{
1129 int i, j, numitems = 0, numallocated = 0, x1, x2, y1, y2; 1117 int i, j, x1, x2, y1, y2;
1130 const char *shop_coords = sign->kv (shstr_shop_coords); 1118 const char *shop_coords = sign->kv [shstr_shop_coords];
1131 object *stack; 1119 object *stack;
1132 shopinv *items; 1120 shopinv *items;
1133 1121
1134 /* Should never happen, but just in case a monster does apply a sign */ 1122 /* Should never happen, but just in case a monster does apply a sign */
1135 if (op->type != PLAYER) 1123 if (!op->is_player ())
1136 return; 1124 return;
1125
1126 dynbuf_text &buf = msg_dynbuf; buf.clear ();
1137 1127
1138 if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2))) 1128 if (!(shop_coords && sscanf (shop_coords, "%d,%d,%d,%d", &x1, &y1, &x2, &y2)))
1139 { 1129 {
1140 x1 = 0; 1130 x1 = 0;
1141 y1 = 0; 1131 y1 = 0;
1142 x2 = op->map->width - 1; 1132 x2 = op->map->width - 1;
1143 y2 = op->map->height - 1; 1133 y2 = op->map->height - 1;
1144 } 1134 }
1145 1135
1146 items = (shopinv *) malloc (40 * sizeof (shopinv));
1147 numallocated = 40; 1136 int numallocated = 40;
1137 int numitems = 0;
1138 items = (shopinv *)malloc (sizeof (shopinv) * numallocated);
1148 1139
1149 /* Find all the appropriate items */ 1140 /* Find all the appropriate items */
1150 for (i = x1; i <= x2; i++) 1141 for (i = x1; i <= x2; i++)
1151 {
1152 for (j = y1; j < y2; j++) 1142 for (j = y1; j < y2; j++)
1143 if (op->map->is_in_shop (i, j))
1153 { 1144 {
1154 if (is_in_shop (op->map, i, j)) 1145 stack = GET_MAP_OB (op->map, i, j);
1146
1147 while (stack)
1155 { 1148 {
1156 stack = GET_MAP_OB (op->map, i, j); 1149 if (stack->flag [FLAG_UNPAID])
1157
1158 while (stack)
1159 { 1150 {
1160 if (QUERY_FLAG (stack, FLAG_UNPAID))
1161 {
1162 if (numitems == numallocated) 1151 if (numitems == numallocated)
1163 {
1164 items = (shopinv *) realloc (items, sizeof (shopinv) * (numallocated + 10)); 1152 items = (shopinv *)realloc (items, sizeof (shopinv) * (numallocated *= 2));
1165 numallocated += 10;
1166 }
1167 1153
1168 add_shop_item (stack, items, &numitems, &numallocated); 1154 add_shop_item (stack, items, &numitems, &numallocated);
1169 }
1170
1171 stack = stack->above;
1172 } 1155 }
1156
1157 stack = stack->above;
1173 } 1158 }
1174 } 1159 }
1175 }
1176 1160
1177 if (numitems == 0) 1161 buf << (numitems ? "T<This shop contains:>\n\n"
1178 { 1162 : "T<This shop is currently empty.>");
1179 new_draw_info (NDI_UNIQUE, 0, op, "The shop is currently empty.\n");
1180 free (items);
1181 return;
1182 }
1183 1163
1184 qsort (items, numitems, sizeof (shopinv), (int (*)(const void *, const void *)) shop_sort); 1164 qsort (items, numitems, sizeof (shopinv), (int (*)(const void *, const void *)) shop_sort);
1185
1186 new_draw_info (NDI_UNIQUE, 0, op, "\nThe shop contains:");
1187 1165
1188 for (i = 0; i < numitems; i++) 1166 for (i = 0; i < numitems; i++)
1189 { 1167 {
1190 /* Collapse items of the same name together */ 1168 /* Collapse items of the same name together */
1191 if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real)) 1169 if ((i + 1) < numitems && !strcmp (items[i].item_real, items[i + 1].item_real))
1192 {
1193 items[i + 1].nrof += items[i].nrof; 1170 items[i + 1].nrof += items[i].nrof;
1194 free (items[i].item_sort);
1195 free (items[i].item_real);
1196 }
1197 else 1171 else
1198 { 1172 {
1199 new_draw_info_format (NDI_UNIQUE, 0, op, "%d %s", 1173 buf.printf (
1200 items[i].nrof ? items[i].nrof : 1, items[i].nrof == 1 ? items[i].item_sort : items[i].item_real); 1174 " %4d %s\n for %s\n",
1175 items[i].nrof ? items[i].nrof : 1,
1176 items[i].nrof == 1 ? items[i].item_sort : items[i].item_real,
1177 cost_string_from_value (items[i].value, op->flag [FLAG_WIZ] ? 0 : 1));
1178 }
1179
1201 free (items[i].item_sort); 1180 free (items[i].item_sort);
1202 free (items[i].item_real); 1181 free (items[i].item_real);
1203 }
1204 } 1182 }
1183
1184 op->contr->infobox (MSG_CHANNEL ("shopitems"), buf);
1205 1185
1206 free (items); 1186 free (items);
1207}
1208
1209/* elmex: this function checks whether the object is in a shop */
1210bool
1211is_in_shop (object *o)
1212{
1213 if (!o->is_on_map ())
1214 return false;
1215
1216 return is_in_shop (o->map, o->x, o->y);
1217} 1187}
1218 1188
1219/* elmex: this function checks whether we are in a shop or not 1189/* elmex: this function checks whether we are in a shop or not
1220 - change 2007-11-26: enhanced the O(n) case by stopping at the first 1190 - change 2007-11-26: enhanced the O(n) case by stopping at the first
1221 floor tile. this possibly will make map bugs where shopfloors are above 1191 floor tile. this possibly will make map bugs where shopfloors are above
1222 floors more obvious. 1192 floors more obvious.
1223*/ 1193*/
1224
1225bool 1194bool
1226is_in_shop (maptile *map, int x, int y) 1195maptile::is_in_shop (int x, int y) const
1227{ 1196{
1228 for (object *floor = GET_MAP_OB (map, x, y); floor; floor = floor->above) 1197 for (object *floor = at (x, y).bot; floor; floor = floor->above)
1229 if (QUERY_FLAG (floor, FLAG_IS_FLOOR)) 1198 if (floor->flag [FLAG_IS_FLOOR])
1230 return floor->type == SHOP_FLOOR; 1199 return floor->type == SHOP_FLOOR;
1231 1200
1232 return false; 1201 return false;
1233} 1202}
1234 1203

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines