OSDN Git Service

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