1 /* source/store1.c: store code, updating store inventory, pricing objects
2
3 Copyright (c) 1989-94 James E. Wilson, Robert A. Koeneke
4
5 This software may be copied and distributed for educational, research, and
6 not for profit purposes provided that this copyright and statement are
7 included in all such copies. */
8
9 #include "config.h"
10 #include "constant.h"
11 #include "types.h"
12 #include "externs.h"
13
14 #ifdef USG
15 #ifndef ATARIST_MWC
16 #include <string.h>
17 #endif
18 #else
19 #include <strings.h>
20 #endif
21
22 #if defined(LINT_ARGS)
23 static void insert_store(int, int, int32, struct inven_type *);
24 static void store_create(int);
25 #else
26 static void insert_store();
27 static void store_create();
28 #endif
29
30
31 /* Returns the value for any given object -RAK- */
item_value(i_ptr)32 int32 item_value(i_ptr)
33 register inven_type *i_ptr;
34 {
35 register int32 value;
36
37 value = i_ptr->cost;
38 /* don't purchase known cursed items */
39 if (i_ptr->ident & ID_DAMD)
40 value = 0;
41 else if (((i_ptr->tval >= TV_BOW) && (i_ptr->tval <= TV_SWORD)) ||
42 ((i_ptr->tval >= TV_BOOTS) && (i_ptr->tval <= TV_SOFT_ARMOR)))
43 { /* Weapons and armor */
44 if (!known2_p(i_ptr))
45 value = object_list[i_ptr->index].cost;
46 else if ((i_ptr->tval >= TV_BOW) && (i_ptr->tval <= TV_SWORD))
47 {
48 if (i_ptr->tohit < 0)
49 value = 0;
50 else if (i_ptr->todam < 0)
51 value = 0;
52 else if (i_ptr->toac < 0)
53 value = 0;
54 else
55 value = i_ptr->cost+(i_ptr->tohit+i_ptr->todam+i_ptr->toac)*100;
56 }
57 else
58 {
59 if (i_ptr->toac < 0)
60 value = 0;
61 else
62 value = i_ptr->cost+i_ptr->toac*100;
63 }
64 }
65 else if ((i_ptr->tval >= TV_SLING_AMMO) && (i_ptr->tval <= TV_SPIKE))
66 { /* Ammo */
67 if (!known2_p(i_ptr))
68 value = object_list[i_ptr->index].cost;
69 else
70 {
71 if (i_ptr->tohit < 0)
72 value = 0;
73 else if (i_ptr->todam < 0)
74 value = 0;
75 else if (i_ptr->toac < 0)
76 value = 0;
77 else
78 /* use 5, because missiles generally appear in groups of 20,
79 so 20 * 5 == 100, which is comparable to weapon bonus above */
80 value = i_ptr->cost+(i_ptr->tohit+i_ptr->todam+i_ptr->toac)*5;
81 }
82 }
83 else if ((i_ptr->tval == TV_SCROLL1) || (i_ptr->tval == TV_SCROLL2) ||
84 (i_ptr->tval == TV_POTION1) || (i_ptr->tval == TV_POTION2))
85 { /* Potions, Scrolls, and Food */
86 if (!known1_p(i_ptr))
87 value = 20;
88 }
89 else if (i_ptr->tval == TV_FOOD)
90 {
91 if ((i_ptr->subval < (ITEM_SINGLE_STACK_MIN + MAX_MUSH))
92 && !known1_p(i_ptr))
93 value = 1;
94 }
95 else if ((i_ptr->tval == TV_AMULET) || (i_ptr->tval == TV_RING))
96 { /* Rings and amulets */
97 if (!known1_p(i_ptr))
98 /* player does not know what type of ring/amulet this is */
99 value = 45;
100 else if (!known2_p(i_ptr))
101 /* player knows what type of ring, but does not know whether it is
102 cursed or not, if refuse to buy cursed objects here, then
103 player can use this to 'identify' cursed objects */
104 value = object_list[i_ptr->index].cost;
105 }
106 else if ((i_ptr->tval == TV_STAFF) || (i_ptr->tval == TV_WAND))
107 { /* Wands and staffs*/
108 if (!known1_p(i_ptr))
109 {
110 if (i_ptr->tval == TV_WAND)
111 value = 50;
112 else
113 value = 70;
114 }
115 else if (known2_p(i_ptr))
116 value = i_ptr->cost + (i_ptr->cost / 20) * i_ptr->p1;
117 }
118 /* picks and shovels */
119 else if (i_ptr->tval == TV_DIGGING)
120 {
121 if (!known2_p(i_ptr))
122 value = object_list[i_ptr->index].cost;
123 else
124 {
125 if (i_ptr->p1 < 0)
126 value = 0;
127 else
128 {
129 /* some digging tools start with non-zero p1 values, so only
130 multiply the plusses by 100, make sure result is positive */
131 value = i_ptr->cost
132 + (i_ptr->p1 - object_list[i_ptr->index].p1) * 100;
133 if (value < 0)
134 value = 0;
135 }
136 }
137 }
138 /* multiply value by number of items if it is a group stack item */
139 if (i_ptr->subval > ITEM_GROUP_MIN) /* do not include torches here */
140 value = value * i_ptr->number;
141 return(value);
142 }
143
144
145 /* Asking price for an item -RAK- */
sell_price(snum,max_sell,min_sell,item)146 int32 sell_price(snum, max_sell, min_sell, item)
147 int snum;
148 int32 *max_sell, *min_sell;
149 inven_type *item;
150 {
151 register int32 i;
152 register store_type *s_ptr;
153
154 s_ptr = &store[snum];
155 i = item_value(item);
156 /* check item->cost in case it is cursed, check i in case it is damaged */
157 if ((item->cost > 0) && (i > 0))
158 {
159 i = i * rgold_adj[owners[s_ptr->owner].owner_race][py.misc.prace] / 100;
160 if (i < 1) i = 1;
161 *max_sell = i * owners[s_ptr->owner].max_inflate / 100;
162 *min_sell = i * owners[s_ptr->owner].min_inflate / 100;
163 if (*min_sell > *max_sell) *min_sell = *max_sell;
164 return(i);
165 }
166 else
167 /* don't let the item get into the store inventory */
168 return(0);
169 }
170
171
172 /* Check to see if he will be carrying too many objects -RAK- */
store_check_num(t_ptr,store_num)173 int store_check_num(t_ptr, store_num)
174 inven_type *t_ptr;
175 int store_num;
176 {
177 register int store_check, i;
178 register store_type *s_ptr;
179 register inven_type *i_ptr;
180
181 store_check = FALSE;
182 s_ptr = &store[store_num];
183 if (s_ptr->store_ctr < STORE_INVEN_MAX)
184 store_check = TRUE;
185 else if (t_ptr->subval >= ITEM_SINGLE_STACK_MIN)
186 for (i = 0; i < s_ptr->store_ctr; i++)
187 {
188 i_ptr = &s_ptr->store_inven[i].sitem;
189 /* note: items with subval of gte ITEM_SINGLE_STACK_MAX only stack
190 if their subvals match */
191 if (i_ptr->tval == t_ptr->tval && i_ptr->subval == t_ptr->subval
192 && ((int)i_ptr->number + (int)t_ptr->number < 256)
193 && (t_ptr->subval < ITEM_GROUP_MIN
194 || (i_ptr->p1 == t_ptr->p1)))
195 store_check = TRUE;
196 }
197 return(store_check);
198 }
199
200
201 /* Insert INVEN_MAX at given location */
insert_store(store_num,pos,icost,i_ptr)202 static void insert_store(store_num, pos, icost, i_ptr)
203 register int pos;
204 int store_num;
205 int32 icost;
206 inven_type *i_ptr;
207 {
208 register int i;
209 register store_type *s_ptr;
210
211 s_ptr = &store[store_num];
212 for (i = s_ptr->store_ctr-1; i >= pos; i--)
213 s_ptr->store_inven[i+1] = s_ptr->store_inven[i];
214 s_ptr->store_inven[pos].sitem = *i_ptr;
215 s_ptr->store_inven[pos].scost = -icost;
216 s_ptr->store_ctr++;
217 }
218
219
220 /* Add the item in INVEN_MAX to stores inventory. -RAK- */
store_carry(store_num,ipos,t_ptr)221 void store_carry(store_num, ipos, t_ptr)
222 int store_num;
223 int *ipos;
224 inven_type *t_ptr;
225 {
226 int item_num, item_val, flag;
227 register int typ, subt;
228 int32 icost, dummy;
229 register inven_type *i_ptr;
230 register store_type *s_ptr;
231
232 *ipos = -1;
233 if (sell_price(store_num, &icost, &dummy, t_ptr) > 0)
234 {
235 s_ptr = &store[store_num];
236 item_val = 0;
237 item_num = t_ptr->number;
238 flag = FALSE;
239 typ = t_ptr->tval;
240 subt = t_ptr->subval;
241 do
242 {
243 i_ptr = &s_ptr->store_inven[item_val].sitem;
244 if (typ == i_ptr->tval)
245 {
246 if (subt == i_ptr->subval && /* Adds to other item */
247 subt >= ITEM_SINGLE_STACK_MIN
248 && (subt < ITEM_GROUP_MIN || i_ptr->p1 == t_ptr->p1))
249 {
250 *ipos = item_val;
251 i_ptr->number += item_num;
252 /* must set new scost for group items, do this only for items
253 strictly greater than group_min, not for torches, this
254 must be recalculated for entire group */
255 if (subt > ITEM_GROUP_MIN)
256 {
257 (void) sell_price (store_num, &icost, &dummy, i_ptr);
258 s_ptr->store_inven[item_val].scost = -icost;
259 }
260 /* must let group objects (except torches) stack over 24
261 since there may be more than 24 in the group */
262 else if (i_ptr->number > 24)
263 i_ptr->number = 24;
264 flag = TRUE;
265 }
266 }
267 else if (typ > i_ptr->tval)
268 { /* Insert into list */
269 insert_store(store_num, item_val, icost, t_ptr);
270 flag = TRUE;
271 *ipos = item_val;
272 }
273 item_val++;
274 }
275 while ((item_val < s_ptr->store_ctr) && (!flag));
276 if (!flag) /* Becomes last item in list */
277 {
278 insert_store(store_num, (int)s_ptr->store_ctr, icost, t_ptr);
279 *ipos = s_ptr->store_ctr - 1;
280 }
281 }
282 }
283
284 /* Destroy an item in the stores inventory. Note that if */
285 /* "one_of" is false, an entire slot is destroyed -RAK- */
store_destroy(store_num,item_val,one_of)286 void store_destroy(store_num, item_val, one_of)
287 int store_num, item_val;
288 int one_of;
289 {
290 register int j, number;
291 register store_type *s_ptr;
292 register inven_type *i_ptr;
293
294 s_ptr = &store[store_num];
295 i_ptr = &s_ptr->store_inven[item_val].sitem;
296
297 /* for single stackable objects, only destroy one half on average,
298 this will help ensure that general store and alchemist have
299 reasonable selection of objects */
300 if ((i_ptr->subval >= ITEM_SINGLE_STACK_MIN) &&
301 (i_ptr->subval <= ITEM_SINGLE_STACK_MAX))
302 {
303 if (one_of)
304 number = 1;
305 else
306 number = randint((int)i_ptr->number);
307 }
308 else
309 number = i_ptr->number;
310
311 if (number != i_ptr->number)
312 i_ptr->number -= number;
313 else
314 {
315 for (j = item_val; j < s_ptr->store_ctr-1; j++)
316 s_ptr->store_inven[j] = s_ptr->store_inven[j+1];
317 invcopy(&s_ptr->store_inven[s_ptr->store_ctr-1].sitem, OBJ_NOTHING);
318 s_ptr->store_inven[s_ptr->store_ctr-1].scost = 0;
319 s_ptr->store_ctr--;
320 }
321 }
322
323
324 /* Initializes the stores with owners -RAK- */
store_init()325 void store_init()
326 {
327 register int i, j, k;
328 register store_type *s_ptr;
329
330 i = MAX_OWNERS / MAX_STORES;
331 for (j = 0; j < MAX_STORES; j++)
332 {
333 s_ptr = &store[j];
334 s_ptr->owner = MAX_STORES*(randint(i)-1) + j;
335 s_ptr->insult_cur = 0;
336 s_ptr->store_open = 0;
337 s_ptr->store_ctr = 0;
338 s_ptr->good_buy = 0;
339 s_ptr->bad_buy = 0;
340 for (k = 0; k < STORE_INVEN_MAX; k++)
341 {
342 invcopy(&s_ptr->store_inven[k].sitem, OBJ_NOTHING);
343 s_ptr->store_inven[k].scost = 0;
344 }
345 }
346 }
347
348
349 /* Creates an item and inserts it into store's inven -RAK- */
store_create(store_num)350 static void store_create(store_num)
351 int store_num;
352 {
353 register int i, tries;
354 int cur_pos, dummy;
355 register store_type *s_ptr;
356 register inven_type *t_ptr;
357
358 tries = 0;
359 cur_pos = popt();
360 s_ptr = &store[store_num];
361 do
362 {
363 i = store_choice[store_num][randint(STORE_CHOICES)-1];
364 invcopy(&t_list[cur_pos], i);
365 magic_treasure(cur_pos, OBJ_TOWN_LEVEL);
366 t_ptr = &t_list[cur_pos];
367 if (store_check_num(t_ptr, store_num))
368 {
369 if ((t_ptr->cost > 0) && /* Item must be good */
370 (t_ptr->cost < owners[s_ptr->owner].max_cost))
371 {
372 /* equivalent to calling ident_spell(), except will not
373 change the object_ident array */
374 store_bought(t_ptr);
375 store_carry(store_num, &dummy, t_ptr);
376 tries = 10;
377 }
378 }
379 tries++;
380 }
381 while (tries <= 3);
382 pusht((int8u)cur_pos);
383 }
384
385
386 /* Initialize and up-keep the store's inventory. -RAK- */
store_maint()387 void store_maint()
388 {
389 register int i, j;
390 register store_type *s_ptr;
391
392 for (i = 0; i < MAX_STORES; i++)
393 {
394 s_ptr = &store[i];
395 s_ptr->insult_cur = 0;
396 if (s_ptr->store_ctr >= STORE_MIN_INVEN)
397 {
398 j = randint(STORE_TURN_AROUND);
399 if (s_ptr->store_ctr >= STORE_MAX_INVEN)
400 j += 1 + s_ptr->store_ctr - STORE_MAX_INVEN;
401 while (--j >= 0)
402 store_destroy(i, randint((int)s_ptr->store_ctr)-1, FALSE);
403 }
404
405 if (s_ptr->store_ctr <= STORE_MAX_INVEN)
406 {
407 j = randint(STORE_TURN_AROUND);
408 if (s_ptr->store_ctr < STORE_MIN_INVEN)
409 j += STORE_MIN_INVEN - s_ptr->store_ctr;
410 while (--j >= 0)
411 store_create(i);
412 }
413 }
414 }
415
416 /* eliminate need to bargain if player has haggled well in the past -DJB- */
noneedtobargain(store_num,minprice)417 int noneedtobargain(store_num, minprice)
418 int store_num;
419 int32 minprice;
420 {
421 register int flagnoneed;
422 int bargain_record;
423 register store_type *s_ptr;
424
425 s_ptr = &store[store_num];
426 if (s_ptr->good_buy == MAX_SHORT)
427 return TRUE;
428 bargain_record = (s_ptr->good_buy - 3 * s_ptr->bad_buy - 5);
429 flagnoneed = ((bargain_record > 0)
430 && ((long)bargain_record * (long)bargain_record
431 > minprice/50));
432 return (flagnoneed);
433 }
434
435
436 /* update the bargin info -DJB- */
updatebargain(store_num,price,minprice)437 void updatebargain(store_num, price, minprice)
438 int store_num;
439 int32 price, minprice;
440 {
441 register store_type *s_ptr;
442
443 s_ptr = &store[store_num];
444 if (minprice > 9)
445 if (price == minprice)
446 {
447 if (s_ptr->good_buy < MAX_SHORT)
448 s_ptr->good_buy++;
449 }
450 else
451 {
452 if (s_ptr->bad_buy < MAX_SHORT)
453 s_ptr->bad_buy++;
454 }
455 }
456