OSDN Git Service

Merge pull request #2866 from habu1010/feature/refactor-del-flavor-type-show-weapon...
[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/object-ego.h"
4 #include "object-enchant/tr-types.h"
5 #include "object/object-flags.h"
6 #include "object/tval-types.h"
7 #include "perception/object-perception.h"
8 #include "sv-definition/sv-food-types.h"
9 #include "system/artifact-type-definition.h"
10 #include "system/baseitem-info.h"
11 #include "system/item-entity.h"
12 #include "util/bit-flags-calculator.h"
13 #include "util/enum-converter.h"
14 #include "util/quarks.h"
15
16 flavor_type *initialize_flavor_type(flavor_type *flavor_ptr, char *buf, ItemEntity *o_ptr, BIT_FLAGS mode)
17 {
18     flavor_ptr->buf = buf;
19     flavor_ptr->o_ptr = o_ptr;
20     flavor_ptr->mode = mode;
21     flavor_ptr->kindname = baseitems_info[o_ptr->bi_id].name.data();
22     flavor_ptr->basenm = flavor_ptr->kindname;
23     flavor_ptr->modstr = "";
24     flavor_ptr->aware = false;
25     flavor_ptr->known = false;
26     flavor_ptr->flavor = true;
27     flavor_ptr->p1 = '(';
28     flavor_ptr->p2 = ')';
29     flavor_ptr->b1 = '[';
30     flavor_ptr->b2 = ']';
31     flavor_ptr->c1 = '{';
32     flavor_ptr->c2 = '}';
33     flavor_ptr->k_ptr = &baseitems_info[o_ptr->bi_id];
34     flavor_ptr->flavor_k_ptr = &baseitems_info[flavor_ptr->k_ptr->flavor];
35     return flavor_ptr;
36 }
37
38 /*!
39  * @brief 対象文字配列に一文字だけをコピーする。
40  * @param t 保管先文字列ポインタ
41  * @param c 保管したい1文字
42  * @details
43  * Print a char "c" into a string "t", as if by sprintf(t, "%c", c),\n
44  * and return a pointer to the terminator (t + 1).\n
45  */
46 char *object_desc_chr(char *t, char c)
47 {
48     *t++ = c;
49     *t = '\0';
50     return t;
51 }
52
53 /*!
54  * @brief 対象文字配列に文字列をコピーする。
55  * @param t 保管先文字列ポインタ
56  * @param s コピーしたい文字列ポインタ
57  * @return 保管先の末尾アドレス
58  * @details
59  * Print a string "s" into a string "t", as if by strcpy(t, s),
60  * and return a pointer to the terminator.
61  */
62 char *object_desc_str(char *t, concptr s)
63 {
64     while (*s) {
65         *t++ = *s++;
66     }
67
68     *t = '\0';
69     return t;
70 }
71
72 /*!
73  * @brief 対象文字配列に符号なし整数値をコピーする。
74  * @param t 保管先文字列ポインタ
75  * @param n コピーしたい数値
76  * @details
77  * Print an unsigned number "n" into a string "t", actually by
78  * sprintf(t, "%u", n), and return a pointer to the terminator.
79  */
80 char *object_desc_num(char *t, uint n)
81 {
82     int ret = sprintf(t, "%u", n);
83     if (ret < 0) {
84         // error
85         ret = 0;
86         *t = '\0';
87     }
88     return t + ret;
89 }
90
91 /*!
92  * @brief 対象文字配列に符号あり整数値をコピーする。
93  * @param t 保管先文字列ポインタ
94  * @param v コピーしたい数値
95  * @details
96  * Print an signed number "v" into a string "t", as if by
97  * sprintf(t, "%+d", n), and return a pointer to the terminator.
98  * Note that we always print a sign, either "+" or "-".
99  */
100 char *object_desc_int(char *t, int v)
101 {
102     uint p, n;
103     if (v < 0) {
104         n = 0 - v;
105         *t++ = '-';
106     } else {
107         n = v;
108         *t++ = '+';
109     }
110
111     /* loop */
112     for (p = 1; n >= p * 10; p = p * 10) {
113         ;
114     }
115
116     while (p >= 1) {
117         *t++ = '0' + n / p;
118         n = n % p;
119         p = p / 10;
120     }
121
122     *t = '\0';
123     return t;
124 }
125
126 /*!
127  * @brief オブジェクトフラグを追加する
128  * @param short_flavor フラグの短縮表現 (反魔法/アンチテレポの"["、耐性の"r"、耐混乱の"乱" 等)
129  * @param ptr 特性短縮表記を格納する文字列ポインタ
130  */
131 static void add_inscription(char **short_flavor, concptr str)
132 {
133     *short_flavor = object_desc_str(*short_flavor, str);
134 }
135
136 /*!
137  * @brief get_inscriptionのサブセットとしてオブジェクトの特性フラグを返す / Helper function for get_inscription()
138  * @param fi_vec 参照する特性表示記号テーブル
139  * @param flgs 対応するオブジェクトのフラグ文字列
140  * @param kanji TRUEならば漢字記述/FALSEならば英語記述
141  * @param ptr フラグ群を保管する文字列参照ポインタ
142  * @return フラグ群を保管する文字列参照ポインタ(ptrと同じ)
143  * @details
144  * Print an signed number "v" into a string "t", as if by
145  * sprintf(t, "%+d", n), and return a pointer to the terminator.
146  * Note that we always print a sign, either "+" or "-".
147  */
148 static char *inscribe_flags_aux(const std::vector<flag_insc_table> &fi_vec, const TrFlags &flgs, bool kanji, char *ptr)
149 {
150 #ifdef JP
151 #else
152     (void)kanji;
153 #endif
154
155     for (const auto &fi : fi_vec) {
156         if (flgs.has(fi.flag) && (!fi.except_flag.has_value() || flgs.has_not(fi.except_flag.value()))) {
157             add_inscription(&ptr, _(kanji ? fi.japanese : fi.english, fi.english));
158         }
159     }
160
161     return ptr;
162 }
163
164 /*!
165  * @brief オブジェクトの特性表示記号テーブル1つに従いオブジェクトの特性フラグ配列に1つでも該当の特性があるかを返す / Special variation of has_flag for
166  * auto-inscription
167  * @param fi_vec 参照する特性表示記号テーブル
168  * @param flgs 対応するオブジェクトのフラグ文字列
169  * @return 1つでも該当の特性があったらTRUEを返す。
170  */
171 static bool has_flag_of(const std::vector<flag_insc_table> &fi_vec, const TrFlags &flgs)
172 {
173     for (const auto &fi : fi_vec) {
174         if (flgs.has(fi.flag) && (!fi.except_flag.has_value() || flgs.has_not(fi.except_flag.value()))) {
175             return true;
176         }
177     }
178
179     return false;
180 }
181
182 /*!
183  * @brief オブジェクト名の特性短縮表記をまとめて提示する。
184  * @param short_flavor 特性短縮表記を格納する文字列ポインタ
185  * @param o_ptr 特性短縮表記を得たいオブジェクト構造体の参照ポインタ
186  * @param kanji TRUEならば漢字表記 / FALSEなら英語表記
187  * @param all TRUEならばベースアイテム上で明らかなフラグは省略する
188  * @return ptrと同じアドレス
189  */
190 char *get_ability_abbreviation(char *short_flavor, ItemEntity *o_ptr, bool kanji, bool all)
191 {
192     char *prev_ptr = short_flavor;
193     auto flgs = object_flags(o_ptr);
194     if (!all) {
195         auto *k_ptr = &baseitems_info[o_ptr->bi_id];
196         flgs.reset(k_ptr->flags);
197
198         if (o_ptr->is_fixed_artifact()) {
199             const auto &a_ref = artifacts_info.at(o_ptr->fixed_artifact_idx);
200             flgs.reset(a_ref.flags);
201         }
202
203         if (o_ptr->is_ego()) {
204             auto *e_ptr = &egos_info[o_ptr->ego_idx];
205             flgs.reset(e_ptr->flags);
206         }
207     }
208
209     if (has_dark_flag(flgs)) {
210         if (flgs.has(TR_LITE_1)) {
211             flgs.reset(TR_LITE_1);
212         }
213
214         if (flgs.has(TR_LITE_2)) {
215             flgs.reset(TR_LITE_2);
216         }
217
218         if (flgs.has(TR_LITE_3)) {
219             flgs.reset(TR_LITE_3);
220         }
221     } else if (has_lite_flag(flgs)) {
222         flgs.set(TR_LITE_1);
223         if (flgs.has(TR_LITE_2)) {
224             flgs.reset(TR_LITE_2);
225         }
226
227         if (flgs.has(TR_LITE_3)) {
228             flgs.reset(TR_LITE_3);
229         }
230     }
231
232     if (has_flag_of(flag_insc_plus, flgs) && kanji) {
233         add_inscription(&short_flavor, "+");
234     }
235
236     short_flavor = inscribe_flags_aux(flag_insc_plus, flgs, kanji, short_flavor);
237
238     if (has_flag_of(flag_insc_immune, flgs)) {
239         if (!kanji && short_flavor != prev_ptr) {
240             add_inscription(&short_flavor, ";");
241             prev_ptr = short_flavor;
242         }
243
244         add_inscription(&short_flavor, "*");
245     }
246
247     short_flavor = inscribe_flags_aux(flag_insc_immune, flgs, kanji, short_flavor);
248
249     if (has_flag_of(flag_insc_vuln, flgs)) {
250         if (!kanji && short_flavor != prev_ptr) {
251             add_inscription(&short_flavor, ";");
252             prev_ptr = short_flavor;
253         }
254
255         add_inscription(&short_flavor, "v");
256     }
257
258     short_flavor = inscribe_flags_aux(flag_insc_vuln, flgs, kanji, short_flavor);
259
260     if (has_flag_of(flag_insc_resistance, flgs)) {
261         if (kanji) {
262             add_inscription(&short_flavor, "r");
263         } else if (short_flavor != prev_ptr) {
264             add_inscription(&short_flavor, ";");
265             prev_ptr = short_flavor;
266         }
267     }
268
269     short_flavor = inscribe_flags_aux(flag_insc_resistance, flgs, kanji, short_flavor);
270
271     if (has_flag_of(flag_insc_misc, flgs) && (short_flavor != prev_ptr)) {
272         add_inscription(&short_flavor, ";");
273         prev_ptr = short_flavor;
274     }
275
276     short_flavor = inscribe_flags_aux(flag_insc_misc, flgs, kanji, short_flavor);
277
278     if (has_flag_of(flag_insc_aura, flgs)) {
279         add_inscription(&short_flavor, "[");
280     }
281
282     short_flavor = inscribe_flags_aux(flag_insc_aura, flgs, kanji, short_flavor);
283
284     if (has_flag_of(flag_insc_brand, flgs)) {
285         add_inscription(&short_flavor, "|");
286     }
287
288     short_flavor = inscribe_flags_aux(flag_insc_brand, flgs, kanji, short_flavor);
289
290     if (has_flag_of(flag_insc_kill, flgs)) {
291         add_inscription(&short_flavor, "/X");
292     }
293
294     short_flavor = inscribe_flags_aux(flag_insc_kill, flgs, kanji, short_flavor);
295
296     if (has_flag_of(flag_insc_slay, flgs)) {
297         add_inscription(&short_flavor, "/");
298     }
299
300     short_flavor = inscribe_flags_aux(flag_insc_slay, flgs, kanji, short_flavor);
301
302     if (kanji) {
303         if (has_flag_of(flag_insc_esp1, flgs) || has_flag_of(flag_insc_esp2, flgs)) {
304             add_inscription(&short_flavor, "~");
305         }
306
307         short_flavor = inscribe_flags_aux(flag_insc_esp1, flgs, kanji, short_flavor);
308         short_flavor = inscribe_flags_aux(flag_insc_esp2, flgs, kanji, short_flavor);
309     } else {
310         if (has_flag_of(flag_insc_esp1, flgs)) {
311             add_inscription(&short_flavor, "~");
312         }
313
314         short_flavor = inscribe_flags_aux(flag_insc_esp1, flgs, kanji, short_flavor);
315
316         if (has_flag_of(flag_insc_esp2, flgs)) {
317             add_inscription(&short_flavor, "~");
318         }
319
320         short_flavor = inscribe_flags_aux(flag_insc_esp2, flgs, kanji, short_flavor);
321     }
322
323     if (has_flag_of(flag_insc_sust, flgs)) {
324         add_inscription(&short_flavor, "(");
325     }
326
327     short_flavor = inscribe_flags_aux(flag_insc_sust, flgs, kanji, short_flavor);
328     *short_flavor = '\0';
329     return short_flavor;
330 }
331
332 /*!
333  * @brief オブジェクト名の特性短縮表記+刻み内容を提示する。 / Get object inscription with auto inscription of object flags.
334  * @param buff 特性短縮表記を格納する文字列ポインタ
335  * @param o_ptr 特性短縮表記を得たいオブジェクト構造体の参照ポインタ
336  */
337 void get_inscription(char *buff, ItemEntity *o_ptr)
338 {
339     concptr insc = quark_str(o_ptr->inscription);
340     char *ptr = buff;
341     if (!o_ptr->is_fully_known()) {
342         while (*insc) {
343             if (*insc == '#') {
344                 break;
345             }
346             if (buff > ptr + MAX_INSCRIPTION - 1) {
347                 break;
348             }
349 #ifdef JP
350             if (iskanji(*insc)) {
351                 *buff++ = *insc++;
352             }
353 #endif
354             *buff++ = *insc++;
355         }
356
357         *buff = '\0';
358         return;
359     }
360
361     *buff = '\0';
362     for (; *insc; insc++) {
363         if (*insc == '#') {
364             break;
365         } else if ('%' == *insc) {
366             bool kanji = false;
367             bool all;
368             concptr start = ptr;
369             if (ptr >= buff + MAX_NLEN) {
370                 continue;
371             }
372
373 #ifdef JP
374             if ('%' == insc[1]) {
375                 insc++;
376                 kanji = false;
377             } else {
378                 kanji = true;
379             }
380 #endif
381
382             if ('a' == insc[1] && 'l' == insc[2] && 'l' == insc[3]) {
383                 all = true;
384                 insc += 3;
385             } else {
386                 all = false;
387             }
388
389             ptr = get_ability_abbreviation(ptr, o_ptr, kanji, all);
390             if (ptr == start) {
391                 add_inscription(&ptr, " ");
392             }
393         } else {
394             *ptr++ = *insc;
395         }
396     }
397
398     *ptr = '\0';
399 }
400
401 #ifdef JP
402 /*!
403  * @brief 日本語の個数表示ルーチン
404  * @param t 保管先文字列ポインタ
405  * @param o_ptr 記述したいオブジェクトの構造体参照ポインタ
406  * @details
407  * cmd1.c で流用するために object_desc_japanese から移動した。
408  */
409 char *object_desc_count_japanese(char *t, ItemEntity *o_ptr)
410 {
411     t = object_desc_num(t, o_ptr->number);
412     switch (o_ptr->tval) {
413     case ItemKindType::BOLT:
414     case ItemKindType::ARROW:
415     case ItemKindType::POLEARM:
416     case ItemKindType::STAFF:
417     case ItemKindType::WAND:
418     case ItemKindType::ROD:
419     case ItemKindType::DIGGING: {
420         t = object_desc_str(t, "本");
421         break;
422     }
423     case ItemKindType::SCROLL: {
424         t = object_desc_str(t, "巻");
425         break;
426     }
427     case ItemKindType::POTION: {
428         t = object_desc_str(t, "服");
429         break;
430     }
431     case ItemKindType::LIFE_BOOK:
432     case ItemKindType::SORCERY_BOOK:
433     case ItemKindType::NATURE_BOOK:
434     case ItemKindType::CHAOS_BOOK:
435     case ItemKindType::DEATH_BOOK:
436     case ItemKindType::TRUMP_BOOK:
437     case ItemKindType::ARCANE_BOOK:
438     case ItemKindType::CRAFT_BOOK:
439     case ItemKindType::DEMON_BOOK:
440     case ItemKindType::CRUSADE_BOOK:
441     case ItemKindType::MUSIC_BOOK:
442     case ItemKindType::HISSATSU_BOOK:
443     case ItemKindType::HEX_BOOK: {
444         t = object_desc_str(t, "冊");
445         break;
446     }
447     case ItemKindType::SOFT_ARMOR:
448     case ItemKindType::HARD_ARMOR:
449     case ItemKindType::DRAG_ARMOR:
450     case ItemKindType::CLOAK: {
451         t = object_desc_str(t, "着");
452         break;
453     }
454     case ItemKindType::SWORD:
455     case ItemKindType::HAFTED:
456     case ItemKindType::BOW: {
457         t = object_desc_str(t, "振");
458         break;
459     }
460     case ItemKindType::BOOTS: {
461         t = object_desc_str(t, "足");
462         break;
463     }
464     case ItemKindType::CARD: {
465         t = object_desc_str(t, "枚");
466         break;
467     }
468     case ItemKindType::FOOD: {
469         if (o_ptr->sval == SV_FOOD_JERKY) {
470             t = object_desc_str(t, "切れ");
471             break;
472         }
473     }
474         [[fallthrough]];
475     default: {
476         if (o_ptr->number < 10) {
477             t = object_desc_str(t, "つ");
478         } else {
479             t = object_desc_str(t, "個");
480         }
481         break;
482     }
483     }
484     return t;
485 }
486 #endif
487
488 bool has_lite_flag(const TrFlags &flags)
489 {
490     return flags.has(TR_LITE_1) || flags.has(TR_LITE_2) || flags.has(TR_LITE_3);
491 }
492
493 bool has_dark_flag(const TrFlags &flags)
494 {
495     return flags.has(TR_LITE_M1) || flags.has(TR_LITE_M2) || flags.has(TR_LITE_M3);
496 }