OSDN Git Service

[Refactor] #3756 BaseitemKey::explain_activation() を定義し、ItemEntity::explain_activatio...
[hengbandforosx/hengbandosx.git] / src / system / baseitem-info.cpp
1 /*!
2  * @brief ベースアイテム情報の構造体 / Information about object "kinds", including player knowledge.
3  * @date 2019/05/01
4  * @author deskull
5  * @details
6  * ゲーム進行用のセーブファイル上では aware と tried のみ保存対象とすること。と英文ではあるが実際はもっとある様子である。 /
7  * Only "aware" and "tried" are saved in the savefile
8  */
9
10 #include "system/baseitem-info.h"
11 #include "object/tval-types.h"
12 #include "sv-definition/sv-armor-types.h"
13 #include "sv-definition/sv-bow-types.h"
14 #include "sv-definition/sv-food-types.h"
15 #include "sv-definition/sv-lite-types.h"
16 #include "sv-definition/sv-protector-types.h"
17 #include "sv-definition/sv-rod-types.h"
18 #include "sv-definition/sv-weapon-types.h"
19 #include "system/angband-exceptions.h"
20 #include <set>
21 #include <unordered_map>
22
23 namespace {
24 constexpr auto ITEM_NOT_BOW = "This item is not a bow!";
25 constexpr auto ITEM_NOT_ROD = "This item is not a rod!";
26 constexpr auto ITEM_NOT_LITE = "This item is not a lite!";
27 }
28
29 bool BaseitemKey::operator==(const BaseitemKey &other) const
30 {
31     return (this->type_value == other.type_value) && (this->subtype_value == other.subtype_value);
32 }
33
34 // @details type_valueに大小があればそれを判定し、同一ならばsubtype_valueの大小を判定する.
35 bool BaseitemKey::operator<(const BaseitemKey &other) const
36 {
37     if (this->type_value < other.type_value) {
38         return true;
39     }
40
41     if (this->type_value > other.type_value) {
42         return false;
43     }
44
45     return this->subtype_value < other.subtype_value;
46 }
47
48 ItemKindType BaseitemKey::tval() const
49 {
50     return this->type_value;
51 }
52
53 std::optional<int> BaseitemKey::sval() const
54 {
55     return this->subtype_value;
56 }
57
58 bool BaseitemKey::is(ItemKindType tval) const
59 {
60     return this->type_value == tval;
61 }
62
63 /*!
64  * @brief 射撃武器に対応する矢/弾薬のベースアイテムIDを返す
65  * @return 対応する矢/弾薬のベースアイテムID
66  */
67 ItemKindType BaseitemKey::get_arrow_kind() const
68 {
69     if ((this->type_value != ItemKindType::BOW) || !this->subtype_value) {
70         THROW_EXCEPTION(std::logic_error, ITEM_NOT_BOW);
71     }
72
73     switch (*this->subtype_value) {
74     case SV_SLING:
75         return ItemKindType::SHOT;
76     case SV_SHORT_BOW:
77     case SV_LONG_BOW:
78     case SV_NAMAKE_BOW:
79         return ItemKindType::ARROW;
80     case SV_LIGHT_XBOW:
81     case SV_HEAVY_XBOW:
82         return ItemKindType::BOLT;
83     case SV_CRIMSON:
84     case SV_HARP:
85         return ItemKindType::NO_AMMO;
86     default:
87         return ItemKindType::NONE;
88     }
89 }
90
91 bool BaseitemKey::is_spell_book() const
92 {
93     switch (this->type_value) {
94     case ItemKindType::LIFE_BOOK:
95     case ItemKindType::SORCERY_BOOK:
96     case ItemKindType::NATURE_BOOK:
97     case ItemKindType::CHAOS_BOOK:
98     case ItemKindType::DEATH_BOOK:
99     case ItemKindType::TRUMP_BOOK:
100     case ItemKindType::ARCANE_BOOK:
101     case ItemKindType::CRAFT_BOOK:
102     case ItemKindType::DEMON_BOOK:
103     case ItemKindType::CRUSADE_BOOK:
104     case ItemKindType::MUSIC_BOOK:
105     case ItemKindType::HISSATSU_BOOK:
106     case ItemKindType::HEX_BOOK:
107         return true;
108     default:
109         return false;
110     }
111 }
112
113 bool BaseitemKey::is_high_level_book() const
114 {
115     if (!this->is_spell_book()) {
116         return false;
117     }
118
119     if (this->type_value == ItemKindType::ARCANE_BOOK) {
120         return false;
121     }
122
123     return this->subtype_value >= 2;
124 }
125
126 bool BaseitemKey::is_melee_weapon() const
127 {
128     switch (this->type_value) {
129     case ItemKindType::POLEARM:
130     case ItemKindType::SWORD:
131     case ItemKindType::DIGGING:
132     case ItemKindType::HAFTED:
133         return true;
134     default:
135         return false;
136     }
137 }
138
139 bool BaseitemKey::is_ammo() const
140 {
141     switch (this->type_value) {
142     case ItemKindType::SHOT:
143     case ItemKindType::ARROW:
144     case ItemKindType::BOLT:
145         return true;
146     default:
147         return false;
148     }
149 }
150
151 /*
152  * @brief 未鑑定名を持つか否かの判定
153  * @details FOODはキノコが該当する
154  */
155 bool BaseitemKey::has_unidentified_name() const
156 {
157     switch (this->type_value) {
158     case ItemKindType::AMULET:
159     case ItemKindType::RING:
160     case ItemKindType::STAFF:
161     case ItemKindType::WAND:
162     case ItemKindType::ROD:
163     case ItemKindType::SCROLL:
164     case ItemKindType::POTION:
165         return true;
166     case ItemKindType::FOOD:
167         return this->is_mushrooms();
168     default:
169         return false;
170     }
171 }
172
173 bool BaseitemKey::can_recharge() const
174 {
175     switch (this->type_value) {
176     case ItemKindType::STAFF:
177     case ItemKindType::WAND:
178     case ItemKindType::ROD:
179         return true;
180     default:
181         return false;
182     }
183 }
184
185 bool BaseitemKey::is_wand_rod() const
186 {
187     switch (this->type_value) {
188     case ItemKindType::WAND:
189     case ItemKindType::ROD:
190         return true;
191     default:
192         return false;
193     }
194 }
195
196 bool BaseitemKey::is_wand_staff() const
197 {
198     switch (this->type_value) {
199     case ItemKindType::WAND:
200     case ItemKindType::STAFF:
201         return true;
202     default:
203         return false;
204     }
205 }
206
207 bool BaseitemKey::is_protector() const
208 {
209     switch (this->type_value) {
210     case ItemKindType::BOOTS:
211     case ItemKindType::GLOVES:
212     case ItemKindType::HELM:
213     case ItemKindType::CROWN:
214     case ItemKindType::SHIELD:
215     case ItemKindType::CLOAK:
216     case ItemKindType::SOFT_ARMOR:
217     case ItemKindType::HARD_ARMOR:
218     case ItemKindType::DRAG_ARMOR:
219         return true;
220     default:
221         return false;
222     }
223 }
224
225 bool BaseitemKey::can_be_aura_protector() const
226 {
227     switch (this->type_value) {
228     case ItemKindType::CLOAK:
229     case ItemKindType::SOFT_ARMOR:
230     case ItemKindType::HARD_ARMOR:
231         return true;
232     default:
233         return false;
234     }
235 }
236
237 bool BaseitemKey::is_wearable() const
238 {
239     switch (this->type_value) {
240     case ItemKindType::BOW:
241     case ItemKindType::DIGGING:
242     case ItemKindType::HAFTED:
243     case ItemKindType::POLEARM:
244     case ItemKindType::SWORD:
245     case ItemKindType::BOOTS:
246     case ItemKindType::GLOVES:
247     case ItemKindType::HELM:
248     case ItemKindType::CROWN:
249     case ItemKindType::SHIELD:
250     case ItemKindType::CLOAK:
251     case ItemKindType::SOFT_ARMOR:
252     case ItemKindType::HARD_ARMOR:
253     case ItemKindType::DRAG_ARMOR:
254     case ItemKindType::LITE:
255     case ItemKindType::AMULET:
256     case ItemKindType::RING:
257     case ItemKindType::CARD:
258         return true;
259     default:
260         return false;
261     }
262 }
263
264 bool BaseitemKey::is_weapon() const
265 {
266     switch (this->type_value) {
267     case ItemKindType::BOW:
268     case ItemKindType::DIGGING:
269     case ItemKindType::HAFTED:
270     case ItemKindType::POLEARM:
271     case ItemKindType::SWORD:
272         return true;
273     default:
274         return false;
275     }
276 }
277
278 bool BaseitemKey::is_equipement() const
279 {
280     return this->is_wearable() || this->is_ammo();
281 }
282
283 bool BaseitemKey::is_melee_ammo() const
284 {
285     switch (this->type_value) {
286     case ItemKindType::HAFTED:
287     case ItemKindType::POLEARM:
288     case ItemKindType::DIGGING:
289     case ItemKindType::BOLT:
290     case ItemKindType::ARROW:
291     case ItemKindType::SHOT:
292         return true;
293     case ItemKindType::SWORD:
294         return this->subtype_value != SV_POISON_NEEDLE;
295     default:
296         return false;
297     }
298 }
299
300 bool BaseitemKey::is_orthodox_melee_weapon() const
301 {
302     switch (this->type_value) {
303     case ItemKindType::HAFTED:
304     case ItemKindType::POLEARM:
305     case ItemKindType::DIGGING:
306         return true;
307     case ItemKindType::SWORD:
308         return this->subtype_value != SV_POISON_NEEDLE;
309     default:
310         return false;
311     }
312 }
313
314 bool BaseitemKey::is_broken_weapon() const
315 {
316     if (this->type_value != ItemKindType::SWORD) {
317         return false;
318     }
319
320     if (!this->subtype_value) {
321         return false;
322     }
323
324     switch (*this->subtype_value) {
325     case SV_BROKEN_DAGGER:
326     case SV_BROKEN_SWORD:
327         return true;
328     default:
329         return false;
330     }
331 }
332
333 bool BaseitemKey::is_throwable() const
334 {
335     switch (this->type_value) {
336     case ItemKindType::DIGGING:
337     case ItemKindType::HAFTED:
338     case ItemKindType::POLEARM:
339     case ItemKindType::SWORD:
340         return true;
341     default:
342         return false;
343     }
344 }
345
346 bool BaseitemKey::is_wieldable_in_etheir_hand() const
347 {
348     switch (this->type_value) {
349     case ItemKindType::DIGGING:
350     case ItemKindType::HAFTED:
351     case ItemKindType::POLEARM:
352     case ItemKindType::SWORD:
353     case ItemKindType::SHIELD:
354     case ItemKindType::CAPTURE:
355     case ItemKindType::CARD:
356         return true;
357     default:
358         return false;
359     }
360 }
361
362 bool BaseitemKey::is_rare() const
363 {
364     static const std::unordered_map<ItemKindType, const std::set<int>> rare_table = {
365         { ItemKindType::HAFTED, { SV_MACE_OF_DISRUPTION, SV_WIZSTAFF } },
366         { ItemKindType::POLEARM, { SV_SCYTHE_OF_SLICING, SV_DEATH_SCYTHE } },
367         { ItemKindType::SWORD, { SV_BLADE_OF_CHAOS, SV_DIAMOND_EDGE, SV_POISON_NEEDLE, SV_HAYABUSA } },
368         { ItemKindType::SHIELD, { SV_DRAGON_SHIELD, SV_MIRROR_SHIELD } },
369         { ItemKindType::HELM, { SV_DRAGON_HELM } },
370         { ItemKindType::BOOTS, { SV_PAIR_OF_DRAGON_GREAVE } },
371         { ItemKindType::CLOAK, { SV_ELVEN_CLOAK, SV_ETHEREAL_CLOAK, SV_SHADOW_CLOAK, SV_MAGIC_RESISTANCE_CLOAK } },
372         { ItemKindType::GLOVES, { SV_SET_OF_DRAGON_GLOVES } },
373         { ItemKindType::SOFT_ARMOR, { SV_KUROSHOUZOKU, SV_ABUNAI_MIZUGI } },
374         { ItemKindType::HARD_ARMOR, { SV_MITHRIL_CHAIN_MAIL, SV_MITHRIL_PLATE_MAIL, SV_ADAMANTITE_PLATE_MAIL } },
375         { ItemKindType::DRAG_ARMOR, { /* Any */ } },
376     };
377
378     if (!this->subtype_value) {
379         return false;
380     }
381
382     if (auto it = rare_table.find(this->type_value); it != rare_table.end()) {
383         const auto &svals = it->second;
384         return svals.empty() || (svals.find(*this->subtype_value) != svals.end());
385     }
386
387     return false;
388 }
389
390 short BaseitemKey::get_bow_energy() const
391 {
392     if ((this->type_value != ItemKindType::BOW) || !this->subtype_value) {
393         THROW_EXCEPTION(std::logic_error, ITEM_NOT_BOW);
394     }
395
396     switch (*this->subtype_value) {
397     case SV_SLING:
398         return 8000;
399     case SV_NAMAKE_BOW:
400         return 7777;
401     case SV_LIGHT_XBOW:
402         return 12000;
403     case SV_HEAVY_XBOW:
404         return 13333;
405     default:
406         return 10000;
407     }
408 }
409
410 int BaseitemKey::get_arrow_magnification() const
411 {
412     if ((this->type_value != ItemKindType::BOW) || !this->subtype_value) {
413         THROW_EXCEPTION(std::logic_error, ITEM_NOT_BOW);
414     }
415
416     switch (*this->subtype_value) {
417     case SV_SLING:
418     case SV_SHORT_BOW:
419         return 2;
420     case SV_LONG_BOW:
421     case SV_NAMAKE_BOW:
422     case SV_LIGHT_XBOW:
423         return 3;
424     case SV_HEAVY_XBOW:
425         return 4;
426     default:
427         return 0;
428     }
429 }
430
431 bool BaseitemKey::is_aiming_rod() const
432 {
433     if ((this->type_value != ItemKindType::ROD) || !this->subtype_value) {
434         THROW_EXCEPTION(std::logic_error, ITEM_NOT_ROD);
435     }
436
437     switch (*this->subtype_value) {
438     case SV_ROD_TELEPORT_AWAY:
439     case SV_ROD_DISARMING:
440     case SV_ROD_LITE:
441     case SV_ROD_SLEEP_MONSTER:
442     case SV_ROD_SLOW_MONSTER:
443     case SV_ROD_HYPODYNAMIA:
444     case SV_ROD_POLYMORPH:
445     case SV_ROD_ACID_BOLT:
446     case SV_ROD_ELEC_BOLT:
447     case SV_ROD_FIRE_BOLT:
448     case SV_ROD_COLD_BOLT:
449     case SV_ROD_ACID_BALL:
450     case SV_ROD_ELEC_BALL:
451     case SV_ROD_FIRE_BALL:
452     case SV_ROD_COLD_BALL:
453     case SV_ROD_STONE_TO_MUD:
454         return true;
455     default:
456         return false;
457     }
458 }
459
460 bool BaseitemKey::is_lite_requiring_fuel() const
461 {
462     if ((this->type_value != ItemKindType::LITE) || !this->subtype_value) {
463         THROW_EXCEPTION(std::logic_error, ITEM_NOT_LITE);
464     }
465
466     switch (*this->subtype_value) {
467     case SV_LITE_TORCH:
468     case SV_LITE_LANTERN:
469         return true;
470     default:
471         return false;
472     }
473 }
474
475 bool BaseitemKey::is_junk() const
476 {
477     switch (this->type_value) {
478     case ItemKindType::SKELETON:
479     case ItemKindType::BOTTLE:
480     case ItemKindType::JUNK:
481     case ItemKindType::STATUE:
482         return true;
483     default:
484         return false;
485     }
486 }
487
488 bool BaseitemKey::is_armour() const
489 {
490     switch (this->type_value) {
491     case ItemKindType::SOFT_ARMOR:
492     case ItemKindType::HARD_ARMOR:
493     case ItemKindType::DRAG_ARMOR:
494         return true;
495     default:
496         return false;
497     }
498 }
499
500 bool BaseitemKey::is_cross_bow() const
501 {
502     if ((this->type_value != ItemKindType::BOW) || !this->subtype_value) {
503         return false;
504     }
505
506     switch (*this->subtype_value) {
507     case SV_LIGHT_XBOW:
508     case SV_HEAVY_XBOW:
509         return true;
510     default:
511         return false;
512     }
513 }
514
515 bool BaseitemKey::refuse_enchant_weapon() const
516 {
517     return *this == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE);
518 }
519
520 /*!
521  * @brief ベースアイテムが発動効果を持つ時、その記述を生成する
522  * @return 発動効果
523  */
524 std::string BaseitemKey::explain_activation() const
525 {
526     switch (this->type_value) {
527     case ItemKindType::WHISTLE:
528         return _("ペット呼び寄せ : 100+d100ターン毎", "call pet every 100+d100 turns");
529     case ItemKindType::CAPTURE:
530         return _("モンスターを捕える、又は解放する。", "captures or releases a monster.");
531     default:
532         return _("何も起きない", "Nothing");
533     }
534 }
535
536 bool BaseitemKey::is_mushrooms() const
537 {
538     if (!this->subtype_value) {
539         return false;
540     }
541
542     switch (*this->subtype_value) {
543     case SV_FOOD_POISON:
544     case SV_FOOD_BLINDNESS:
545     case SV_FOOD_PARANOIA:
546     case SV_FOOD_CONFUSION:
547     case SV_FOOD_HALLUCINATION:
548     case SV_FOOD_PARALYSIS:
549     case SV_FOOD_WEAKNESS:
550     case SV_FOOD_SICKNESS:
551     case SV_FOOD_STUPIDITY:
552     case SV_FOOD_NAIVETY:
553     case SV_FOOD_UNHEALTH:
554     case SV_FOOD_DISEASE:
555     case SV_FOOD_CURE_POISON:
556     case SV_FOOD_CURE_BLINDNESS:
557     case SV_FOOD_CURE_PARANOIA:
558     case SV_FOOD_CURE_CONFUSION:
559     case SV_FOOD_CURE_SERIOUS:
560     case SV_FOOD_RESTORE_STR:
561     case SV_FOOD_RESTORE_CON:
562     case SV_FOOD_RESTORING:
563         return true;
564     default:
565         return false;
566     }
567 }
568
569 BaseitemInfo::BaseitemInfo()
570     : bi_key(ItemKindType::NONE)
571 {
572 }
573
574 /*!
575  * @brief 最初から簡易な名称が明らかなベースアイテムにその旨のフラグを立てる
576  */
577 void BaseitemInfo::decide_easy_know()
578 {
579     switch (this->bi_key.tval()) {
580     case ItemKindType::LIFE_BOOK:
581     case ItemKindType::SORCERY_BOOK:
582     case ItemKindType::NATURE_BOOK:
583     case ItemKindType::CHAOS_BOOK:
584     case ItemKindType::DEATH_BOOK:
585     case ItemKindType::TRUMP_BOOK:
586     case ItemKindType::ARCANE_BOOK:
587     case ItemKindType::CRAFT_BOOK:
588     case ItemKindType::DEMON_BOOK:
589     case ItemKindType::CRUSADE_BOOK:
590     case ItemKindType::MUSIC_BOOK:
591     case ItemKindType::HISSATSU_BOOK:
592     case ItemKindType::HEX_BOOK:
593     case ItemKindType::FLASK:
594     case ItemKindType::JUNK:
595     case ItemKindType::BOTTLE:
596     case ItemKindType::SKELETON:
597     case ItemKindType::SPIKE:
598     case ItemKindType::WHISTLE:
599     case ItemKindType::FOOD:
600     case ItemKindType::POTION:
601     case ItemKindType::SCROLL:
602     case ItemKindType::ROD:
603     case ItemKindType::STATUE:
604     case ItemKindType::PARCHMENT:
605         this->easy_know = true;
606         return;
607     default:
608         this->easy_know = false;
609         return;
610     }
611 }
612
613 /*!
614  * @brief オブジェクトを試行済にする
615  */
616 void BaseitemInfo::mark_as_tried()
617 {
618     this->tried = true;
619 }
620
621 std::vector<BaseitemInfo> baseitems_info;