OSDN Git Service

Merge pull request #3532 from sikabane-works/release/3.0.0.87-alpha
[hengbandforosx/hengbandosx.git] / src / info-reader / baseitem-reader.cpp
1 /*
2  * @brief ベースアイテム定義の読み込み処理
3  * @author Hourier
4  * @date 2022/10/10
5  */
6
7 #include "info-reader/baseitem-reader.h"
8 #include "artifact/random-art-effects.h"
9 #include "info-reader/baseitem-tokens-table.h"
10 #include "info-reader/info-reader-util.h"
11 #include "info-reader/parse-error-types.h"
12 #include "main/angband-headers.h"
13 #include "object-enchant/tr-types.h"
14 #include "object/tval-types.h"
15 #include "system/baseitem-info.h"
16 #include "term/gameterm.h"
17 #include "util/bit-flags-calculator.h"
18 #include "util/enum-converter.h"
19 #include "util/string-processor.h"
20 #include "view/display-messages.h"
21
22 /*!
23  * @brief テキストトークンを走査してフラグを一つ得る(ベースアイテム用) /
24  * Grab one flag in an BaseitemInfo from a textual string
25  * @param bii_ptr 保管先のベースアイテム構造体参照ポインタ
26  * @param what 参照元の文字列ポインタ
27  * @return 見つけたらtrue
28  */
29 static bool grab_one_baseitem_flag(BaseitemInfo *bii_ptr, std::string_view what)
30 {
31     if (TrFlags::grab_one_flag(bii_ptr->flags, baseitem_flags, what)) {
32         return true;
33     }
34
35     if (EnumClassFlagGroup<ItemGenerationTraitType>::grab_one_flag(bii_ptr->gen_flags, baseitem_geneneration_flags, what)) {
36         return true;
37     }
38
39     msg_format(_("未知のアイテム・フラグ '%s'。", "Unknown object flag '%s'."), what.data());
40     return false;
41 }
42
43 /*!
44  * @brief ベースアイテム(BaseitemDefinitions)のパース関数
45  * @param buf テキスト列
46  * @param head ヘッダ構造体
47  * @return エラーコード
48  */
49 errr parse_baseitems_info(std::string_view buf, angband_header *head)
50 {
51     (void)head;
52     static BaseitemInfo *bii_ptr = nullptr;
53     const auto &tokens = str_split(buf, ':', false, 10);
54
55     if (tokens[0] == "N") {
56         // N:index:name_ja
57         if (tokens.size() < 3 || tokens[1].size() == 0) {
58             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
59         }
60
61         auto i = std::stoi(tokens[1]);
62         if (i < error_idx) {
63             return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
64         }
65         if (i >= static_cast<int>(baseitems_info.size())) {
66             baseitems_info.resize(i + 1);
67         }
68
69         error_idx = i;
70         bii_ptr = &baseitems_info[i];
71         bii_ptr->idx = static_cast<short>(i);
72 #ifdef JP
73         bii_ptr->name = tokens[2];
74 #endif
75         if (tokens.size() > 3) {
76             bii_ptr->flavor_name = tokens[3];
77         }
78
79     } else if (!bii_ptr) {
80         return PARSE_ERROR_MISSING_RECORD_HEADER;
81     } else if (tokens[0] == "E") {
82         // E:name_en
83 #ifndef JP
84         if (tokens.size() < 2 || tokens[1].size() == 0) {
85             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
86         }
87         bii_ptr->name = tokens[1];
88
89         if (tokens.size() > 2) {
90             bii_ptr->flavor_name = tokens[2];
91         }
92 #endif
93     } else if (tokens[0] == "D") {
94         // D:text_ja
95         // D:$text_en
96         if (tokens.size() < 2 || tokens[1].size() == 0) {
97             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
98         }
99 #ifdef JP
100         if (tokens[1][0] == '$') {
101             return PARSE_ERROR_NONE;
102         }
103         bii_ptr->text.append(buf.substr(2));
104 #else
105         if (tokens[1][0] != '$') {
106             return PARSE_ERROR_NONE;
107         }
108         append_english_text(bii_ptr->text, buf.substr(3));
109 #endif
110     } else if (tokens[0] == "G") {
111         // G:color:symbol
112         if (tokens.size() < 3 || tokens[1].size() == 0 || tokens[2].size() == 0) {
113             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
114         }
115
116         auto a = color_char_to_attr(tokens[2][0]);
117         if (a > 127) {
118             return PARSE_ERROR_GENERIC;
119         }
120
121         bii_ptr->d_attr = a;
122         bii_ptr->d_char = tokens[1][0];
123     } else if (tokens[0] == "I") {
124         // I:tval:sval:pval
125         if (tokens.size() < 4) {
126             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
127         }
128
129         constexpr auto base = 10;
130         const auto tval = i2enum<ItemKindType>(std::stoi(tokens[1], nullptr, base));
131         const auto sval = std::stoi(tokens[2], nullptr, base);
132         bii_ptr->bi_key = { tval, sval };
133         info_set_value(bii_ptr->pval, tokens[3]);
134         if ((tval == ItemKindType::ROD) && (bii_ptr->pval <= 0)) {
135             return PAESE_ERROR_INVALID_PVAL;
136         }
137     } else if (tokens[0] == "W") {
138         // W:level:weight:cost
139         if (tokens.size() < 4) {
140             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
141         }
142
143         info_set_value(bii_ptr->level, tokens[1]);
144         info_set_value(bii_ptr->weight, tokens[2]);
145         info_set_value(bii_ptr->cost, tokens[3]);
146     } else if (tokens[0] == "A") {
147         // A:level/chance(:level/chance:level/chance:level/chance)
148         if (tokens.size() < 2 || tokens.size() > 5) {
149             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
150         }
151
152         auto i = 0;
153         for (auto t = tokens.begin() + 1; t != tokens.end(); t++) {
154             const auto &rarity = str_split(*t, '/', false, 2);
155             if (rarity.size() != 2 || rarity[0].size() == 0 || rarity[1].size() == 0) {
156                 return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
157             }
158
159             auto &table = bii_ptr->alloc_tables[i];
160             info_set_value(table.level, rarity[0]);
161             info_set_value(table.chance, rarity[1]);
162             i++;
163         }
164     } else if (tokens[0] == "P") {
165         // P:ac:dd:ds:to_h:to_d:to_a
166         if (tokens.size() < 6) {
167             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
168         }
169
170         const auto &dice = str_split(tokens[2], 'd', false, 2);
171         if (dice.size() != 2) {
172             return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
173         }
174
175         info_set_value(bii_ptr->ac, tokens[1]);
176         info_set_value(bii_ptr->dd, dice[0]);
177         info_set_value(bii_ptr->ds, dice[1]);
178         info_set_value(bii_ptr->to_h, tokens[3]);
179         info_set_value(bii_ptr->to_d, tokens[4]);
180         info_set_value(bii_ptr->to_a, tokens[5]);
181     } else if (tokens[0] == "U") {
182         // U:activation_flag
183         if (tokens.size() < 2 || tokens[1].size() == 0) {
184             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
185         }
186         auto n = grab_one_activation_flag(tokens[1].data());
187         if (n <= RandomArtActType::NONE) {
188             return PARSE_ERROR_INVALID_FLAG;
189         }
190
191         bii_ptr->act_idx = n;
192     } else if (tokens[0] == "F") {
193         // F:flags
194         if (tokens.size() < 2 || tokens[1].size() == 0) {
195             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
196         }
197
198         const auto &flags = str_split(tokens[1], '|', true, 10);
199         for (const auto &f : flags) {
200             if (f.size() == 0) {
201                 continue;
202             }
203             if (!grab_one_baseitem_flag(bii_ptr, f)) {
204                 return PARSE_ERROR_INVALID_FLAG;
205             }
206         }
207     } else {
208         return PARSE_ERROR_UNDEFINED_DIRECTIVE;
209     }
210
211     return PARSE_ERROR_NONE;
212 }