OSDN Git Service

Merge pull request #41491 (taotao/hengband/fix-impure_calc_num_blow into develop).
[hengband/hengband.git] / src / object / object-info.c
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 "object/object-flags.h"
23 #include "object/object-kind.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/floor-type-definition.h"
29 #include "term/term-color-types.h"
30 #include "util/bit-flags-calculator.h"
31 #include "util/int-char-converter.h"
32
33 /*!
34  * @brief オブジェクトの発動効果名称を返す(サブルーチン/ブレス)
35  * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
36  * @return concptr 発動名称を返す文字列ポインタ
37  */
38 static concptr item_activation_dragon_breath(player_type *owner_ptr, object_type *o_ptr)
39 {
40     static char desc[256];
41     BIT_FLAGS flgs[TR_FLAG_SIZE]; /* for resistance flags */
42     int n = 0;
43
44     object_flags(owner_ptr, o_ptr, flgs);
45     strcpy(desc, _("", "breath "));
46
47     for (int i = 0; dragonbreath_info[i].flag != 0; i++) {
48         if (has_flag(flgs, dragonbreath_info[i].flag)) {
49             if (n > 0)
50                 strcat(desc, _("、", ", "));
51
52             strcat(desc, dragonbreath_info[i].name);
53             n++;
54         }
55     }
56
57     strcat(desc, _("のブレス(250)", ""));
58     return (desc);
59 }
60
61 /*!
62  * @brief オブジェクトの発動効果名称を返す(サブルーチン/汎用)
63  * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
64  * @return concptr 発動名称を返す文字列ポインタ
65  */
66 static concptr item_activation_aux(player_type *owner_ptr, object_type *o_ptr)
67 {
68     static char activation_detail[256];
69     char timeout[32];
70     const activation_type *const act_ptr = find_activation_info(owner_ptr, o_ptr);
71
72     if (!act_ptr)
73         return _("未定義", "something undefined");
74
75     concptr desc = act_ptr->desc;
76     switch (act_ptr->index) {
77     case ACT_BR_FIRE:
78         if ((o_ptr->tval == TV_RING) && (o_ptr->sval == SV_RING_FLAMES))
79             desc = _("火炎のブレス (200) と火への耐性", "breath of fire (200) and resist fire");
80         break;
81     case ACT_BR_COLD:
82         if ((o_ptr->tval == TV_RING) && (o_ptr->sval == SV_RING_ICE))
83             desc = _("冷気のブレス (200) と冷気への耐性", "breath of cold (200) and resist cold");
84         break;
85     case ACT_BR_DRAGON:
86         desc = item_activation_dragon_breath(owner_ptr, o_ptr);
87         break;
88     case ACT_AGGRAVATE:
89         if (o_ptr->name1 == ART_HYOUSIGI)
90             desc = _("拍子木を打ちならす", "beat wooden clappers");
91         break;
92     case ACT_ACID_BALL_AND_RESISTANCE:
93         desc = _("アシッド・ボール (100) と酸への耐性", "ball of acid (100) and resist acid");
94         break;
95     case ACT_FIRE_BALL_AND_RESISTANCE:
96         desc = _("ファイア・ボール (100) と火への耐性", "ball of fire (100) and resist fire");
97         break;
98     case ACT_COLD_BALL_AND_RESISTANCE:
99         desc = _("アイス・ボール (100) と冷気への耐性", "ball of cold (100) and resist cold");
100         break;
101     case ACT_ELEC_BALL_AND_RESISTANCE:
102         desc = _("サンダー・ボール (100) と電撃への耐性", "ball of elec (100) and resist elec");
103         break;
104     case ACT_POIS_BALL_AND_RESISTANCE:
105         desc = _("ポイズン・ボール (100) と毒への耐性", "ball of poison (100) and resist elec");
106         break;
107     case ACT_RESIST_ACID:
108         desc = _("一時的な酸への耐性", "tempral resist acid");
109         break;
110     case ACT_RESIST_FIRE:
111         desc = _("一時的な火への耐性", "tempral resist fire");
112         break;
113     case ACT_RESIST_COLD:
114         desc = _("一時的な冷気への耐性", "tempral resist cold");
115         break;
116     case ACT_RESIST_ELEC:
117         desc = _("一時的な電撃への耐性", "tempral resist elec");
118         break;
119     case ACT_RESIST_POIS:
120         desc = _("一時的な毒への耐性", "tempral resist elec");
121         break;
122     }
123
124     /* Timeout description */
125     int constant = act_ptr->timeout.constant;
126     int dice = act_ptr->timeout.dice;
127     if (constant == 0 && dice == 0) {
128         /* We can activate it every turn */
129         strcpy(timeout, _("いつでも", "every turn"));
130     } else if (constant < 0) {
131         /* Activations that have special timeout */
132         switch (act_ptr->index) {
133         case ACT_BR_FIRE:
134             sprintf(timeout, _("%d ターン毎", "every %d turns"), ((o_ptr->tval == TV_RING) && (o_ptr->sval == SV_RING_FLAMES)) ? 200 : 250);
135             break;
136         case ACT_BR_COLD:
137             sprintf(timeout, _("%d ターン毎", "every %d turns"), ((o_ptr->tval == TV_RING) && (o_ptr->sval == SV_RING_ICE)) ? 200 : 250);
138             break;
139         case ACT_TERROR:
140             strcpy(timeout, _("3*(レベル+10) ターン毎", "every 3 * (level+10) turns"));
141             break;
142         case ACT_MURAMASA:
143             strcpy(timeout, _("確率50%で壊れる", "(destroyed 50%)"));
144             break;
145         default:
146             strcpy(timeout, "undefined");
147             break;
148         }
149     } else {
150         char constant_str[16], dice_str[16];
151         sprintf(constant_str, "%d", constant);
152         sprintf(dice_str, "d%d", dice);
153         sprintf(timeout, _("%s%s%s ターン毎", "every %s%s%s turns"), (constant > 0) ? constant_str : "", (constant > 0 && dice > 0) ? "+" : "",
154             (dice > 0) ? dice_str : "");
155     }
156
157     sprintf(activation_detail, _("%s : %s", "%s %s"), desc, timeout);
158     return activation_detail;
159 }
160
161 /*!
162  * @brief オブジェクトの発動効果名称を返す(メインルーチン) /
163  * Determine the "Activation" (if any) for an artifact Return a string, or NULL for "no activation"
164  * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
165  * @return concptr 発動名称を返す文字列ポインタ
166  */
167 concptr activation_explanation(player_type *owner_ptr, object_type *o_ptr)
168 {
169     BIT_FLAGS flgs[TR_FLAG_SIZE];
170     object_flags(owner_ptr, o_ptr, flgs);
171     if (!(has_flag(flgs, TR_ACTIVATE)))
172         return (_("なし", "nothing"));
173
174     if (activation_index(owner_ptr, o_ptr)) {
175         return item_activation_aux(owner_ptr, o_ptr);
176     }
177
178     if (o_ptr->tval == TV_WHISTLE) {
179         return _("ペット呼び寄せ : 100+d100ターン毎", "call pet every 100+d100 turns");
180     }
181
182     if (o_ptr->tval == TV_CAPTURE) {
183         return _("モンスターを捕える、又は解放する。", "captures or releases a monster.");
184     }
185
186     return _("何も起きない", "Nothing");
187 }
188
189 /*!
190  * @brief オブジェクト選択時の選択アルファベットラベルを返す /
191  * Convert an inventory index into a one character label
192  * @param i プレイヤーの所持/装備オブジェクトID
193  * @return 対応するアルファベット
194  * @details Note that the label does NOT distinguish inven/equip.
195  */
196 char index_to_label(int i) { return (i < INVEN_MAIN_HAND) ? (I2A(i)) : (I2A(i - INVEN_MAIN_HAND)); }
197
198 /*!
199  * @brief オブジェクトの該当装備部位IDを返す /
200  * Determine which equipment slot (if any) an item likes
201  * @param o_ptr 名称を取得する元のオブジェクト構造体参照ポインタ
202  * @return 対応する装備部位ID
203  */
204 s16b wield_slot(player_type *owner_ptr, object_type *o_ptr)
205 {
206     switch (o_ptr->tval) {
207     case TV_DIGGING:
208     case TV_HAFTED:
209     case TV_POLEARM:
210     case TV_SWORD: {
211         if (!owner_ptr->inventory_list[INVEN_MAIN_HAND].k_idx)
212             return (INVEN_MAIN_HAND);
213         if (owner_ptr->inventory_list[INVEN_SUB_HAND].k_idx)
214             return (INVEN_MAIN_HAND);
215         return (INVEN_SUB_HAND);
216     }
217     case TV_CAPTURE:
218     case TV_CARD:
219     case TV_SHIELD: {
220         if (!owner_ptr->inventory_list[INVEN_SUB_HAND].k_idx)
221             return (INVEN_SUB_HAND);
222         if (owner_ptr->inventory_list[INVEN_MAIN_HAND].k_idx)
223             return (INVEN_SUB_HAND);
224         return (INVEN_MAIN_HAND);
225     }
226     case TV_BOW: {
227         return (INVEN_BOW);
228     }
229     case TV_RING: {
230         if (!owner_ptr->inventory_list[INVEN_MAIN_RING].k_idx)
231             return (INVEN_MAIN_RING);
232
233         return (INVEN_SUB_RING);
234     }
235     case TV_AMULET:
236     case TV_WHISTLE: {
237         return (INVEN_NECK);
238     }
239     case TV_LITE: {
240         return (INVEN_LITE);
241     }
242     case TV_DRAG_ARMOR:
243     case TV_HARD_ARMOR:
244     case TV_SOFT_ARMOR: {
245         return (INVEN_BODY);
246     }
247     case TV_CLOAK: {
248         return (INVEN_OUTER);
249     }
250     case TV_CROWN:
251     case TV_HELM: {
252         return (INVEN_HEAD);
253     }
254     case TV_GLOVES: {
255         return (INVEN_ARMS);
256     }
257     case TV_BOOTS: {
258         return (INVEN_FEET);
259     }
260     }
261
262     return -1;
263 }
264
265 /*!
266  * @brief tval/sval指定のベースアイテムがプレイヤーの使用可能な魔法書かどうかを返す /
267  * Hack: Check if a spellbook is one of the realms we can use. -- TY
268  * @param book_tval ベースアイテムのtval
269  * @param book_sval ベースアイテムのsval
270  * @return 使用可能な魔法書ならばTRUEを返す。
271  */
272 bool check_book_realm(player_type *owner_ptr, const tval_type book_tval, const OBJECT_SUBTYPE_VALUE book_sval)
273 {
274     if (book_tval < TV_LIFE_BOOK)
275         return FALSE;
276     if (owner_ptr->pclass == CLASS_SORCERER) {
277         return is_magic(tval2realm(book_tval));
278     } else if (owner_ptr->pclass == CLASS_RED_MAGE) {
279         if (is_magic(tval2realm(book_tval)))
280             return ((book_tval == TV_ARCANE_BOOK) || (book_sval < 2));
281     }
282
283     return (get_realm1_book(owner_ptr) == book_tval || get_realm2_book(owner_ptr) == book_tval);
284 }
285
286 object_type *ref_item(player_type *owner_ptr, INVENTORY_IDX item)
287 {
288     floor_type *floor_ptr = owner_ptr->current_floor_ptr;
289     return item >= 0 ? &owner_ptr->inventory_list[item] : &(floor_ptr->o_list[0 - item]);
290 }
291
292 /*
293  * Return the "attr" for a given item.
294  * Use "flavor" if available.
295  * Default to user definitions.
296  */
297 TERM_COLOR object_attr(object_type *o_ptr)
298 {
299     return ((k_info[o_ptr->k_idx].flavor)
300             ? (k_info[k_info[o_ptr->k_idx].flavor].x_attr)
301             : ((!o_ptr->k_idx || (o_ptr->tval != TV_CORPSE) || (o_ptr->sval != SV_CORPSE) || (k_info[o_ptr->k_idx].x_attr != TERM_DARK))
302                     ? (k_info[o_ptr->k_idx].x_attr)
303                     : (r_info[o_ptr->pval].x_attr)));
304 }