OSDN Git Service

[Refactor] #3677 object_known() をItemEntity のオブジェクトメソッドに繰り込んだ
[hengbandforosx/hengbandosx.git] / src / object / object-info.cpp
1 /*!
2  * @brief オブジェクトの実装 / Object code, part 1
3  * @date 2014/01/10
4  * @author
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n
6  *\n
7  * This software may be copied and distributed for educational, research,\n
8  * and not for profit purposes provided that this copyright and statement\n
9  * are included in all such copies.  Other copyrights may also apply.\n
10  * 2014 Deskull rearranged comment for Doxygen.\n
11  */
12
13 #include "object/object-info.h"
14 #include "artifact/artifact-info.h"
15 #include "artifact/fixed-art-types.h"
16 #include "artifact/random-art-effects.h"
17 #include "inventory/inventory-slot-types.h"
18 #include "monster-race/monster-race.h"
19 #include "object-enchant/activation-info-table.h"
20 #include "object-enchant/dragon-breaths-table.h"
21 #include "object-enchant/object-ego.h"
22 #include "player-base/player-class.h"
23 #include "player/player-realm.h"
24 #include "realm/realm-names-table.h"
25 #include "sv-definition/sv-other-types.h"
26 #include "sv-definition/sv-ring-types.h"
27 #include "system/baseitem-info.h"
28 #include "system/floor-type-definition.h"
29 #include "system/item-entity.h"
30 #include "system/monster-race-info.h"
31 #include "system/player-type-definition.h"
32 #include "term/term-color-types.h"
33 #include "util/bit-flags-calculator.h"
34 #include "util/int-char-converter.h"
35 #include <sstream>
36
37 /*!
38  * @brief オブジェクトの発動効果名称を返す(サブルーチン/ブレス)
39  * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
40  * @return std::string 発動名称を返す文字列ポインタ
41  */
42 static std::string item_activation_dragon_breath(const ItemEntity *o_ptr)
43 {
44     std::string desc = _("", "breathe ");
45     int n = 0;
46
47     const auto flags = o_ptr->get_flags();
48
49     for (int i = 0; dragonbreath_info[i].flag != 0; i++) {
50         if (flags.has(dragonbreath_info[i].flag)) {
51             if (n > 0) {
52                 desc.append(_("、", ", "));
53             }
54
55             desc.append(dragonbreath_info[i].name);
56             n++;
57         }
58     }
59
60     desc.append(_("のブレス(250)", " (250)"));
61     return desc;
62 }
63
64 /*!
65  * @brief オブジェクトの発動効果名称を返す(サブルーチン/汎用)
66  * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
67  * @return concptr 発動名称を返す文字列ポインタ
68  */
69 static concptr item_activation_aux(const ItemEntity *o_ptr)
70 {
71     static std::string activation_detail;
72     auto tmp_act_ptr = find_activation_info(o_ptr);
73     if (!tmp_act_ptr.has_value()) {
74         return _("未定義", "something undefined");
75     }
76
77     auto *act_ptr = tmp_act_ptr.value();
78     concptr desc = act_ptr->desc;
79     std::string dragon_breath;
80     switch (act_ptr->index) {
81     case RandomArtActType::NONE:
82         break;
83     case RandomArtActType::BR_FIRE:
84         if (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES)) {
85             desc = _("火炎のブレス (200) と火への耐性", "breathe fire (200) and resist fire");
86         }
87         break;
88     case RandomArtActType::BR_COLD:
89         if (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE)) {
90             desc = _("冷気のブレス (200) と冷気への耐性", "breathe cold (200) and resist cold");
91         }
92         break;
93     case RandomArtActType::BR_DRAGON:
94         dragon_breath = item_activation_dragon_breath(o_ptr);
95         desc = dragon_breath.data();
96         break;
97     case RandomArtActType::AGGRAVATE:
98         if (o_ptr->is_specific_artifact(FixedArtifactId::HYOUSIGI)) {
99             desc = _("拍子木を打ちならす", "beat wooden clappers");
100         }
101         break;
102     case RandomArtActType::ACID_BALL_AND_RESISTANCE:
103         desc = _("アシッド・ボール (100) と酸への耐性", "ball of acid (100) and resist acid");
104         break;
105     case RandomArtActType::FIRE_BALL_AND_RESISTANCE:
106         desc = _("ファイア・ボール (100) と火への耐性", "ball of fire (100) and resist fire");
107         break;
108     case RandomArtActType::COLD_BALL_AND_RESISTANCE:
109         desc = _("アイス・ボール (100) と冷気への耐性", "ball of cold (100) and resist cold");
110         break;
111     case RandomArtActType::ELEC_BALL_AND_RESISTANCE:
112         desc = _("サンダー・ボール (100) と電撃への耐性", "ball of elec (100) and resist elec");
113         break;
114     case RandomArtActType::POIS_BALL_AND_RESISTANCE:
115         desc = _("ポイズン・ボール (100) と毒への耐性", "ball of poison (100) and resist elec");
116         break;
117     case RandomArtActType::RESIST_ACID:
118         desc = _("一時的な酸への耐性", "temporary resist acid");
119         break;
120     case RandomArtActType::RESIST_FIRE:
121         desc = _("一時的な火への耐性", "temporary resist fire");
122         break;
123     case RandomArtActType::RESIST_COLD:
124         desc = _("一時的な冷気への耐性", "temporary resist cold");
125         break;
126     case RandomArtActType::RESIST_ELEC:
127         desc = _("一時的な電撃への耐性", "temporary resist elec");
128         break;
129     case RandomArtActType::RESIST_POIS:
130         desc = _("一時的な毒への耐性", "temporary resist elec");
131         break;
132     default:
133         break;
134     }
135
136     /* Timeout description */
137     std::stringstream timeout;
138     int constant = act_ptr->timeout.constant;
139     int dice = act_ptr->timeout.dice;
140     if (constant == 0 && dice == 0) {
141         /* We can activate it every turn */
142         timeout << _("いつでも", "every turn");
143     } else if (constant < 0) {
144         /* Activations that have special timeout */
145         switch (act_ptr->index) {
146         case RandomArtActType::BR_FIRE:
147             timeout << _("", "every ") << (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES) ? 200 : 250) << _(" ターン毎", " turns");
148             break;
149         case RandomArtActType::BR_COLD:
150             timeout << _("", "every ") << (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE) ? 200 : 250) << _(" ターン毎", " turns");
151             break;
152         case RandomArtActType::TERROR:
153             timeout << _("3*(レベル+10) ターン毎", "every 3 * (level+10) turns");
154             break;
155         case RandomArtActType::MURAMASA:
156             timeout << _("確率50%で壊れる", "(destroyed 50%)");
157             break;
158         default:
159             timeout << "undefined";
160             break;
161         }
162     } else {
163         timeout << _("", "every ");
164         if (constant > 0) {
165             timeout << constant;
166             if (dice > 0) {
167                 timeout << '+';
168             }
169         }
170         if (dice > 0) {
171             timeout << 'd' << dice;
172         }
173         timeout << _(" ターン毎", " turns");
174     }
175
176     activation_detail = desc;
177     activation_detail.append(_(" : ", " ")).append(timeout.str());
178     return activation_detail.data();
179 }
180
181 /*!
182  * @brief オブジェクトの発動効果名称を返す(メインルーチン) /
183  * Determine the "Activation" (if any) for an artifact Return a string, or nullptr for "no activation"
184  * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
185  * @return concptr 発動名称を返す文字列ポインタ
186  */
187 std::string activation_explanation(const ItemEntity *o_ptr)
188 {
189     const auto flags = o_ptr->get_flags();
190     if (flags.has_not(TR_ACTIVATE)) {
191         return _("なし", "nothing");
192     }
193
194     if (activation_index(o_ptr) > RandomArtActType::NONE) {
195         return item_activation_aux(o_ptr);
196     }
197
198     const auto tval = o_ptr->bi_key.tval();
199     if (tval == ItemKindType::WHISTLE) {
200         return _("ペット呼び寄せ : 100+d100ターン毎", "call pet every 100+d100 turns");
201     }
202
203     if (tval == ItemKindType::CAPTURE) {
204         return _("モンスターを捕える、又は解放する。", "captures or releases a monster.");
205     }
206
207     return _("何も起きない", "Nothing");
208 }
209
210 /*!
211  * @brief オブジェクト選択時の選択アルファベットラベルを返す /
212  * Convert an inventory index into a one character label
213  * @param i プレイヤーの所持/装備オブジェクトID
214  * @return 対応するアルファベット
215  * @details Note that the label does NOT distinguish inven/equip.
216  */
217 char index_to_label(int i)
218 {
219     return i < INVEN_MAIN_HAND ? I2A(i) : I2A(i - INVEN_MAIN_HAND);
220 }
221
222 /*!
223  * @brief オブジェクトの該当装備部位IDを返す /
224  * Determine which equipment slot (if any) an item likes
225  * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
226  * @return 対応する装備部位ID
227  */
228 int16_t wield_slot(PlayerType *player_ptr, const ItemEntity *o_ptr)
229 {
230     switch (o_ptr->bi_key.tval()) {
231     case ItemKindType::DIGGING:
232     case ItemKindType::HAFTED:
233     case ItemKindType::POLEARM:
234     case ItemKindType::SWORD:
235         if (!player_ptr->inventory_list[INVEN_MAIN_HAND].bi_id) {
236             return INVEN_MAIN_HAND;
237         }
238
239         if (player_ptr->inventory_list[INVEN_SUB_HAND].bi_id) {
240             return INVEN_MAIN_HAND;
241         }
242
243         return INVEN_SUB_HAND;
244     case ItemKindType::CAPTURE:
245     case ItemKindType::CARD:
246     case ItemKindType::SHIELD:
247         if (!player_ptr->inventory_list[INVEN_SUB_HAND].bi_id) {
248             return INVEN_SUB_HAND;
249         }
250
251         if (player_ptr->inventory_list[INVEN_MAIN_HAND].bi_id) {
252             return INVEN_SUB_HAND;
253         }
254
255         return INVEN_MAIN_HAND;
256     case ItemKindType::BOW:
257         return INVEN_BOW;
258     case ItemKindType::RING:
259         if (!player_ptr->inventory_list[INVEN_MAIN_RING].bi_id) {
260             return INVEN_MAIN_RING;
261         }
262
263         return INVEN_SUB_RING;
264     case ItemKindType::AMULET:
265     case ItemKindType::WHISTLE:
266         return INVEN_NECK;
267     case ItemKindType::LITE:
268         return INVEN_LITE;
269     case ItemKindType::DRAG_ARMOR:
270     case ItemKindType::HARD_ARMOR:
271     case ItemKindType::SOFT_ARMOR:
272         return INVEN_BODY;
273     case ItemKindType::CLOAK:
274         return INVEN_OUTER;
275     case ItemKindType::CROWN:
276     case ItemKindType::HELM:
277         return INVEN_HEAD;
278     case ItemKindType::GLOVES:
279         return INVEN_ARMS;
280     case ItemKindType::BOOTS:
281         return INVEN_FEET;
282     default:
283         return -1;
284     }
285 }
286
287 /*!
288  * @brief tval/sval指定のベースアイテムがプレイヤーの使用可能な魔法書かどうかを返す
289  * @param player_ptr プレイヤーへの参照ポインタ
290  * @param bi_key ベースアイテム特定キー
291  * @return 使用可能な魔法書ならばTRUEを返す。
292  */
293 bool check_book_realm(PlayerType *player_ptr, const BaseitemKey &bi_key)
294 {
295     if (!bi_key.is_spell_book()) {
296         return false;
297     }
298
299     const auto tval = bi_key.tval();
300     PlayerClass pc(player_ptr);
301     if (pc.equals(PlayerClassType::SORCERER)) {
302         return is_magic(tval2realm(tval));
303     } else if (pc.equals(PlayerClassType::RED_MAGE)) {
304         if (is_magic(tval2realm(tval))) {
305             return ((tval == ItemKindType::ARCANE_BOOK) || (bi_key.sval() < 2));
306         }
307     }
308
309     return (get_realm1_book(player_ptr) == tval) || (get_realm2_book(player_ptr) == tval);
310 }
311
312 ItemEntity *ref_item(PlayerType *player_ptr, INVENTORY_IDX i_idx)
313 {
314     auto *floor_ptr = player_ptr->current_floor_ptr;
315     return i_idx >= 0 ? &player_ptr->inventory_list[i_idx] : &(floor_ptr->o_list[0 - i_idx]);
316 }