1 #include "info-reader/race-reader.h"
2 #include "info-reader/info-reader-util.h"
3 #include "info-reader/parse-error-types.h"
4 #include "info-reader/race-info-tokens-table.h"
5 #include "main/angband-headers.h"
6 #include "monster-race/monster-race.h"
7 #include "player-ability/player-ability-types.h"
8 #include "system/monster-race-info.h"
9 #include "term/gameterm.h"
10 #include "util/enum-converter.h"
11 #include "util/string-processor.h"
12 #include "view/display-messages.h"
15 * @brief テキストトークンを走査してフラグを一つ得る(モンスター用1) /
16 * Grab one (basic) flag in a MonsterRaceInfo from a textual string
17 * @param r_ptr 保管先のモンスター種族構造体参照ポインタ
18 * @param what 参照元の文字列ポインタ
21 static bool grab_one_basic_flag(MonsterRaceInfo *r_ptr, std::string_view what)
23 if (info_grab_one_flag(r_ptr->flags1, r_info_flags1, what)) {
27 if (info_grab_one_flag(r_ptr->flags2, r_info_flags2, what)) {
31 if (info_grab_one_flag(r_ptr->flags7, r_info_flags7, what)) {
35 if (info_grab_one_flag(r_ptr->flags8, r_info_flags8, what)) {
39 if (EnumClassFlagGroup<MonsterResistanceType>::grab_one_flag(r_ptr->resistance_flags, r_info_flagsr, what)) {
43 if (EnumClassFlagGroup<MonsterAuraType>::grab_one_flag(r_ptr->aura_flags, r_info_aura_flags, what)) {
47 if (EnumClassFlagGroup<MonsterBehaviorType>::grab_one_flag(r_ptr->behavior_flags, r_info_behavior_flags, what)) {
51 if (EnumClassFlagGroup<MonsterVisualType>::grab_one_flag(r_ptr->visual_flags, r_info_visual_flags, what)) {
55 if (EnumClassFlagGroup<MonsterKindType>::grab_one_flag(r_ptr->kind_flags, r_info_kind_flags, what)) {
59 if (EnumClassFlagGroup<MonsterDropType>::grab_one_flag(r_ptr->drop_flags, r_info_drop_flags, what)) {
63 if (EnumClassFlagGroup<MonsterWildernessType>::grab_one_flag(r_ptr->wilderness_flags, r_info_wilderness_flags, what)) {
67 if (EnumClassFlagGroup<MonsterFeatureType>::grab_one_flag(r_ptr->feature_flags, r_info_feature_flags, what)) {
71 if (EnumClassFlagGroup<MonsterPopulationType>::grab_one_flag(r_ptr->population_flags, r_info_population_flags, what)) {
75 if (EnumClassFlagGroup<MonsterSpeakType>::grab_one_flag(r_ptr->speak_flags, r_info_speak_flags, what)) {
79 if (EnumClassFlagGroup<MonsterBrightnessType>::grab_one_flag(r_ptr->brightness_flags, r_info_brightness_flags, what)) {
83 if (EnumClassFlagGroup<MonsterSpecialType>::grab_one_flag(r_ptr->special_flags, r_info_special_flags, what)) {
87 msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data());
92 * @brief テキストトークンを走査してフラグを一つ得る(モンスター用2) /
93 * Grab one (spell) flag in a MonsterRaceInfo from a textual string
94 * @param r_ptr 保管先のモンスター種族構造体参照ポインタ
95 * @param what 参照元の文字列ポインタ
98 static bool grab_one_spell_flag(MonsterRaceInfo *r_ptr, std::string_view what)
100 if (EnumClassFlagGroup<MonsterAbilityType>::grab_one_flag(r_ptr->ability_flags, r_info_ability_flags, what)) {
104 msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data());
109 * @brief モンスター種族情報(MonsterRaceDefinition)のパース関数
114 errr parse_monraces_info(std::string_view buf, angband_header *)
116 static MonsterRaceInfo *r_ptr = nullptr;
117 const auto &tokens = str_split(buf, ':', true, 10);
119 if (tokens[0] == "N") {
121 if (tokens.size() < 3 || tokens[1].size() == 0) {
122 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
125 auto i = std::stoi(tokens[1]);
127 return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
131 r_ptr = &(monraces_info.emplace_hint(monraces_info.end(), i2enum<MonsterRaceId>(i), MonsterRaceInfo{})->second);
132 r_ptr->idx = i2enum<MonsterRaceId>(i);
134 r_ptr->name = tokens[2];
137 return PARSE_ERROR_MISSING_RECORD_HEADER;
138 } else if (tokens[0] == "E") {
140 if (tokens.size() < 2 || tokens[1].size() == 0) {
141 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
144 r_ptr->E_name = tokens[1];
146 r_ptr->name = tokens[1];
148 } else if (tokens[0] == "D") {
151 if (tokens.size() < 2 || buf.length() < 3) {
152 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
156 return PARSE_ERROR_NONE;
158 r_ptr->text.append(buf.substr(2));
161 return PARSE_ERROR_NONE;
163 if (buf.length() == 3) {
164 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
166 append_english_text(r_ptr->text, buf.substr(3));
168 } else if (tokens[0] == "G") {
170 if (tokens.size() < 3 || tokens[1].size() == 0 || tokens[2].size() == 0) {
171 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
174 auto a = color_char_to_attr(tokens[2][0]);
176 return PARSE_ERROR_GENERIC;
180 r_ptr->d_char = tokens[1][0];
181 } else if (tokens[0] == "I") {
182 // G:speed:hp_dice:affect_range:ac:sleep_degree
183 if (tokens.size() < 6) {
184 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
187 const auto &dice = str_split(tokens[2], 'd', false, 2);
188 if (dice.size() < 2) {
189 return PARSE_ERROR_GENERIC;
192 info_set_value(r_ptr->speed, tokens[1]);
193 info_set_value(r_ptr->hdice, dice[0]);
194 info_set_value(r_ptr->hside, dice.size() == 1 ? "1" : dice[1]);
195 info_set_value(r_ptr->aaf, tokens[3]);
196 info_set_value(r_ptr->ac, tokens[4]);
197 info_set_value(r_ptr->sleep, tokens[5]);
198 } else if (tokens[0] == "W") {
199 // W:level:ratity:exp:next_exp:next_id
200 if ((tokens.size() < 4) || (tokens.size() == 5)) {
201 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
204 info_set_value(r_ptr->level, tokens[1]);
205 info_set_value(r_ptr->rarity, tokens[2]);
206 info_set_value(r_ptr->mexp, tokens[3]);
208 if (tokens.size() < 5) {
209 return PARSE_ERROR_NONE;
212 info_set_value(r_ptr->next_exp, tokens[4]);
213 info_set_value(r_ptr->next_r_idx, tokens[5]);
214 } else if (tokens[0] == "R") {
215 // R:reinforcer_idx:number_dice
216 if (tokens.size() < 3) {
217 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
219 if (tokens[1].size() == 0 || tokens[2].size() == 0) {
220 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
223 const auto &dice = str_split(tokens[2], 'd', false, 2);
227 info_set_value(r_idx, tokens[1]);
228 info_set_value(dd, dice[0]);
229 info_set_value(ds, dice[1]);
230 r_ptr->reinforces.emplace_back(r_idx, dd, ds);
231 } else if (tokens[0] == "B") {
232 // B:blow_type:blow_effect:dice
235 if (r_ptr->blows[i].method == RaceBlowMethodType::NONE) {
241 return PARSE_ERROR_GENERIC;
244 if (tokens.size() < 3) {
245 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
247 if (tokens[1].size() == 0 || tokens[2].size() == 0) {
248 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
251 auto rbm = r_info_blow_method.find(tokens[1]);
252 if (rbm == r_info_blow_method.end()) {
253 return PARSE_ERROR_INVALID_FLAG;
256 auto rbe = r_info_blow_effect.find(tokens[2]);
257 if (rbe == r_info_blow_effect.end()) {
258 return PARSE_ERROR_INVALID_FLAG;
261 r_ptr->blows[i].method = rbm->second;
262 r_ptr->blows[i].effect = rbe->second;
264 if (tokens.size() < 4) {
265 return PARSE_ERROR_NONE;
268 const auto &dice = str_split(tokens[3], 'd', false, 2);
269 info_set_value(r_ptr->blows[i].d_dice, dice[0]);
270 info_set_value(r_ptr->blows[i].d_side, dice[1]);
271 } else if (tokens[0] == "F") {
273 if (tokens.size() < 2 || tokens[1].size() == 0) {
274 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
277 const auto &flags = str_split(tokens[1], '|', true, 10);
278 for (const auto &f : flags) {
280 const auto &s_tokens = str_split(f, '_', false, 2);
281 if (s_tokens.size() == 2 && s_tokens[0] == "PERHP") {
282 info_set_value(r_ptr->cur_hp_per, s_tokens[1]);
290 if (!grab_one_basic_flag(r_ptr, f)) {
291 return PARSE_ERROR_INVALID_FLAG;
294 } else if (tokens[0] == "S") {
296 if (tokens.size() < 2 || tokens[1].size() == 0) {
297 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
300 const auto &flags = str_split(tokens[1], '|', true, 10);
301 for (const auto &f : flags) {
306 const auto &s_tokens = str_split(f, '_', false, 3);
307 if (s_tokens.size() == 3 && s_tokens[1] == "IN") {
308 if (s_tokens[0] != "1") {
309 return PARSE_ERROR_GENERIC;
312 info_set_value(i, s_tokens[2]);
313 r_ptr->freq_spell = 100 / i;
317 if (!grab_one_spell_flag(r_ptr, f)) {
318 return PARSE_ERROR_INVALID_FLAG;
322 } else if (tokens[0] == "A") {
323 // A:artifact_idx:chance
324 if (tokens.size() < 3) {
325 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
328 FixedArtifactId a_idx;
330 info_set_value(a_idx, tokens[1]);
331 info_set_value(chance, tokens[2]);
332 r_ptr->drop_artifacts.emplace_back(a_idx, chance);
333 } else if (tokens[0] == "X") {
334 if (tokens.size() < 2) {
335 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
338 if (!info_grab_one_const(sex, r_info_sex, tokens[1])) {
339 return PARSE_ERROR_INVALID_FLAG;
341 r_ptr->sex = static_cast<MonsterSex>(sex);
343 } else if (tokens[0] == "V") {
345 if (tokens.size() < 2) {
346 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
349 info_set_value(r_ptr->arena_ratio, tokens[1]);
351 return PARSE_ERROR_UNDEFINED_DIRECTIVE;
354 return PARSE_ERROR_NONE;