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 "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"
38 * @brief オブジェクトの発動効果名称を返す(サブルーチン/ブレス)
39 * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
40 * @return std::string 発動名称を返す文字列ポインタ
42 static std::string item_activation_dragon_breath(const ItemEntity *o_ptr)
44 std::string desc = _("", "breathe ");
47 const auto flags = o_ptr->get_flags();
49 for (int i = 0; dragonbreath_info[i].flag != 0; i++) {
50 if (flags.has(dragonbreath_info[i].flag)) {
52 desc.append(_("、", ", "));
55 desc.append(dragonbreath_info[i].name);
60 desc.append(_("のブレス(250)", " (250)"));
65 * @brief オブジェクトの発動効果名称を返す(サブルーチン/汎用)
66 * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
67 * @return concptr 発動名称を返す文字列ポインタ
69 static concptr item_activation_aux(const ItemEntity *o_ptr)
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");
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:
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");
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");
93 case RandomArtActType::BR_DRAGON:
94 dragon_breath = item_activation_dragon_breath(o_ptr);
95 desc = dragon_breath.data();
97 case RandomArtActType::AGGRAVATE:
98 if (o_ptr->is_specific_artifact(FixedArtifactId::HYOUSIGI)) {
99 desc = _("拍子木を打ちならす", "beat wooden clappers");
102 case RandomArtActType::ACID_BALL_AND_RESISTANCE:
103 desc = _("アシッド・ボール (100) と酸への耐性", "ball of acid (100) and resist acid");
105 case RandomArtActType::FIRE_BALL_AND_RESISTANCE:
106 desc = _("ファイア・ボール (100) と火への耐性", "ball of fire (100) and resist fire");
108 case RandomArtActType::COLD_BALL_AND_RESISTANCE:
109 desc = _("アイス・ボール (100) と冷気への耐性", "ball of cold (100) and resist cold");
111 case RandomArtActType::ELEC_BALL_AND_RESISTANCE:
112 desc = _("サンダー・ボール (100) と電撃への耐性", "ball of elec (100) and resist elec");
114 case RandomArtActType::POIS_BALL_AND_RESISTANCE:
115 desc = _("ポイズン・ボール (100) と毒への耐性", "ball of poison (100) and resist elec");
117 case RandomArtActType::RESIST_ACID:
118 desc = _("一時的な酸への耐性", "temporary resist acid");
120 case RandomArtActType::RESIST_FIRE:
121 desc = _("一時的な火への耐性", "temporary resist fire");
123 case RandomArtActType::RESIST_COLD:
124 desc = _("一時的な冷気への耐性", "temporary resist cold");
126 case RandomArtActType::RESIST_ELEC:
127 desc = _("一時的な電撃への耐性", "temporary resist elec");
129 case RandomArtActType::RESIST_POIS:
130 desc = _("一時的な毒への耐性", "temporary resist elec");
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");
149 case RandomArtActType::BR_COLD:
150 timeout << _("", "every ") << (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE) ? 200 : 250) << _(" ターン毎", " turns");
152 case RandomArtActType::TERROR:
153 timeout << _("3*(レベル+10) ターン毎", "every 3 * (level+10) turns");
155 case RandomArtActType::MURAMASA:
156 timeout << _("確率50%で壊れる", "(destroyed 50%)");
159 timeout << "undefined";
163 timeout << _("", "every ");
171 timeout << 'd' << dice;
173 timeout << _(" ターン毎", " turns");
176 activation_detail = desc;
177 activation_detail.append(_(" : ", " ")).append(timeout.str());
178 return activation_detail.data();
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 発動名称を返す文字列ポインタ
187 std::string activation_explanation(const ItemEntity *o_ptr)
189 const auto flags = o_ptr->get_flags();
190 if (flags.has_not(TR_ACTIVATE)) {
191 return _("なし", "nothing");
194 if (activation_index(o_ptr) > RandomArtActType::NONE) {
195 return item_activation_aux(o_ptr);
198 const auto tval = o_ptr->bi_key.tval();
199 if (tval == ItemKindType::WHISTLE) {
200 return _("ペット呼び寄せ : 100+d100ターン毎", "call pet every 100+d100 turns");
203 if (tval == ItemKindType::CAPTURE) {
204 return _("モンスターを捕える、又は解放する。", "captures or releases a monster.");
207 return _("何も起きない", "Nothing");
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.
217 char index_to_label(int i)
219 return i < INVEN_MAIN_HAND ? I2A(i) : I2A(i - INVEN_MAIN_HAND);
223 * @brief オブジェクトの該当装備部位IDを返す /
224 * Determine which equipment slot (if any) an item likes
225 * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
228 int16_t wield_slot(PlayerType *player_ptr, const ItemEntity *o_ptr)
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;
239 if (player_ptr->inventory_list[INVEN_SUB_HAND].bi_id) {
240 return INVEN_MAIN_HAND;
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;
251 if (player_ptr->inventory_list[INVEN_MAIN_HAND].bi_id) {
252 return INVEN_SUB_HAND;
255 return INVEN_MAIN_HAND;
256 case ItemKindType::BOW:
258 case ItemKindType::RING:
259 if (!player_ptr->inventory_list[INVEN_MAIN_RING].bi_id) {
260 return INVEN_MAIN_RING;
263 return INVEN_SUB_RING;
264 case ItemKindType::AMULET:
265 case ItemKindType::WHISTLE:
267 case ItemKindType::LITE:
269 case ItemKindType::DRAG_ARMOR:
270 case ItemKindType::HARD_ARMOR:
271 case ItemKindType::SOFT_ARMOR:
273 case ItemKindType::CLOAK:
275 case ItemKindType::CROWN:
276 case ItemKindType::HELM:
278 case ItemKindType::GLOVES:
280 case ItemKindType::BOOTS:
288 * @brief tval/sval指定のベースアイテムがプレイヤーの使用可能な魔法書かどうかを返す
289 * @param player_ptr プレイヤーへの参照ポインタ
290 * @param bi_key ベースアイテム特定キー
291 * @return 使用可能な魔法書ならばTRUEを返す。
293 bool check_book_realm(PlayerType *player_ptr, const BaseitemKey &bi_key)
295 if (!bi_key.is_spell_book()) {
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));
309 return (get_realm1_book(player_ptr) == tval) || (get_realm2_book(player_ptr) == tval);
312 ItemEntity *ref_item(PlayerType *player_ptr, INVENTORY_IDX i_idx)
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]);