OSDN Git Service

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