OSDN Git Service

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