OSDN Git Service

[Refactor] ボール系魔法のコピペを低減
[hengbandforosx/hengbandosx.git] / src / store / service-checker.cpp
1 #include "store/service-checker.h"
2 #include "monster-race/monster-race.h"
3 #include "monster-race/race-flags3.h"
4 #include "object-enchant/tr-types.h"
5 #include "object/object-flags.h"
6 #include "object/object-value.h"
7 #include "object/tval-types.h"
8 #include "store/store-util.h"
9 #include "sv-definition/sv-potion-types.h"
10 #include "sv-definition/sv-rod-types.h"
11 #include "sv-definition/sv-scroll-types.h"
12 #include "sv-definition/sv-weapon-types.h"
13 #include "system/monster-race-definition.h"
14 #include "system/object-type-definition.h"
15 #include "system/player-type-definition.h"
16 #include "util/bit-flags-calculator.h"
17 #include "util/string-processor.h"
18
19 /*!
20  * @brief オブジェクトが祝福されているかの判定を返す /
21  * @param o_ptr 判定したいオブジェクト構造体の参照ポインタ
22  * @return アイテムが祝福されたアイテムならばTRUEを返す
23  */
24 static bool is_blessed_item(const ObjectType *o_ptr)
25 {
26     auto flgs = object_flags(o_ptr);
27     return flgs.has(TR_BLESSED);
28 }
29
30 static bool check_store_general(const ObjectType *o_ptr)
31 {
32     switch (o_ptr->tval) {
33     case ItemKindType::ROD:
34         return (o_ptr->sval == SV_ROD_PESTICIDE);
35     case ItemKindType::POTION:
36         return (o_ptr->sval == SV_POTION_WATER);
37     case ItemKindType::WHISTLE:
38     case ItemKindType::FOOD:
39     case ItemKindType::LITE:
40     case ItemKindType::FLASK:
41     case ItemKindType::SPIKE:
42     case ItemKindType::SHOT:
43     case ItemKindType::ARROW:
44     case ItemKindType::BOLT:
45     case ItemKindType::DIGGING:
46     case ItemKindType::CLOAK:
47     case ItemKindType::BOTTLE:
48     case ItemKindType::FIGURINE:
49     case ItemKindType::STATUE:
50     case ItemKindType::CAPTURE:
51     case ItemKindType::CARD:
52         return true;
53     default:
54         return false;
55     }
56 }
57
58 static bool check_store_armoury(const ObjectType *o_ptr)
59 {
60     switch (o_ptr->tval) {
61     case ItemKindType::BOOTS:
62     case ItemKindType::GLOVES:
63     case ItemKindType::CROWN:
64     case ItemKindType::HELM:
65     case ItemKindType::SHIELD:
66     case ItemKindType::CLOAK:
67     case ItemKindType::SOFT_ARMOR:
68     case ItemKindType::HARD_ARMOR:
69     case ItemKindType::DRAG_ARMOR:
70         return true;
71     default:
72         return false;
73     }
74 }
75
76 static bool check_store_weapon(const ObjectType *o_ptr)
77 {
78     switch (o_ptr->tval) {
79     case ItemKindType::SHOT:
80     case ItemKindType::BOLT:
81     case ItemKindType::ARROW:
82     case ItemKindType::BOW:
83     case ItemKindType::DIGGING:
84     case ItemKindType::POLEARM:
85     case ItemKindType::SWORD:
86     case ItemKindType::HISSATSU_BOOK:
87         return true;
88     case ItemKindType::HAFTED:
89         return o_ptr->sval != SV_WIZSTAFF;
90     default:
91         return false;
92     }
93 }
94
95 static bool check_store_temple(const ObjectType *o_ptr)
96 {
97     switch (o_ptr->tval) {
98     case ItemKindType::LIFE_BOOK:
99     case ItemKindType::CRUSADE_BOOK:
100     case ItemKindType::SCROLL:
101     case ItemKindType::POTION:
102     case ItemKindType::HAFTED:
103         return true;
104     case ItemKindType::FIGURINE:
105     case ItemKindType::STATUE: {
106         auto *r_ptr = &r_info[i2enum<MonsterRaceId>(o_ptr->pval)];
107         if (r_ptr->kind_flags.has_not(MonsterKindType::EVIL)) {
108             if ((r_ptr->kind_flags.has(MonsterKindType::GOOD)) || (r_ptr->kind_flags.has(MonsterKindType::ANIMAL)) || (angband_strchr("?!", r_ptr->d_char) != nullptr)) {
109                 return true;
110             }
111         }
112     }
113         /* Fall through */
114     case ItemKindType::POLEARM:
115     case ItemKindType::SWORD:
116         if (is_blessed_item(o_ptr)) {
117             return true;
118         }
119
120         /* Fall through */
121     default:
122         return false;
123     }
124 }
125
126 static bool check_store_alchemist(const ObjectType *o_ptr)
127 {
128     switch (o_ptr->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 ObjectType *o_ptr)
138 {
139     switch (o_ptr->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 o_ptr->sval == SV_WIZSTAFF;
161     default:
162         return false;
163     }
164 }
165
166 static bool check_store_book(const ObjectType *o_ptr)
167 {
168     switch (o_ptr->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 ObjectType *o_ptr, StoreSaleType store_num)
188 {
189     switch (store_num) {
190     case StoreSaleType::GENERAL:
191         return check_store_general(o_ptr);
192     case StoreSaleType::ARMOURY:
193         return check_store_armoury(o_ptr);
194     case StoreSaleType::WEAPON:
195         return check_store_weapon(o_ptr);
196     case StoreSaleType::TEMPLE:
197         return check_store_temple(o_ptr);
198     case StoreSaleType::ALCHEMIST:
199         return check_store_alchemist(o_ptr);
200     case StoreSaleType::MAGIC:
201         return check_store_magic(o_ptr);
202     case StoreSaleType::BOOK:
203         return check_store_book(o_ptr);
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 ObjectType *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 object_value(o_ptr) > 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(ObjectType *o_ptr, 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     if (o_ptr->sval == SV_SCROLL_STAR_IDENTIFY) {
261         size += damroll(3, 5);
262     }
263
264     if (o_ptr->sval == SV_SCROLL_STAR_REMOVE_CURSE) {
265         size += damroll(1, 4);
266     }
267
268     return size;
269 }
270
271 static int mass_book_produce(const PRICE cost)
272 {
273     int size = 1;
274     if (cost <= 50L) {
275         size += damroll(2, 3);
276     }
277
278     if (cost <= 500L) {
279         size += damroll(1, 3);
280     }
281
282     return size;
283 }
284
285 static int mass_equipment_produce(ObjectType *o_ptr, const PRICE cost)
286 {
287     int size = 1;
288     if (o_ptr->is_artifact() || o_ptr->is_ego()) {
289         return size;
290     }
291
292     if (cost <= 10L) {
293         size += damroll(3, 5);
294     }
295
296     if (cost <= 100L) {
297         size += damroll(3, 5);
298     }
299
300     return size;
301 }
302
303 static int mass_arrow_produce(const PRICE cost)
304 {
305     int size = 1;
306     if (cost <= 5L) {
307         size += damroll(5, 5);
308     }
309
310     if (cost <= 50L) {
311         size += damroll(5, 5);
312     }
313
314     if (cost <= 500L) {
315         size += damroll(5, 5);
316     }
317
318     return size;
319 }
320
321 static int mass_figurine_produce(const PRICE cost)
322 {
323     int size = 1;
324     if (cost <= 100L) {
325         size += damroll(2, 2);
326     }
327
328     if (cost <= 1000L) {
329         size += damroll(2, 2);
330     }
331
332     return size;
333 }
334
335 static int mass_magic_produce(const PRICE cost, StoreSaleType store_num)
336 {
337     int size = 1;
338     if ((store_num != StoreSaleType::BLACK) || !one_in_(3)) {
339         return size;
340     }
341
342     if (cost < 1601L) {
343         size += damroll(1, 5);
344     } else if (cost < 3201L) {
345         size += damroll(1, 3);
346     }
347
348     return size;
349 }
350
351 static int switch_mass_production(ObjectType *o_ptr, const PRICE cost, StoreSaleType store_num)
352 {
353     switch (o_ptr->tval) {
354     case ItemKindType::FOOD:
355     case ItemKindType::FLASK:
356     case ItemKindType::LITE:
357         return mass_lite_produce(cost);
358     case ItemKindType::POTION:
359     case ItemKindType::SCROLL:
360         return mass_scroll_produce(o_ptr, cost);
361     case ItemKindType::LIFE_BOOK:
362     case ItemKindType::SORCERY_BOOK:
363     case ItemKindType::NATURE_BOOK:
364     case ItemKindType::CHAOS_BOOK:
365     case ItemKindType::DEATH_BOOK:
366     case ItemKindType::TRUMP_BOOK:
367     case ItemKindType::ARCANE_BOOK:
368     case ItemKindType::CRAFT_BOOK:
369     case ItemKindType::DEMON_BOOK:
370     case ItemKindType::CRUSADE_BOOK:
371     case ItemKindType::MUSIC_BOOK:
372     case ItemKindType::HISSATSU_BOOK:
373     case ItemKindType::HEX_BOOK:
374         return mass_book_produce(cost);
375     case ItemKindType::SOFT_ARMOR:
376     case ItemKindType::HARD_ARMOR:
377     case ItemKindType::SHIELD:
378     case ItemKindType::GLOVES:
379     case ItemKindType::BOOTS:
380     case ItemKindType::CLOAK:
381     case ItemKindType::HELM:
382     case ItemKindType::CROWN:
383     case ItemKindType::SWORD:
384     case ItemKindType::POLEARM:
385     case ItemKindType::HAFTED:
386     case ItemKindType::DIGGING:
387     case ItemKindType::BOW:
388         return mass_equipment_produce(o_ptr, cost);
389     case ItemKindType::SPIKE:
390     case ItemKindType::SHOT:
391     case ItemKindType::ARROW:
392     case ItemKindType::BOLT:
393         return mass_arrow_produce(cost);
394     case ItemKindType::FIGURINE:
395         return mass_figurine_produce(cost);
396     case ItemKindType::CAPTURE:
397     case ItemKindType::STATUE:
398     case ItemKindType::CARD:
399         return 1;
400     case ItemKindType::ROD:
401     case ItemKindType::WAND:
402     case ItemKindType::STAFF:
403         return mass_magic_produce(cost, store_num);
404     default:
405         return 1;
406     }
407 }
408
409 static byte decide_discount_rate(const PRICE cost)
410 {
411     if (cost < 5) {
412         return 0;
413     }
414
415     if (one_in_(25)) {
416         return 25;
417     }
418
419     if (one_in_(150)) {
420         return 50;
421     }
422
423     if (one_in_(300)) {
424         return 75;
425     }
426
427     if (one_in_(500)) {
428         return 90;
429     }
430
431     return 0;
432 }
433
434 /*!
435  * @brief 安価な消耗品の販売数を増やし、低確率で割引にする /
436  * Certain "cheap" objects should be created in "piles"
437  * @param o_ptr 店舗に並べるオブジェクト構造体の参照ポインタ
438  * @details
439  * <pre>
440  * Some objects can be sold at a "discount" (in small piles)
441  * </pre>
442  */
443 void mass_produce(PlayerType *, ObjectType *o_ptr, StoreSaleType store_num)
444 {
445     const PRICE cost = object_value(o_ptr);
446     int size = switch_mass_production(o_ptr, cost, store_num);
447     auto discount = decide_discount_rate(cost);
448     if (o_ptr->art_name) {
449         discount = 0;
450     }
451
452     o_ptr->discount = discount;
453     o_ptr->number = size - (size * discount / 100);
454     if ((o_ptr->tval == ItemKindType::ROD) || (o_ptr->tval == ItemKindType::WAND)) {
455         o_ptr->pval *= (PARAMETER_VALUE)o_ptr->number;
456     }
457 }