OSDN Git Service

[Feature] 啓蒙/周辺感知で壁の中の壁も感知する / 壁に囲まれた壁を表示するオプション #643
[hengbandforosx/hengbandosx.git] / src / knowledge / knowledge-inventory.cpp
1 /*
2  * @brief 装備の耐性を表示する
3  * @date 2020/04/20
4  * @author Hourier
5  */
6
7 #include "knowledge/knowledge-inventory.h"
8 #include "core/show-file.h"
9 #include "flavor/flavor-describer.h"
10 #include "flavor/object-flavor-types.h"
11 #include "floor/floor-town.h"
12 #include "inventory/inventory-slot-types.h"
13 #include "io-dump/dump-util.h"
14 #include "object-enchant/special-object-flags.h"
15 #include "object-enchant/tr-types.h"
16 #include "object-hook/hook-enchant.h"
17 #include "object-hook/hook-weapon.h"
18 #include "object/object-flags.h"
19 #include "perception/object-perception.h"
20 #include "store/store-util.h"
21 #include "sv-definition/sv-amulet-types.h"
22 #include "sv-definition/sv-protector-types.h"
23 #include "sv-definition/sv-ring-types.h"
24 #include "util/angband-files.h"
25 #include "util/bit-flags-calculator.h"
26
27 static concptr inven_res_label = _(
28     "                               酸電火冷毒閃暗破轟獄因沌劣 盲恐乱麻視経感遅活浮",
29     "                               AcElFiCoPoLiDkShSoNtNxCaDi BlFeCfFaSiHlEpSdRgLv");
30
31 #define IM_FLAG_STR _("*", "* ")
32 #define HAS_FLAG_STR _("+", "+ ")
33 #define NO_FLAG_STR _("・", ". ")
34
35 /*!
36  * @brief 4元素耐性を表示する
37  * @param immunity 4元素耐性の種類 (二重?)
38  * @param resistance 4元素耐性
39  * @param flags 耐性配列へのポインタ
40  * @param fff 一時ファイルへのポインタ
41  * @return なし
42  */
43 static void print_im_or_res_flag(int immunity, int resistance, BIT_FLAGS *flags, FILE *fff)
44 {
45     fputs(has_flag(flags, immunity) ? IM_FLAG_STR : (has_flag(flags, resistance) ? HAS_FLAG_STR : NO_FLAG_STR), fff);
46 }
47
48 /*!
49  * @brief 4元素以外の耐性を表示する
50  * @param tr 耐性
51  * @param flags 耐性配列へのポインタ
52  * @param fff 一時ファイルへのポインタ
53  * @return なし
54  */
55 static void print_flag(int tr, BIT_FLAGS *flags, FILE *fff) { fputs(has_flag(flags, tr) ? HAS_FLAG_STR : NO_FLAG_STR, fff); }
56
57 /*!
58  * @brief 特殊なアイテムかどうかを調べる
59  * @param o_ptr アイテムへの参照ポインタ
60  * @param tval アイテム主分類番号
61  * @return 特殊なアイテムならTRUE
62  */
63 static bool determine_spcial_item_type(object_type *o_ptr, tval_type tval)
64 {
65     bool is_special_item_type = (object_is_wearable(o_ptr) && object_is_ego(o_ptr)) || ((tval == TV_AMULET) && (o_ptr->sval == SV_AMULET_RESISTANCE))
66         || ((tval == TV_RING) && (o_ptr->sval == SV_RING_LORDLY)) || ((tval == TV_SHIELD) && (o_ptr->sval == SV_DRAGON_SHIELD))
67         || ((tval == TV_HELM) && (o_ptr->sval == SV_DRAGON_HELM)) || ((tval == TV_GLOVES) && (o_ptr->sval == SV_SET_OF_DRAGON_GLOVES))
68         || ((tval == TV_BOOTS) && (o_ptr->sval == SV_PAIR_OF_DRAGON_GREAVE)) || object_is_artifact(o_ptr);
69
70     return is_special_item_type;
71 }
72
73 /*!
74  * @brief アイテムに耐性の表示をする必要があるかを判定する
75  * @param o_ptr アイテムへの参照ポインタ
76  * @param tval アイテム主分類番号
77  * @return 必要があるならTRUE
78  */
79 static bool check_item_knowledge(object_type *o_ptr, tval_type tval)
80 {
81     if (o_ptr->k_idx == 0)
82         return FALSE;
83     if (o_ptr->tval != tval)
84         return FALSE;
85     if (!object_is_known(o_ptr))
86         return FALSE;
87     if (!determine_spcial_item_type(o_ptr, tval))
88         return FALSE;
89
90     return TRUE;
91 }
92
93 /*!
94  * @brief 鑑定済アイテムの耐性を表示する
95  * @param o_ptr アイテムへの参照ポインタ
96  * @param fff 一時ファイルへの参照ポインタ
97  * @return なし
98  * @todo ここの関数から表示用の関数に移したい
99  */
100 static void display_identified_resistances_flag(player_type *creature_ptr, object_type *o_ptr, FILE *fff)
101 {
102     BIT_FLAGS flags[TR_FLAG_SIZE];
103     object_flags_known(creature_ptr, o_ptr, flags);
104
105     print_im_or_res_flag(TR_IM_ACID, TR_RES_ACID, flags, fff);
106     print_im_or_res_flag(TR_IM_ELEC, TR_RES_ELEC, flags, fff);
107     print_im_or_res_flag(TR_IM_FIRE, TR_RES_FIRE, flags, fff);
108     print_im_or_res_flag(TR_IM_COLD, TR_RES_COLD, flags, fff);
109     print_flag(TR_RES_POIS, flags, fff);
110     print_flag(TR_RES_LITE, flags, fff);
111     print_flag(TR_RES_DARK, flags, fff);
112     print_flag(TR_RES_SHARDS, flags, fff);
113     print_flag(TR_RES_SOUND, flags, fff);
114     print_flag(TR_RES_NETHER, flags, fff);
115     print_flag(TR_RES_NEXUS, flags, fff);
116     print_flag(TR_RES_CHAOS, flags, fff);
117     print_flag(TR_RES_DISEN, flags, fff);
118
119     fputs(" ", fff);
120
121     print_flag(TR_RES_BLIND, flags, fff);
122     print_flag(TR_RES_FEAR, flags, fff);
123     print_flag(TR_RES_CONF, flags, fff);
124     print_flag(TR_FREE_ACT, flags, fff);
125     print_flag(TR_SEE_INVIS, flags, fff);
126     print_flag(TR_HOLD_EXP, flags, fff);
127     print_flag(TR_TELEPATHY, flags, fff);
128     print_flag(TR_SLOW_DIGEST, flags, fff);
129     print_flag(TR_REGEN, flags, fff);
130     print_flag(TR_LEVITATION, flags, fff);
131
132     fputc('\n', fff);
133 }
134
135 /*!
136  * @brief アイテム1つ当たりの耐性を表示する
137  * @param creature_ptr プレーヤーへの参照ポインタ
138  * @param fff 一時ファイルへの参照ポインタ
139  * @param o_ptr アイテムへの参照ポインタ
140  * @param where アイテムの場所 (手持ち、家等) を示す文字列への参照ポインタ
141  * @return なし
142  */
143 static void do_cmd_knowledge_inventory_aux(player_type *creature_ptr, FILE *fff, object_type *o_ptr, char *where)
144 {
145     int i = 0;
146     GAME_TEXT o_name[MAX_NLEN];
147     describe_flavor(creature_ptr, o_name, o_ptr, OD_NAME_ONLY);
148     while (o_name[i] && (i < 26)) {
149 #ifdef JP
150         if (iskanji(o_name[i]))
151             i++;
152 #endif
153         i++;
154     }
155
156     if (i < 28) {
157         while (i < 28) {
158             o_name[i] = ' ';
159             i++;
160         }
161     }
162
163     o_name[i] = '\0';
164
165     fprintf(fff, "%s %s", where, o_name);
166
167     if (!object_is_fully_known(o_ptr)) {
168         fputs(_("-------不明--------------- -------不明---------\n", "-------unknown------------ -------unknown------\n"), fff);
169         return;
170     }
171
172     display_identified_resistances_flag(creature_ptr, o_ptr, fff);
173 }
174
175 /*!
176  * @brief 9行おきにラベルを追加する
177  * @param label_number 現在の行数
178  * @param fff 一時ファイルへの参照ポインタ
179  * @return なし
180  */
181 static void add_res_label(int *label_number, FILE *fff)
182 {
183     (*label_number)++;
184     if (*label_number == 9) {
185         *label_number = 0;
186         fprintf(fff, "%s\n", inven_res_label);
187     }
188 }
189
190 /*!
191  * @brief 9行ごとに行数をリセットする
192  * @param label_number 現在の行数
193  * @param fff 一時ファイルへの参照ポインタ
194  * @return なし
195  */
196 static void reset_label_number(int *label_number, FILE *fff)
197 {
198     if (*label_number == 0)
199         return;
200
201     for (; *label_number < 9; (*label_number)++) {
202         fputc('\n', fff);
203     }
204
205     *label_number = 0;
206     fprintf(fff, "%s\n", inven_res_label);
207 }
208
209 /*!
210  * 装備中のアイテムについて、耐性を表示する
211  * @param creature_ptr プレーヤーへの参照ポインタ
212  * @param tval アイテム主分類番号
213  * @param label_number 現在の行数
214  * @param fff ファイルへの参照ポインタ
215  * @return なし
216  */
217 static void show_wearing_equipment_resistances(player_type *creature_ptr, tval_type tval, int *label_number, FILE *fff)
218 {
219     char where[32];
220     strcpy(where, _("装", "E "));
221     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
222         object_type *o_ptr = &creature_ptr->inventory_list[i];
223         if (!check_item_knowledge(o_ptr, tval))
224             continue;
225
226         do_cmd_knowledge_inventory_aux(creature_ptr, fff, o_ptr, where);
227         add_res_label(label_number, fff);
228     }
229 }
230
231 /*!
232  * 手持ち中のアイテムについて、耐性を表示する
233  * @param creature_ptr プレーヤーへの参照ポインタ
234  * @param tval アイテム主分類番号
235  * @param label_number 現在の行数
236  * @param fff ファイルへの参照ポインタ
237  * @return なし
238  */
239 static void show_holding_equipment_resistances(player_type *creature_ptr, tval_type tval, int *label_number, FILE *fff)
240 {
241     char where[32];
242     strcpy(where, _("持", "I "));
243     for (int i = 0; i < INVEN_PACK; i++) {
244         object_type *o_ptr = &creature_ptr->inventory_list[i];
245         if (!check_item_knowledge(o_ptr, tval))
246             continue;
247
248         do_cmd_knowledge_inventory_aux(creature_ptr, fff, o_ptr, where);
249         add_res_label(label_number, fff);
250     }
251 }
252
253 /*!
254  * 我が家のアイテムについて、耐性を表示する
255  * @param creature_ptr プレーヤーへの参照ポインタ
256  * @param tval アイテム主分類番号
257  * @param label_number 現在の行数
258  * @param fff ファイルへの参照ポインタ
259  * @return なし
260  */
261 static void show_home_equipment_resistances(player_type *creature_ptr, tval_type tval, int *label_number, FILE *fff)
262 {
263     store_type *store_ptr;
264     store_ptr = &town_info[1].store[STORE_HOME];
265     char where[32];
266     strcpy(where, _("家", "H "));
267     for (int i = 0; i < store_ptr->stock_num; i++) {
268         object_type *o_ptr = &store_ptr->stock[i];
269         if (!check_item_knowledge(o_ptr, tval))
270             continue;
271
272         do_cmd_knowledge_inventory_aux(creature_ptr, fff, o_ptr, where);
273         add_res_label(label_number, fff);
274     }
275 }
276
277 /*
278  * @brief Display *ID* ed weapons/armors's resistances
279  * @param creature_ptr プレーヤーへの参照ポインタ
280  * @return なし
281  */
282 void do_cmd_knowledge_inventory(player_type *creature_ptr)
283 {
284     FILE *fff = NULL;
285     GAME_TEXT file_name[FILE_NAME_SIZE];
286     if (!open_temporary_file(&fff, file_name))
287         return;
288
289     fprintf(fff, "%s\n", inven_res_label);
290     int label_number = 0;
291     for (int tval = TV_WEARABLE_BEGIN; tval <= TV_WEARABLE_END; tval++) {
292         reset_label_number(&label_number, fff);
293         show_wearing_equipment_resistances(creature_ptr, static_cast<tval_type>(tval), &label_number, fff);
294         show_holding_equipment_resistances(creature_ptr, static_cast<tval_type>(tval), &label_number, fff);
295         show_home_equipment_resistances(creature_ptr, static_cast<tval_type>(tval), &label_number, fff);
296     }
297
298     angband_fclose(fff);
299     (void)show_file(creature_ptr, TRUE, file_name, _("*鑑定*済み武器/防具の耐性リスト", "Resistances of *identified* equipment"), 0, 0);
300     fd_kill(file_name);
301 }