OSDN Git Service

Merge branch 'develop' into macos-develop
[hengbandforosx/hengbandosx.git] / src / info-reader / ego-reader.cpp
1 #include "info-reader/ego-reader.h"
2 #include "artifact/random-art-effects.h"
3 #include "info-reader/baseitem-tokens-table.h"
4 #include "info-reader/info-reader-util.h"
5 #include "info-reader/parse-error-types.h"
6 #include "main/angband-headers.h"
7 #include "object-enchant/object-ego.h"
8 #include "object-enchant/tr-types.h"
9 #include "util/bit-flags-calculator.h"
10 #include "util/enum-converter.h"
11 #include "util/string-processor.h"
12 #include "view/display-messages.h"
13
14 /*!
15  * @brief テキストトークンを走査してフラグを一つ得る(エゴ用) /
16  * Grab one flag in a ego-item_type from a textual string
17  * @param e_ptr 保管先のエゴ構造体参照ポインタ
18  * @param what 参照元の文字列ポインタ
19  * @return 見つけたらtrue
20  */
21 static bool grab_one_ego_item_flag(EgoItemDefinition *e_ptr, std::string_view what)
22 {
23     if (TrFlags::grab_one_flag(e_ptr->flags, baseitem_flags, what)) {
24         return true;
25     }
26
27     if (EnumClassFlagGroup<ItemGenerationTraitType>::grab_one_flag(e_ptr->gen_flags, baseitem_geneneration_flags, what)) {
28         return true;
29     }
30
31     msg_format(_("未知の名のあるアイテム・フラグ '%s'。", "Unknown ego-item flag '%s'."), what.data());
32     return false;
33 }
34
35 /*!
36  * @brief テキストトークンを走査して生成フラグを一つ得る(エゴ用) /
37  * Grab one genetation flag in a ego-item_type from a textual string
38  * @param e_ptr 保管先のエゴ構造体参照ポインタ
39  * @param what 参照元の文字列ポインタ
40  * @return 見つけたらtrue
41  */
42 static bool grab_ego_generate_flags(ego_generate_type &xtra, std::string_view what)
43 {
44     if (auto it = baseitem_flags.find(what); it != baseitem_flags.end()) {
45         xtra.tr_flags.push_back(it->second);
46         return true;
47     }
48
49     if (auto it = baseitem_geneneration_flags.find(what); it != baseitem_geneneration_flags.end()) {
50         xtra.trg_flags.push_back(it->second);
51         return true;
52     }
53
54     return false;
55 }
56
57 /*!
58  * @brief アイテムエゴ情報(EgoDefinitions)のパース関数
59  * @param buf テキスト列
60  * @param head ヘッダ構造体
61  * @return エラーコード
62  */
63 errr parse_egos_info(std::string_view buf, angband_header *)
64 {
65     static EgoItemDefinition *e_ptr = nullptr;
66     const auto &tokens = str_split(buf, ':', false, 10);
67
68     error_idx = 0; //!< @note 順不同で登録しているため
69
70     if (tokens[0] == "N") {
71         // N:index:name_ja
72         if (tokens.size() < 3 || tokens[1].size() == 0) {
73             return PARSE_ERROR_GENERIC;
74         }
75
76         auto i = std::stoi(tokens[1]);
77         if (i < error_idx) {
78             return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
79         }
80
81         error_idx = i;
82         e_ptr = &(egos_info.emplace_hint(egos_info.end(), i2enum<EgoType>(i), EgoItemDefinition{})->second);
83         e_ptr->idx = i2enum<EgoType>(i);
84 #ifdef JP
85         e_ptr->name = tokens[2];
86 #endif
87     } else if (!e_ptr) {
88         return PARSE_ERROR_MISSING_RECORD_HEADER;
89     } else if (tokens[0] == "E") {
90         // E:name_en
91 #ifndef JP
92         if (tokens[1].size() == 0) {
93             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
94         }
95         e_ptr->name = tokens[1];
96 #endif
97     } else if (tokens[0] == "X") {
98         // X:slot:rating
99         if (tokens.size() < 3) {
100             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
101         }
102
103         info_set_value(e_ptr->slot, tokens[1]);
104         info_set_value(e_ptr->rating, tokens[2]);
105     } else if (tokens[0] == "W") {
106         // W:level:ratiry:xtra:cost
107         // xtra is not used
108         if (tokens.size() < 5) {
109             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
110         }
111
112         info_set_value(e_ptr->level, tokens[1]);
113         info_set_value(e_ptr->rarity, tokens[2]);
114         info_set_value(e_ptr->cost, tokens[4]);
115     } else if (tokens[0] == "B") {
116         // Base bonuses
117         // B:to_hit:to_dam:to_ac
118         if (tokens.size() < 4) {
119             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
120         }
121
122         info_set_value(e_ptr->base_to_h, tokens[1]);
123         info_set_value(e_ptr->base_to_d, tokens[2]);
124         info_set_value(e_ptr->base_to_a, tokens[3]);
125     } else if (tokens[0] == "C") {
126         // Creation bonuses (random plus)
127         // C:to_hit:to_dam:to_ac:pval
128         if (tokens.size() < 5) {
129             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
130         }
131
132         info_set_value(e_ptr->max_to_h, tokens[1]);
133         info_set_value(e_ptr->max_to_d, tokens[2]);
134         info_set_value(e_ptr->max_to_a, tokens[3]);
135         info_set_value(e_ptr->max_pval, tokens[4]);
136     } else if (tokens[0] == "U") {
137         // U:activation_flag
138         if (tokens.size() < 2 || tokens[1].size() == 0) {
139             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
140         }
141
142         auto n = grab_one_activation_flag(tokens[1]);
143         if (n <= RandomArtActType::NONE) {
144             return PARSE_ERROR_INVALID_FLAG;
145         }
146
147         e_ptr->act_idx = n;
148     } else if (tokens[0] == "F") {
149         // F:flags
150         if (tokens.size() < 2 || tokens[1].size() == 0) {
151             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
152         }
153
154         const auto &flags = str_split(tokens[1], '|', true, 10);
155         for (const auto &f : flags) {
156             if (f.size() == 0) {
157                 continue;
158             }
159             if (!grab_one_ego_item_flag(e_ptr, f)) {
160                 return PARSE_ERROR_INVALID_FLAG;
161             }
162         }
163     } else if (tokens[0] == "G") {
164         // G:mul/dev:flags
165         if (tokens.size() < 3) {
166             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
167         }
168
169         const auto &prob = str_split(tokens[1], '/', false, 2);
170         if (prob.size() != 2 || tokens[1].size() == 0 || tokens[2].size() == 0) {
171             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
172         }
173
174         ego_generate_type xtra;
175         xtra.mul = std::stoi(prob[0]);
176         xtra.dev = std::stoi(prob[1]);
177
178         const auto &flags = str_split(tokens[2], '|', true, 10);
179         for (const auto &f : flags) {
180             if (f.size() == 0) {
181                 continue;
182             }
183             if (!grab_ego_generate_flags(xtra, f)) {
184                 return PARSE_ERROR_INVALID_FLAG;
185             }
186         }
187
188         e_ptr->xtra_flags.push_back(std::move(xtra));
189     } else {
190         return PARSE_ERROR_UNDEFINED_DIRECTIVE;
191     }
192
193     return PARSE_ERROR_NONE;
194 }