OSDN Git Service

Merge branch 'develop' into macos-develop
[hengbandforosx/hengbandosx.git] / src / info-reader / race-reader.cpp
1 #include "info-reader/race-reader.h"
2 #include "artifact/fixed-art-types.h"
3 #include "info-reader/info-reader-util.h"
4 #include "info-reader/parse-error-types.h"
5 #include "info-reader/race-info-tokens-table.h"
6 #include "locale/japanese.h"
7 #include "main/angband-headers.h"
8 #include "monster-race/monster-race.h"
9 #include "player-ability/player-ability-types.h"
10 #include "system/monster-race-info.h"
11 #include "term/gameterm.h"
12 #include "util/enum-converter.h"
13 #include "util/string-processor.h"
14 #include "view/display-messages.h"
15 #include <string>
16
17 /*!
18  * @brief テキストトークンを走査してフラグを一つ得る(モンスター用1) /
19  * Grab one (basic) flag in a MonsterRaceInfo from a textual string
20  * @param monrace 保管先のモンスター種族構造体
21  * @param what 参照元の文字列ポインタ
22  * @return 見つけたらtrue
23  */
24 static bool grab_one_basic_flag(MonsterRaceInfo &monrace, std::string_view what)
25 {
26     if (EnumClassFlagGroup<MonsterResistanceType>::grab_one_flag(monrace.resistance_flags, r_info_flagsr, what)) {
27         return true;
28     }
29
30     if (EnumClassFlagGroup<MonsterAuraType>::grab_one_flag(monrace.aura_flags, r_info_aura_flags, what)) {
31         return true;
32     }
33
34     if (EnumClassFlagGroup<MonsterBehaviorType>::grab_one_flag(monrace.behavior_flags, r_info_behavior_flags, what)) {
35         return true;
36     }
37
38     if (EnumClassFlagGroup<MonsterVisualType>::grab_one_flag(monrace.visual_flags, r_info_visual_flags, what)) {
39         return true;
40     }
41
42     if (EnumClassFlagGroup<MonsterKindType>::grab_one_flag(monrace.kind_flags, r_info_kind_flags, what)) {
43         return true;
44     }
45
46     if (EnumClassFlagGroup<MonsterDropType>::grab_one_flag(monrace.drop_flags, r_info_drop_flags, what)) {
47         return true;
48     }
49
50     if (EnumClassFlagGroup<MonsterWildernessType>::grab_one_flag(monrace.wilderness_flags, r_info_wilderness_flags, what)) {
51         return true;
52     }
53
54     if (EnumClassFlagGroup<MonsterFeatureType>::grab_one_flag(monrace.feature_flags, r_info_feature_flags, what)) {
55         return true;
56     }
57
58     if (EnumClassFlagGroup<MonsterPopulationType>::grab_one_flag(monrace.population_flags, r_info_population_flags, what)) {
59         return true;
60     }
61
62     if (EnumClassFlagGroup<MonsterSpeakType>::grab_one_flag(monrace.speak_flags, r_info_speak_flags, what)) {
63         return true;
64     }
65
66     if (EnumClassFlagGroup<MonsterBrightnessType>::grab_one_flag(monrace.brightness_flags, r_info_brightness_flags, what)) {
67         return true;
68     }
69
70     if (EnumClassFlagGroup<MonsterSpecialType>::grab_one_flag(monrace.special_flags, r_info_special_flags, what)) {
71         return true;
72     }
73     if (EnumClassFlagGroup<MonsterMiscType>::grab_one_flag(monrace.misc_flags, r_info_misc_flags, what)) {
74         return true;
75     }
76
77     msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data());
78     return false;
79 }
80
81 /*!
82  * @brief テキストトークンを走査してフラグを一つ得る(モンスター用2) /
83  * Grab one (spell) flag in a MonsterRaceInfo from a textual string
84  * @param monrace 保管先のモンスター種族構造体
85  * @param what 参照元の文字列ポインタ
86  * @return 見つけたらtrue
87  */
88 static bool grab_one_spell_flag(MonsterRaceInfo &monrace, std::string_view what)
89 {
90     if (EnumClassFlagGroup<MonsterAbilityType>::grab_one_flag(monrace.ability_flags, r_info_ability_flags, what)) {
91         return true;
92     }
93
94     msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data());
95     return false;
96 }
97
98 /*!
99  * @brief JSON Objectからモンスター名をセットする
100  * @param name_data 名前情報の格納されたJSON Object
101  * @param monrace 保管先のモンスター種族構造体
102  * @return エラーコード
103  */
104 static errr set_mon_name(const nlohmann::json &name_data, MonsterRaceInfo &monrace)
105 {
106     if (name_data.is_null()) {
107         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
108     }
109     if (!name_data["ja"].is_string() || !name_data["en"].is_string()) {
110         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
111     }
112
113     const auto ja_name = name_data["ja"].get<std::string>();
114     const auto en_name = name_data["en"].get<std::string>();
115
116 #ifdef JP
117     auto ja_name_sys = utf8_to_sys(ja_name);
118     if (!ja_name_sys) {
119         return PARSE_ERROR_INVALID_FLAG;
120     }
121     monrace.name = std::move(*ja_name_sys);
122     monrace.E_name = en_name;
123 #else
124     monrace.name = en_name;
125 #endif
126     return PARSE_ERROR_NONE;
127 }
128
129 /*!
130  * @brief JSON Objectからモンスターシンボルをセットする
131  * @param symbol_data シンボル情報の格納されたJSON Object
132  * @param monrace 保管先のモンスター種族構造体
133  * @return エラーコード
134  */
135 static errr set_mon_symbol(const nlohmann::json &symbol_data, MonsterRaceInfo &monrace)
136 {
137     if (symbol_data.is_null()) {
138         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
139     }
140
141     const auto &character_obj = symbol_data["character"];
142     if (!character_obj.is_string()) {
143         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
144     }
145
146     const auto &color_obj = symbol_data["color"];
147     if (!color_obj.is_string()) {
148         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
149     }
150
151     const auto color = color_list.find(color_obj.get<std::string>());
152     if (color == color_list.end()) {
153         return PARSE_ERROR_INVALID_FLAG;
154     }
155     if (color->second > 127) {
156         return PARSE_ERROR_GENERIC;
157     }
158
159     monrace.cc_def = { color->second, character_obj.get<std::string>().front() };
160     return PARSE_ERROR_NONE;
161 }
162
163 /*!
164  * @brief JSON Objectからモンスター速度をセットする
165  * @param speed_data 速度情報の格納されたJSON Object
166  * @param monrace 保管先のモンスター種族構造体
167  * @return エラーコード
168  */
169 static errr set_mon_speed(const nlohmann::json &speed_data, MonsterRaceInfo &monrace)
170 {
171     if (!speed_data.is_number_integer()) {
172         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
173     }
174
175     const auto speed = speed_data.get<int8_t>();
176     if (speed < -50 || speed > 99) {
177         return PARSE_ERROR_INVALID_FLAG;
178     }
179     monrace.speed = speed + STANDARD_SPEED;
180     return PARSE_ERROR_NONE;
181 }
182
183 /*!
184  * @brief JSON Objectからモンスター体力をセットする
185  * @param hp_data 体力情報の格納されたJSON Object
186  * @param monrace 保管先のモンスター種族構造体
187  * @return エラーコード
188  */
189 static errr set_mon_hp(const nlohmann::json &hp_data, MonsterRaceInfo &monrace)
190 {
191     if (!hp_data.is_string()) {
192         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
193     }
194
195     const auto hit_point = hp_data.get<std::string>();
196     const auto &dice = str_split(hit_point, 'd', false, 2);
197     if (dice.size() < 2) {
198         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
199     }
200     monrace.hdice = std::stoi(dice[0]);
201     monrace.hside = std::stoi(dice[1]);
202     return PARSE_ERROR_NONE;
203 }
204
205 /*!
206  * @brief JSON Objectからモンスターの感知範囲をセットする
207  * @param vision_data 感知範囲情報の格納されたJSON Object
208  * @param monrace 保管先のモンスター種族構造体
209  * @return エラーコード
210  */
211 static errr set_mon_vision(const nlohmann::json &vision_data, MonsterRaceInfo &monrace)
212 {
213     if (!vision_data.is_number_integer()) {
214         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
215     }
216
217     const auto vision = vision_data.get<int>();
218     if (vision < 0 || vision > 999) {
219         return PARSE_ERROR_INVALID_FLAG;
220     }
221     monrace.aaf = vision;
222     return PARSE_ERROR_NONE;
223 }
224
225 /*!
226  * @brief JSON Objectからモンスターの物理防御力をセットする
227  * @param ac_data 物理防御力情報の格納されたJSON Object
228  * @param monrace 保管先のモンスター種族構造体
229  * @return エラーコード
230  */
231 static errr set_mon_ac(const nlohmann::json &ac_data, MonsterRaceInfo &monrace)
232 {
233     if (!ac_data.is_number_integer()) {
234         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
235     }
236
237     const auto armour_class = ac_data.get<short>();
238     if (armour_class < 0 || armour_class > 10000) {
239         return PARSE_ERROR_INVALID_FLAG;
240     }
241     monrace.ac = armour_class;
242     return PARSE_ERROR_NONE;
243 }
244
245 /*!
246  * @brief JSON Objectからモンスターの警戒度をセットする
247  * @param alertness_data 物理防御力情報の格納されたJSON Object
248  * @param monrace 保管先のモンスター種族構造体
249  * @return エラーコード
250  */
251 static errr set_mon_alertness(const nlohmann::json &alertness_data, MonsterRaceInfo &monrace)
252 {
253     if (!alertness_data.is_number_integer()) {
254         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
255     }
256
257     const auto alertness = alertness_data.get<short>();
258     if (alertness < 0 || alertness > 255) {
259         return PARSE_ERROR_INVALID_FLAG;
260     }
261     monrace.sleep = alertness;
262     return PARSE_ERROR_NONE;
263 }
264
265 /*!
266  * @brief JSON Objectからモンスターの出現階層をセットする
267  * @param level_data 出現階層情報の格納されたJSON Object
268  * @param monrace 保管先のモンスター種族構造体
269  * @return エラーコード
270  */
271 static errr set_mon_level(const nlohmann::json &level_data, MonsterRaceInfo &monrace)
272 {
273     if (!level_data.is_number_integer()) {
274         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
275     }
276
277     const auto level = level_data.get<int>();
278     if (level < 0 || level > 255) {
279         return PARSE_ERROR_INVALID_FLAG;
280     }
281     monrace.level = level;
282     return PARSE_ERROR_NONE;
283 }
284
285 /*!
286  * @brief JSON Objectからモンスターの出現階層をセットする
287  * @param rarity_data 出現階層情報の格納されたJSON Object
288  * @param monrace 保管先のモンスター種族構造体
289  * @return エラーコード
290  */
291 static errr set_mon_rarity(const nlohmann::json &rarity_data, MonsterRaceInfo &monrace)
292 {
293     if (!rarity_data.is_number_integer()) {
294         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
295     }
296
297     const auto rarity = rarity_data.get<int>();
298     if (rarity < 0 || rarity > 255) {
299         return PARSE_ERROR_INVALID_FLAG;
300     }
301     monrace.rarity = (RARITY)rarity;
302     return PARSE_ERROR_NONE;
303 }
304
305 /*!
306  * @brief JSON Objectからモンスターの経験値をセットする
307  * @param exp_data 経験値情報の格納されたJSON Object
308  * @param monrace 保管先のモンスター種族構造体
309  * @return エラーコード
310  */
311 static errr set_mon_exp(const nlohmann::json &exp_data, MonsterRaceInfo &monrace)
312 {
313     if (!exp_data.is_number_integer()) {
314         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
315     }
316
317     const auto exp = exp_data.get<int>();
318     if (exp < 0 || exp > 9999999) {
319         return PARSE_ERROR_INVALID_FLAG;
320     }
321     monrace.mexp = exp;
322     return PARSE_ERROR_NONE;
323 }
324
325 /*!
326  * @brief JSON Objectからモンスターの進化をセットする
327  * @param evolve_data 進化情報の格納されたJSON Object
328  * @param monrace 保管先のモンスター種族構造体
329  * @return エラーコード
330  */
331 static errr set_mon_evolve(const nlohmann::json &evolve_data, MonsterRaceInfo &monrace)
332 {
333     if (evolve_data.is_null()) {
334         return PARSE_ERROR_NONE;
335     }
336
337     const auto &need_exp_obj = evolve_data["need_exp"];
338     const auto &evlove_to_obj = evolve_data["to"];
339     if (!need_exp_obj.is_number_integer()) {
340         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
341     }
342     if (!evlove_to_obj.is_number_integer()) {
343         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
344     }
345     const auto need_exp = need_exp_obj.get<int>();
346     const auto evlove_to = evlove_to_obj.get<int>();
347     if (need_exp <= 0 || need_exp > 9999999) {
348         return PARSE_ERROR_INVALID_FLAG;
349     }
350     if (evlove_to <= 0 || evlove_to > 9999) {
351         return PARSE_ERROR_INVALID_FLAG;
352     }
353     monrace.next_exp = need_exp;
354     monrace.next_r_idx = static_cast<MonsterRaceId>(evlove_to);
355     return PARSE_ERROR_NONE;
356 }
357
358 /*!
359  * @brief JSON Objectからモンスターの性別をセットする
360  * @param sex_data 性別情報の格納されたJSON Object
361  * @param monrace 保管先のモンスター種族構造体
362  * @return エラーコード
363  */
364 static errr set_mon_sex(const nlohmann::json &sex_data, MonsterRaceInfo &monrace)
365 {
366     if (sex_data.is_null()) {
367         return PARSE_ERROR_NONE;
368     }
369     if (!sex_data.is_string()) {
370         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
371     }
372
373     uint32_t sex;
374     if (!info_grab_one_const(sex, r_info_sex, sex_data.get<std::string>())) {
375         return PARSE_ERROR_INVALID_FLAG;
376     }
377     monrace.sex = static_cast<MonsterSex>(sex);
378     return PARSE_ERROR_NONE;
379 }
380
381 /*!
382  * @brief JSON Objectからモンスターの闘技場オッズをセットする
383  * @param odds_data オッズ情報の格納されたJSON Object
384  * @param monrace 保管先のモンスター種族構造体
385  * @return エラーコード
386  */
387 static errr set_mon_odds_rate(const nlohmann::json &odds_data, MonsterRaceInfo &monrace)
388 {
389     if (odds_data.is_null()) {
390         return PARSE_ERROR_NONE;
391     }
392     if (!odds_data.is_number_integer()) {
393         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
394     }
395
396     const auto odds = odds_data.get<int>();
397     if (odds <= 0 || odds > 9999) {
398         return PARSE_ERROR_INVALID_FLAG;
399     }
400     monrace.arena_ratio = odds;
401     return PARSE_ERROR_NONE;
402 }
403
404 /*!
405  * @brief JSON Objectからモンスターの初期体力をセットする
406  * @param start_hp_data 初期体力情報の格納されたJSON Object
407  * @param monrace 保管先のモンスター種族構造体
408  * @return エラーコード
409  */
410 static errr set_mon_start_hp_percentage(const nlohmann::json &start_hp_data, MonsterRaceInfo &monrace)
411 {
412     if (start_hp_data.is_null()) {
413         return PARSE_ERROR_NONE;
414     }
415     if (!start_hp_data.is_number_integer()) {
416         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
417     }
418
419     const auto start_hp = start_hp_data.get<int>();
420     if (start_hp < 0 || start_hp > 99) {
421         return PARSE_ERROR_INVALID_FLAG;
422     }
423     monrace.cur_hp_per = start_hp;
424     return PARSE_ERROR_NONE;
425 }
426
427 /*!
428  * @brief JSON Objectからモンスターの固定アーティファクトドロップ情報をセットする
429  * @param artifact_data 固定アーティファクトドロップ情報の格納されたJSON Object
430  * @param monrace 保管先のモンスター種族構造体
431  * @return エラーコード
432  */
433 static errr set_mon_artifacts(const nlohmann::json &artifact_data, MonsterRaceInfo &monrace)
434 {
435     if (artifact_data.is_null()) {
436         return PARSE_ERROR_NONE;
437     }
438     if (!artifact_data.is_array()) {
439         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
440     }
441
442     for (auto &artifact : artifact_data.items()) {
443         const auto &artifact_id_obj = artifact.value()["drop_artifact_id"];
444         const auto &artifact_chance_obj = artifact.value()["drop_probability"];
445
446         if (!artifact_id_obj.is_number_integer()) {
447             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
448         }
449         if (!artifact_chance_obj.is_number_integer()) {
450             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
451         }
452         const auto artifact_id = artifact_id_obj.get<int>();
453         if (artifact_id < 0 || artifact_id > 1024) {
454             return PARSE_ERROR_INVALID_FLAG;
455         }
456         const auto a_idx = static_cast<FixedArtifactId>(artifact_id);
457         const auto artifact_chance = artifact_chance_obj.get<int>();
458         if (artifact_chance <= 0 || artifact_chance > 100) {
459             return PARSE_ERROR_INVALID_FLAG;
460         }
461         monrace.drop_artifacts.emplace_back(a_idx, artifact_chance);
462     }
463     return PARSE_ERROR_NONE;
464 }
465
466 /*!
467  * @brief JSON Objectからモンスターの護衛情報をセットする
468  * @param escort_data 護衛情報の格納されたJSON Object
469  * @param monrace 保管先のモンスター種族構造体
470  * @return エラーコード
471  */
472 static errr set_mon_escorts(const nlohmann::json &escort_data, MonsterRaceInfo &monrace)
473 {
474     if (escort_data.is_null()) {
475         return PARSE_ERROR_NONE;
476     }
477     if (!escort_data.is_array()) {
478         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
479     }
480
481     for (auto &escort : escort_data.items()) {
482         const auto &escorts_id_obj = escort.value()["escorts_id"];
483         const auto &escort_num_obj = escort.value()["escort_num"];
484         if (!escorts_id_obj.is_number_integer()) {
485             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
486         }
487         if (!escort_num_obj.is_string()) {
488             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
489         }
490
491         const auto escorts_id = escorts_id_obj.get<int>();
492         if (escorts_id < 0 || escorts_id > 8192) {
493             return PARSE_ERROR_INVALID_FLAG;
494         }
495
496         const auto monrace_id = static_cast<MonsterRaceId>(escorts_id);
497         const auto escort_num = escort_num_obj.get<std::string>();
498         const auto &dice = str_split(escort_num, 'd', false, 2);
499         DICE_NUMBER dd;
500         DICE_SID ds;
501         info_set_value(dd, dice[0]);
502         info_set_value(ds, dice[1]);
503         monrace.reinforces.emplace_back(monrace_id, dd, ds);
504     }
505     return PARSE_ERROR_NONE;
506 }
507
508 /*!
509  * @brief JSON Objectからモンスターの打撃攻撃をセットする
510  * @param blow_data 打撃攻撃情報の格納されたJSON Object
511  * @param monrace 保管先のモンスター種族構造体
512  * @return エラーコード
513  */
514 static errr set_mon_blows(const nlohmann::json &blow_data, MonsterRaceInfo &monrace)
515 {
516     if (blow_data.is_null()) {
517         return PARSE_ERROR_NONE;
518     }
519     if (!blow_data.is_array()) {
520         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
521     }
522
523     auto blow_num = 0;
524     for (auto &blow : blow_data.items()) {
525         if (blow_num > 5) {
526             return PARSE_ERROR_GENERIC;
527         }
528
529         const auto &blow_method = blow.value()["method"];
530         const auto &blow_effect = blow.value()["effect"];
531         if (blow_method.is_null() || blow_effect.is_null()) {
532             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
533         }
534
535         const auto rbm = r_info_blow_method.find(blow_method.get<std::string>());
536         if (rbm == r_info_blow_method.end()) {
537             return PARSE_ERROR_INVALID_FLAG;
538         }
539
540         const auto rbe = r_info_blow_effect.find(blow_effect.get<std::string>());
541         if (rbe == r_info_blow_effect.end()) {
542             return PARSE_ERROR_INVALID_FLAG;
543         }
544         monrace.blows[blow_num].method = rbm->second;
545         monrace.blows[blow_num].effect = rbe->second;
546
547         const auto &blow_dice = blow.value().find("damage_dice");
548         if (blow_dice != blow.value().end()) {
549             const auto &dice = str_split(blow_dice->get<std::string>(), 'd', false, 2);
550             info_set_value(monrace.blows[blow_num].d_dice, dice[0]);
551             info_set_value(monrace.blows[blow_num].d_side, dice[1]);
552         }
553
554         blow_num++;
555     }
556     return PARSE_ERROR_NONE;
557 }
558
559 /*!
560  * @brief JSON Objectからモンスターフラグをセットする
561  * @param flag_data モンスターフラグ情報の格納されたJSON Object
562  * @param monrace 保管先のモンスター種族構造体
563  * @return エラーコード
564  */
565 static errr set_mon_flags(const nlohmann::json &flag_data, MonsterRaceInfo &monrace)
566 {
567     if (flag_data.is_null()) {
568         return PARSE_ERROR_NONE;
569     }
570     if (!flag_data.is_array()) {
571         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
572     }
573
574     for (auto &flag : flag_data.items()) {
575         if (!grab_one_basic_flag(monrace, flag.value().get<std::string>())) {
576             return PARSE_ERROR_INVALID_FLAG;
577         }
578     }
579     return PARSE_ERROR_NONE;
580 }
581
582 /*!
583  * @brief JSON Objectからモンスターの発動能力をセットする
584  * @param skill_data 発動能力情報の格納されたJSON Object
585  * @param monrace 保管先のモンスター種族構造体
586  * @return エラーコード
587  */
588 static errr set_mon_skills(const nlohmann::json &skill_data, MonsterRaceInfo &monrace)
589 {
590     if (skill_data.is_null()) {
591         return PARSE_ERROR_NONE;
592     }
593     if (!skill_data.is_object()) {
594         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
595     }
596
597     const auto &prob = skill_data["probability"];
598     if (!prob.is_string()) {
599         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
600     }
601
602     const auto &prob_token = str_split(prob.get<std::string>(), '_', false, 2);
603     if (prob_token.size() == 3 && prob_token[1] == "IN") {
604         if (prob_token[0] != "1") {
605             return PARSE_ERROR_GENERIC;
606         }
607         byte denominator;
608         info_set_value(denominator, prob_token[2]);
609         monrace.freq_spell = 100 / denominator;
610     }
611
612     const auto &shoot_dice = skill_data.find("shoot");
613     const auto shoot = (shoot_dice != skill_data.end());
614     if (shoot) {
615         const auto &dice = str_split(shoot_dice->get<std::string>(), 'd', false, 2);
616         info_set_value(monrace.shoot_dam_dice, dice[0]);
617         info_set_value(monrace.shoot_dam_side, dice[1]);
618         monrace.ability_flags.set(MonsterAbilityType::SHOOT);
619     }
620
621     const auto &skill_list = skill_data.find("list");
622     if (skill_list == skill_data.end()) {
623         if (!shoot) {
624             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
625         }
626         return PARSE_ERROR_NONE;
627     }
628
629     for (auto &skill : skill_list->items()) {
630         if (!grab_one_spell_flag(monrace, skill.value().get<std::string>())) {
631             return PARSE_ERROR_INVALID_FLAG;
632         }
633     }
634     return PARSE_ERROR_NONE;
635 }
636
637 /*!
638  * @brief JSON Objectからモンスターの説明文をセットする
639  * @param flag_data 説明文の情報の格納されたJSON Object
640  * @param monrace 保管先のモンスター種族構造体
641  * @return エラーコード
642  */
643 static errr set_mon_flavor(const nlohmann::json &flavor_data, MonsterRaceInfo &monrace)
644 {
645     if (flavor_data.is_null()) {
646         return PARSE_ERROR_NONE;
647     }
648     if (!flavor_data.is_object()) {
649         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
650     }
651
652 #ifdef JP
653     const auto &flavor_ja = flavor_data.find("ja");
654     if (flavor_ja == flavor_data.end()) {
655         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
656     }
657     auto flavor_ja_sys = utf8_to_sys(flavor_ja->get<std::string>());
658     if (!flavor_ja_sys) {
659         return PARSE_ERROR_INVALID_FLAG;
660     }
661     monrace.text = std::move(*flavor_ja_sys);
662 #else
663     const auto &flavor_en = flavor_data.find("en");
664     if (flavor_en == flavor_data.end()) {
665         return PARSE_ERROR_NONE;
666     }
667     monrace.text = flavor_en->get<std::string>();
668 #endif
669     return PARSE_ERROR_NONE;
670 }
671
672 /*!
673  * @brief モンスター種族情報(JSON Object)のパース関数
674  * @param mon_data モンスターデータの格納されたJSON Object
675  * @param head ヘッダ構造体
676  * @return エラーコード
677  */
678 errr parse_monraces_info(nlohmann::json &mon_data, angband_header *)
679 {
680     if (!mon_data["id"].is_number_integer()) {
681         return PARSE_ERROR_TOO_FEW_ARGUMENTS;
682     }
683
684     const auto monster_idx = mon_data["id"].get<int>();
685     if (monster_idx < error_idx) {
686         return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
687     }
688     error_idx = monster_idx;
689     auto &monrace = monraces_info.emplace_hint(monraces_info.end(), i2enum<MonsterRaceId>(monster_idx), MonsterRaceInfo{})->second;
690     monrace.idx = i2enum<MonsterRaceId>(monster_idx);
691
692     errr err;
693     err = set_mon_name(mon_data["name"], monrace);
694     if (err) {
695         msg_format(_("モンスター名読込失敗。ID: '%d'。", "Failed to load monster name. ID: '%d'."), error_idx);
696         return err;
697     }
698     err = set_mon_symbol(mon_data["symbol"], monrace);
699     if (err) {
700         msg_format(_("モンスターシンボル読込失敗。ID: '%d'。", "Failed to load monster symbol. ID: '%d'."), error_idx);
701         return err;
702     }
703     err = set_mon_speed(mon_data["speed"], monrace);
704     if (err) {
705         msg_format(_("モンスター速度読込失敗。ID: '%d'。", "Failed to load monster speed. ID: '%d'."), error_idx);
706         return err;
707     }
708     err = set_mon_hp(mon_data["hit_point"], monrace);
709     if (err) {
710         msg_format(_("モンスターHP読込失敗。ID: '%d'。", "Failed to load monster HP. ID: '%d'."), error_idx);
711         return err;
712     }
713     err = set_mon_vision(mon_data["vision"], monrace);
714     if (err) {
715         msg_format(_("モンスター感知範囲読込失敗。ID: '%d'。", "Failed to load monster vision. ID: '%d'."), error_idx);
716         return err;
717     }
718     err = set_mon_ac(mon_data["armor_class"], monrace);
719     if (err) {
720         msg_format(_("モンスターAC読込失敗。ID: '%d'。", "Failed to load monster AC. ID: '%d'."), error_idx);
721         return err;
722     }
723     err = set_mon_alertness(mon_data["alertness"], monrace);
724     if (err) {
725         msg_format(_("モンスター警戒度読込失敗。ID: '%d'。", "Failed to load monster alertness. ID: '%d'."), error_idx);
726         return err;
727     }
728     err = set_mon_level(mon_data["level"], monrace);
729     if (err) {
730         msg_format(_("モンスターレベル読込失敗。ID: '%d'。", "Failed to load monster level. ID: '%d'."), error_idx);
731         return err;
732     }
733     err = set_mon_rarity(mon_data["rarity"], monrace);
734     if (err) {
735         msg_format(_("モンスター希少度読込失敗。ID: '%d'。", "Failed to load monster rarity. ID: '%d'."), error_idx);
736         return err;
737     }
738     err = set_mon_exp(mon_data["exp"], monrace);
739     if (err) {
740         msg_format(_("モンスター経験値読込失敗。ID: '%d'。", "Failed to load monster exp. ID: '%d'."), error_idx);
741         return err;
742     }
743     err = set_mon_evolve(mon_data["evolve"], monrace);
744     if (err) {
745         msg_format(_("モンスター進化情報読込失敗。ID: '%d'。", "Failed to load monster evolve data. ID: '%d'."), error_idx);
746         return err;
747     }
748     err = set_mon_sex(mon_data["sex"], monrace);
749     if (err) {
750         msg_format(_("モンスター性別読込失敗。ID: '%d'。", "Failed to load monster sex. ID: '%d'."), error_idx);
751         return err;
752     }
753     err = set_mon_odds_rate(mon_data["odds_correction_ratio"], monrace);
754     if (err) {
755         msg_format(_("モンスター賭け倍率読込失敗。ID: '%d'。", "Failed to load monster odds for arena. ID: '%d'."), error_idx);
756         return err;
757     }
758     err = set_mon_start_hp_percentage(mon_data["start_hp_percentage"], monrace);
759     if (err) {
760         msg_format(_("モンスター初期体力読込失敗。ID: '%d'。", "Failed to load monster starting HP. ID: '%d'."), error_idx);
761         return err;
762     }
763     err = set_mon_artifacts(mon_data["artifacts"], monrace);
764     if (err) {
765         msg_format(_("モンスター固定アーティファクトドロップ情報読込失敗。ID: '%d'。", "Failed to load monster artifact drop data. ID: '%d'."), error_idx);
766         return err;
767     }
768     err = set_mon_escorts(mon_data["escorts"], monrace);
769     if (err) {
770         msg_format(_("モンスター護衛情報読込失敗。ID: '%d'。", "Failed to load monster escorts. ID: '%d'."), error_idx);
771         return err;
772     }
773     err = set_mon_blows(mon_data["blows"], monrace);
774     if (err) {
775         msg_format(_("モンスター打撃情報読込失敗。ID: '%d'。", "Failed to load monster blow data. ID: '%d'."), error_idx);
776         return err;
777     }
778     err = set_mon_flags(mon_data["flags"], monrace);
779     if (err) {
780         msg_format(_("モンスターフラグ読込失敗。ID: '%d'。", "Failed to load monster flag data. ID: '%d'."), error_idx);
781         return err;
782     }
783     err = set_mon_skills(mon_data["skill"], monrace);
784     if (err) {
785         msg_format(_("モンスター発動能力情報読込失敗。ID: '%d'。", "Failed to load monster skill data. ID: '%d'."), error_idx);
786         return err;
787     }
788     err = set_mon_flavor(mon_data["flavor"], monrace);
789     if (err) {
790         msg_format(_("モンスター説明文読込失敗。ID: '%d'。", "Failed to load monster flavor text. ID: '%d'."), error_idx);
791         return err;
792     }
793
794     return PARSE_ERROR_NONE;
795 }