OSDN Git Service

[Refactor] #3496 optional 型の存在判定 has_value() を撤廃した その4
[hengbandforosx/hengbandosx.git] / src / object / object-kind-hook.cpp
1 /*!
2  * @brief アイテムが特定種別のものであるかどうかの判定関数群
3  * @date 2018/12/15
4  * @author deskull
5  */
6
7 #include "object/object-kind-hook.h"
8 #include "object/tval-types.h"
9 #include "sv-definition/sv-amulet-types.h"
10 #include "sv-definition/sv-other-types.h"
11 #include "sv-definition/sv-ring-types.h"
12 #include "system/baseitem-info.h"
13 #include <algorithm>
14 #include <map>
15 #include <sstream>
16 #include <vector>
17
18 // @brief 3冊目の魔法書からは上質アイテムとして扱う.
19 static const int SV_BOOK_MIN_GOOD = 2;
20
21 /*!
22  * @brief オブジェクトがクロークかどうかを判定する /
23  * @param bi_id 判定したいオブジェクトのベースアイテムID
24  * @return オブジェクトがクロークならばTRUEを返す
25  */
26 bool kind_is_cloak(short bi_id)
27 {
28     return baseitems_info[bi_id].bi_key.tval() == ItemKindType::CLOAK;
29 }
30
31 /*!
32  * @brief オブジェクトが竿状武器かどうかを判定する /
33  * @param bi_id 判定したいオブジェクトのベースアイテムID
34  * @return オブジェクトが竿状武器ならばTRUEを返す
35  */
36 bool kind_is_polearm(short bi_id)
37 {
38     return baseitems_info[bi_id].bi_key.tval() == ItemKindType::POLEARM;
39 }
40
41 /*!
42  * @brief オブジェクトが剣かどうかを判定する /
43  * @param bi_id 判定したいオブジェクトのベースアイテムID
44  * @return オブジェクトが剣ならばTRUEを返す
45  */
46 bool kind_is_sword(short bi_id)
47 {
48     const auto &baseitem = baseitems_info[bi_id];
49     return (baseitem.bi_key.tval() == ItemKindType::SWORD) && (baseitem.bi_key.sval() > 2);
50 }
51
52 /*!
53  * @brief オブジェクトが魔法書かどうかを判定する
54  * @param bi_id 判定したいオブジェクトのベースアイテムID
55  * @return オブジェクトが魔法書ならばTRUEを返す
56  */
57 bool kind_is_book(short bi_id)
58 {
59     const auto &baseitem = baseitems_info[bi_id];
60     return baseitem.bi_key.is_spell_book();
61 }
62
63 /*!
64  * @brief オブジェクトがベースアイテム時点でGOODかどうかを判定する
65  * @param bi_id 判定したいオブジェクトのベースアイテムID
66  * @return オブジェクトがベースアイテム時点でGOODなアイテムならばTRUEを返す
67  */
68 bool kind_is_good_book(short bi_id)
69 {
70     const auto &baseitem = baseitems_info[bi_id];
71     return baseitem.bi_key.is_high_level_book();
72 }
73
74 /*!
75  * @brief オブジェクトが鎧かどうかを判定する /
76  * @param bi_id 判定したいオブジェクトのベースアイテムID
77  * @return オブジェクトが鎧ならばTRUEを返す
78  */
79 bool kind_is_armor(short bi_id)
80 {
81     return baseitems_info[bi_id].bi_key.tval() == ItemKindType::HARD_ARMOR;
82 }
83
84 /*!
85  * @brief オブジェクトが打撃武器かどうかを判定する /
86  * @param bi_id 判定したいオブジェクトのベースアイテムID
87  * @return オブジェクトが打撃武器ならばTRUEを返す
88  */
89 bool kind_is_hafted(short bi_id)
90 {
91     return baseitems_info[bi_id].bi_key.tval() == ItemKindType::HAFTED;
92 }
93
94 /*!
95  * @brief オブジェクトが薬かどうかを判定する /
96  * @param bi_id 判定したいオブジェクトのベースアイテムID
97  * @return オブジェクトが薬ならばTRUEを返す
98  */
99 bool kind_is_potion(short bi_id)
100 {
101     return baseitems_info[bi_id].bi_key.tval() == ItemKindType::POTION;
102 }
103
104 /*!
105  * @brief オブジェクトが靴かどうかを判定する /
106  * @param bi_id 判定したいオブジェクトのベースアイテムID
107  * @return オブジェクトが靴ならばTRUEを返す
108  */
109 bool kind_is_boots(short bi_id)
110 {
111     return baseitems_info[bi_id].bi_key.tval() == ItemKindType::BOOTS;
112 }
113
114 /*!
115  * @brief オブジェクトがアミュレットかどうかを判定する /
116  * @param bi_id 判定したいオブジェクトのベースアイテムID
117  * @return オブジェクトがアミュレットならばTRUEを返す
118  */
119 bool kind_is_amulet(short bi_id)
120 {
121     return baseitems_info[bi_id].bi_key.tval() == ItemKindType::AMULET;
122 }
123
124 /*!
125  * @brief ベースアイテムが上質として扱われるかどうかを返す。
126  * Hack -- determine if a template is "good"
127  * @param bi_id 判定したいベースアイテムのID
128  * @return ベースアイテムが上質ならばTRUEを返す。
129  */
130 bool kind_is_good(short bi_id)
131 {
132     const auto &baseitem = baseitems_info[bi_id];
133     switch (baseitem.bi_key.tval()) {
134         /* Armor -- Good unless damaged */
135     case ItemKindType::HARD_ARMOR:
136     case ItemKindType::SOFT_ARMOR:
137     case ItemKindType::DRAG_ARMOR:
138     case ItemKindType::SHIELD:
139     case ItemKindType::CLOAK:
140     case ItemKindType::BOOTS:
141     case ItemKindType::GLOVES:
142     case ItemKindType::HELM:
143     case ItemKindType::CROWN:
144         return baseitem.to_a >= 0;
145
146     /* Weapons -- Good unless damaged */
147     case ItemKindType::BOW:
148     case ItemKindType::SWORD:
149     case ItemKindType::HAFTED:
150     case ItemKindType::POLEARM:
151     case ItemKindType::DIGGING:
152         return (baseitem.to_h >= 0) && (baseitem.to_d >= 0);
153
154     /* Ammo -- Arrows/Bolts are good */
155     case ItemKindType::BOLT:
156     case ItemKindType::ARROW:
157         return true;
158
159     /* Books -- High level books are good (except Arcane books) */
160     case ItemKindType::LIFE_BOOK:
161     case ItemKindType::SORCERY_BOOK:
162     case ItemKindType::NATURE_BOOK:
163     case ItemKindType::CHAOS_BOOK:
164     case ItemKindType::DEATH_BOOK:
165     case ItemKindType::TRUMP_BOOK:
166     case ItemKindType::CRAFT_BOOK:
167     case ItemKindType::DEMON_BOOK:
168     case ItemKindType::CRUSADE_BOOK:
169     case ItemKindType::MUSIC_BOOK:
170     case ItemKindType::HISSATSU_BOOK:
171     case ItemKindType::HEX_BOOK:
172         return baseitem.bi_key.sval() >= SV_BOOK_MIN_GOOD;
173
174     /* Rings -- Rings of Speed are good */
175     case ItemKindType::RING:
176         return (baseitem.bi_key.sval() == SV_RING_SPEED) || (baseitem.bi_key.sval() == SV_RING_LORDLY);
177
178     /* Amulets -- Amulets of the Magi and Resistance are good */
179     case ItemKindType::AMULET:
180         return (baseitem.bi_key.sval() == SV_AMULET_THE_MAGI) || (baseitem.bi_key.sval() == SV_AMULET_RESISTANCE);
181     default:
182         return false;
183     }
184 }
185
186 /*
187  * @brief 特定のtvalとランダムなsvalの組み合わせからベースアイテムを選択するためのキャッシュを生成する
188  * @return tvalをキーに、svalのリストを値とした辞書
189  */
190 static const std::map<ItemKindType, std::vector<int>> &create_baseitems_cache()
191 {
192     static std::map<ItemKindType, std::vector<int>> cache;
193     for (const auto &baseitem : baseitems_info) {
194         const auto &bi_key = baseitem.bi_key;
195         const auto tval = bi_key.tval();
196         if (tval == ItemKindType::NONE) {
197             continue;
198         }
199
200         cache[tval].push_back(bi_key.sval().value());
201     }
202
203     return cache;
204 }
205
206 /*
207  * @brief tvalとbi_key.svalに対応する、BaseitenDefinitions のIDを返すためのキャッシュを生成する
208  * @return tvalと(実在する)svalの組み合わせをキーに、ベースアイテムIDを値とした辞書
209  */
210 static const std::map<BaseitemKey, short> &create_baseitem_index_chache()
211 {
212     static std::map<BaseitemKey, short> cache;
213     for (const auto &baseitem : baseitems_info) {
214         const auto &bi_key = baseitem.bi_key;
215         if (bi_key.tval() == ItemKindType::NONE) {
216             continue;
217         }
218
219         cache[bi_key] = baseitem.idx;
220     }
221
222     return cache;
223 }
224
225 /*!
226  * @brief tvalとsvalに対応するベースアイテムのIDを検索する
227  * @param key 検索したいベースアイテムの、tval/svalのペア (svalがnulloptの可能性はない)
228  * @return tvalとsvalに対応するベースアイテムが存在すればそのID、存在しなければ0
229  * @details 存在しないことはリファクタリング成果により考えにくく、自作の不存在例外を投げればいいはず.
230  * 但し呼び出し側全部の処理を保証するのが面倒なので旧処理のままとする.
231  */
232 static short exe_lookup(const BaseitemKey &key)
233 {
234     static const auto &cache = create_baseitem_index_chache();
235     const auto itr = cache.find(key);
236     if (itr == cache.end()) {
237         return 0;
238     }
239
240     return itr->second;
241 }
242
243 /*!
244  * @brief ベースアイテムのtval/svalからIDを引いて返す
245  * @param key tval/svalのペア、但しsvalはランダム (nullopt)の可能性がある
246  * @return ベースアイテムID
247  * @details 「tvalが不存在」という状況は事実上ないが、辞書探索のお作法として「有無チェック」を入れておく.
248  * 万が一tvalがキャッシュになかったらベースアイテムID 0を返す.
249  */
250 short lookup_baseitem_id(const BaseitemKey &key)
251 {
252     const auto sval = key.sval();
253     if (sval) {
254         return exe_lookup(key);
255     }
256
257     static const auto &cache = create_baseitems_cache();
258     const auto itr = cache.find(key.tval());
259     if (itr == cache.end()) {
260         return 0;
261     }
262
263     const auto &svals = itr->second;
264     return exe_lookup({ key.tval(), rand_choice(svals) });
265 }