OSDN Git Service

Merge branch 'master' of https://github.com/hengband/hengband
[hengbandforosx/hengbandosx.git] / src / wizard / artifact-analyzer.cpp
1 #include "wizard/artifact-analyzer.h"
2 #include "flavor/flavor-describer.h"
3 #include "flavor/object-flavor-types.h"
4 #include "locale/japanese.h"
5 #include "object-enchant/object-ego.h"
6 #include "object-enchant/trc-types.h"
7 #include "object-enchant/trg-types.h"
8 #include "object/object-flags.h"
9 #include "object/object-info.h"
10 #include "system/artifact-type-definition.h"
11 #include "system/item-entity.h"
12 #include "term/z-form.h"
13 #include "util/bit-flags-calculator.h"
14 #include "util/enum-converter.h"
15 #include "util/enum-range.h"
16 #include "util/quarks.h"
17 #include "util/string-processor.h"
18 #include "wizard/spoiler-util.h"
19
20 /*!
21  * @brief アーティファクトの特性一覧を出力する /
22  * Write a line to the spoiler file and then "underline" it with hypens
23  * @param art_flags アーティファクトのフラグ群
24  * @param flag_ptr フラグ記述情報の参照ポインタ
25  * @param desc_ptr 記述内容を返すための文字列参照ポインタ
26  * @param n_elmnts フラグの要素数
27  * @return desc_ptrと同じアドレス
28  * @details
29  * <pre>
30  * This function does most of the actual "analysis". Given a set of bit flags
31  * (which will be from one of the flags fields from the object in question),
32  * a "flag description structure", a "description list", and the number of
33  * elements in the "flag description structure", this function sets the
34  * "description list" members to the appropriate descriptions contained in
35  * the "flag description structure".
36  * The possibly updated description pointer is returned.
37  * </pre>
38  */
39 static concptr *spoiler_flag_aux(const TrFlags &art_flags, const flag_desc *flag_ptr, concptr *desc_ptr, const int n_elmnts)
40 {
41     for (int i = 0; i < n_elmnts; ++i) {
42         if (art_flags.has(flag_ptr[i].flag)) {
43             *desc_ptr++ = flag_ptr[i].desc;
44         }
45     }
46
47     return desc_ptr;
48 }
49
50 /*!
51  * @brief アイテムの特定記述内容を返す /
52  * Acquire a "basic" description "The Cloak of Death [1,+10]"
53  * @param o_ptr 記述を得たいオブジェクトの参照ポインタ
54  * @param desc_ptr 記述内容を返すための文字列参照ポインタ
55  */
56 static std::string analyze_general(PlayerType *player_ptr, ItemEntity *o_ptr)
57 {
58     return describe_flavor(player_ptr, o_ptr, OD_NAME_AND_ENCHANT | OD_STORE | OD_DEBUG);
59 }
60
61 /*!
62  * @brief アーティファクトがプレイヤーに与えるpval修正を構造体に収める /
63  * List "player traits" altered by an artifact's pval. These include stats,
64  * speed, infravision, tunneling, stealth, searching, and extra attacks.
65  * @param o_ptr オブジェクト構造体の参照ポインタ
66  * @param pi_ptr pval修正構造体の参照ポインタ
67  */
68 static void analyze_pval(ItemEntity *o_ptr, pval_info_type *pi_ptr)
69 {
70     concptr *affects_list;
71     if (!o_ptr->pval) {
72         pi_ptr->pval_desc[0] = '\0';
73         return;
74     }
75
76     auto flags = object_flags(o_ptr);
77     affects_list = pi_ptr->pval_affects;
78     strnfmt(pi_ptr->pval_desc, sizeof(pi_ptr->pval_desc), "%s%d", o_ptr->pval >= 0 ? "+" : "", o_ptr->pval);
79     if (flags.has_all_of(EnumRange(TR_STR, TR_CHR))) {
80         *affects_list++ = _("全能力", "All stats");
81     } else if (flags.has_any_of(EnumRange(TR_STR, TR_CHR))) {
82         affects_list = spoiler_flag_aux(flags, stat_flags_desc, affects_list, N_ELEMENTS(stat_flags_desc));
83     }
84
85     affects_list = spoiler_flag_aux(flags, pval_flags1_desc, affects_list, N_ELEMENTS(pval_flags1_desc));
86     *affects_list = nullptr;
87 }
88
89 /*!
90  * @brief アーティファクトの種族スレイ特性を構造体に収める /
91  * Note the slaying specialties of a weapon
92  * @param o_ptr オブジェクト構造体の参照ポインタ
93  * @param slay_list 種族スレイ構造体の参照ポインタ
94  */
95 static void analyze_slay(ItemEntity *o_ptr, concptr *slay_list)
96 {
97     auto flags = object_flags(o_ptr);
98     slay_list = spoiler_flag_aux(flags, slay_flags_desc, slay_list, N_ELEMENTS(slay_flags_desc));
99     *slay_list = nullptr;
100 }
101
102 /*!
103  * @brief アーティファクトの属性ブランド特性を構造体に収める /
104  * Note an object's elemental brands
105  * @param o_ptr オブジェクト構造体の参照ポインタ
106  * @param brand_list 属性ブランド構造体の参照ポインタ
107  */
108 static void analyze_brand(ItemEntity *o_ptr, concptr *brand_list)
109 {
110     auto flags = object_flags(o_ptr);
111     brand_list = spoiler_flag_aux(flags, brand_flags_desc, brand_list, N_ELEMENTS(brand_flags_desc));
112     *brand_list = nullptr;
113 }
114
115 /*!
116  * @brief アーティファクトの通常耐性を構造体に収める /
117  * Note an object's elemental brands
118  * @param o_ptr オブジェクト構造体の参照ポインタ
119  * @param resist_list 通常耐性構造体の参照ポインタ
120  */
121 static void analyze_resist(ItemEntity *o_ptr, concptr *resist_list)
122 {
123     auto flags = object_flags(o_ptr);
124     resist_list = spoiler_flag_aux(flags, resist_flags_desc, resist_list, N_ELEMENTS(resist_flags_desc));
125     *resist_list = nullptr;
126 }
127
128 /*!
129  * @brief アーティファクトの免疫特性を構造体に収める /
130  * Note the immunities granted by an object
131  * @param o_ptr オブジェクト構造体の参照ポインタ
132  * @param immune_list 免疫構造体の参照ポインタ
133  */
134 static void analyze_immune(ItemEntity *o_ptr, concptr *immune_list)
135 {
136     auto flags = object_flags(o_ptr);
137     immune_list = spoiler_flag_aux(flags, immune_flags_desc, immune_list, N_ELEMENTS(immune_flags_desc));
138     *immune_list = nullptr;
139 }
140
141 /*!
142  * @brief アーティファクトの弱点付与を構造体に収める /
143  * Note the immunities granted by an object
144  * @param o_ptr オブジェクト構造体の参照ポインタ
145  * @param immune_list 弱点構造体の参照ポインタ
146  */
147 static void analyze_vulnerable(ItemEntity *o_ptr, concptr *vulnerable_list)
148 {
149     auto flags = object_flags(o_ptr);
150     vulnerable_list = spoiler_flag_aux(flags, vulnerable_flags_desc, vulnerable_list, N_ELEMENTS(vulnerable_flags_desc));
151     *vulnerable_list = nullptr;
152 }
153
154 /*!
155  * @brief アーティファクトの維持特性を構造体に収める /
156  * Note which stats an object sustains
157  * @param o_ptr オブジェクト構造体の参照ポインタ
158  * @param sustain_list 維持特性構造体の参照ポインタ
159  */
160 static void analyze_sustains(ItemEntity *o_ptr, concptr *sustain_list)
161 {
162     auto flags = object_flags(o_ptr);
163     if (flags.has_all_of(EnumRange(TR_SUST_STR, TR_SUST_CHR))) {
164         *sustain_list++ = _("全能力", "All stats");
165     } else if (flags.has_any_of(EnumRange(TR_SUST_STR, TR_SUST_CHR))) {
166         sustain_list = spoiler_flag_aux(flags, sustain_flags_desc, sustain_list, N_ELEMENTS(sustain_flags_desc));
167     }
168
169     *sustain_list = nullptr;
170 }
171
172 /*!
173  * @brief アーティファクトのその他の特性を構造体に収める /
174  * Note miscellaneous powers bestowed by an artifact such as see invisible,
175  * free action, permanent light, etc.
176  * @param o_ptr オブジェクト構造体の参照ポインタ
177  * @param misc_list その他の特性構造体の参照ポインタ
178  */
179 static void analyze_misc_magic(ItemEntity *o_ptr, concptr *misc_list)
180 {
181     auto flags = object_flags(o_ptr);
182     misc_list = spoiler_flag_aux(flags, misc_flags2_desc, misc_list, N_ELEMENTS(misc_flags2_desc));
183     misc_list = spoiler_flag_aux(flags, misc_flags3_desc, misc_list, N_ELEMENTS(misc_flags3_desc));
184     POSITION rad = 0;
185     if (flags.has(TR_LITE_1)) {
186         rad += 1;
187     }
188
189     if (flags.has(TR_LITE_2)) {
190         rad += 2;
191     }
192
193     if (flags.has(TR_LITE_3)) {
194         rad += 3;
195     }
196
197     if (flags.has(TR_LITE_M1)) {
198         rad -= 1;
199     }
200
201     if (flags.has(TR_LITE_M2)) {
202         rad -= 2;
203     }
204
205     if (flags.has(TR_LITE_M3)) {
206         rad -= 3;
207     }
208
209     if (o_ptr->ego_idx == EgoType::LITE_SHINE) {
210         rad++;
211     }
212
213     std::string desc;
214     if (flags.has(TR_LITE_FUEL)) {
215         if (rad > 0) {
216             desc = format(_("それは燃料補給によって明かり(半径 %d)を授ける。", "It provides light (radius %d) when fueled."), (int)rad);
217         }
218     } else {
219         if (rad > 0) {
220             desc = format(_("永久光源(半径 %d)", "Permanent Light(radius %d)"), (int)rad);
221         } else if (rad < 0) {
222             desc = format(_("永久光源(半径-%d)。", "Permanent Light(radius -%d)"), (int)-rad);
223         }
224     }
225
226     if (rad != 0) {
227         *misc_list++ = quark_str(quark_add(desc.data()));
228     }
229
230     if (flags.has(TR_TY_CURSE)) {
231         *misc_list++ = _("太古の怨念", "Ancient Curse");
232     }
233
234     if (o_ptr->curse_flags.has(CurseTraitType::PERMA_CURSE)) {
235         *misc_list++ = _("永遠の呪い", "Permanently Cursed");
236     } else if (o_ptr->curse_flags.has(CurseTraitType::HEAVY_CURSE)) {
237         *misc_list++ = _("強力な呪い", "Heavily Cursed");
238     } else if (o_ptr->curse_flags.has(CurseTraitType::CURSED)) {
239         *misc_list++ = _("呪い", "Cursed");
240     }
241
242     if (flags.has(TR_ADD_L_CURSE)) {
243         *misc_list++ = _("呪いを増やす", "Cursing");
244     }
245
246     if (flags.has(TR_ADD_H_CURSE)) {
247         *misc_list++ = _("強力な呪いを増やす", "Heavily Cursing");
248     }
249
250     *misc_list = nullptr;
251 }
252
253 /*!
254  * @brief アーティファクトの追加ランダム特性を構造体に収める /
255  * Note additional ability and/or resistance of fixed artifacts
256  * @param o_ptr オブジェクト構造体の参照ポインタ
257  * @param addition 追加ランダム耐性構造体の参照ポインタ
258  * @param addition_sz addition に書き込めるバイト数
259  */
260 static void analyze_addition(ItemEntity *o_ptr, char *addition, size_t addition_sz)
261 {
262     const auto &artifact = o_ptr->get_fixed_artifact();
263     strcpy(addition, "");
264
265     if (artifact.gen_flags.has_all_of({ ItemGenerationTraitType::XTRA_POWER, ItemGenerationTraitType::XTRA_H_RES })) {
266         angband_strcat(addition, _("能力and耐性", "Ability and Resistance"), addition_sz);
267     } else if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_POWER)) {
268         angband_strcat(addition, _("能力", "Ability"), addition_sz);
269         if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_RES_OR_POWER)) {
270             angband_strcat(addition, _("(1/2でand耐性)", "(plus Resistance about 1/2)"), addition_sz);
271         }
272     } else if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_H_RES)) {
273         angband_strcat(addition, _("耐性", "Resistance"), addition_sz);
274         if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_RES_OR_POWER)) {
275             angband_strcat(addition, _("(1/2でand能力)", "(plus Ability about 1/2)"), addition_sz);
276         }
277     } else if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_RES_OR_POWER)) {
278         angband_strcat(addition, _("能力or耐性", "Ability or Resistance"), addition_sz);
279     }
280
281     if (artifact.gen_flags.has(ItemGenerationTraitType::XTRA_DICE)) {
282         if (strlen(addition) > 0) {
283             angband_strcat(addition, _("、", ", "), addition_sz);
284         }
285         angband_strcat(addition, _("ダイス数", "Dice number"), addition_sz);
286     }
287 }
288
289 /*!
290  * @brief アーティファクトの基本情報を文字列に収める /
291  * Determine the minimum depth an artifact can appear, its rarity, its weight,
292  * and its value in gold pieces
293  * @param o_ptr オブジェクト構造体の参照ポインタ
294  * @param misc_desc 基本情報を収める文字列参照ポインタ
295  * @param misc_desc_sz misc_desc に書き込めるバイト数
296  */
297 static void analyze_misc(ItemEntity *o_ptr, char *misc_desc, size_t misc_desc_sz)
298 {
299     const auto &artifact = o_ptr->get_fixed_artifact();
300     const auto *mes = _("レベル %d, 希少度 %u, %d.%d kg, $%ld", "Level %d, Rarity %u, %d.%d lbs, %ld Gold");
301     strnfmt(misc_desc, misc_desc_sz, mes, (int)artifact.level, artifact.rarity,
302         _(lb_to_kg_integer(artifact.weight), artifact.weight / 10), _(lb_to_kg_fraction(artifact.weight), artifact.weight % 10), (long int)artifact.cost);
303 }
304
305 /*!
306  * @brief アーティファクトの情報全体を構造体に収める /
307  * Fill in an object description structure for a given object
308  * and its value in gold pieces
309  * @param player_ptr プレイヤーへの参照ポインタ
310  * @param o_ptr オブジェクト構造体の参照ポインタ
311  * @param desc_ptr 全アーティファクト情報を収める文字列参照ポインタ
312  */
313 void object_analyze(PlayerType *player_ptr, ItemEntity *o_ptr, obj_desc_list *desc_ptr)
314 {
315     angband_strcpy(desc_ptr->description, analyze_general(player_ptr, o_ptr).data(), MAX_NLEN);
316     analyze_pval(o_ptr, &desc_ptr->pval_info);
317     analyze_brand(o_ptr, desc_ptr->brands);
318     analyze_slay(o_ptr, desc_ptr->slays);
319     analyze_immune(o_ptr, desc_ptr->immunities);
320     analyze_resist(o_ptr, desc_ptr->resistances);
321     analyze_vulnerable(o_ptr, desc_ptr->vulnerables);
322     analyze_sustains(o_ptr, desc_ptr->sustains);
323     analyze_misc_magic(o_ptr, desc_ptr->misc_magic);
324     analyze_addition(o_ptr, desc_ptr->addition, sizeof(desc_ptr->addition));
325     analyze_misc(o_ptr, desc_ptr->misc_desc, sizeof(desc_ptr->misc_desc));
326     desc_ptr->activation = activation_explanation(o_ptr);
327 }
328
329 /*!
330  * @brief ランダムアーティファクト1件を解析する /
331  * Fill in an object description structure for a given object
332  * @param player_ptr プレイヤーへの参照ポインタ
333  * @param o_ptr ランダムアーティファクトのオブジェクト構造体参照ポインタ
334  * @param desc_ptr 記述内容を収める構造体参照ポインタ
335  */
336 void random_artifact_analyze(PlayerType *player_ptr, ItemEntity *o_ptr, obj_desc_list *desc_ptr)
337 {
338     angband_strcpy(desc_ptr->description, analyze_general(player_ptr, o_ptr).data(), MAX_NLEN);
339     analyze_pval(o_ptr, &desc_ptr->pval_info);
340     analyze_brand(o_ptr, desc_ptr->brands);
341     analyze_slay(o_ptr, desc_ptr->slays);
342     analyze_immune(o_ptr, desc_ptr->immunities);
343     analyze_resist(o_ptr, desc_ptr->resistances);
344     analyze_vulnerable(o_ptr, desc_ptr->vulnerables);
345     analyze_sustains(o_ptr, desc_ptr->sustains);
346     analyze_misc_magic(o_ptr, desc_ptr->misc_magic);
347     desc_ptr->activation = activation_explanation(o_ptr);
348     strnfmt(desc_ptr->misc_desc, sizeof(desc_ptr->misc_desc), _("重さ %d.%d kg", "Weight %d.%d lbs"), _(lb_to_kg_integer(o_ptr->weight), o_ptr->weight / 10),
349         _(lb_to_kg_fraction(o_ptr->weight), o_ptr->weight % 10));
350 }