OSDN Git Service

Merge branch 'master' of https://github.com/hengband/hengband
[hengbandforosx/hengbandosx.git] / src / store / service-checker.cpp
1 #include "store/service-checker.h"
2 #include "object-enchant/tr-types.h"
3 #include "object/object-value.h"
4 #include "object/tval-types.h"
5 #include "store/store-util.h"
6 #include "sv-definition/sv-potion-types.h"
7 #include "sv-definition/sv-rod-types.h"
8 #include "sv-definition/sv-scroll-types.h"
9 #include "sv-definition/sv-weapon-types.h"
10 #include "system/item-entity.h"
11 #include "system/monster-race-info.h"
12 #include "system/player-type-definition.h"
13 #include "util/bit-flags-calculator.h"
14 #include "util/string-processor.h"
15
16 /*!
17  * @brief オブジェクトが祝福されているかの判定を返す /
18  * @param item_ptr 判定したいオブジェクト構造体の参照ポインタ
19  * @return アイテムが祝福されたアイテムならばTRUEを返す
20  */
21 static bool is_blessed_item(const ItemEntity *item_ptr)
22 {
23     return item_ptr->get_flags().has(TR_BLESSED);
24 }
25
26 static bool check_store_general(const ItemEntity &item)
27 {
28     const auto &bi_key = item.bi_key;
29     switch (bi_key.tval()) {
30     case ItemKindType::ROD:
31         return (bi_key.sval() == SV_ROD_PESTICIDE);
32     case ItemKindType::POTION:
33         return (bi_key.sval() == SV_POTION_WATER);
34     case ItemKindType::WHISTLE:
35     case ItemKindType::FOOD:
36     case ItemKindType::LITE:
37     case ItemKindType::FLASK:
38     case ItemKindType::SPIKE:
39     case ItemKindType::SHOT:
40     case ItemKindType::ARROW:
41     case ItemKindType::BOLT:
42     case ItemKindType::DIGGING:
43     case ItemKindType::CLOAK:
44     case ItemKindType::BOTTLE:
45     case ItemKindType::FIGURINE:
46     case ItemKindType::STATUE:
47     case ItemKindType::CAPTURE:
48     case ItemKindType::CARD:
49         return true;
50     default:
51         return false;
52     }
53 }
54
55 static bool check_store_armoury(const ItemEntity &item)
56 {
57     switch (item.bi_key.tval()) {
58     case ItemKindType::BOOTS:
59     case ItemKindType::GLOVES:
60     case ItemKindType::CROWN:
61     case ItemKindType::HELM:
62     case ItemKindType::SHIELD:
63     case ItemKindType::CLOAK:
64     case ItemKindType::SOFT_ARMOR:
65     case ItemKindType::HARD_ARMOR:
66     case ItemKindType::DRAG_ARMOR:
67         return true;
68     default:
69         return false;
70     }
71 }
72
73 static bool check_store_weapon(const ItemEntity &item)
74 {
75     switch (item.bi_key.tval()) {
76     case ItemKindType::SHOT:
77     case ItemKindType::BOLT:
78     case ItemKindType::ARROW:
79     case ItemKindType::BOW:
80     case ItemKindType::DIGGING:
81     case ItemKindType::POLEARM:
82     case ItemKindType::SWORD:
83     case ItemKindType::HISSATSU_BOOK:
84         return true;
85     case ItemKindType::HAFTED:
86         return item.bi_key.sval() != SV_WIZSTAFF;
87     default:
88         return false;
89     }
90 }
91
92 static bool check_store_temple(const ItemEntity &item)
93 {
94     switch (item.bi_key.tval()) {
95     case ItemKindType::LIFE_BOOK:
96     case ItemKindType::CRUSADE_BOOK:
97     case ItemKindType::SCROLL:
98     case ItemKindType::POTION:
99     case ItemKindType::HAFTED:
100         return true;
101     case ItemKindType::FIGURINE:
102     case ItemKindType::STATUE: {
103         const auto &monrace = item.get_monrace();
104         if (monrace.kind_flags.has_not(MonsterKindType::EVIL)) {
105             auto can_sell = monrace.kind_flags.has(MonsterKindType::GOOD);
106             can_sell |= monrace.kind_flags.has(MonsterKindType::ANIMAL);
107             can_sell |= monrace.symbol_char_is_any_of("?!");
108             if (can_sell) {
109                 return true;
110             }
111         }
112     }
113         [[fallthrough]];
114     case ItemKindType::POLEARM:
115     case ItemKindType::SWORD:
116         if (is_blessed_item(&item)) {
117             return true;
118         }
119
120         [[fallthrough]];
121     default:
122         return false;
123     }
124 }
125
126 static bool check_store_alchemist(const ItemEntity &item)
127 {
128     switch (item.bi_key.tval()) {
129     case ItemKindType::SCROLL:
130     case ItemKindType::POTION:
131         return true;
132     default:
133         return false;
134     }
135 }
136
137 static bool check_store_magic(const ItemEntity &item)
138 {
139     switch (item.bi_key.tval()) {
140     case ItemKindType::SORCERY_BOOK:
141     case ItemKindType::NATURE_BOOK:
142     case ItemKindType::CHAOS_BOOK:
143     case ItemKindType::DEATH_BOOK:
144     case ItemKindType::TRUMP_BOOK:
145     case ItemKindType::ARCANE_BOOK:
146     case ItemKindType::CRAFT_BOOK:
147     case ItemKindType::DEMON_BOOK:
148     case ItemKindType::MUSIC_BOOK:
149     case ItemKindType::HEX_BOOK:
150     case ItemKindType::AMULET:
151     case ItemKindType::RING:
152     case ItemKindType::STAFF:
153     case ItemKindType::WAND:
154     case ItemKindType::ROD:
155     case ItemKindType::SCROLL:
156     case ItemKindType::POTION:
157     case ItemKindType::FIGURINE:
158         return true;
159     case ItemKindType::HAFTED:
160         return item.bi_key.sval() == SV_WIZSTAFF;
161     default:
162         return false;
163     }
164 }
165
166 static bool check_store_book(const ItemEntity &item)
167 {
168     switch (item.bi_key.tval()) {
169     case ItemKindType::SORCERY_BOOK:
170     case ItemKindType::NATURE_BOOK:
171     case ItemKindType::CHAOS_BOOK:
172     case ItemKindType::DEATH_BOOK:
173     case ItemKindType::LIFE_BOOK:
174     case ItemKindType::TRUMP_BOOK:
175     case ItemKindType::ARCANE_BOOK:
176     case ItemKindType::CRAFT_BOOK:
177     case ItemKindType::DEMON_BOOK:
178     case ItemKindType::CRUSADE_BOOK:
179     case ItemKindType::MUSIC_BOOK:
180     case ItemKindType::HEX_BOOK:
181         return true;
182     default:
183         return false;
184     }
185 }
186
187 static bool switch_store_check(const ItemEntity &item, StoreSaleType store_num)
188 {
189     switch (store_num) {
190     case StoreSaleType::GENERAL:
191         return check_store_general(item);
192     case StoreSaleType::ARMOURY:
193         return check_store_armoury(item);
194     case StoreSaleType::WEAPON:
195         return check_store_weapon(item);
196     case StoreSaleType::TEMPLE:
197         return check_store_temple(item);
198     case StoreSaleType::ALCHEMIST:
199         return check_store_alchemist(item);
200     case StoreSaleType::MAGIC:
201         return check_store_magic(item);
202     case StoreSaleType::BOOK:
203         return check_store_book(item);
204     default:
205         return true;
206     }
207 }
208
209 /*!
210  * @brief オブジェクトが所定の店舗で引き取れるかどうかを返す /
211  * Determine if the current store will purchase the given item
212  * @param o_ptr 判定したいオブジェクト構造体の参照ポインタ
213  * @return アイテムが買い取れるならばTRUEを返す
214  * @note
215  * Note that a shop-keeper must refuse to buy "worthless" items
216  */
217
218 bool store_will_buy(PlayerType *, const ItemEntity *o_ptr, StoreSaleType store_num)
219 {
220     if ((store_num == StoreSaleType::HOME) || (store_num == StoreSaleType::MUSEUM)) {
221         return true;
222     }
223
224     if (!switch_store_check(*o_ptr, store_num)) {
225         return false;
226     }
227
228     return o_ptr->get_price() > 0;
229 }
230
231 static int mass_lite_produce(const PRICE cost)
232 {
233     int size = 1;
234     if (cost <= 5L) {
235         size += damroll(3, 5);
236     }
237
238     if (cost <= 20L) {
239         size += damroll(3, 5);
240     }
241
242     if (cost <= 50L) {
243         size += damroll(2, 2);
244     }
245
246     return size;
247 }
248
249 static int mass_scroll_produce(const ItemEntity &item, const PRICE cost)
250 {
251     int size = 1;
252     if (cost <= 60L) {
253         size += damroll(3, 5);
254     }
255
256     if (cost <= 240L) {
257         size += damroll(1, 5);
258     }
259
260     const auto sval = item.bi_key.sval();
261     if (sval == SV_SCROLL_STAR_IDENTIFY) {
262         size += damroll(3, 5);
263     }
264
265     if (sval == SV_SCROLL_STAR_REMOVE_CURSE) {
266         size += damroll(1, 4);
267     }
268
269     return size;
270 }
271
272 static int mass_book_produce(const PRICE cost)
273 {
274     int size = 1;
275     if (cost <= 50L) {
276         size += damroll(2, 3);
277     }
278
279     if (cost <= 500L) {
280         size += damroll(1, 3);
281     }
282
283     return size;
284 }
285
286 static int mass_equipment_produce(const ItemEntity &item, const PRICE cost)
287 {
288     int size = 1;
289     if (item.is_fixed_or_random_artifact() || item.is_ego()) {
290         return size;
291     }
292
293     if (cost <= 10L) {
294         size += damroll(3, 5);
295     }
296
297     if (cost <= 100L) {
298         size += damroll(3, 5);
299     }
300
301     return size;
302 }
303
304 static int mass_arrow_produce(const PRICE cost)
305 {
306     int size = 1;
307     if (cost <= 5L) {
308         size += damroll(5, 5);
309     }
310
311     if (cost <= 50L) {
312         size += damroll(5, 5);
313     }
314
315     if (cost <= 500L) {
316         size += damroll(5, 5);
317     }
318
319     return size;
320 }
321
322 static int mass_figurine_produce(const PRICE cost)
323 {
324     int size = 1;
325     if (cost <= 100L) {
326         size += damroll(2, 2);
327     }
328
329     if (cost <= 1000L) {
330         size += damroll(2, 2);
331     }
332
333     return size;
334 }
335
336 static int mass_magic_produce(const PRICE cost, StoreSaleType store_num)
337 {
338     int size = 1;
339     if ((store_num != StoreSaleType::BLACK) || !one_in_(3)) {
340         return size;
341     }
342
343     if (cost < 1601L) {
344         size += damroll(1, 5);
345     } else if (cost < 3201L) {
346         size += damroll(1, 3);
347     }
348
349     return size;
350 }
351
352 static int switch_mass_production(const ItemEntity &item, const PRICE cost, StoreSaleType store_num)
353 {
354     switch (item.bi_key.tval()) {
355     case ItemKindType::FOOD:
356     case ItemKindType::FLASK:
357     case ItemKindType::LITE:
358         return mass_lite_produce(cost);
359     case ItemKindType::POTION:
360     case ItemKindType::SCROLL:
361         return mass_scroll_produce(item, cost);
362     case ItemKindType::LIFE_BOOK:
363     case ItemKindType::SORCERY_BOOK:
364     case ItemKindType::NATURE_BOOK:
365     case ItemKindType::CHAOS_BOOK:
366     case ItemKindType::DEATH_BOOK:
367     case ItemKindType::TRUMP_BOOK:
368     case ItemKindType::ARCANE_BOOK:
369     case ItemKindType::CRAFT_BOOK:
370     case ItemKindType::DEMON_BOOK:
371     case ItemKindType::CRUSADE_BOOK:
372     case ItemKindType::MUSIC_BOOK:
373     case ItemKindType::HISSATSU_BOOK:
374     case ItemKindType::HEX_BOOK:
375         return mass_book_produce(cost);
376     case ItemKindType::SOFT_ARMOR:
377     case ItemKindType::HARD_ARMOR:
378     case ItemKindType::SHIELD:
379     case ItemKindType::GLOVES:
380     case ItemKindType::BOOTS:
381     case ItemKindType::CLOAK:
382     case ItemKindType::HELM:
383     case ItemKindType::CROWN:
384     case ItemKindType::SWORD:
385     case ItemKindType::POLEARM:
386     case ItemKindType::HAFTED:
387     case ItemKindType::DIGGING:
388     case ItemKindType::BOW:
389         return mass_equipment_produce(item, cost);
390     case ItemKindType::SPIKE:
391     case ItemKindType::SHOT:
392     case ItemKindType::ARROW:
393     case ItemKindType::BOLT:
394         return mass_arrow_produce(cost);
395     case ItemKindType::FIGURINE:
396         return mass_figurine_produce(cost);
397     case ItemKindType::CAPTURE:
398     case ItemKindType::STATUE:
399     case ItemKindType::CARD:
400         return 1;
401     case ItemKindType::ROD:
402     case ItemKindType::WAND:
403     case ItemKindType::STAFF:
404         return mass_magic_produce(cost, store_num);
405     default:
406         return 1;
407     }
408 }
409
410 static byte decide_discount_rate(const PRICE cost)
411 {
412     if (cost < 5) {
413         return 0;
414     }
415
416     if (one_in_(25)) {
417         return 25;
418     }
419
420     if (one_in_(150)) {
421         return 50;
422     }
423
424     if (one_in_(300)) {
425         return 75;
426     }
427
428     if (one_in_(500)) {
429         return 90;
430     }
431
432     return 0;
433 }
434
435 /*!
436  * @brief 安価な消耗品の販売数を増やし、低確率で割引にする /
437  * Certain "cheap" objects should be created in "piles"
438  * @param o_ptr 店舗に並べるオブジェクト構造体の参照ポインタ
439  * @details
440  * <pre>
441  * Some objects can be sold at a "discount" (in small piles)
442  * </pre>
443  */
444 void mass_produce(ItemEntity *o_ptr, StoreSaleType store_num)
445 {
446     const auto cost = o_ptr->get_price();
447     int size = switch_mass_production(*o_ptr, cost, store_num);
448     auto discount = decide_discount_rate(cost);
449     if (o_ptr->is_random_artifact()) {
450         discount = 0;
451     }
452
453     o_ptr->discount = discount;
454     o_ptr->number = size - (size * discount / 100);
455     if (o_ptr->is_wand_rod()) {
456         o_ptr->pval *= (PARAMETER_VALUE)o_ptr->number;
457     }
458 }