OSDN Git Service

[Refactor] #3733 optional 型の値取得処理 value() を撤廃した その3
[hengbandforosx/hengbandosx.git] / src / flavor / flavor-util.cpp
1 #include "flavor/flavor-util.h"
2 #include "flavor/flag-inscriptions-table.h"
3 #include "object-enchant/tr-flags.h"
4 #include "object-enchant/tr-types.h"
5 #include "object/tval-types.h"
6 #include "sv-definition/sv-food-types.h"
7 #include "system/artifact-type-definition.h"
8 #include "system/item-entity.h"
9 #include "util/string-processor.h"
10 #include <sstream>
11
12 static bool has_lite_flag(const TrFlags &flags)
13 {
14     return flags.has(TR_LITE_1) || flags.has(TR_LITE_2) || flags.has(TR_LITE_3);
15 }
16
17 static bool has_dark_flag(const TrFlags &flags)
18 {
19     return flags.has(TR_LITE_M1) || flags.has(TR_LITE_M2) || flags.has(TR_LITE_M3);
20 }
21
22 /*!
23  * @brief get_inscriptionのサブセットとしてアイテムの特性フラグを表す文字列を返す
24  * @param fi_vec 参照する特性表示記号テーブル
25  * @param flags 対応するアイテムの特性フラグ
26  * @param is_kanji trueならば漢字記述/falseならば英語記述
27  * @return アイテムの特性フラグを表す文字列
28  */
29 static std::string inscribe_flags_aux(const std::vector<flag_insc_table> &fi_vec, const TrFlags &flags, [[maybe_unused]] bool is_kanji)
30 {
31     std::stringstream ss;
32
33     for (const auto &fi : fi_vec) {
34         if (flags.has(fi.flag) && (!fi.except_flag || flags.has_not(*fi.except_flag))) {
35             const auto flag_str = _(is_kanji ? fi.japanese : fi.english, fi.english);
36             ss << flag_str;
37         }
38     }
39
40     return ss.str();
41 }
42
43 /*!
44  * @brief オブジェクトの特性表示記号テーブル1つに従いオブジェクトの特性フラグ配列に1つでも該当の特性があるかを返す / Special variation of has_flag for
45  * auto-inscription
46  * @param fi_vec 参照する特性表示記号テーブル
47  * @param flags 対応するオブジェクトのフラグ文字列
48  * @return 1つでも該当の特性があったらTRUEを返す。
49  */
50 static bool has_flag_of(const std::vector<flag_insc_table> &fi_vec, const TrFlags &flags)
51 {
52     for (const auto &fi : fi_vec) {
53         if (flags.has(fi.flag) && (!fi.except_flag || flags.has_not(*fi.except_flag))) {
54             return true;
55         }
56     }
57
58     return false;
59 }
60
61 /*!
62  * @brief アイテムの特性短縮表記をまとめて提示する。
63  * @param item 特性短縮表記を得たいアイテムの参照
64  * @param is_kanji trueならば漢字表記 / falseなら英語表記
65  * @param all falseならばベースアイテム上で明らかなフラグは省略する
66  * @return アイテムの特性短縮表記
67  */
68 std::string get_ability_abbreviation(const ItemEntity &item, bool is_kanji, bool all)
69 {
70     auto flags = item.get_flags();
71     if (!all) {
72         const auto &baseitem = item.get_baseitem();
73         flags.reset(baseitem.flags);
74
75         if (item.is_fixed_artifact()) {
76             const auto &artifact = item.get_fixed_artifact();
77             flags.reset(artifact.flags);
78         }
79
80         if (item.is_ego()) {
81             const auto &ego = item.get_ego();
82             flags.reset(ego.flags);
83         }
84     }
85
86     if (has_dark_flag(flags)) {
87         if (flags.has(TR_LITE_1)) {
88             flags.reset(TR_LITE_1);
89         }
90
91         if (flags.has(TR_LITE_2)) {
92             flags.reset(TR_LITE_2);
93         }
94
95         if (flags.has(TR_LITE_3)) {
96             flags.reset(TR_LITE_3);
97         }
98     } else if (has_lite_flag(flags)) {
99         flags.set(TR_LITE_1);
100         if (flags.has(TR_LITE_2)) {
101             flags.reset(TR_LITE_2);
102         }
103
104         if (flags.has(TR_LITE_3)) {
105             flags.reset(TR_LITE_3);
106         }
107     }
108
109     std::stringstream ss;
110     auto prev_tellp = ss.tellp();
111
112     if (has_flag_of(flag_insc_plus, flags) && is_kanji) {
113         ss << '+';
114     }
115
116     ss << inscribe_flags_aux(flag_insc_plus, flags, is_kanji);
117
118     if (has_flag_of(flag_insc_immune, flags)) {
119         if (!is_kanji && (ss.tellp() != prev_tellp)) {
120             ss << ';';
121             prev_tellp = ss.tellp();
122         }
123
124         ss << '*';
125     }
126
127     ss << inscribe_flags_aux(flag_insc_immune, flags, is_kanji);
128
129     if (has_flag_of(flag_insc_vuln, flags)) {
130         if (!is_kanji && (ss.tellp() != prev_tellp)) {
131             ss << ';';
132             prev_tellp = ss.tellp();
133         }
134
135         ss << 'v';
136     }
137
138     ss << inscribe_flags_aux(flag_insc_vuln, flags, is_kanji);
139
140     if (has_flag_of(flag_insc_resistance, flags)) {
141         if (is_kanji) {
142             ss << 'r';
143         } else if (ss.tellp() != prev_tellp) {
144             ss << ';';
145             prev_tellp = ss.tellp();
146         }
147     }
148
149     ss << inscribe_flags_aux(flag_insc_resistance, flags, is_kanji);
150
151     if (has_flag_of(flag_insc_misc, flags) && (ss.tellp() != prev_tellp)) {
152         ss << ';';
153         prev_tellp = ss.tellp();
154     }
155
156     ss << inscribe_flags_aux(flag_insc_misc, flags, is_kanji);
157
158     if (has_flag_of(flag_insc_aura, flags)) {
159         ss << '[';
160     }
161
162     ss << inscribe_flags_aux(flag_insc_aura, flags, is_kanji);
163
164     if (has_flag_of(flag_insc_brand, flags)) {
165         ss << '|';
166     }
167
168     ss << inscribe_flags_aux(flag_insc_brand, flags, is_kanji);
169
170     if (has_flag_of(flag_insc_kill, flags)) {
171         ss << "/X";
172     }
173
174     ss << inscribe_flags_aux(flag_insc_kill, flags, is_kanji);
175
176     if (has_flag_of(flag_insc_slay, flags)) {
177         ss << '/';
178     }
179
180     ss << inscribe_flags_aux(flag_insc_slay, flags, is_kanji);
181
182     if (is_kanji) {
183         if (has_flag_of(flag_insc_esp1, flags) || has_flag_of(flag_insc_esp2, flags)) {
184             ss << '~';
185         }
186
187         ss << inscribe_flags_aux(flag_insc_esp1, flags, is_kanji)
188            << inscribe_flags_aux(flag_insc_esp2, flags, is_kanji);
189     } else {
190         if (has_flag_of(flag_insc_esp1, flags)) {
191             ss << '~';
192         }
193
194         ss << inscribe_flags_aux(flag_insc_esp1, flags, is_kanji);
195
196         if (has_flag_of(flag_insc_esp2, flags)) {
197             ss << '~';
198         }
199
200         ss << inscribe_flags_aux(flag_insc_esp2, flags, is_kanji);
201     }
202
203     if (has_flag_of(flag_insc_sust, flags)) {
204         ss << '(';
205     }
206
207     ss << inscribe_flags_aux(flag_insc_sust, flags, is_kanji);
208
209     return ss.str();
210 }
211
212 /*!
213  * @brief オブジェクト名の特性短縮表記+刻み内容を提示する。 / Get object inscription with auto inscription of object flags.
214  * @param buff 特性短縮表記を格納する文字列ポインタ
215  * @param o_ptr 特性短縮表記を得たいオブジェクト構造体の参照ポインタ
216  */
217 std::string get_inscription(const ItemEntity &item)
218 {
219     if (!item.is_inscribed()) {
220         return {};
221     }
222
223     std::stringstream ss;
224
225     if (!item.is_fully_known()) {
226         for (std::string_view sv = *item.inscription; !sv.empty(); sv.remove_prefix(1)) {
227             if (sv.front() == '#') {
228                 break;
229             }
230             if (ss.tellp() > MAX_INSCRIPTION - 1) {
231                 break;
232             }
233 #ifdef JP
234             if (iskanji(sv.front())) {
235                 ss << sv.front();
236                 sv.remove_prefix(1);
237             }
238 #endif
239             ss << sv.front();
240         }
241
242         return ss.str();
243     }
244
245     for (std::string_view sv = *item.inscription; !sv.empty(); sv.remove_prefix(1)) {
246         switch (sv.front()) {
247         case '#':
248             return ss.str();
249         case '%': {
250             const auto start_pos = ss.tellp();
251             if (start_pos >= MAX_NLEN) {
252                 break;
253             }
254
255             auto is_kanji = false;
256 #ifdef JP
257             if ((sv.size() > 1) && ('%' == sv[1])) {
258                 sv.remove_prefix(1);
259             } else {
260                 is_kanji = true;
261             }
262 #endif
263
264             auto all = false;
265             if (sv.substr(1, 3) == "all") {
266                 all = true;
267                 sv.remove_prefix(3);
268             }
269
270             ss << get_ability_abbreviation(item, is_kanji, all);
271             if (ss.tellp() == start_pos) {
272                 ss << ' ';
273             }
274             break;
275         }
276         default:
277             ss << sv.front();
278             break;
279         }
280     }
281
282     return ss.str();
283 }
284
285 #ifdef JP
286 /*!
287  * @brief アイテムにふさわしい助数詞をつけて数を記述する
288  * @param item 数を記述したいアイテムの参照
289  * @return 記述した文字列
290  */
291 std::string describe_count_with_counter_suffix(const ItemEntity &item)
292 {
293     std::stringstream ss;
294     ss << item.number;
295
296     switch (item.bi_key.tval()) {
297     case ItemKindType::BOLT:
298     case ItemKindType::ARROW:
299     case ItemKindType::POLEARM:
300     case ItemKindType::STAFF:
301     case ItemKindType::WAND:
302     case ItemKindType::ROD:
303     case ItemKindType::DIGGING:
304         ss << "本";
305         break;
306     case ItemKindType::SCROLL:
307         ss << "巻";
308         break;
309     case ItemKindType::POTION:
310         ss << "服";
311         break;
312     case ItemKindType::LIFE_BOOK:
313     case ItemKindType::SORCERY_BOOK:
314     case ItemKindType::NATURE_BOOK:
315     case ItemKindType::CHAOS_BOOK:
316     case ItemKindType::DEATH_BOOK:
317     case ItemKindType::TRUMP_BOOK:
318     case ItemKindType::ARCANE_BOOK:
319     case ItemKindType::CRAFT_BOOK:
320     case ItemKindType::DEMON_BOOK:
321     case ItemKindType::CRUSADE_BOOK:
322     case ItemKindType::MUSIC_BOOK:
323     case ItemKindType::HISSATSU_BOOK:
324     case ItemKindType::HEX_BOOK:
325         ss << "冊";
326         break;
327     case ItemKindType::SOFT_ARMOR:
328     case ItemKindType::HARD_ARMOR:
329     case ItemKindType::DRAG_ARMOR:
330     case ItemKindType::CLOAK:
331         ss << "着";
332         break;
333     case ItemKindType::SWORD:
334     case ItemKindType::HAFTED:
335     case ItemKindType::BOW:
336         ss << "振";
337         break;
338     case ItemKindType::BOOTS:
339         ss << "足";
340         break;
341
342     case ItemKindType::CARD:
343         ss << "枚";
344         break;
345
346     case ItemKindType::FOOD:
347         if (item.bi_key.sval() == SV_FOOD_JERKY) {
348             ss << "切れ";
349             break;
350         }
351         [[fallthrough]];
352     default:
353         if (item.number < 10) {
354             ss << "つ";
355         } else {
356             ss << "個";
357         }
358         break;
359     }
360
361     return ss.str();
362 }
363 #endif