2 * @brief オブジェクトの実装 / Object code, part 1
5 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\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
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 "object/object-flags.h"
23 #include "player-base/player-class.h"
24 #include "player/player-realm.h"
25 #include "realm/realm-names-table.h"
26 #include "sv-definition/sv-other-types.h"
27 #include "sv-definition/sv-ring-types.h"
28 #include "system/baseitem-info.h"
29 #include "system/floor-type-definition.h"
30 #include "system/item-entity.h"
31 #include "system/monster-race-info.h"
32 #include "system/player-type-definition.h"
33 #include "term/term-color-types.h"
34 #include "util/bit-flags-calculator.h"
35 #include "util/int-char-converter.h"
39 * @brief オブジェクトの発動効果名称を返す(サブルーチン/ブレス)
40 * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
41 * @return std::string 発動名称を返す文字列ポインタ
43 static std::string item_activation_dragon_breath(ItemEntity *o_ptr)
45 std::string desc = _("", "breathe ");
48 auto flags = object_flags(o_ptr);
50 for (int i = 0; dragonbreath_info[i].flag != 0; i++) {
51 if (flags.has(dragonbreath_info[i].flag)) {
53 desc.append(_("、", ", "));
56 desc.append(dragonbreath_info[i].name);
61 desc.append(_("のブレス(250)", " (250)"));
66 * @brief オブジェクトの発動効果名称を返す(サブルーチン/汎用)
67 * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
68 * @return concptr 発動名称を返す文字列ポインタ
70 static concptr item_activation_aux(ItemEntity *o_ptr)
72 static std::string activation_detail;
73 auto tmp_act_ptr = find_activation_info(o_ptr);
74 if (!tmp_act_ptr.has_value()) {
75 return _("未定義", "something undefined");
78 auto *act_ptr = tmp_act_ptr.value();
79 concptr desc = act_ptr->desc;
80 std::string dragon_breath;
81 switch (act_ptr->index) {
82 case RandomArtActType::NONE:
84 case RandomArtActType::BR_FIRE:
85 if (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES)) {
86 desc = _("火炎のブレス (200) と火への耐性", "breathe fire (200) and resist fire");
89 case RandomArtActType::BR_COLD:
90 if (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE)) {
91 desc = _("冷気のブレス (200) と冷気への耐性", "breathe cold (200) and resist cold");
94 case RandomArtActType::BR_DRAGON:
95 dragon_breath = item_activation_dragon_breath(o_ptr);
96 desc = dragon_breath.data();
98 case RandomArtActType::AGGRAVATE:
99 if (o_ptr->is_specific_artifact(FixedArtifactId::HYOUSIGI)) {
100 desc = _("拍子木を打ちならす", "beat wooden clappers");
103 case RandomArtActType::ACID_BALL_AND_RESISTANCE:
104 desc = _("アシッド・ボール (100) と酸への耐性", "ball of acid (100) and resist acid");
106 case RandomArtActType::FIRE_BALL_AND_RESISTANCE:
107 desc = _("ファイア・ボール (100) と火への耐性", "ball of fire (100) and resist fire");
109 case RandomArtActType::COLD_BALL_AND_RESISTANCE:
110 desc = _("アイス・ボール (100) と冷気への耐性", "ball of cold (100) and resist cold");
112 case RandomArtActType::ELEC_BALL_AND_RESISTANCE:
113 desc = _("サンダー・ボール (100) と電撃への耐性", "ball of elec (100) and resist elec");
115 case RandomArtActType::POIS_BALL_AND_RESISTANCE:
116 desc = _("ポイズン・ボール (100) と毒への耐性", "ball of poison (100) and resist elec");
118 case RandomArtActType::RESIST_ACID:
119 desc = _("一時的な酸への耐性", "temporary resist acid");
121 case RandomArtActType::RESIST_FIRE:
122 desc = _("一時的な火への耐性", "temporary resist fire");
124 case RandomArtActType::RESIST_COLD:
125 desc = _("一時的な冷気への耐性", "temporary resist cold");
127 case RandomArtActType::RESIST_ELEC:
128 desc = _("一時的な電撃への耐性", "temporary resist elec");
130 case RandomArtActType::RESIST_POIS:
131 desc = _("一時的な毒への耐性", "temporary resist elec");
137 /* Timeout description */
138 std::stringstream timeout;
139 int constant = act_ptr->timeout.constant;
140 int dice = act_ptr->timeout.dice;
141 if (constant == 0 && dice == 0) {
142 /* We can activate it every turn */
143 timeout << _("いつでも", "every turn");
144 } else if (constant < 0) {
145 /* Activations that have special timeout */
146 switch (act_ptr->index) {
147 case RandomArtActType::BR_FIRE:
148 timeout << _("", "every ") << (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES) ? 200 : 250) << _(" ターン毎", " turns");
150 case RandomArtActType::BR_COLD:
151 timeout << _("", "every ") << (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE) ? 200 : 250) << _(" ターン毎", " turns");
153 case RandomArtActType::TERROR:
154 timeout << _("3*(レベル+10) ターン毎", "every 3 * (level+10) turns");
156 case RandomArtActType::MURAMASA:
157 timeout << _("確率50%で壊れる", "(destroyed 50%)");
160 timeout << "undefined";
164 timeout << _("", "every ");
172 timeout << 'd' << dice;
174 timeout << _(" ターン毎", " turns");
177 activation_detail = desc;
178 activation_detail.append(_(" : ", " ")).append(timeout.str());
179 return activation_detail.data();
183 * @brief オブジェクトの発動効果名称を返す(メインルーチン) /
184 * Determine the "Activation" (if any) for an artifact Return a string, or nullptr for "no activation"
185 * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
186 * @return concptr 発動名称を返す文字列ポインタ
188 concptr activation_explanation(ItemEntity *o_ptr)
190 auto flags = object_flags(o_ptr);
191 if (flags.has_not(TR_ACTIVATE)) {
192 return _("なし", "nothing");
195 if (activation_index(o_ptr) > RandomArtActType::NONE) {
196 return item_activation_aux(o_ptr);
199 const auto tval = o_ptr->bi_key.tval();
200 if (tval == ItemKindType::WHISTLE) {
201 return _("ペット呼び寄せ : 100+d100ターン毎", "call pet every 100+d100 turns");
204 if (tval == ItemKindType::CAPTURE) {
205 return _("モンスターを捕える、又は解放する。", "captures or releases a monster.");
208 return _("何も起きない", "Nothing");
212 * @brief オブジェクト選択時の選択アルファベットラベルを返す /
213 * Convert an inventory index into a one character label
214 * @param i プレイヤーの所持/装備オブジェクトID
215 * @return 対応するアルファベット
216 * @details Note that the label does NOT distinguish inven/equip.
218 char index_to_label(int i)
220 return i < INVEN_MAIN_HAND ? I2A(i) : I2A(i - INVEN_MAIN_HAND);
224 * @brief オブジェクトの該当装備部位IDを返す /
225 * Determine which equipment slot (if any) an item likes
226 * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
229 int16_t wield_slot(PlayerType *player_ptr, const ItemEntity *o_ptr)
231 switch (o_ptr->bi_key.tval()) {
232 case ItemKindType::DIGGING:
233 case ItemKindType::HAFTED:
234 case ItemKindType::POLEARM:
235 case ItemKindType::SWORD:
236 if (!player_ptr->inventory_list[INVEN_MAIN_HAND].bi_id) {
237 return INVEN_MAIN_HAND;
240 if (player_ptr->inventory_list[INVEN_SUB_HAND].bi_id) {
241 return INVEN_MAIN_HAND;
244 return INVEN_SUB_HAND;
245 case ItemKindType::CAPTURE:
246 case ItemKindType::CARD:
247 case ItemKindType::SHIELD:
248 if (!player_ptr->inventory_list[INVEN_SUB_HAND].bi_id) {
249 return INVEN_SUB_HAND;
252 if (player_ptr->inventory_list[INVEN_MAIN_HAND].bi_id) {
253 return INVEN_SUB_HAND;
256 return INVEN_MAIN_HAND;
257 case ItemKindType::BOW:
259 case ItemKindType::RING:
260 if (!player_ptr->inventory_list[INVEN_MAIN_RING].bi_id) {
261 return INVEN_MAIN_RING;
264 return INVEN_SUB_RING;
265 case ItemKindType::AMULET:
266 case ItemKindType::WHISTLE:
268 case ItemKindType::LITE:
270 case ItemKindType::DRAG_ARMOR:
271 case ItemKindType::HARD_ARMOR:
272 case ItemKindType::SOFT_ARMOR:
274 case ItemKindType::CLOAK:
276 case ItemKindType::CROWN:
277 case ItemKindType::HELM:
279 case ItemKindType::GLOVES:
281 case ItemKindType::BOOTS:
289 * @brief tval/sval指定のベースアイテムがプレイヤーの使用可能な魔法書かどうかを返す
290 * @param player_ptr プレイヤーへの参照ポインタ
291 * @param bi_key ベースアイテム特定キー
292 * @return 使用可能な魔法書ならばTRUEを返す。
294 bool check_book_realm(PlayerType *player_ptr, const BaseitemKey &bi_key)
296 if (!bi_key.is_spell_book()) {
300 const auto tval = bi_key.tval();
301 PlayerClass pc(player_ptr);
302 if (pc.equals(PlayerClassType::SORCERER)) {
303 return is_magic(tval2realm(tval));
304 } else if (pc.equals(PlayerClassType::RED_MAGE)) {
305 if (is_magic(tval2realm(tval))) {
306 return ((tval == ItemKindType::ARCANE_BOOK) || (bi_key.sval() < 2));
310 return (get_realm1_book(player_ptr) == tval) || (get_realm2_book(player_ptr) == tval);
313 ItemEntity *ref_item(PlayerType *player_ptr, INVENTORY_IDX item)
315 auto *floor_ptr = player_ptr->current_floor_ptr;
316 return item >= 0 ? &player_ptr->inventory_list[item] : &(floor_ptr->o_list[0 - item]);