OSDN Git Service

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