The master and develop branches track hengband.
OS X development happens on the macos-1-6-2, macos-2-2-1, and macos-develop branches.
Revision | f60b24f1c913ea6f0ac347a70af690e58d696ed2 (tree) |
---|---|
Time | 2021-05-12 20:11:40 |
Author | iks <iks3@user...> |
Commiter | GitHub |
Merge pull request #909 from iks3/refactor-parser-to-cpp-like
[Refactor] 各パーサをstd::string系の処理を利用して書き直し
@@ -266,23 +266,30 @@ void flavor_init(void) | ||
266 | 266 | */ |
267 | 267 | void strip_name(char *buf, KIND_OBJECT_IDX k_idx) |
268 | 268 | { |
269 | - object_kind *k_ptr = &k_info[k_idx]; | |
270 | - concptr str = k_ptr->name.c_str(); | |
271 | - while ((*str == ' ') || (*str == '&') || (*str == '#')) | |
272 | - str++; | |
269 | + auto k_ptr = &k_info[k_idx]; | |
270 | + auto tok = str_split(k_ptr->name, ' '); | |
271 | + std::string name = ""; | |
272 | + for (auto s : tok) { | |
273 | + if (s == "" || s == "~" || s == "&" || s == "#") | |
274 | + continue; | |
275 | + | |
276 | + auto offset = 0; | |
277 | + auto endpos = s.size(); | |
278 | + auto is_kanji = false; | |
273 | 279 | |
274 | - char *t; | |
275 | - for (t = buf; *str; str++) { | |
280 | + if (s[0] == '~' || s[0] == '#') | |
281 | + offset++; | |
276 | 282 | #ifdef JP |
277 | - if (iskanji(*str)) { | |
278 | - *t++ = *str++; | |
279 | - *t++ = *str; | |
280 | - continue; | |
281 | - } | |
283 | + if (s.size() > 2) | |
284 | + is_kanji = iskanji(s[endpos - 2]); | |
285 | + | |
282 | 286 | #endif |
283 | - if (*str != '~' && *str != '#') | |
284 | - *t++ = *str; | |
287 | + if (!is_kanji && (s[endpos - 1] == '~' || s[endpos - 1] == '#')) | |
288 | + endpos--; | |
289 | + | |
290 | + name += s.substr(offset, endpos); | |
285 | 291 | } |
286 | 292 | |
287 | - *t = '\0'; | |
293 | + name += " "; | |
294 | + strcpy(buf, name.c_str()); | |
288 | 295 | } |
@@ -51,6 +51,7 @@ enum feature_flag_type : int { | ||
51 | 51 | FF_CAN_PASS = 55, /*!< 通過可能な地形である */ |
52 | 52 | FF_CAN_DIG = 57, /*!< 掘削コマンドの対象となる地形である */ |
53 | 53 | FF_TREE = 83, /*!< 木の生えた地形である */ |
54 | + FF_PLANT = 88, //!< 植物の生えた地形である | |
54 | 55 | FF_SPECIAL = 96, /*!< クエストやダンジョンに関わる特別な地形である */ |
55 | 56 | FF_HURT_DISI = 97, /*!< 分解属性の対象となる地形である */ |
56 | 57 | FF_QUEST_ENTER = 98, /*!< クエストの入り口である */ |
@@ -1,32 +1,31 @@ | ||
1 | 1 | #include "info-reader/artifact-reader.h" |
2 | +#include "info-reader/info-reader-util.h" | |
2 | 3 | #include "info-reader/kind-info-tokens-table.h" |
4 | +#include "info-reader/parse-error-types.h" | |
3 | 5 | #include "main/angband-headers.h" |
4 | 6 | #include "object-enchant/tr-types.h" |
5 | 7 | #include "system/artifact-type-definition.h" |
6 | 8 | #include "util/bit-flags-calculator.h" |
7 | 9 | #include "util/string-processor.h" |
8 | 10 | #include "view/display-messages.h" |
9 | -#include <string> | |
10 | 11 | |
11 | 12 | /*! |
12 | 13 | * @brief テキストトークンを走査してフラグを一つ得る(アーティファクト用) / |
13 | 14 | * Grab one activation index flag |
14 | 15 | * @param a_ptr 保管先のアーティファクト構造体参照ポインタ |
15 | 16 | * @param what 参照元の文字列ポインタ |
16 | - * @return エラーがあった場合1、エラーがない場合0を返す | |
17 | + * @return 見つかったらtrue | |
17 | 18 | */ |
18 | -static errr grab_one_artifact_flag(artifact_type *a_ptr, concptr what) | |
19 | +static bool grab_one_artifact_flag(artifact_type *a_ptr, std::string_view what) | |
19 | 20 | { |
20 | - if (k_info_flags.find(what) != k_info_flags.end()) { | |
21 | - add_flag(a_ptr->flags, k_info_flags[what]); | |
22 | - return 0; | |
23 | - } | |
21 | + if (info_grab_one_flag(a_ptr->flags, k_info_flags, what)) | |
22 | + return true; | |
24 | 23 | |
25 | 24 | if (EnumClassFlagGroup<TRG>::grab_one_flag(a_ptr->gen_flags, k_info_gen_flags, what)) |
26 | - return 0; | |
25 | + return true; | |
27 | 26 | |
28 | - msg_format(_("未知の伝説のアイテム・フラグ '%s'。", "Unknown artifact flag '%s'."), what); | |
29 | - return 1; | |
27 | + msg_format(_("未知の伝説のアイテム・フラグ '%s'。", "Unknown artifact flag '%s'."), what.data()); | |
28 | + return false; | |
30 | 29 | } |
31 | 30 | |
32 | 31 | /*! |
@@ -36,25 +35,21 @@ static errr grab_one_artifact_flag(artifact_type *a_ptr, concptr what) | ||
36 | 35 | * @param head ヘッダ構造体 |
37 | 36 | * @return エラーコード |
38 | 37 | */ |
39 | -errr parse_a_info(char *buf, angband_header *head) | |
38 | +errr parse_a_info(std::string_view buf, angband_header *head) | |
40 | 39 | { |
41 | 40 | static artifact_type *a_ptr = NULL; |
42 | - char *s, *t; | |
43 | - if (buf[0] == 'N') { | |
44 | - s = angband_strchr(buf + 2, ':'); | |
45 | - if (!s) | |
46 | - return 1; | |
41 | + const auto &tokens = str_split(buf, ':', false, 10); | |
47 | 42 | |
48 | - *s++ = '\0'; | |
49 | -#ifdef JP | |
50 | - if (!*s) | |
51 | - return 1; | |
52 | -#endif | |
53 | - int i = atoi(buf + 2); | |
43 | + if (tokens[0] == "N") { | |
44 | + // N:index:name_ja | |
45 | + if (tokens.size() < 3 || tokens[1].size() == 0) | |
46 | + return PARSE_ERROR_GENERIC; | |
47 | + | |
48 | + auto i = std::stoi(tokens[1]); | |
54 | 49 | if (i < error_idx) |
55 | - return 4; | |
50 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
56 | 51 | if (i >= head->info_num) |
57 | - return 2; | |
52 | + return PARSE_ERROR_OUT_OF_BOUNDS; | |
58 | 53 | |
59 | 54 | error_idx = i; |
60 | 55 | a_ptr = &a_info[i]; |
@@ -62,92 +57,88 @@ errr parse_a_info(char *buf, angband_header *head) | ||
62 | 57 | add_flag(a_ptr->flags, TR_IGNORE_ELEC); |
63 | 58 | add_flag(a_ptr->flags, TR_IGNORE_FIRE); |
64 | 59 | add_flag(a_ptr->flags, TR_IGNORE_COLD); |
60 | + | |
65 | 61 | #ifdef JP |
66 | - a_ptr->name = std::string(s); | |
62 | + a_ptr->name = tokens[2]; | |
67 | 63 | #endif |
68 | - } else if (!a_ptr) { | |
69 | - return 3; | |
70 | - } | |
71 | -#ifdef JP | |
72 | - /* 英語名を読むルーチンを追加 */ | |
73 | - /* 'E' から始まる行は英語名としている */ | |
74 | - else if (buf[0] == 'E') { | |
75 | - /* nothing to do */ | |
76 | - } | |
77 | -#else | |
78 | - else if (buf[0] == 'E') { | |
79 | - s = buf + 2; | |
80 | - a_ptr->name = std::string(s); | |
81 | - } | |
64 | + } else if (!a_ptr) | |
65 | + return PARSE_ERROR_MISSING_RECORD_HEADER; | |
66 | + else if (tokens[0] == "E") { | |
67 | + // E:name_en | |
68 | +#ifndef JP | |
69 | + if (tokens[1].size() == 0) | |
70 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
71 | + a_ptr->name = tokens[1]; | |
82 | 72 | #endif |
83 | - else if (buf[0] == 'D') { | |
73 | + } else if (tokens[0] == "D") { | |
74 | + // D:JapaneseText | |
75 | + // D:$EnglishText | |
76 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
77 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
84 | 78 | #ifdef JP |
85 | - if (buf[2] == '$') | |
86 | - return 0; | |
87 | - s = buf + 2; | |
79 | + if (tokens[1][0] == '$') | |
80 | + return PARSE_ERROR_NONE; | |
81 | + a_ptr->text.append(buf.substr(2)); | |
88 | 82 | #else |
89 | - if (buf[2] != '$') | |
90 | - return 0; | |
91 | - s = buf + 3; | |
83 | + if (tokens[1][0] != '$') | |
84 | + return PARSE_ERROR_NONE; | |
85 | + a_ptr->text.append(buf.substr(3)); | |
92 | 86 | #endif |
93 | - a_ptr->text.append(s); | |
94 | - } else if (buf[0] == 'I') { | |
95 | - int tval, sval, pval; | |
96 | - if (3 != sscanf(buf + 2, "%d:%d:%d", &tval, &sval, &pval)) | |
97 | - return 1; | |
87 | + } else if (tokens[0] == "I") { | |
88 | + // I:tval:sval:pval | |
89 | + if (tokens.size() < 4) | |
90 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
98 | 91 | |
99 | - a_ptr->tval = (tval_type)tval; | |
100 | - a_ptr->sval = (OBJECT_SUBTYPE_VALUE)sval; | |
101 | - a_ptr->pval = (PARAMETER_VALUE)pval; | |
102 | - } else if (buf[0] == 'W') { | |
103 | - int level, rarity, wgt; | |
104 | - long cost; | |
105 | - if (4 != sscanf(buf + 2, "%d:%d:%d:%ld", &level, &rarity, &wgt, &cost)) | |
106 | - return 1; | |
92 | + info_set_value(a_ptr->tval, tokens[1]); | |
93 | + info_set_value(a_ptr->sval, tokens[2]); | |
94 | + info_set_value(a_ptr->pval, tokens[3]); | |
95 | + } else if (tokens[0] == "W") { | |
96 | + // W:level:ratiry:weight:cost | |
97 | + if (tokens.size() < 5) | |
98 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
107 | 99 | |
108 | - a_ptr->level = (DEPTH)level; | |
109 | - a_ptr->rarity = (RARITY)rarity; | |
110 | - a_ptr->weight = (WEIGHT)wgt; | |
111 | - a_ptr->cost = (PRICE)cost; | |
112 | - } else if (buf[0] == 'P') { | |
113 | - int ac, hd1, hd2, th, td, ta; | |
114 | - if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d", &ac, &hd1, &hd2, &th, &td, &ta)) | |
115 | - return 1; | |
100 | + info_set_value(a_ptr->level, tokens[1]); | |
101 | + info_set_value(a_ptr->rarity, tokens[2]); | |
102 | + info_set_value(a_ptr->weight, tokens[3]); | |
103 | + info_set_value(a_ptr->cost, tokens[4]); | |
104 | + } else if (tokens[0] == "P") { | |
105 | + // P:ac:dd:ds:to_h:to_d:to_a | |
106 | + if (tokens.size() < 6) | |
107 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
116 | 108 | |
117 | - a_ptr->ac = (ARMOUR_CLASS)ac; | |
118 | - a_ptr->dd = (DICE_NUMBER)hd1; | |
119 | - a_ptr->ds = (DICE_SID)hd2; | |
120 | - a_ptr->to_h = (HIT_PROB)th; | |
121 | - a_ptr->to_d = (HIT_POINT)td; | |
122 | - a_ptr->to_a = (ARMOUR_CLASS)ta; | |
123 | - } else if (buf[0] == 'U') { | |
124 | - byte n; | |
125 | - n = grab_one_activation_flag(buf + 2); | |
126 | - if (n > 0) { | |
127 | - a_ptr->act_idx = n; | |
128 | - } else { | |
129 | - return 5; | |
130 | - } | |
131 | - } else if (buf[0] == 'F') { | |
132 | - for (s = buf + 2; *s;) { | |
133 | - /* loop */ | |
134 | - for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) | |
135 | - ; | |
109 | + const auto &dice = str_split(tokens[2], 'd', false, 2); | |
110 | + if (dice.size() != 2) | |
111 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
136 | 112 | |
137 | - if (*t) { | |
138 | - *t++ = '\0'; | |
139 | - while ((*t == ' ') || (*t == '|')) | |
140 | - t++; | |
141 | - } | |
113 | + info_set_value(a_ptr->ac, tokens[1]); | |
114 | + info_set_value(a_ptr->dd, dice[0]); | |
115 | + info_set_value(a_ptr->ds, dice[1]); | |
116 | + info_set_value(a_ptr->to_h, tokens[3]); | |
117 | + info_set_value(a_ptr->to_d, tokens[4]); | |
118 | + info_set_value(a_ptr->to_a, tokens[5]); | |
119 | + } else if (tokens[0] == "U") { | |
120 | + // U:activation_flag | |
121 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
122 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
123 | + auto n = grab_one_activation_flag(tokens[1].c_str()); | |
124 | + if (n <= 0) | |
125 | + return PARSE_ERROR_INVALID_FLAG; | |
142 | 126 | |
143 | - if (0 != grab_one_artifact_flag(a_ptr, s)) | |
144 | - return 5; | |
127 | + a_ptr->act_idx = (IDX)n; | |
128 | + } else if (tokens[0] == "F") { | |
129 | + // F:flags | |
130 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
131 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
145 | 132 | |
146 | - s = t; | |
133 | + const auto &flags = str_split(tokens[1], '|', true, 10); | |
134 | + for (const auto &f : flags) { | |
135 | + if (f.size() == 0) | |
136 | + continue; | |
137 | + if (!grab_one_artifact_flag(a_ptr, f)) | |
138 | + return PARSE_ERROR_INVALID_FLAG; | |
147 | 139 | } |
148 | - } else { | |
149 | - return 6; | |
150 | - } | |
140 | + } else | |
141 | + return PARSE_ERROR_UNDEFINED_DIRECTIVE; | |
151 | 142 | |
152 | - return 0; | |
143 | + return PARSE_ERROR_NONE; | |
153 | 144 | } |
@@ -1,6 +1,7 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | -#include "info-reader/info-reader-util.h" | |
4 | 3 | #include "system/angband.h" |
4 | +#include <string_view> | |
5 | 5 | |
6 | -errr parse_a_info(char *buf, angband_header *head); | |
6 | +struct angband_header; | |
7 | +errr parse_a_info(std::string_view buf, angband_header *head); |
@@ -3,28 +3,28 @@ | ||
3 | 3 | #include "grid/feature.h" |
4 | 4 | #include "info-reader/dungeon-info-tokens-table.h" |
5 | 5 | #include "info-reader/feature-reader.h" |
6 | +#include "info-reader/info-reader-util.h" | |
6 | 7 | #include "info-reader/parse-error-types.h" |
7 | 8 | #include "info-reader/race-info-tokens-table.h" |
8 | 9 | #include "io/tokenizer.h" |
9 | 10 | #include "main/angband-headers.h" |
10 | 11 | #include "util/string-processor.h" |
11 | 12 | #include "view/display-messages.h" |
12 | -#include <string> | |
13 | 13 | |
14 | 14 | /*! |
15 | 15 | * @brief テキストトークンを走査してフラグを一つ得る(ダンジョン用) / |
16 | 16 | * Grab one flag for a dungeon type from a textual string |
17 | 17 | * @param d_ptr 保管先のダンジョン構造体参照ポインタ |
18 | 18 | * @param what 参照元の文字列ポインタ |
19 | - * @return エラーコード | |
19 | + * @return 見つけたらtrue | |
20 | 20 | */ |
21 | -static errr grab_one_dungeon_flag(dungeon_type *d_ptr, concptr what) | |
21 | +static bool grab_one_dungeon_flag(dungeon_type *d_ptr, std::string_view what) | |
22 | 22 | { |
23 | 23 | if (EnumClassFlagGroup<DF>::grab_one_flag(d_ptr->flags, d_info_flags, what)) |
24 | - return 0; | |
24 | + return true; | |
25 | 25 | |
26 | - msg_format(_("未知のダンジョン・フラグ '%s'。", "Unknown dungeon type flag '%s'."), what); | |
27 | - return 1; | |
26 | + msg_format(_("未知のダンジョン・フラグ '%s'。", "Unknown dungeon type flag '%s'."), what.data()); | |
27 | + return false; | |
28 | 28 | } |
29 | 29 | |
30 | 30 | /*! |
@@ -32,33 +32,33 @@ static errr grab_one_dungeon_flag(dungeon_type *d_ptr, concptr what) | ||
32 | 32 | * Grab one (basic) flag in a monster_race from a textual string |
33 | 33 | * @param d_ptr 保管先のダンジョン構造体参照ポインタ |
34 | 34 | * @param what 参照元の文字列ポインタ |
35 | - * @return エラーコード | |
35 | + * @return 見つけたらtrue | |
36 | 36 | */ |
37 | -static errr grab_one_basic_monster_flag(dungeon_type *d_ptr, concptr what) | |
37 | +static bool grab_one_basic_monster_flag(dungeon_type *d_ptr, std::string_view what) | |
38 | 38 | { |
39 | - if (grab_one_flag(&d_ptr->mflags1, r_info_flags1, what) == 0) | |
40 | - return 0; | |
39 | + if (info_grab_one_flag(d_ptr->mflags1, r_info_flags1, what)) | |
40 | + return true; | |
41 | 41 | |
42 | - if (grab_one_flag(&d_ptr->mflags2, r_info_flags2, what) == 0) | |
43 | - return 0; | |
42 | + if (info_grab_one_flag(d_ptr->mflags2, r_info_flags2, what)) | |
43 | + return true; | |
44 | 44 | |
45 | - if (grab_one_flag(&d_ptr->mflags3, r_info_flags3, what) == 0) | |
46 | - return 0; | |
45 | + if (info_grab_one_flag(d_ptr->mflags3, r_info_flags3, what)) | |
46 | + return true; | |
47 | 47 | |
48 | - if (grab_one_flag(&d_ptr->mflags7, r_info_flags7, what) == 0) | |
49 | - return 0; | |
48 | + if (info_grab_one_flag(d_ptr->mflags7, r_info_flags7, what)) | |
49 | + return true; | |
50 | 50 | |
51 | - if (grab_one_flag(&d_ptr->mflags8, r_info_flags8, what) == 0) | |
52 | - return 0; | |
51 | + if (info_grab_one_flag(d_ptr->mflags8, r_info_flags8, what)) | |
52 | + return true; | |
53 | 53 | |
54 | - if (grab_one_flag(&d_ptr->mflags9, r_info_flags9, what) == 0) | |
55 | - return 0; | |
54 | + if (info_grab_one_flag(d_ptr->mflags9, r_info_flags9, what)) | |
55 | + return true; | |
56 | 56 | |
57 | - if (grab_one_flag(&d_ptr->mflagsr, r_info_flagsr, what) == 0) | |
58 | - return 0; | |
57 | + if (info_grab_one_flag(d_ptr->mflagsr, r_info_flagsr, what)) | |
58 | + return true; | |
59 | 59 | |
60 | - msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what); | |
61 | - return 1; | |
60 | + msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data()); | |
61 | + return false; | |
62 | 62 | } |
63 | 63 | |
64 | 64 | /*! |
@@ -66,15 +66,15 @@ static errr grab_one_basic_monster_flag(dungeon_type *d_ptr, concptr what) | ||
66 | 66 | * Grab one (spell) flag in a monster_race from a textual string |
67 | 67 | * @param d_ptr 保管先のダンジョン構造体参照ポインタ |
68 | 68 | * @param what 参照元の文字列ポインタ |
69 | - * @return エラーコード | |
69 | + * @return 見つけたらtrue | |
70 | 70 | */ |
71 | -static errr grab_one_spell_monster_flag(dungeon_type *d_ptr, concptr what) | |
71 | +static bool grab_one_spell_monster_flag(dungeon_type *d_ptr, std::string_view what) | |
72 | 72 | { |
73 | 73 | if (EnumClassFlagGroup<RF_ABILITY>::grab_one_flag(d_ptr->m_ability_flags, r_info_ability_flags, what)) |
74 | - return 0; | |
74 | + return true; | |
75 | 75 | |
76 | - msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what); | |
77 | - return 1; | |
76 | + msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data()); | |
77 | + return false; | |
78 | 78 | } |
79 | 79 | |
80 | 80 | /*! |
@@ -84,220 +84,203 @@ static errr grab_one_spell_monster_flag(dungeon_type *d_ptr, concptr what) | ||
84 | 84 | * @param head ヘッダ構造体 |
85 | 85 | * @return エラーコード |
86 | 86 | */ |
87 | -errr parse_d_info(char *buf, angband_header *head) | |
87 | +errr parse_d_info(std::string_view buf, angband_header *head) | |
88 | 88 | { |
89 | 89 | static dungeon_type *d_ptr = NULL; |
90 | - char *s, *t; | |
91 | - if (buf[0] == 'N') { | |
92 | - s = angband_strchr(buf + 2, ':'); | |
93 | - if (!s) | |
94 | - return 1; | |
90 | + const auto &tokens = str_split(buf, ':', false); | |
95 | 91 | |
96 | - *s++ = '\0'; | |
97 | -#ifdef JP | |
98 | - if (!*s) | |
99 | - return 1; | |
100 | -#endif | |
92 | + if (tokens[0] == "N") { | |
93 | + // N:index:name_ja | |
94 | + if (tokens.size() < 3 || tokens[1].size() == 0) | |
95 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
101 | 96 | |
102 | - int i = atoi(buf + 2); | |
97 | + auto i = std::stoi(tokens[1]); | |
103 | 98 | if (i < error_idx) |
104 | - return 4; | |
99 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
105 | 100 | if (i >= head->info_num) |
106 | - return 2; | |
101 | + return PARSE_ERROR_OUT_OF_BOUNDS; | |
107 | 102 | |
108 | 103 | error_idx = i; |
109 | 104 | d_ptr = &d_info[i]; |
110 | 105 | #ifdef JP |
111 | - d_ptr->name = std::string(s); | |
106 | + d_ptr->name = tokens[2]; | |
112 | 107 | #endif |
113 | - } | |
114 | -#ifdef JP | |
115 | - else if (buf[0] == 'E') | |
116 | - return 0; | |
117 | -#else | |
118 | - else if (buf[0] == 'E') { | |
119 | - /* Acquire the Text */ | |
120 | - s = buf + 2; | |
121 | - | |
122 | - /* Store the name */ | |
123 | - d_ptr->name = std::string(s); | |
124 | - } | |
108 | + } else if (!d_ptr) | |
109 | + return PARSE_ERROR_MISSING_RECORD_HEADER; | |
110 | + else if (tokens[0] == "E") { | |
111 | + // E:name_en | |
112 | +#ifndef JP | |
113 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
114 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
115 | + d_ptr->name = tokens[1]; | |
125 | 116 | #endif |
126 | - else if (buf[0] == 'D') { | |
117 | + } else if (tokens[0] == "D") { | |
118 | + // D:text_ja | |
119 | + // D:$text_en | |
120 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
121 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
127 | 122 | #ifdef JP |
128 | - if (buf[2] == '$') | |
129 | - return 0; | |
130 | - s = buf + 2; | |
123 | + if (tokens[1][0] == '$') | |
124 | + return PARSE_ERROR_NONE; | |
125 | + d_ptr->text.append(buf.substr(2)); | |
131 | 126 | #else |
132 | - if (buf[2] != '$') | |
133 | - return 0; | |
134 | - s = buf + 3; | |
127 | + if (tokens[1][0] != '$') | |
128 | + return PARSE_ERROR_NONE; | |
129 | + d_ptr->text.append(buf.substr(3)); | |
135 | 130 | #endif |
136 | - d_ptr->text.append(s); | |
137 | - } else if (buf[0] == 'W') { | |
138 | - int min_lev, max_lev; | |
139 | - int min_plev, mode; | |
140 | - int min_alloc, max_chance; | |
141 | - int obj_good, obj_great; | |
142 | - int pit, nest; | |
143 | - | |
144 | - if (10 | |
145 | - != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%d:%d:%x:%x", &min_lev, &max_lev, &min_plev, &mode, &min_alloc, &max_chance, &obj_good, &obj_great, | |
146 | - (unsigned int *)&pit, (unsigned int *)&nest)) | |
147 | - return 1; | |
148 | - | |
149 | - d_ptr->mindepth = (DEPTH)min_lev; | |
150 | - d_ptr->maxdepth = (DEPTH)max_lev; | |
151 | - d_ptr->min_plev = (PLAYER_LEVEL)min_plev; | |
152 | - d_ptr->mode = (BIT_FLAGS8)mode; | |
153 | - d_ptr->min_m_alloc_level = min_alloc; | |
154 | - d_ptr->max_m_alloc_chance = max_chance; | |
155 | - d_ptr->obj_good = obj_good; | |
156 | - d_ptr->obj_great = obj_great; | |
157 | - d_ptr->pit = (BIT_FLAGS16)pit; | |
158 | - d_ptr->nest = (BIT_FLAGS16)nest; | |
159 | - } else if (buf[0] == 'P') { | |
160 | - int dy, dx; | |
161 | - if (2 != sscanf(buf + 2, "%d:%d", &dy, &dx)) | |
162 | - return 1; | |
163 | - | |
164 | - d_ptr->dy = dy; | |
165 | - d_ptr->dx = dx; | |
166 | - } else if (buf[0] == 'L') { | |
167 | - char *zz[16]; | |
168 | - if (tokenize(buf + 2, DUNGEON_FEAT_PROB_NUM * 2 + 1, zz, 0) != (DUNGEON_FEAT_PROB_NUM * 2 + 1)) | |
169 | - return 1; | |
170 | - | |
171 | - for (int i = 0; i < DUNGEON_FEAT_PROB_NUM; i++) { | |
172 | - d_ptr->floor[i].feat = f_tag_to_index(zz[i * 2]); | |
131 | + } else if (tokens[0] == "W") { | |
132 | + // W:min_level:max_level:(1):mode:(2):(3):(4):(5):prob_pit:prob_nest | |
133 | + // (1)minimum player level (unused) | |
134 | + // (2)minimum level of allocating monster | |
135 | + // (3)maximum probability of level boost of allocation monster | |
136 | + // (4)maximum probability of dropping good objects | |
137 | + // (5)maximum probability of dropping great objects | |
138 | + if (tokens.size() < 11) | |
139 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
140 | + | |
141 | + info_set_value(d_ptr->mindepth, tokens[1]); | |
142 | + info_set_value(d_ptr->maxdepth, tokens[2]); | |
143 | + info_set_value(d_ptr->min_plev, tokens[3]); | |
144 | + info_set_value(d_ptr->mode, tokens[4]); | |
145 | + info_set_value(d_ptr->min_m_alloc_level, tokens[5]); | |
146 | + info_set_value(d_ptr->max_m_alloc_chance, tokens[6]); | |
147 | + info_set_value(d_ptr->obj_good, tokens[7]); | |
148 | + info_set_value(d_ptr->obj_great, tokens[8]); | |
149 | + info_set_value(d_ptr->pit, tokens[9]); | |
150 | + info_set_value(d_ptr->nest, tokens[10]); | |
151 | + } else if (tokens[0] == "P") { | |
152 | + // P:wild_y:wild_x | |
153 | + if (tokens.size() < 3) | |
154 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
155 | + | |
156 | + info_set_value(d_ptr->dy, tokens[1]); | |
157 | + info_set_value(d_ptr->dx, tokens[2]); | |
158 | + } else if (tokens[0] == "L") { | |
159 | + // L:floor_1:prob_1:floor_2:prob_2:floor_3:prob_3:tunnel_prob | |
160 | + if (tokens.size() < DUNGEON_FEAT_PROB_NUM * 2 + 2) | |
161 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
162 | + | |
163 | + for (size_t i = 0; i < DUNGEON_FEAT_PROB_NUM; i++) { | |
164 | + auto feat_idx = i * 2 + 1; | |
165 | + auto per_idx = feat_idx + 1; | |
166 | + d_ptr->floor[i].feat = f_tag_to_index(tokens[feat_idx]); | |
173 | 167 | if (d_ptr->floor[i].feat < 0) |
174 | 168 | return PARSE_ERROR_UNDEFINED_TERRAIN_TAG; |
175 | 169 | |
176 | - d_ptr->floor[i].percent = (PERCENTAGE)atoi(zz[i * 2 + 1]); | |
170 | + info_set_value(d_ptr->floor[i].percent, tokens[per_idx]); | |
177 | 171 | } |
178 | 172 | |
179 | - d_ptr->tunnel_percent = atoi(zz[DUNGEON_FEAT_PROB_NUM * 2]); | |
180 | - } else if (buf[0] == 'A') { | |
181 | - char *zz[16]; | |
182 | - if (tokenize(buf + 2, DUNGEON_FEAT_PROB_NUM * 2 + 4, zz, 0) != (DUNGEON_FEAT_PROB_NUM * 2 + 4)) | |
183 | - return 1; | |
173 | + auto tunnel_idx = DUNGEON_FEAT_PROB_NUM * 2 + 1; | |
174 | + info_set_value(d_ptr->tunnel_percent, tokens[tunnel_idx]); | |
175 | + } else if (tokens[0] == "A") { | |
176 | + // A:wall_1:prob_1:wall_2:prob_2:wall_3:prob_3:outer_wall:inner_wall:stream_1:stream_2 | |
177 | + if (tokens.size() < DUNGEON_FEAT_PROB_NUM * 2 + 5) | |
178 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
184 | 179 | |
185 | 180 | for (int i = 0; i < DUNGEON_FEAT_PROB_NUM; i++) { |
186 | - d_ptr->fill[i].feat = f_tag_to_index(zz[i * 2]); | |
181 | + auto feat_idx = i * 2 + 1; | |
182 | + auto prob_idx = feat_idx + 1; | |
183 | + d_ptr->fill[i].feat = f_tag_to_index(tokens[feat_idx]); | |
187 | 184 | if (d_ptr->fill[i].feat < 0) |
188 | 185 | return PARSE_ERROR_UNDEFINED_TERRAIN_TAG; |
189 | 186 | |
190 | - d_ptr->fill[i].percent = (PERCENTAGE)atoi(zz[i * 2 + 1]); | |
187 | + info_set_value(d_ptr->fill[i].percent, tokens[prob_idx]); | |
191 | 188 | } |
192 | 189 | |
193 | - d_ptr->outer_wall = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2]); | |
190 | + auto idx = DUNGEON_FEAT_PROB_NUM * 2 + 1; | |
191 | + d_ptr->outer_wall = f_tag_to_index(tokens[idx++]); | |
194 | 192 | if (d_ptr->outer_wall < 0) |
195 | 193 | return PARSE_ERROR_UNDEFINED_TERRAIN_TAG; |
196 | 194 | |
197 | - d_ptr->inner_wall = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2 + 1]); | |
195 | + d_ptr->inner_wall = f_tag_to_index(tokens[idx++]); | |
198 | 196 | if (d_ptr->inner_wall < 0) |
199 | 197 | return PARSE_ERROR_UNDEFINED_TERRAIN_TAG; |
200 | 198 | |
201 | - d_ptr->stream1 = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2 + 2]); | |
199 | + d_ptr->stream1 = f_tag_to_index(tokens[idx++]); | |
202 | 200 | if (d_ptr->stream1 < 0) |
203 | 201 | return PARSE_ERROR_UNDEFINED_TERRAIN_TAG; |
204 | 202 | |
205 | - d_ptr->stream2 = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2 + 3]); | |
203 | + d_ptr->stream2 = f_tag_to_index(tokens[idx]); | |
206 | 204 | if (d_ptr->stream2 < 0) |
207 | 205 | return PARSE_ERROR_UNDEFINED_TERRAIN_TAG; |
208 | - } else if (buf[0] == 'F') { | |
209 | - int artif = 0, monst = 0; | |
210 | - | |
211 | - for (s = buf + 2; *s;) { | |
212 | - /* loop */ | |
213 | - for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) | |
214 | - ; | |
215 | - | |
216 | - if (*t) { | |
217 | - *t++ = '\0'; | |
218 | - while (*t == ' ' || *t == '|') | |
219 | - t++; | |
220 | - } | |
221 | - | |
222 | - if (1 == sscanf(s, "FINAL_ARTIFACT_%d", &artif)) { | |
223 | - d_ptr->final_artifact = (ARTIFACT_IDX)artif; | |
224 | - s = t; | |
206 | + } else if (tokens[0] == "F") { | |
207 | + // F:flags | |
208 | + if (tokens.size() < 2) | |
209 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
210 | + | |
211 | + const auto &flags = str_split(tokens[1], '|', true); | |
212 | + for (const auto &f : flags) { | |
213 | + if (f.size() == 0) | |
225 | 214 | continue; |
226 | - } | |
227 | 215 | |
228 | - if (1 == sscanf(s, "FINAL_OBJECT_%d", &artif)) { | |
229 | - d_ptr->final_object = (KIND_OBJECT_IDX)artif; | |
230 | - s = t; | |
231 | - continue; | |
232 | - } | |
233 | - | |
234 | - if (1 == sscanf(s, "FINAL_GUARDIAN_%d", &monst)) { | |
235 | - d_ptr->final_guardian = (MONRACE_IDX)monst; | |
236 | - s = t; | |
237 | - continue; | |
216 | + const auto &f_tokens = str_split(f, '_'); | |
217 | + if (f_tokens.size() == 3) { | |
218 | + if (f_tokens[0] == "FINAL" && f_tokens[1] == "ARTIFACT") { | |
219 | + info_set_value(d_ptr->final_artifact, f_tokens[2]); | |
220 | + continue; | |
221 | + } | |
222 | + if (f_tokens[0] == "FINAL" && f_tokens[1] == "OBJECT") { | |
223 | + info_set_value(d_ptr->final_object, f_tokens[2]); | |
224 | + continue; | |
225 | + } | |
226 | + if (f_tokens[0] == "FINAL" && f_tokens[1] == "GUARDIAN") { | |
227 | + info_set_value(d_ptr->final_guardian, f_tokens[2]); | |
228 | + continue; | |
229 | + } | |
230 | + if (f_tokens[0] == "MONSTER" && f_tokens[1] == "DIV") { | |
231 | + info_set_value(d_ptr->special_div, f_tokens[2]); | |
232 | + continue; | |
233 | + } | |
238 | 234 | } |
239 | 235 | |
240 | - if (1 == sscanf(s, "MONSTER_DIV_%d", &monst)) { | |
241 | - d_ptr->special_div = (PROB)monst; | |
242 | - s = t; | |
236 | + if (!grab_one_dungeon_flag(d_ptr, f)) | |
237 | + return PARSE_ERROR_INVALID_FLAG; | |
238 | + } | |
239 | + } else if (tokens[0] == "M") { | |
240 | + // M:monsterflags | |
241 | + if (tokens.size() < 2) | |
242 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
243 | + | |
244 | + const auto &flags = str_split(tokens[1], '|', true); | |
245 | + for (const auto &f : flags) { | |
246 | + if (f.size() == 0) | |
243 | 247 | continue; |
244 | - } | |
245 | - | |
246 | - if (0 != grab_one_dungeon_flag(d_ptr, s)) | |
247 | - return 5; | |
248 | 248 | |
249 | - s = t; | |
250 | - } | |
251 | - } else if (buf[0] == 'M') { | |
252 | - for (s = buf + 2; *s;) { | |
253 | - /* loop */ | |
254 | - for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) | |
255 | - ; | |
256 | - | |
257 | - if (*t) { | |
258 | - *t++ = '\0'; | |
259 | - while (*t == ' ' || *t == '|') | |
260 | - t++; | |
261 | - } | |
249 | + const auto &m_tokens = str_split(f, '_'); | |
250 | + if (m_tokens[0] == "R" && m_tokens[1] == "CHAR") { | |
251 | + if (m_tokens[2].size() > 4) | |
252 | + return PARSE_ERROR_GENERIC; | |
262 | 253 | |
263 | - if (!strncmp(s, "R_CHAR_", 7)) { | |
264 | - s += 7; | |
265 | - angband_strcpy(d_ptr->r_char, s, sizeof(d_ptr->r_char)); | |
266 | - s = t; | |
254 | + strcpy(d_ptr->r_char, m_tokens[2].c_str()); | |
267 | 255 | continue; |
268 | 256 | } |
269 | 257 | |
270 | - if (0 != grab_one_basic_monster_flag(d_ptr, s)) | |
271 | - return 5; | |
272 | - | |
273 | - s = t; | |
258 | + if (!grab_one_basic_monster_flag(d_ptr, f)) | |
259 | + return PARSE_ERROR_INVALID_FLAG; | |
274 | 260 | } |
275 | - } else if (buf[0] == 'S') { | |
276 | - for (s = buf + 2; *s;) { | |
277 | - /* loop */ | |
278 | - for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) | |
279 | - ; | |
280 | - | |
281 | - if (*t) { | |
282 | - *t++ = '\0'; | |
283 | - while ((*t == ' ') || (*t == '|')) | |
284 | - t++; | |
285 | - } | |
286 | - | |
287 | - int i; | |
288 | - if (1 == sscanf(s, "1_IN_%d", &i)) { | |
289 | - s = t; | |
261 | + } else if (tokens[0] == "S") { | |
262 | + // S: flags | |
263 | + if (tokens.size() < 2) | |
264 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
265 | + | |
266 | + const auto &flags = str_split(tokens[1], '|', true); | |
267 | + for (const auto &f : flags) { | |
268 | + if (f.size() == 0) | |
290 | 269 | continue; |
291 | - } | |
292 | 270 | |
293 | - if (0 != grab_one_spell_monster_flag(d_ptr, s)) | |
294 | - return 5; | |
271 | + const auto &s_tokens = str_split(f, '_'); | |
272 | + if (s_tokens.size() == 3 && s_tokens[1] == "IN") { | |
273 | + if (s_tokens[0] != "1") | |
274 | + return PARSE_ERROR_GENERIC; | |
275 | + continue; //!< r_info.txtからのコピペ対策 | |
276 | + } | |
295 | 277 | |
296 | - s = t; | |
278 | + if (!grab_one_spell_monster_flag(d_ptr, f)) | |
279 | + return PARSE_ERROR_INVALID_FLAG; | |
297 | 280 | } |
298 | - } else { | |
299 | - return 6; | |
300 | 281 | } |
282 | + else | |
283 | + return PARSE_ERROR_UNDEFINED_DIRECTIVE; | |
301 | 284 | |
302 | 285 | return 0; |
303 | 286 | } |
@@ -1,6 +1,7 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | 3 | #include "system/angband.h" |
4 | -#include "info-reader/info-reader-util.h" | |
4 | +#include <string_view> | |
5 | 5 | |
6 | -errr parse_d_info(char *buf, angband_header *head); | |
6 | +struct angband_header; | |
7 | +errr parse_d_info(std::string_view buf, angband_header *head); |
@@ -1,53 +1,55 @@ | ||
1 | 1 | #include "info-reader/ego-reader.h" |
2 | +#include "info-reader/info-reader-util.h" | |
2 | 3 | #include "info-reader/kind-info-tokens-table.h" |
4 | +#include "info-reader/parse-error-types.h" | |
3 | 5 | #include "main/angband-headers.h" |
4 | 6 | #include "object-enchant/object-ego.h" |
5 | 7 | #include "object-enchant/tr-types.h" |
6 | -#include "parse-error-types.h" | |
7 | 8 | #include "util/bit-flags-calculator.h" |
8 | 9 | #include "util/string-processor.h" |
9 | 10 | #include "view/display-messages.h" |
10 | -#include <string> | |
11 | -#include <utility> | |
12 | 11 | |
13 | 12 | /*! |
14 | 13 | * @brief テキストトークンを走査してフラグを一つ得る(エゴ用) / |
15 | 14 | * Grab one flag in a ego-item_type from a textual string |
16 | 15 | * @param e_ptr 保管先のエゴ構造体参照ポインタ |
17 | 16 | * @param what 参照元の文字列ポインタ |
18 | - * @return エラーがあった場合1、エラーがない場合0を返す | |
17 | + * @return 見つけたらtrue | |
19 | 18 | */ |
20 | 19 | static bool grab_one_ego_item_flag(ego_item_type *e_ptr, std::string_view what) |
21 | 20 | { |
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 | - } | |
21 | + if (info_grab_one_flag(e_ptr->flags, k_info_flags, what)) | |
22 | + return true; | |
26 | 23 | |
27 | 24 | if (EnumClassFlagGroup<TRG>::grab_one_flag(e_ptr->gen_flags, k_info_gen_flags, what)) |
28 | - return 0; | |
25 | + return true; | |
29 | 26 | |
30 | - msg_format(_("未知の名のあるアイテム・フラグ '%s'。", "Unknown ego-item flag '%s'."), what); | |
31 | - return 1; | |
27 | + msg_format(_("未知の名のあるアイテム・フラグ '%s'。", "Unknown ego-item flag '%s'."), what.data()); | |
28 | + return false; | |
32 | 29 | } |
33 | 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 | + */ | |
34 | 38 | static bool grab_ego_generate_flags(ego_generate_type &xtra, std::string_view what) |
35 | 39 | { |
36 | - if (k_info_flags.find(what) != k_info_flags.end()) { | |
37 | - xtra.tr_flags.push_back(k_info_flags[what]); | |
38 | - return 0; | |
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; | |
39 | 43 | } |
40 | 44 | |
41 | - auto it = k_info_gen_flags.find(what); | |
42 | - if (it != k_info_gen_flags.end()) { | |
45 | + if (auto it = k_info_gen_flags.find(what); it != k_info_gen_flags.end()) { | |
43 | 46 | xtra.trg_flags.push_back(it->second); |
44 | - return false; | |
47 | + return true; | |
45 | 48 | } |
46 | 49 | |
47 | - return true; | |
50 | + return false; | |
48 | 51 | } |
49 | 52 | |
50 | - | |
51 | 53 | /*! |
52 | 54 | * @brief アイテムエゴ情報(e_info)のパース関数 / |
53 | 55 | * Initialize the "e_info" array, by parsing an ascii "template" file |
@@ -55,20 +57,19 @@ static bool grab_ego_generate_flags(ego_generate_type &xtra, std::string_view wh | ||
55 | 57 | * @param head ヘッダ構造体 |
56 | 58 | * @return エラーコード |
57 | 59 | */ |
58 | -errr parse_e_info(char *buf, angband_header *head) | |
60 | +errr parse_e_info(std::string_view buf, angband_header *head) | |
59 | 61 | { |
60 | 62 | static ego_item_type *e_ptr = NULL; |
61 | - auto line = std::string(buf); | |
62 | - auto tok = str_split(line, ':', false); | |
63 | + const auto &tokens = str_split(buf, ':', false, 10); | |
63 | 64 | |
64 | - error_idx = 0; | |
65 | + error_idx = 0; //!< @note 順不同で登録しているため | |
65 | 66 | |
66 | - if (tok[0] == "N") { | |
67 | + if (tokens[0] == "N") { | |
67 | 68 | // N:index:name_ja |
68 | - if (tok[1].size() == 0) | |
69 | + if (tokens.size() < 3 || tokens[1].size() == 0) | |
69 | 70 | return PARSE_ERROR_GENERIC; |
70 | 71 | |
71 | - auto i = std::stoi(tok[1]); | |
72 | + auto i = std::stoi(tokens[1]); | |
72 | 73 | if (i < error_idx) |
73 | 74 | return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; |
74 | 75 | if (i >= head->info_num) |
@@ -77,87 +78,92 @@ errr parse_e_info(char *buf, angband_header *head) | ||
77 | 78 | error_idx = i; |
78 | 79 | e_ptr = &e_info[i]; |
79 | 80 | #ifdef JP |
80 | - e_ptr->name = tok[2]; | |
81 | + e_ptr->name = tokens[2]; | |
81 | 82 | #endif |
82 | 83 | } else if (!e_ptr) |
83 | 84 | return PARSE_ERROR_MISSING_RECORD_HEADER; |
84 | - else if (tok[0] == "E") { | |
85 | + else if (tokens[0] == "E") { | |
85 | 86 | // E:name_en |
86 | 87 | #ifndef JP |
87 | - if (tok[1].size() == 0) | |
88 | - return 1; | |
89 | - e_ptr->name = tok[1]; | |
88 | + if (tokens[1].size() == 0) | |
89 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
90 | + e_ptr->name = tokens[1]; | |
90 | 91 | #endif |
91 | - } | |
92 | - else if (tok[0] == "X") { | |
92 | + } else if (tokens[0] == "X") { | |
93 | 93 | // X:slot:rating |
94 | - if (tok.size() < 3) | |
94 | + if (tokens.size() < 3) | |
95 | 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") { | |
96 | + | |
97 | + info_set_value(e_ptr->slot, tokens[1]); | |
98 | + info_set_value(e_ptr->rating, tokens[2]); | |
99 | + } else if (tokens[0] == "W") { | |
99 | 100 | // W:level:ratiry:xtra:cost |
100 | 101 | // xtra is not used |
101 | - if (tok.size() < 5) | |
102 | + if (tokens.size() < 5) | |
102 | 103 | 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] == "B") { | |
104 | + | |
105 | + info_set_value(e_ptr->level, tokens[1]); | |
106 | + info_set_value(e_ptr->rarity, tokens[2]); | |
107 | + info_set_value(e_ptr->cost, tokens[4]); | |
108 | + } else if (tokens[0] == "B") { | |
107 | 109 | // Base bonuses |
108 | 110 | // B:to_hit:to_dam:to_ac |
109 | - if (tok.size() < 4) | |
110 | - return 1; | |
111 | - e_ptr->base_to_h = (HIT_PROB)std::stoi(tok[1]); | |
112 | - e_ptr->base_to_d = (HIT_POINT)std::stoi(tok[2]); | |
113 | - e_ptr->base_to_a = (ARMOUR_CLASS)std::stoi(tok[3]); | |
114 | - } else if (tok[0] == "C") { | |
111 | + if (tokens.size() < 4) | |
112 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
113 | + | |
114 | + info_set_value(e_ptr->base_to_h, tokens[1]); | |
115 | + info_set_value(e_ptr->base_to_d, tokens[2]); | |
116 | + info_set_value(e_ptr->base_to_a, tokens[3]); | |
117 | + } else if (tokens[0] == "C") { | |
115 | 118 | // Creation bonuses (random plus) |
116 | 119 | // C:to_hit:to_dam:to_ac:pval |
117 | - if (tok.size() < 5) | |
120 | + if (tokens.size() < 5) | |
118 | 121 | return PARSE_ERROR_TOO_FEW_ARGUMENTS; |
119 | - e_ptr->max_to_h = (HIT_PROB)std::stoi(tok[1]); | |
120 | - e_ptr->max_to_d = (HIT_POINT)std::stoi(tok[2]); | |
121 | - e_ptr->max_to_a = (ARMOUR_CLASS)std::stoi(tok[3]); | |
122 | - e_ptr->max_pval = (PARAMETER_VALUE)std::stoi(tok[4]); | |
123 | - } else if (tok[0] == "U") { | |
122 | + | |
123 | + info_set_value(e_ptr->max_to_h, tokens[1]); | |
124 | + info_set_value(e_ptr->max_to_d, tokens[2]); | |
125 | + info_set_value(e_ptr->max_to_a, tokens[3]); | |
126 | + info_set_value(e_ptr->max_pval, tokens[4]); | |
127 | + } else if (tokens[0] == "U") { | |
124 | 128 | // U:activation_flag |
125 | - if (tok.size() < 2 || tok[1].size() == 0) | |
129 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
126 | 130 | return PARSE_ERROR_TOO_FEW_ARGUMENTS; |
127 | - auto n = grab_one_activation_flag(tok[1].c_str()); | |
131 | + | |
132 | + auto n = grab_one_activation_flag(tokens[1].c_str()); | |
128 | 133 | if (n <= 0) |
129 | 134 | return PARSE_ERROR_INVALID_FLAG; |
135 | + | |
130 | 136 | e_ptr->act_idx = (IDX)n; |
131 | - } else if (tok[0] == "F") { | |
137 | + } else if (tokens[0] == "F") { | |
132 | 138 | // F:flags |
133 | - if (tok.size() < 2 || tok[1].size() == 0) | |
134 | - return PARSE_ERROR_UNDEFINED_TERRAIN_TAG; | |
139 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
140 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
135 | 141 | |
136 | - const auto& flags = str_split(tok[1], '|', true); | |
142 | + const auto& flags = str_split(tokens[1], '|', true, 10); | |
137 | 143 | for (const auto& f : flags) { |
138 | 144 | if (f.size() == 0) |
139 | 145 | continue; |
140 | - if (0 != grab_one_ego_item_flag(e_ptr, f)) | |
146 | + if (!grab_one_ego_item_flag(e_ptr, f)) | |
141 | 147 | return PARSE_ERROR_INVALID_FLAG; |
142 | 148 | } |
143 | - } else if (tok[0] == "G") { | |
149 | + } else if (tokens[0] == "G") { | |
144 | 150 | // G:mul/dev:flags |
145 | - if (tok.size() < 3) | |
146 | - return PARSE_ERROR_UNDEFINED_TERRAIN_TAG; | |
151 | + if (tokens.size() < 3) | |
152 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
147 | 153 | |
148 | - auto prob = str_split(tok[1], '/'); | |
149 | - if (prob.size() != 2 || tok[1].size() == 0 || tok[2].size() == 0) | |
154 | + const auto &prob = str_split(tokens[1], '/', false, 2); | |
155 | + if (prob.size() != 2 || tokens[1].size() == 0 || tokens[2].size() == 0) | |
150 | 156 | return PARSE_ERROR_TOO_FEW_ARGUMENTS; |
151 | 157 | |
152 | 158 | ego_generate_type xtra; |
153 | 159 | xtra.mul = std::stoi(prob[0]); |
154 | 160 | xtra.dev = std::stoi(prob[1]); |
155 | 161 | |
156 | - const auto& flags = str_split(tok[2], '|', true); | |
162 | + const auto& flags = str_split(tokens[2], '|', true, 10); | |
157 | 163 | for (const auto& f : flags) { |
158 | 164 | if (f.size() == 0) |
159 | 165 | continue; |
160 | - if (grab_ego_generate_flags(xtra, f)) | |
166 | + if (!grab_ego_generate_flags(xtra, f)) | |
161 | 167 | return PARSE_ERROR_INVALID_FLAG; |
162 | 168 | } |
163 | 169 |
@@ -1,7 +1,7 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | 3 | #include "system/angband.h" |
4 | -#include "parse-error-types.h" | |
5 | -#include "info-reader/info-reader-util.h" | |
4 | +#include <string_view> | |
6 | 5 | |
7 | -errr parse_e_info(char *buf, angband_header *head); | |
6 | +struct angband_header; | |
7 | +errr parse_e_info(std::string_view buf, angband_header *head); |
@@ -1,124 +1,123 @@ | ||
1 | 1 | #include "info-reader/feature-info-tokens-table.h" |
2 | 2 | |
3 | 3 | /*! |
4 | - * 地形属性トークンの定義 / | |
5 | - * Feature info flags | |
4 | + * @brief 地形属性トークンの定義 / Feature info flags | |
6 | 5 | */ |
7 | -concptr f_info_flags[NUM_F_FLAGS] = { | |
8 | - "LOS", | |
9 | - "PROJECT", | |
10 | - "MOVE", | |
11 | - "PLACE", | |
12 | - "DROP", | |
13 | - "SECRET", | |
14 | - "NOTICE", | |
15 | - "REMEMBER", | |
16 | - "OPEN", | |
17 | - "CLOSE", | |
18 | - "BASH", | |
19 | - "SPIKE", | |
20 | - "DISARM", | |
21 | - "STORE", | |
22 | - "TUNNEL", | |
23 | - "MAY_HAVE_GOLD", | |
24 | - "HAS_GOLD", | |
25 | - "HAS_ITEM", | |
26 | - "DOOR", | |
27 | - "TRAP", | |
28 | - "STAIRS", | |
29 | - "RUNE_PROTECTION", | |
30 | - "LESS", | |
31 | - "MORE", | |
32 | - "AVOID_RUN", | |
33 | - "FLOOR", | |
34 | - "WALL", | |
35 | - "PERMANENT", | |
36 | - "XXX00", | |
37 | - "XXX01", | |
38 | - "XXX02", | |
39 | - "HIT_TRAP", | |
6 | +const std::unordered_map<std::string_view, feature_flag_type> f_info_flags = { | |
7 | + { "LOS", FF_LOS }, | |
8 | + { "PROJECT", FF_PROJECT }, | |
9 | + { "MOVE", FF_MOVE }, | |
10 | + { "PLACE", FF_PLACE }, | |
11 | + { "DROP", FF_DROP }, | |
12 | + { "SECRET", FF_SECRET }, | |
13 | + { "NOTICE", FF_NOTICE }, | |
14 | + { "REMEMBER", FF_REMEMBER }, | |
15 | + { "OPEN", FF_OPEN }, | |
16 | + { "CLOSE", FF_CLOSE }, | |
17 | + { "BASH", FF_BASH }, | |
18 | + { "SPIKE", FF_SPIKE }, | |
19 | + { "DISARM", FF_DISARM }, | |
20 | + { "STORE", FF_STORE }, | |
21 | + { "TUNNEL", FF_TUNNEL }, | |
22 | + { "MAY_HAVE_GOLD", FF_MAY_HAVE_GOLD }, | |
23 | + { "HAS_GOLD", FF_HAS_GOLD }, | |
24 | + { "HAS_ITEM", FF_HAS_ITEM }, | |
25 | + { "DOOR", FF_DOOR }, | |
26 | + { "TRAP", FF_TRAP }, | |
27 | + { "STAIRS", FF_STAIRS }, | |
28 | + { "RUNE_PROTECTION", FF_RUNE_PROTECTION }, | |
29 | + { "LESS", FF_LESS }, | |
30 | + { "MORE", FF_MORE }, | |
31 | + { "AVOID_RUN", FF_AVOID_RUN }, | |
32 | + { "FLOOR", FF_FLOOR }, | |
33 | + { "WALL", FF_WALL }, | |
34 | + { "PERMANENT", FF_PERMANENT }, | |
35 | + // { "XXX00", FF_XXX00 }, | |
36 | + // { "XXX01", FF_XXX01 }, | |
37 | + // { "XXX02", FF_XXX02 }, | |
38 | + { "HIT_TRAP", FF_HIT_TRAP }, | |
40 | 39 | |
41 | - "BRIDGE", | |
42 | - "RIVER", | |
43 | - "LAKE", | |
44 | - "BRIDGED", | |
45 | - "COVERED", | |
46 | - "GLOW", | |
47 | - "ENSECRET", | |
48 | - "WATER", | |
49 | - "LAVA", | |
50 | - "SHALLOW", | |
51 | - "DEEP", | |
52 | - "POISON_PUDDLE", | |
53 | - "HURT_ROCK", | |
54 | - "HURT_FIRE", | |
55 | - "HURT_COLD", | |
56 | - "HURT_ACID", | |
57 | - "COLD_PUDDLE", | |
58 | - "ACID_PUDDLE", | |
59 | - "OIL", | |
60 | - "ELEC_PUDDLE", | |
61 | - "CAN_CLIMB", | |
62 | - "CAN_FLY", | |
63 | - "CAN_SWIM", | |
64 | - "CAN_PASS", | |
65 | - "CAN_OOZE", | |
66 | - "CAN_DIG", | |
67 | - "HIDE_ITEM", | |
68 | - "HIDE_SNEAK", | |
69 | - "HIDE_SWIM", | |
70 | - "HIDE_DIG", | |
71 | - "KILL_HUGE", | |
72 | - "KILL_MOVE", | |
40 | + // { "BRIDGE", FF_BRIDGE }, | |
41 | + // { "RIVER", FF_RIVER }, | |
42 | + // { "LAKE", FF_LAKE }, | |
43 | + // { "BRIDGED", FF_BRIDGED }, | |
44 | + // { "COVERED", FF_COVERED }, | |
45 | + { "GLOW", FF_GLOW }, | |
46 | + { "ENSECRET", FF_ENSECRET }, | |
47 | + { "WATER", FF_WATER }, | |
48 | + { "LAVA", FF_LAVA }, | |
49 | + { "SHALLOW", FF_SHALLOW }, | |
50 | + { "DEEP", FF_DEEP }, | |
51 | + { "POISON_PUDDLE", FF_POISON_PUDDLE }, | |
52 | + { "HURT_ROCK", FF_HURT_ROCK }, | |
53 | + // { "HURT_FIRE", FF_HURT_FIRE }, | |
54 | + // { "HURT_COLD", FF_HURT_COLD }, | |
55 | + // { "HURT_ACID", FF_HURT_ACID }, | |
56 | + { "COLD_PUDDLE", FF_COLD_PUDDLE }, | |
57 | + { "ACID_PUDDLE", FF_ACID_PUDDLE }, | |
58 | + // { "OIL", FF_OIL }, | |
59 | + { "ELEC_PUDDLE", FF_ELEC_PUDDLE }, | |
60 | + // { "CAN_CLIMB", FF_CAN_CLIMB }, | |
61 | + { "CAN_FLY", FF_CAN_FLY }, | |
62 | + { "CAN_SWIM", FF_CAN_SWIM }, | |
63 | + { "CAN_PASS", FF_CAN_PASS }, | |
64 | + // { "CAN_OOZE", FF_CAN_OOZE }, | |
65 | + { "CAN_DIG", FF_CAN_DIG }, | |
66 | + // { "HIDE_ITEM", FF_HIDE_ITEM }, | |
67 | + // { "HIDE_SNEAK", FF_HIDE_SNEAK }, | |
68 | + // { "HIDE_SWIM", FF_HIDE_SWIM }, | |
69 | + // { "HIDE_DIG", FF_HIDE_DIG }, | |
70 | + // { "KILL_HUGE", FF_KILL_HUGE }, | |
71 | + // { "KILL_MOVE", FF_KILL_MOVE }, | |
73 | 72 | |
74 | - "PICK_TRAP", | |
75 | - "PICK_DOOR", | |
76 | - "ALLOC", | |
77 | - "CHEST", | |
78 | - "DROP_1D2", | |
79 | - "DROP_2D2", | |
80 | - "DROP_GOOD", | |
81 | - "DROP_GREAT", | |
82 | - "HURT_POIS", | |
83 | - "HURT_ELEC", | |
84 | - "HURT_WATER", | |
85 | - "HURT_BWATER", | |
86 | - "USE_FEAT", | |
87 | - "GET_FEAT", | |
88 | - "GROUND", | |
89 | - "OUTSIDE", | |
90 | - "EASY_HIDE", | |
91 | - "EASY_CLIMB", | |
92 | - "MUST_CLIMB", | |
93 | - "TREE", | |
94 | - "NEED_TREE", | |
95 | - "BLOOD", | |
96 | - "DUST", | |
97 | - "SLIME", | |
98 | - "PLANT", | |
99 | - "XXX2", | |
100 | - "INSTANT", | |
101 | - "EXPLODE", | |
102 | - "TIMED", | |
103 | - "ERUPT", | |
104 | - "STRIKE", | |
105 | - "SPREAD", | |
73 | + // { "PICK_TRAP", FF_PICK_TRAP }, | |
74 | + // { "PICK_DOOR", FF_PICK_DOOR }, | |
75 | + // { "ALLOC", FF_ALLOC }, | |
76 | + // { "CHEST", FF_CHEST }, | |
77 | + // { "DROP_1D2", FF_DROP_1D2 }, | |
78 | + // { "DROP_2D2", FF_DROP_2D2 }, | |
79 | + // { "DROP_GOOD", FF_DROP_GOOD }, | |
80 | + // { "DROP_GREAT", FF_DROP_GREAT }, | |
81 | + // { "HURT_POIS", FF_HURT_POIS }, | |
82 | + // { "HURT_ELEC", FF_HURT_ELEC }, | |
83 | + // { "HURT_WATER", FF_HURT_WATER }, | |
84 | + // { "HURT_BWATER", FF_HURT_BWATER }, | |
85 | + // { "USE_FEAT", FF_USE_FEAT }, | |
86 | + // { "GET_FEAT", FF_GET_FEAT }, | |
87 | + // { "GROUND", FF_GROUND }, | |
88 | + // { "OUTSIDE", FF_OUTSIDE }, | |
89 | + // { "EASY_HIDE", FF_EASY_HIDE }, | |
90 | + // { "EASY_CLIMB", FF_EASY_CLIMB }, | |
91 | + // { "MUST_CLIMB", FF_MUST_CLIMB }, | |
92 | + { "TREE", FF_TREE }, | |
93 | + // { "NEED_TREE", FF_NEED_TREE }, | |
94 | + // { "BLOOD", FF_BLOOD }, | |
95 | + // { "DUST", FF_DUST }, | |
96 | + // { "SLIME", FF_SLIME }, | |
97 | + { "PLANT", FF_PLANT }, | |
98 | + // { "XXX2", FF_XXX2 }, | |
99 | + // { "INSTANT", FF_INSTANT }, | |
100 | + // { "EXPLODE", FF_EXPLODE }, | |
101 | + // { "TIMED", FF_TIMED }, | |
102 | + // { "ERUPT", FF_ERUPT }, | |
103 | + // { "STRIKE", FF_STRIKE }, | |
104 | + // { "SPREAD", FF_SPREAD }, | |
106 | 105 | |
107 | - "SPECIAL", | |
108 | - "HURT_DISI", | |
109 | - "QUEST_ENTER", | |
110 | - "QUEST_EXIT", | |
111 | - "QUEST", | |
112 | - "SHAFT", | |
113 | - "MOUNTAIN", | |
114 | - "BLDG", | |
115 | - "RUNE_EXPLOSION", | |
116 | - "PATTERN", | |
117 | - "TOWN", | |
118 | - "ENTRANCE", | |
119 | - "MIRROR", | |
120 | - "UNPERM", | |
121 | - "TELEPORTABLE", | |
122 | - "CONVERT", | |
123 | - "GLASS", | |
106 | + { "SPECIAL", FF_SPECIAL }, | |
107 | + { "HURT_DISI", FF_HURT_DISI }, | |
108 | + { "QUEST_ENTER", FF_QUEST_ENTER }, | |
109 | + { "QUEST_EXIT", FF_QUEST_EXIT }, | |
110 | + { "QUEST", FF_QUEST }, | |
111 | + { "SHAFT", FF_SHAFT }, | |
112 | + { "MOUNTAIN", FF_MOUNTAIN }, | |
113 | + { "BLDG", FF_BLDG }, | |
114 | + { "RUNE_EXPLOSION", FF_RUNE_EXPLOSION }, | |
115 | + { "PATTERN", FF_PATTERN }, | |
116 | + { "TOWN", FF_TOWN }, | |
117 | + { "ENTRANCE", FF_ENTRANCE }, | |
118 | + { "MIRROR", FF_MIRROR }, | |
119 | + { "UNPERM", FF_UNPERM }, | |
120 | + { "TELEPORTABLE", FF_TELEPORTABLE }, | |
121 | + { "CONVERT", FF_CONVERT }, | |
122 | + { "GLASS", FF_GLASS }, | |
124 | 123 | }; |
@@ -1,6 +1,8 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | 3 | #include "system/angband.h" |
4 | +#include "grid/feature-flag-types.h" | |
5 | +#include <string_view> | |
6 | +#include <unordered_map> | |
4 | 7 | |
5 | -#define NUM_F_FLAGS 113 | |
6 | -extern concptr f_info_flags[NUM_F_FLAGS]; | |
8 | +extern const std::unordered_map<std::string_view, feature_flag_type> f_info_flags; |
@@ -4,6 +4,7 @@ | ||
4 | 4 | #include "grid/grid.h" |
5 | 5 | #include "grid/trap.h" |
6 | 6 | #include "info-reader/feature-info-tokens-table.h" |
7 | +#include "info-reader/info-reader-util.h" | |
7 | 8 | #include "info-reader/parse-error-types.h" |
8 | 9 | #include "main/angband-headers.h" |
9 | 10 | #include "room/door-definition.h" |
@@ -11,30 +12,24 @@ | ||
11 | 12 | #include "util/bit-flags-calculator.h" |
12 | 13 | #include "util/string-processor.h" |
13 | 14 | #include "view/display-messages.h" |
14 | -#include <string> | |
15 | -#include <string_view> | |
16 | 15 | |
17 | -/*! 地形タグ情報から地形IDを得られなかった場合にTRUEを返す */ | |
18 | -static bool feat_tag_is_not_found = FALSE; | |
16 | +/*! 地形タグ情報から地形IDを得られなかった場合にtrueを返す */ | |
17 | +static bool feat_tag_is_not_found = false; | |
19 | 18 | |
20 | 19 | /*! |
21 | 20 | * @brief テキストトークンを走査してフラグを一つ得る(地形情報向け) / |
22 | 21 | * Grab one flag in an feature_type from a textual string |
23 | 22 | * @param f_ptr 地形情報を保管する先の構造体参照ポインタ |
24 | 23 | * @param what 参照元の文字列ポインタ |
25 | - * @return エラーコード | |
24 | + * @return 見つけたらtrue | |
26 | 25 | */ |
27 | -static errr grab_one_feat_flag(feature_type *f_ptr, concptr what) | |
26 | +static bool grab_one_feat_flag(feature_type *f_ptr, std::string_view what) | |
28 | 27 | { |
29 | - for (int i = 0; i < FF_FLAG_MAX; i++) { | |
30 | - if (streq(what, f_info_flags[i])) { | |
31 | - add_flag(f_ptr->flags, i); | |
32 | - return 0; | |
33 | - } | |
34 | - } | |
28 | + if (info_grab_one_flag(f_ptr->flags, f_info_flags, what)) | |
29 | + return true; | |
35 | 30 | |
36 | - msg_format(_("未知の地形フラグ '%s'。", "Unknown feature flag '%s'."), what); | |
37 | - return PARSE_ERROR_GENERIC; | |
31 | + msg_format(_("未知の地形フラグ '%s'。", "Unknown feature flag '%s'."), what.data()); | |
32 | + return false; | |
38 | 33 | } |
39 | 34 | |
40 | 35 | /*! |
@@ -43,19 +38,17 @@ static errr grab_one_feat_flag(feature_type *f_ptr, concptr what) | ||
43 | 38 | * @param f_ptr 地形情報を保管する先の構造体参照ポインタ |
44 | 39 | * @param what 参照元の文字列ポインタ |
45 | 40 | * @param count ステートの保存先ID |
46 | - * @return エラーコード | |
41 | + * @return 見つけたらtrue | |
47 | 42 | */ |
48 | -static errr grab_one_feat_action(feature_type *f_ptr, concptr what, int count) | |
43 | +static bool grab_one_feat_action(feature_type *f_ptr, std::string_view what, int count) | |
49 | 44 | { |
50 | - for (FF_FLAGS_IDX i = 0; i < FF_FLAG_MAX; i++) { | |
51 | - if (streq(what, f_info_flags[i])) { | |
52 | - f_ptr->state[count].action = i; | |
53 | - return 0; | |
54 | - } | |
45 | + if (auto it = f_info_flags.find(what); it != f_info_flags.end()) { | |
46 | + f_ptr->state[count].action = static_cast<FF_FLAGS_IDX>(it->second); | |
47 | + return true; | |
55 | 48 | } |
56 | 49 | |
57 | - msg_format(_("未知の地形アクション '%s'。", "Unknown feature action '%s'."), what); | |
58 | - return PARSE_ERROR_GENERIC; | |
50 | + msg_format(_("未知の地形アクション '%s'。", "Unknown feature action '%s'."), what.data()); | |
51 | + return false; | |
59 | 52 | } |
60 | 53 | |
61 | 54 | /*! |
@@ -65,172 +58,162 @@ static errr grab_one_feat_action(feature_type *f_ptr, concptr what, int count) | ||
65 | 58 | * @param head ヘッダ構造体 |
66 | 59 | * @return エラーコード |
67 | 60 | */ |
68 | -errr parse_f_info(char *buf, angband_header *head) | |
61 | +errr parse_f_info(std::string_view buf, angband_header *head) | |
69 | 62 | { |
70 | 63 | static feature_type *f_ptr = NULL; |
71 | - int i; | |
72 | - char *s, *t; | |
73 | - if (buf[0] == 'N') { | |
74 | - s = angband_strchr(buf + 2, ':'); | |
64 | + const auto &tokens = str_split(buf, ':', false, 10); | |
75 | 65 | |
76 | - if (s) { | |
77 | - *s++ = '\0'; | |
78 | - } | |
66 | + if (tokens[0] == "N") { | |
67 | + // N:index:tag | |
68 | + if (tokens.size() < 3) | |
69 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
70 | + | |
71 | + if (tokens[1].size() == 0 || tokens[2].size() == 0) | |
72 | + return PARSE_ERROR_GENERIC; | |
79 | 73 | |
80 | - i = atoi(buf + 2); | |
81 | - if (i <= error_idx) | |
82 | - return 4; | |
74 | + auto i = std::stoi(tokens[1]); | |
75 | + if (i < error_idx) | |
76 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
83 | 77 | if (i >= head->info_num) |
84 | - return 2; | |
78 | + return PARSE_ERROR_OUT_OF_BOUNDS; | |
85 | 79 | |
86 | 80 | error_idx = i; |
87 | 81 | f_ptr = &f_info[i]; |
88 | - if (s) { | |
89 | - f_ptr->tag = std::string(s); | |
90 | - } | |
82 | + f_ptr->tag = tokens[2]; | |
91 | 83 | |
92 | 84 | f_ptr->mimic = (FEAT_IDX)i; |
93 | 85 | f_ptr->destroyed = (FEAT_IDX)i; |
94 | 86 | for (i = 0; i < MAX_FEAT_STATES; i++) |
95 | 87 | f_ptr->state[i].action = FF_FLAG_MAX; |
96 | - } else if (!f_ptr) { | |
97 | - return 3; | |
98 | - } | |
99 | -#ifdef JP | |
100 | - else if (buf[0] == 'J') { | |
101 | - f_ptr->name = std::string(buf + 2); | |
102 | - } else if (buf[0] == 'E') { | |
103 | - } | |
104 | -#else | |
105 | - else if (buf[0] == 'J') { | |
106 | - } else if (buf[0] == 'E') { | |
107 | - f_ptr->name = std::string(buf + 2); | |
108 | - } | |
109 | -#endif | |
110 | - else if (buf[0] == 'M') { | |
111 | - f_ptr->mimic_tag = std::string(buf + 2); | |
112 | - } else if (buf[0] == 'G') { | |
113 | - int j; | |
114 | - byte s_attr; | |
115 | - char char_tmp[F_LIT_MAX]; | |
116 | - if (buf[1] != ':') | |
117 | - return 1; | |
118 | - if (!buf[2]) | |
119 | - return 1; | |
120 | - if (buf[3] != ':') | |
121 | - return 1; | |
122 | - if (!buf[4]) | |
123 | - return 1; | |
124 | - | |
125 | - char_tmp[F_LIT_STANDARD] = buf[2]; | |
126 | - s_attr = color_char_to_attr(buf[4]); | |
88 | + | |
89 | + } else if (!f_ptr) | |
90 | + return PARSE_ERROR_MISSING_RECORD_HEADER; | |
91 | + else if (tokens[0] == _("J", "E")) { | |
92 | + // J:name_ja | |
93 | + // E:name_en | |
94 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
95 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
96 | + f_ptr->name = tokens[1]; | |
97 | + } else if (tokens[0] == _("E", "J")) { | |
98 | + //pass | |
99 | + } else if (tokens[0] == "M") { | |
100 | + // M:mimic_tag | |
101 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
102 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
103 | + f_ptr->mimic_tag = tokens[1]; | |
104 | + } else if (tokens[0] == "G") { | |
105 | + // G:symbol:color:lite:lite_symbol:lite_color:dark_symbol:dark_color | |
106 | + if (tokens.size() < 3) | |
107 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
108 | + | |
109 | + size_t n; | |
110 | + char s_char; | |
111 | + if (tokens[1].size() == 1) { | |
112 | + s_char = tokens[1][0]; | |
113 | + n = 2; | |
114 | + } else if (tokens[1].size() == 0 && tokens[2].size() == 0) { | |
115 | + if (tokens.size() < 4) | |
116 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
117 | + | |
118 | + s_char = ':'; | |
119 | + n = 3; | |
120 | + } else | |
121 | + return PARSE_ERROR_GENERIC; | |
122 | + | |
123 | + auto s_attr = color_char_to_attr(tokens[n++][0]); | |
127 | 124 | if (s_attr > 127) |
128 | - return 1; | |
125 | + return PARSE_ERROR_GENERIC; | |
129 | 126 | |
127 | + f_ptr->d_char[F_LIT_STANDARD] = s_char; | |
130 | 128 | f_ptr->d_attr[F_LIT_STANDARD] = s_attr; |
131 | - f_ptr->d_char[F_LIT_STANDARD] = char_tmp[F_LIT_STANDARD]; | |
132 | - if (buf[5] == ':') { | |
129 | + if (tokens.size() == n) { | |
130 | + for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) { | |
131 | + f_ptr->d_char[j] = s_char; | |
132 | + f_ptr->d_attr[j] = s_attr; | |
133 | + } | |
134 | + } else if (tokens[n++] == "LIT") { | |
133 | 135 | apply_default_feat_lighting(f_ptr->d_attr, f_ptr->d_char); |
134 | - if (!streq(buf + 6, "LIT")) { | |
135 | - char attr_lite_tmp[F_LIT_MAX - F_LIT_NS_BEGIN]; | |
136 | - | |
137 | - if ((F_LIT_MAX - F_LIT_NS_BEGIN) * 2 | |
138 | - != sscanf(buf + 6, "%c:%c:%c:%c", &char_tmp[F_LIT_LITE], &attr_lite_tmp[F_LIT_LITE - F_LIT_NS_BEGIN], &char_tmp[F_LIT_DARK], | |
139 | - &attr_lite_tmp[F_LIT_DARK - F_LIT_NS_BEGIN])) | |
140 | - return 1; | |
141 | - if (buf[F_LIT_MAX * 4 + 1]) | |
142 | - return 1; | |
143 | - | |
144 | - for (j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) { | |
145 | - switch (attr_lite_tmp[j - F_LIT_NS_BEGIN]) { | |
146 | - case '*': | |
147 | - /* Use default lighting */ | |
148 | - break; | |
149 | - case '-': | |
150 | - /* No lighting support */ | |
151 | - f_ptr->d_attr[j] = f_ptr->d_attr[F_LIT_STANDARD]; | |
152 | - break; | |
153 | - default: | |
154 | - /* Extract the color */ | |
155 | - f_ptr->d_attr[j] = color_char_to_attr(attr_lite_tmp[j - F_LIT_NS_BEGIN]); | |
156 | - if (f_ptr->d_attr[j] > 127) | |
157 | - return 1; | |
158 | - break; | |
159 | - } | |
160 | - f_ptr->d_char[j] = char_tmp[j]; | |
136 | + | |
137 | + for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) { | |
138 | + auto c_idx = n + (j - F_LIT_NS_BEGIN) * 2; | |
139 | + auto a_idx = c_idx + 1; | |
140 | + if (tokens.size() <= (size_t)a_idx) | |
141 | + continue; | |
142 | + if (tokens[c_idx].size() != 1 || tokens[a_idx].size() != 1) | |
143 | + continue; | |
144 | + | |
145 | + f_ptr->d_char[j] = tokens[c_idx][0]; | |
146 | + | |
147 | + if (tokens[a_idx] == "*") { | |
148 | + // pass | |
149 | + } else if (tokens[a_idx] == "-") { | |
150 | + f_ptr->d_attr[j] = s_attr; | |
151 | + } else { | |
152 | + f_ptr->d_attr[j] = color_char_to_attr(tokens[a_idx][0]); | |
153 | + if (f_ptr->d_attr[j] > 127) | |
154 | + return PARSE_ERROR_GENERIC; | |
161 | 155 | } |
162 | 156 | } |
163 | - } else if (!buf[5]) { | |
164 | - for (j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) { | |
165 | - f_ptr->d_attr[j] = s_attr; | |
166 | - f_ptr->d_char[j] = char_tmp[F_LIT_STANDARD]; | |
167 | - } | |
168 | 157 | } else |
169 | - return 1; | |
170 | - } else if (buf[0] == 'F') { | |
171 | - for (s = buf + 2; *s;) { | |
172 | - /* loop */ | |
173 | - for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) | |
174 | - ; | |
175 | - | |
176 | - if (*t) { | |
177 | - *t++ = '\0'; | |
178 | - while (*t == ' ' || *t == '|') | |
179 | - t++; | |
180 | - } | |
181 | - | |
182 | - if (1 == sscanf(s, "SUBTYPE_%d", &i)) { | |
183 | - f_ptr->subtype = (FEAT_SUBTYPE)i; | |
184 | - s = t; | |
185 | - | |
158 | + return PARSE_ERROR_GENERIC; | |
159 | + } else if (tokens[0] == "F") { | |
160 | + // F:flags | |
161 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
162 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
163 | + | |
164 | + const auto &flags = str_split(tokens[1], '|', true, 10); | |
165 | + for (const auto &f : flags) { | |
166 | + if (f.size() == 0) | |
186 | 167 | continue; |
187 | - } | |
188 | 168 | |
189 | - if (1 == sscanf(s, "POWER_%d", &i)) { | |
190 | - f_ptr->power = (FEAT_POWER)i; | |
191 | - s = t; | |
192 | - continue; | |
169 | + const auto &f_tokens = str_split(f, '_', false, 2); | |
170 | + if (f_tokens.size() == 2) { | |
171 | + if (f_tokens[0] == "SUBTYPE") { | |
172 | + info_set_value(f_ptr->subtype, f_tokens[1]); | |
173 | + continue; | |
174 | + } else if (f_tokens[0] == "POWER") { | |
175 | + info_set_value(f_ptr->power, f_tokens[1]); | |
176 | + continue; | |
177 | + } | |
193 | 178 | } |
194 | 179 | |
195 | - if (0 != grab_one_feat_flag(f_ptr, s)) | |
196 | - return (PARSE_ERROR_INVALID_FLAG); | |
197 | - | |
198 | - s = t; | |
180 | + if (!grab_one_feat_flag(f_ptr, f)) | |
181 | + return PARSE_ERROR_INVALID_FLAG; | |
199 | 182 | } |
200 | - } else if (buf[0] == 'W') { | |
201 | - int priority; | |
202 | - if (1 != sscanf(buf + 2, "%d", &priority)) | |
203 | - return (PARSE_ERROR_GENERIC); | |
204 | - f_ptr->priority = (FEAT_PRIORITY)priority; | |
205 | - } else if (buf[0] == 'K') { | |
206 | - for (i = 0; i < MAX_FEAT_STATES; i++) | |
183 | + } else if (tokens[0] == "W") { | |
184 | + // W:priority | |
185 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
186 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
187 | + info_set_value(f_ptr->priority, tokens[1]); | |
188 | + } else if (tokens[0] == "K") { | |
189 | + // K:state:feat | |
190 | + if (tokens.size() < 3) | |
191 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
192 | + if (tokens[1].size() == 0 || tokens[2].size() == 0) | |
193 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
194 | + | |
195 | + int i = 0; | |
196 | + for (; i < MAX_FEAT_STATES; i++) { | |
207 | 197 | if (f_ptr->state[i].action == FF_FLAG_MAX) |
208 | 198 | break; |
199 | + } | |
209 | 200 | |
210 | 201 | if (i == MAX_FEAT_STATES) |
211 | 202 | return PARSE_ERROR_GENERIC; |
212 | 203 | |
213 | - /* loop */ | |
214 | - for (s = t = buf + 2; *t && (*t != ':'); t++) | |
215 | - ; | |
216 | - | |
217 | - if (*t == ':') | |
218 | - *t++ = '\0'; | |
219 | - | |
220 | - if (streq(s, "DESTROYED")) { | |
221 | - f_ptr->destroyed_tag = std::string(t); | |
222 | - } else { | |
204 | + if (tokens[1] == "DESTROYED") | |
205 | + f_ptr->destroyed_tag = tokens[2]; | |
206 | + else { | |
223 | 207 | f_ptr->state[i].action = 0; |
224 | - if (0 != grab_one_feat_action(f_ptr, s, i)) | |
208 | + if (!grab_one_feat_action(f_ptr, tokens[1], i)) | |
225 | 209 | return PARSE_ERROR_INVALID_FLAG; |
226 | 210 | |
227 | - f_ptr->state[i].result_tag = std::string(t); | |
211 | + f_ptr->state[i].result_tag = tokens[2]; | |
228 | 212 | } |
229 | - } else { | |
230 | - return 6; | |
231 | - } | |
213 | + } else | |
214 | + return PARSE_ERROR_UNDEFINED_DIRECTIVE; | |
232 | 215 | |
233 | - return 0; | |
216 | + return PARSE_ERROR_NONE; | |
234 | 217 | } |
235 | 218 | |
236 | 219 | /*! |
@@ -393,12 +376,11 @@ errr init_feat_variables(void) | ||
393 | 376 | * @param str タグ文字列 |
394 | 377 | * @return 地形ID |
395 | 378 | */ |
396 | -s16b f_tag_to_index(concptr str) | |
379 | +FEAT_IDX f_tag_to_index(std::string_view str) | |
397 | 380 | { |
398 | - for (u16b i = 0; i < f_head.info_num; i++) { | |
399 | - if (streq(f_info[i].tag.c_str(), str)) { | |
400 | - return (s16b)i; | |
401 | - } | |
381 | + for (size_t i = 0; i < f_head.info_num; i++) { | |
382 | + if (f_info[i].tag == str) | |
383 | + return (FEAT_IDX)i; | |
402 | 384 | } |
403 | 385 | |
404 | 386 | return -1; |
@@ -1,10 +1,11 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | 3 | #include "system/angband.h" |
4 | -#include "info-reader/info-reader-util.h" | |
4 | +#include <string_view> | |
5 | 5 | |
6 | -errr parse_f_info(char *buf, angband_header *head); | |
6 | +struct angband_header; | |
7 | +errr parse_f_info(std::string_view buf, angband_header *head); | |
7 | 8 | errr init_feat_variables(void); |
8 | -s16b f_tag_to_index(concptr str); | |
9 | +FEAT_IDX f_tag_to_index(std::string_view str); | |
9 | 10 | s16b f_tag_to_index_in_init(concptr str); |
10 | 11 | void retouch_f_info(angband_header *head); |
@@ -2,6 +2,7 @@ | ||
2 | 2 | #include "dungeon/quest.h" |
3 | 3 | #include "grid/feature.h" |
4 | 4 | #include "info-reader/feature-reader.h" |
5 | +#include "info-reader/info-reader-util.h" | |
5 | 6 | #include "info-reader/parse-error-types.h" |
6 | 7 | #include "info-reader/random-grid-effect-types.h" |
7 | 8 | #include "io/tokenizer.h" |
@@ -15,6 +16,7 @@ | ||
15 | 16 | #include "system/system-variables.h" |
16 | 17 | #include "util/angband-files.h" |
17 | 18 | #include "util/string-processor.h" |
19 | +#include <string> | |
18 | 20 | |
19 | 21 | dungeon_grid letter[255]; |
20 | 22 |
@@ -27,7 +29,7 @@ dungeon_grid letter[255]; | ||
27 | 29 | * @param parse_info_txt_line パース関数 |
28 | 30 | * @return エラーコード |
29 | 31 | */ |
30 | -errr init_info_txt(FILE *fp, char *buf, angband_header *head, parse_info_txt_func parse_info_txt_line) | |
32 | +errr init_info_txt(FILE *fp, char *buf, angband_header *head, std::function<errr(std::string_view, angband_header *)> parse_info_txt_line) | |
31 | 33 | { |
32 | 34 | error_idx = -1; |
33 | 35 | error_line = 0; |
@@ -53,7 +55,7 @@ errr init_info_txt(FILE *fp, char *buf, angband_header *head, parse_info_txt_fun | ||
53 | 55 | } |
54 | 56 | } |
55 | 57 | |
56 | - if ((err = (*parse_info_txt_line)(buf, head)) != 0) | |
58 | + if ((err = parse_info_txt_line(buf, head)) != 0) | |
57 | 59 | return (err); |
58 | 60 | } |
59 | 61 |
@@ -1,6 +1,7 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | 3 | #include "system/angband.h" |
4 | +#include <string_view> | |
4 | 5 | |
5 | 6 | enum parse_error_type : int; |
6 | 7 |
@@ -18,9 +19,9 @@ typedef struct dungeon_grid { | ||
18 | 19 | |
19 | 20 | extern dungeon_grid letter[255]; |
20 | 21 | |
21 | -typedef struct angband_header angband_header; | |
22 | -typedef struct floor_type floor_type; | |
23 | -typedef errr (*parse_info_txt_func)(char *buf, angband_header *head); | |
24 | -errr init_info_txt(FILE *fp, char *buf, angband_header *head, parse_info_txt_func parse_info_txt_line); | |
22 | +struct angband_header; | |
23 | +struct floor_type; | |
24 | + | |
25 | +errr init_info_txt(FILE *fp, char *buf, angband_header *head, std::function<errr(std::string_view, angband_header *)> parse_info_txt_line); | |
25 | 26 | parse_error_type parse_line_feature(floor_type *floor_ptr, char *buf); |
26 | 27 | parse_error_type parse_line_building(char *buf); |
@@ -8,26 +8,6 @@ int error_idx; /*!< データ読み込み/初期化時に汎用的にエラー | ||
8 | 8 | int error_line; /*!< データ読み込み/初期化時に汎用的にエラー行数を保存するグローバル変数 */ |
9 | 9 | |
10 | 10 | /*! |
11 | - * @brief テキストトークンを走査してフラグを一つ得る(汎用) / | |
12 | - * Grab one flag from a textual string | |
13 | - * @param flags ビットフラグを追加する先の参照ポインタ | |
14 | - * @param names トークン定義配列 | |
15 | - * @param what 参照元の文字列ポインタ | |
16 | - * @return エラーコード | |
17 | - */ | |
18 | -errr grab_one_flag(u32b *flags, concptr names[], concptr what) | |
19 | -{ | |
20 | - for (int i = 0; i < 32; i++) { | |
21 | - if (streq(what, names[i])) { | |
22 | - *flags |= (1UL << i); | |
23 | - return 0; | |
24 | - } | |
25 | - } | |
26 | - | |
27 | - return -1; | |
28 | -} | |
29 | - | |
30 | -/*! | |
31 | 11 | * @brief テキストトークンを走査してフラグを一つ得る(発動能力用) / |
32 | 12 | * Grab one activation index flag |
33 | 13 | * @param what 参照元の文字列ポインタ |
@@ -1,13 +1,62 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | 3 | #include "system/angband.h" |
4 | +#include "util/bit-flags-calculator.h" | |
5 | +#include <string> | |
6 | +#include <string_view> | |
7 | +#include <unordered_map> | |
4 | 8 | |
5 | 9 | /* |
6 | 10 | * Size of memory reserved for initialization of some arrays |
7 | 11 | */ |
8 | -extern int error_idx; | |
9 | -extern int error_line; | |
12 | +extern int error_idx; //!< エラーが発生したinfo ID | |
13 | +extern int error_line; //!< エラーが発生した行 | |
10 | 14 | |
11 | -typedef struct angband_header angband_header; | |
12 | -errr grab_one_flag(u32b *flags, concptr names[], concptr what); | |
13 | 15 | byte grab_one_activation_flag(concptr what); |
16 | + | |
17 | +using sview = std::string_view; | |
18 | + | |
19 | +/*! | |
20 | + * @brief infoフラグ文字列をフラグビットに変換する | |
21 | + * @param flags ビットフラグ変数 | |
22 | + * @param names フラグ文字列変換表 | |
23 | + * @param what フラグ文字列 | |
24 | + * @return 見つけたらtrue | |
25 | + */ | |
26 | +template <typename T> | |
27 | +bool info_grab_one_flag(u32b &flags, const std::unordered_map<sview, T> &names, sview what) | |
28 | +{ | |
29 | + if (auto it = names.find(what); it != names.end()) { | |
30 | + set_bits(flags, it->second); | |
31 | + return true; | |
32 | + } | |
33 | + return false; | |
34 | +} | |
35 | + | |
36 | +/*! | |
37 | + * @brief infoフラグ文字列をフラグビットに変換する | |
38 | + * @param flags ビットフラグ配列 | |
39 | + * @param names フラグ文字列変換表 | |
40 | + * @param what フラグ文字列 | |
41 | + * @return 見つけたらtrue | |
42 | + */ | |
43 | +template <typename T> | |
44 | +bool info_grab_one_flag(u32b *flags, const std::unordered_map<sview, T> &names, sview what) | |
45 | +{ | |
46 | + if (auto it = names.find(what); it != names.end()) { | |
47 | + add_flag(flags, it->second); | |
48 | + return true; | |
49 | + } | |
50 | + return false; | |
51 | +} | |
52 | + | |
53 | +/*! | |
54 | + * @brief infoパラメータに値をセットする | |
55 | + * @param パラメータ変数 | |
56 | + * @val 値 | |
57 | + */ | |
58 | +template <typename T> | |
59 | +void info_set_value(T &arg, const std::string &val) | |
60 | +{ | |
61 | + arg = static_cast<T>(std::stoi(val)); | |
62 | +} |
@@ -5,7 +5,7 @@ | ||
5 | 5 | * オブジェクト基本特性トークンの定義 / |
6 | 6 | * Object flags |
7 | 7 | */ |
8 | -std::unordered_map<std::string_view, tr_type> k_info_flags = { | |
8 | +const std::unordered_map<std::string_view, tr_type> k_info_flags = { | |
9 | 9 | { "STR", TR_STR }, |
10 | 10 | { "INT", TR_INT }, |
11 | 11 | { "WIS", TR_WIS }, |
@@ -176,7 +176,7 @@ std::unordered_map<std::string_view, tr_type> k_info_flags = { | ||
176 | 176 | * オブジェクト生成特性トークンの定義 / |
177 | 177 | * Object flags |
178 | 178 | */ |
179 | -std::unordered_map<std::string_view, TRG> k_info_gen_flags = { | |
179 | +const std::unordered_map<std::string_view, TRG> k_info_gen_flags = { | |
180 | 180 | { "INSTA_ART", TRG::INSTA_ART }, |
181 | 181 | { "QUESTITEM", TRG::QUESTITEM }, |
182 | 182 | { "XTRA_POWER", TRG::XTRA_POWER }, |
@@ -3,8 +3,8 @@ | ||
3 | 3 | #include "system/angband.h" |
4 | 4 | #include "object-enchant/tr-types.h" |
5 | 5 | #include "object-enchant/trg-types.h" |
6 | -#include <string> | |
6 | +#include <string_view> | |
7 | 7 | #include <unordered_map> |
8 | 8 | |
9 | -extern std::unordered_map<std::string_view, tr_type> k_info_flags; | |
10 | -extern std::unordered_map<std::string_view, TRG> k_info_gen_flags; | |
9 | +extern const std::unordered_map<std::string_view, tr_type> k_info_flags; | |
10 | +extern const std::unordered_map<std::string_view, TRG> k_info_gen_flags; |
@@ -1,5 +1,7 @@ | ||
1 | 1 | #include "info-reader/kind-reader.h" |
2 | +#include "info-reader/info-reader-util.h" | |
2 | 3 | #include "info-reader/kind-info-tokens-table.h" |
4 | +#include "info-reader/parse-error-types.h" | |
3 | 5 | #include "main/angband-headers.h" |
4 | 6 | #include "object-enchant/tr-types.h" |
5 | 7 | #include "object/object-kind.h" |
@@ -7,27 +9,24 @@ | ||
7 | 9 | #include "util/bit-flags-calculator.h" |
8 | 10 | #include "util/string-processor.h" |
9 | 11 | #include "view/display-messages.h" |
10 | -#include <string> | |
11 | 12 | |
12 | 13 | /*! |
13 | 14 | * @brief テキストトークンを走査してフラグを一つ得る(ベースアイテム用) / |
14 | 15 | * Grab one flag in an object_kind from a textual string |
15 | 16 | * @param k_ptr 保管先のベースアイテム構造体参照ポインタ |
16 | 17 | * @param what 参照元の文字列ポインタ |
17 | - * @return エラーコード | |
18 | + * @return 見つけたらtrue | |
18 | 19 | */ |
19 | -static errr grab_one_kind_flag(object_kind *k_ptr, concptr what) | |
20 | +static bool grab_one_kind_flag(object_kind *k_ptr, std::string_view what) | |
20 | 21 | { |
21 | - if (k_info_flags.find(what) != k_info_flags.end()) { | |
22 | - add_flag(k_ptr->flags, k_info_flags[what]); | |
23 | - return 0; | |
24 | - } | |
22 | + if (info_grab_one_flag(k_ptr->flags, k_info_flags, what)) | |
23 | + return true; | |
25 | 24 | |
26 | 25 | if (EnumClassFlagGroup<TRG>::grab_one_flag(k_ptr->gen_flags, k_info_gen_flags, what)) |
27 | - return 0; | |
26 | + return true; | |
28 | 27 | |
29 | - msg_format(_("未知のアイテム・フラグ '%s'。", "Unknown object flag '%s'."), what); | |
30 | - return 1; | |
28 | + msg_format(_("未知のアイテム・フラグ '%s'。", "Unknown object flag '%s'."), what.data()); | |
29 | + return false; | |
31 | 30 | } |
32 | 31 | |
33 | 32 | /*! |
@@ -37,163 +36,136 @@ static errr grab_one_kind_flag(object_kind *k_ptr, concptr what) | ||
37 | 36 | * @param head ヘッダ構造体 |
38 | 37 | * @return エラーコード |
39 | 38 | */ |
40 | -errr parse_k_info(char *buf, angband_header *head) | |
39 | +errr parse_k_info(std::string_view buf, angband_header *head) | |
41 | 40 | { |
42 | 41 | static object_kind *k_ptr = NULL; |
42 | + const auto &tokens = str_split(buf, ':', false, 10); | |
43 | 43 | |
44 | - char *s, *t; | |
45 | - if (buf[0] == 'N') { | |
46 | -#ifdef JP | |
47 | - char *flavor; | |
48 | -#endif | |
49 | - s = angband_strchr(buf + 2, ':'); | |
50 | - if (!s) | |
51 | - return 1; | |
52 | - | |
53 | - *s++ = '\0'; | |
54 | - int i = atoi(buf + 2); | |
44 | + if (tokens[0] == "N") { | |
45 | + // N:index:name_ja | |
46 | + if (tokens.size() < 3 || tokens[1].size() == 0) | |
47 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
55 | 48 | |
56 | - if (i <= error_idx) | |
57 | - return 4; | |
49 | + auto i = std::stoi(tokens[1]); | |
50 | + if (i < error_idx) | |
51 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
58 | 52 | if (i >= head->info_num) |
59 | - return 2; | |
53 | + return PARSE_ERROR_OUT_OF_BOUNDS; | |
60 | 54 | |
61 | 55 | error_idx = i; |
62 | 56 | k_ptr = &k_info[i]; |
63 | - | |
64 | 57 | #ifdef JP |
65 | - if (!*s) | |
66 | - return 1; | |
67 | - | |
68 | - flavor = angband_strchr(s, ':'); | |
69 | - if (flavor) { | |
70 | - *flavor++ = '\0'; | |
71 | - k_ptr->flavor_name = std::string(flavor); | |
72 | - } | |
73 | - | |
74 | - k_ptr->name = std::string(s); | |
58 | + k_ptr->name = tokens[2]; | |
75 | 59 | #endif |
76 | - } else if (!k_ptr) { | |
77 | - return 3; | |
78 | - } | |
79 | -#ifdef JP | |
80 | - /* 英語名を読むルーチンを追加 */ | |
81 | - /* 'E' から始まる行は英語名としている */ | |
82 | - else if (buf[0] == 'E') { | |
83 | - /* nothing to do */ | |
84 | - } | |
85 | -#else | |
86 | - else if (buf[0] == 'E') { | |
87 | - char *flavor; | |
88 | - s = buf + 2; | |
89 | - flavor = angband_strchr(s, ':'); | |
90 | - if (flavor) { | |
91 | - *flavor++ = '\0'; | |
92 | - k_ptr->flavor_name = std::string(flavor); | |
93 | - } | |
94 | - | |
95 | - k_ptr->name = std::string(s); | |
96 | - } | |
60 | + if (tokens.size() > 3) | |
61 | + k_ptr->flavor_name = tokens[3]; | |
62 | + | |
63 | + } else if (!k_ptr) | |
64 | + return PARSE_ERROR_MISSING_RECORD_HEADER; | |
65 | + else if (tokens[0] == "E") { | |
66 | + // E:name_en | |
67 | +#ifndef JP | |
68 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
69 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
70 | + k_ptr->name = tokens[1]; | |
71 | + | |
72 | + if (tokens.size() > 2) | |
73 | + k_ptr->flavor_name = tokens[2]; | |
97 | 74 | #endif |
98 | - else if (buf[0] == 'D') { | |
75 | + } else if (tokens[0] == "D") { | |
76 | + // D:text_ja | |
77 | + // D:$text_en | |
78 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
79 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
99 | 80 | #ifdef JP |
100 | - if (buf[2] == '$') | |
101 | - return 0; | |
102 | - s = buf + 2; | |
81 | + if (tokens[1][0] == '$') | |
82 | + return PARSE_ERROR_NONE; | |
83 | + k_ptr->text.append(buf.substr(2)); | |
103 | 84 | #else |
104 | - if (buf[2] != '$') | |
105 | - return 0; | |
106 | - s = buf + 3; | |
85 | + if (tokens[1][0] != '$') | |
86 | + return PARSE_ERROR_NONE; | |
87 | + k_ptr->text.append(buf.substr(3)); | |
107 | 88 | #endif |
108 | - k_ptr->text.append(s); | |
109 | - } else if (buf[0] == 'G') { | |
110 | - char sym; | |
111 | - byte tmp; | |
112 | - if (buf[1] != ':') | |
113 | - return 1; | |
114 | - if (!buf[2]) | |
115 | - return 1; | |
116 | - if (buf[3] != ':') | |
117 | - return 1; | |
118 | - if (!buf[4]) | |
119 | - return 1; | |
120 | - | |
121 | - sym = buf[2]; | |
122 | - tmp = color_char_to_attr(buf[4]); | |
123 | - if (tmp > 127) | |
124 | - return 1; | |
125 | - | |
126 | - k_ptr->d_attr = tmp; | |
127 | - k_ptr->d_char = sym; | |
128 | - } else if (buf[0] == 'I') { | |
129 | - int tval, sval, pval; | |
130 | - if (3 != sscanf(buf + 2, "%d:%d:%d", &tval, &sval, &pval)) | |
131 | - return 1; | |
132 | - | |
133 | - k_ptr->tval = (tval_type)tval; | |
134 | - k_ptr->sval = (OBJECT_SUBTYPE_VALUE)sval; | |
135 | - k_ptr->pval = (PARAMETER_VALUE)pval; | |
136 | - } else if (buf[0] == 'W') { | |
137 | - int level, extra, wgt; | |
138 | - long cost; | |
139 | - if (4 != sscanf(buf + 2, "%d:%d:%d:%ld", &level, &extra, &wgt, &cost)) | |
140 | - return 1; | |
141 | - | |
142 | - k_ptr->level = (DEPTH)level; | |
143 | - k_ptr->extra = (BIT_FLAGS8)extra; | |
144 | - k_ptr->weight = (WEIGHT)wgt; | |
145 | - k_ptr->cost = (PRICE)cost; | |
146 | - } else if (buf[0] == 'A') { | |
147 | - int i = 0; | |
148 | - for (s = buf + 1; s && (s[0] == ':') && s[1]; ++i) { | |
149 | - k_ptr->chance[i] = 1; | |
150 | - k_ptr->locale[i] = atoi(s + 1); | |
151 | - t = angband_strchr(s + 1, '/'); | |
152 | - s = angband_strchr(s + 1, ':'); | |
153 | - if (t && (!s || t < s)) { | |
154 | - int chance = atoi(t + 1); | |
155 | - if (chance > 0) | |
156 | - k_ptr->chance[i] = (PROB)chance; | |
157 | - } | |
158 | - } | |
159 | - } else if (buf[0] == 'P') { | |
160 | - int ac, hd1, hd2, th, td, ta; | |
161 | - if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d", &ac, &hd1, &hd2, &th, &td, &ta)) | |
162 | - return 1; | |
163 | - | |
164 | - k_ptr->ac = (ARMOUR_CLASS)ac; | |
165 | - k_ptr->dd = (DICE_NUMBER)hd1; | |
166 | - k_ptr->ds = (DICE_SID)hd2; | |
167 | - k_ptr->to_h = (HIT_PROB)th; | |
168 | - k_ptr->to_d = (HIT_POINT)td; | |
169 | - k_ptr->to_a = (ARMOUR_CLASS)ta; | |
170 | - } else if (buf[0] == 'U') { | |
171 | - byte n; | |
172 | - n = grab_one_activation_flag(buf + 2); | |
173 | - if (n > 0) { | |
174 | - k_ptr->act_idx = n; | |
175 | - } else { | |
176 | - return 5; | |
89 | + } else if (tokens[0] == "G") { | |
90 | + // G:color:symbol | |
91 | + if (tokens.size() < 3 || tokens[1].size() == 0 || tokens[2].size() == 0) | |
92 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
93 | + | |
94 | + auto a = color_char_to_attr(tokens[2][0]); | |
95 | + if (a > 127) | |
96 | + return PARSE_ERROR_GENERIC; | |
97 | + | |
98 | + k_ptr->d_attr = a; | |
99 | + k_ptr->d_char = tokens[1][0]; | |
100 | + } else if (tokens[0] == "I") { | |
101 | + // I:tval:sval:pval | |
102 | + if (tokens.size() < 4) | |
103 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
104 | + | |
105 | + info_set_value(k_ptr->tval, tokens[1]); | |
106 | + info_set_value(k_ptr->sval, tokens[2]); | |
107 | + info_set_value(k_ptr->pval, tokens[3]); | |
108 | + } else if (tokens[0] == "W") { | |
109 | + // W:level:extra:weight:cost | |
110 | + if (tokens.size() < 5) | |
111 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
112 | + | |
113 | + info_set_value(k_ptr->level, tokens[1]); | |
114 | + info_set_value(k_ptr->extra, tokens[2]); | |
115 | + info_set_value(k_ptr->weight, tokens[3]); | |
116 | + info_set_value(k_ptr->cost, tokens[4]); | |
117 | + } else if (tokens[0] == "A") { | |
118 | + // A:level/chance(:level/chance:level/chance:level/chance) | |
119 | + if (tokens.size() < 2 || tokens.size() > 5) | |
120 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
121 | + | |
122 | + auto i = 0; | |
123 | + for (auto t = tokens.begin() + 1; t != tokens.end(); t++) { | |
124 | + const auto &rarity = str_split(*t, '/', false, 2); | |
125 | + if (rarity.size() != 2 || rarity[0].size() == 0 || rarity[1].size() == 0) | |
126 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
127 | + info_set_value(k_ptr->locale[i], rarity[0]); | |
128 | + info_set_value(k_ptr->chance[i], rarity[1]); | |
129 | + i++; | |
177 | 130 | } |
178 | - } else if (buf[0] == 'F') { | |
179 | - for (s = buf + 2; *s;) { | |
180 | - /* loop */ | |
181 | - for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) | |
182 | - ; | |
183 | - | |
184 | - if (*t) { | |
185 | - *t++ = '\0'; | |
186 | - while (*t == ' ' || *t == '|') | |
187 | - t++; | |
188 | - } | |
189 | - | |
190 | - if (0 != grab_one_kind_flag(k_ptr, s)) | |
191 | - return 5; | |
192 | - s = t; | |
131 | + } else if (tokens[0] == "P") { | |
132 | + // P:ac:dd:ds:to_h:to_d:to_a | |
133 | + if (tokens.size() < 6) | |
134 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
135 | + | |
136 | + const auto &dice = str_split(tokens[2], 'd', false, 2); | |
137 | + if (dice.size() != 2) | |
138 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
139 | + | |
140 | + info_set_value(k_ptr->ac, tokens[1]); | |
141 | + info_set_value(k_ptr->dd, dice[0]); | |
142 | + info_set_value(k_ptr->ds, dice[1]); | |
143 | + info_set_value(k_ptr->to_h, tokens[3]); | |
144 | + info_set_value(k_ptr->to_d, tokens[4]); | |
145 | + info_set_value(k_ptr->to_a, tokens[5]); | |
146 | + } else if (tokens[0] == "U") { | |
147 | + // U:activation_flag | |
148 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
149 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
150 | + auto n = grab_one_activation_flag(tokens[1].c_str()); | |
151 | + if (n <= 0) | |
152 | + return PARSE_ERROR_INVALID_FLAG; | |
153 | + | |
154 | + k_ptr->act_idx = (IDX)n; | |
155 | + } else if (tokens[0] == "F") { | |
156 | + // F:flags | |
157 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
158 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
159 | + | |
160 | + const auto &flags = str_split(tokens[1], '|', true, 10); | |
161 | + for (const auto &f : flags) { | |
162 | + if (f.size() == 0) | |
163 | + continue; | |
164 | + if (!grab_one_kind_flag(k_ptr, f)) | |
165 | + return PARSE_ERROR_INVALID_FLAG; | |
193 | 166 | } |
194 | - } else { | |
195 | - return 6; | |
196 | - } | |
167 | + } else | |
168 | + return PARSE_ERROR_UNDEFINED_DIRECTIVE; | |
197 | 169 | |
198 | - return 0; | |
170 | + return PARSE_ERROR_NONE; | |
199 | 171 | } |
@@ -1,6 +1,7 @@ | ||
1 | -#pragma once | |
1 | +#pragma once | |
2 | 2 | |
3 | 3 | #include "system/angband.h" |
4 | -#include "info-reader/info-reader-util.h" | |
4 | +#include <string_view> | |
5 | 5 | |
6 | -errr parse_k_info(char *buf, angband_header *head); | |
6 | +struct angband_header; | |
7 | +errr parse_k_info(std::string_view buf, angband_header *head); |
@@ -1,9 +1,36 @@ | ||
1 | 1 | #include "info-reader/magic-reader.h" |
2 | +#include "info-reader/info-reader-util.h" | |
3 | +#include "info-reader/parse-error-types.h" | |
2 | 4 | #include "main/angband-headers.h" |
3 | 5 | #include "player-ability/player-ability-types.h" |
4 | 6 | #include "player/player-class.h" |
5 | 7 | #include "util/string-processor.h" |
6 | 8 | |
9 | +namespace { | |
10 | +/*! | |
11 | + * @brief 魔法タイプ名とtvalの対応表 | |
12 | + */ | |
13 | +const std::unordered_map<std::string_view, tval_type> name_to_tval = { | |
14 | + { "SORCERY", TV_SORCERY_BOOK }, | |
15 | + { "LIFE", TV_LIFE_BOOK }, | |
16 | + { "MUSIC", TV_MUSIC_BOOK }, | |
17 | + { "HISSATSU", TV_HISSATSU_BOOK }, | |
18 | + { "NONE", TV_NONE }, | |
19 | +}; | |
20 | + | |
21 | +/*! | |
22 | + * @brief 魔法必須能力とenumの対応表 | |
23 | + */ | |
24 | +const std::unordered_map<std::string_view, int> name_to_stat = { | |
25 | + { "STR", A_STR }, | |
26 | + { "INT", A_INT }, | |
27 | + { "WIS", A_WIS }, | |
28 | + { "DEX", A_DEX }, | |
29 | + { "CON", A_CON }, | |
30 | + { "CHR", A_CHR }, | |
31 | +}; | |
32 | +} | |
33 | + | |
7 | 34 | /*! |
8 | 35 | * @brief 職業魔法情報(m_info)のパース関数 / |
9 | 36 | * Initialize the "m_info" array, by parsing an ascii "template" file |
@@ -11,99 +38,69 @@ | ||
11 | 38 | * @param head ヘッダ構造体 |
12 | 39 | * @return エラーコード |
13 | 40 | */ |
14 | -errr parse_m_info(char *buf, angband_header *head) | |
41 | +errr parse_m_info(std::string_view buf, angband_header *head) | |
15 | 42 | { |
16 | 43 | static player_magic *m_ptr = NULL; |
17 | 44 | static int realm, magic_idx = 0, readable = 0; |
45 | + const auto &tokens = str_split(buf, ':', false, 7); | |
18 | 46 | |
19 | - if (buf[0] == 'N') { | |
20 | - int i = atoi(buf + 2); | |
47 | + if (tokens[0] == "N") { | |
48 | + // N:class-index | |
49 | + if (tokens.size() < 2 && tokens[1].size() == 0) | |
50 | + return PARSE_ERROR_GENERIC; | |
21 | 51 | |
22 | - if (i <= error_idx) | |
23 | - return 4; | |
52 | + auto i = std::stoi(tokens[1]); | |
53 | + if (i < error_idx) | |
54 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
24 | 55 | if (i >= head->info_num) |
25 | - return 2; | |
56 | + return PARSE_ERROR_OUT_OF_BOUNDS; | |
26 | 57 | |
27 | 58 | error_idx = i; |
28 | 59 | m_ptr = &m_info[i]; |
29 | - } else if (!m_ptr) { | |
30 | - return 3; | |
31 | - } else if (buf[0] == 'I') { | |
32 | - char *book, *stat; | |
33 | - int xtra, type, first, weight; | |
34 | - char *s; | |
35 | - s = angband_strchr(buf + 2, ':'); | |
36 | - | |
37 | - /* Verify that colon */ | |
38 | - if (!s) | |
39 | - return 1; | |
40 | - | |
41 | - /* Nuke the colon, advance to the name */ | |
42 | - *s++ = '\0'; | |
43 | - | |
44 | - book = buf + 2; | |
45 | - | |
46 | - if (streq(book, "SORCERY")) | |
47 | - m_ptr->spell_book = TV_SORCERY_BOOK; | |
48 | - else if (streq(book, "LIFE")) | |
49 | - m_ptr->spell_book = TV_LIFE_BOOK; | |
50 | - else if (streq(book, "MUSIC")) | |
51 | - m_ptr->spell_book = TV_MUSIC_BOOK; | |
52 | - else if (streq(book, "HISSATSU")) | |
53 | - m_ptr->spell_book = TV_HISSATSU_BOOK; | |
54 | - else if (streq(book, "NONE")) | |
55 | - m_ptr->spell_book = TV_NONE; | |
56 | - else | |
57 | - return 5; | |
58 | - | |
59 | - stat = s; | |
60 | - s = angband_strchr(s, ':'); | |
61 | - if (!s) | |
62 | - return 1; | |
63 | - *s++ = '\0'; | |
64 | - | |
65 | - if (streq(stat, "STR")) | |
66 | - m_ptr->spell_stat = A_STR; | |
67 | - else if (streq(stat, "INT")) | |
68 | - m_ptr->spell_stat = A_INT; | |
69 | - else if (streq(stat, "WIS")) | |
70 | - m_ptr->spell_stat = A_WIS; | |
71 | - else if (streq(stat, "DEX")) | |
72 | - m_ptr->spell_stat = A_DEX; | |
73 | - else if (streq(stat, "CON")) | |
74 | - m_ptr->spell_stat = A_CON; | |
75 | - else if (streq(stat, "CHR")) | |
76 | - m_ptr->spell_stat = A_CHR; | |
77 | - else | |
78 | - return 5; | |
79 | - | |
80 | - if (4 != sscanf(s, "%x:%d:%d:%d", (uint *)&xtra, &type, &first, &weight)) | |
81 | - return 1; | |
82 | - | |
83 | - m_ptr->spell_xtra = xtra; | |
84 | - m_ptr->spell_type = type; | |
85 | - m_ptr->spell_first = first; | |
86 | - m_ptr->spell_weight = weight; | |
87 | - } else if (buf[0] == 'R') { | |
88 | - if (2 != sscanf(buf + 2, "%d:%d", &realm, &readable)) | |
89 | - return 1; | |
90 | - | |
60 | + } else if (!m_ptr) | |
61 | + return PARSE_ERROR_MISSING_RECORD_HEADER; | |
62 | + else if (tokens[0] == "I") { | |
63 | + if (tokens.size() < 7 || tokens[1].size() == 0) | |
64 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
65 | + | |
66 | + const auto tval = name_to_tval.find(tokens[1]); | |
67 | + if (tval == name_to_tval.end()) | |
68 | + return PARSE_ERROR_INVALID_FLAG; | |
69 | + | |
70 | + m_ptr->spell_book = tval->second; | |
71 | + | |
72 | + const auto stat = name_to_stat.find(tokens[2]); | |
73 | + if (stat == name_to_stat.end()) | |
74 | + return PARSE_ERROR_INVALID_FLAG; | |
75 | + | |
76 | + m_ptr->spell_stat = stat->second; | |
77 | + | |
78 | + info_set_value(m_ptr->spell_xtra, tokens[3]); | |
79 | + info_set_value(m_ptr->spell_type, tokens[4]); | |
80 | + info_set_value(m_ptr->spell_first, tokens[5]); | |
81 | + info_set_value(m_ptr->spell_weight, tokens[6]); | |
82 | + } else if (tokens[0] == "R") { | |
83 | + if (tokens.size() < 3) | |
84 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
85 | + | |
86 | + info_set_value(realm, tokens[1]); | |
87 | + info_set_value(readable, tokens[2]); | |
91 | 88 | magic_idx = 0; |
92 | - } else if (buf[0] == 'T') { | |
93 | - int level, mana, fail, exp; | |
94 | - | |
89 | + } else if (tokens[0] == "T") { | |
95 | 90 | if (!readable) |
96 | - return 1; | |
97 | - if (4 != sscanf(buf + 2, "%d:%d:%d:%d", &level, &mana, &fail, &exp)) | |
98 | - return 1; | |
91 | + return PARSE_ERROR_GENERIC; | |
92 | + | |
93 | + if (tokens.size() < 5) | |
94 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
99 | 95 | |
100 | - m_ptr->info[realm][magic_idx].slevel = (PLAYER_LEVEL)level; | |
101 | - m_ptr->info[realm][magic_idx].smana = (MANA_POINT)mana; | |
102 | - m_ptr->info[realm][magic_idx].sfail = (PERCENTAGE)fail; | |
103 | - m_ptr->info[realm][magic_idx].sexp = (EXP)exp; | |
96 | + auto &magic = m_ptr->info[realm][magic_idx]; | |
97 | + info_set_value(magic.slevel, tokens[1]); | |
98 | + info_set_value(magic.smana, tokens[2]); | |
99 | + info_set_value(magic.sfail, tokens[3]); | |
100 | + info_set_value(magic.sexp, tokens[4]); | |
104 | 101 | magic_idx++; |
105 | 102 | } else |
106 | - return 6; | |
103 | + return PARSE_ERROR_UNDEFINED_DIRECTIVE; | |
107 | 104 | |
108 | - return 0; | |
105 | + return PARSE_ERROR_NONE; | |
109 | 106 | } |
@@ -1,6 +1,7 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | -#include "info-reader/info-reader-util.h" | |
4 | 3 | #include "system/angband.h" |
4 | +#include <string_view> | |
5 | 5 | |
6 | -errr parse_m_info(char *buf, angband_header *head); | |
6 | +struct angband_header; | |
7 | +errr parse_m_info(std::string_view buf, angband_header *head); |
@@ -7,196 +7,173 @@ | ||
7 | 7 | * モンスターの打撃手段トークンの定義 / |
8 | 8 | * Monster Blow Methods |
9 | 9 | */ |
10 | -concptr r_info_blow_method[NB_RBM_TYPE + 1] = { | |
11 | - "", | |
12 | - "HIT", | |
13 | - "TOUCH", | |
14 | - "PUNCH", | |
15 | - "KICK", | |
16 | - "CLAW", | |
17 | - "BITE", | |
18 | - "STING", | |
19 | - "SLASH", | |
20 | - "BUTT", | |
21 | - "CRUSH", | |
22 | - "ENGULF", | |
23 | - "CHARGE", | |
24 | - "CRAWL", | |
25 | - "DROOL", | |
26 | - "SPIT", | |
27 | - "EXPLODE", | |
28 | - "GAZE", | |
29 | - "WAIL", | |
30 | - "SPORE", | |
31 | - "XXX4", | |
32 | - "BEG", | |
33 | - "INSULT", | |
34 | - "MOAN", | |
35 | - "SHOW", | |
36 | - "SHOOT", | |
37 | - NULL | |
10 | +const std::unordered_map<std::string_view, rbm_type> r_info_blow_method = { | |
11 | + { "HIT", RBM_HIT }, | |
12 | + { "TOUCH", RBM_TOUCH }, | |
13 | + { "PUNCH", RBM_PUNCH }, | |
14 | + { "KICK", RBM_KICK }, | |
15 | + { "CLAW", RBM_CLAW }, | |
16 | + { "BITE", RBM_BITE }, | |
17 | + { "STING", RBM_STING }, | |
18 | + { "SLASH", RBM_SLASH }, | |
19 | + { "BUTT", RBM_BUTT }, | |
20 | + { "CRUSH", RBM_CRUSH }, | |
21 | + { "ENGULF", RBM_ENGULF }, | |
22 | + { "CHARGE", RBM_CHARGE }, | |
23 | + { "CRAWL", RBM_CRAWL }, | |
24 | + { "DROOL", RBM_DROOL }, | |
25 | + { "SPIT", RBM_SPIT }, | |
26 | + { "EXPLODE", RBM_EXPLODE }, | |
27 | + { "GAZE", RBM_GAZE }, | |
28 | + { "WAIL", RBM_WAIL }, | |
29 | + { "SPORE", RBM_SPORE }, | |
30 | + { "XXX4", RBM_XXX4 }, | |
31 | + { "BEG", RBM_BEG }, | |
32 | + { "INSULT", RBM_INSULT }, | |
33 | + { "MOAN", RBM_MOAN }, | |
34 | + { "SHOW", RBM_SHOW }, | |
35 | + { "SHOOT", RBM_SHOOT }, | |
38 | 36 | }; |
39 | 37 | |
40 | 38 | /*! |
41 | 39 | * モンスターの打撃属性トークンの定義 / |
42 | 40 | * Monster Blow Effects |
43 | 41 | */ |
44 | -concptr r_info_blow_effect[NB_RBE_TYPE + 1] = { | |
45 | - "", | |
46 | - "HURT", | |
47 | - "POISON", | |
48 | - "UN_BONUS", | |
49 | - "UN_POWER", | |
50 | - "EAT_GOLD", | |
51 | - "EAT_ITEM", | |
52 | - "EAT_FOOD", | |
53 | - "EAT_LITE", | |
54 | - "ACID", | |
55 | - "ELEC", | |
56 | - "FIRE", | |
57 | - "COLD", | |
58 | - "BLIND", | |
59 | - "CONFUSE", | |
60 | - "TERRIFY", | |
61 | - "PARALYZE", | |
62 | - "LOSE_STR", | |
63 | - "LOSE_INT", | |
64 | - "LOSE_WIS", | |
65 | - "LOSE_DEX", | |
66 | - "LOSE_CON", | |
67 | - "LOSE_CHR", | |
68 | - "LOSE_ALL", | |
69 | - "SHATTER", | |
70 | - "EXP_10", | |
71 | - "EXP_20", | |
72 | - "EXP_40", | |
73 | - "EXP_80", | |
74 | - "DISEASE", | |
75 | - "TIME", | |
76 | - "EXP_VAMP", | |
77 | - "DR_MANA", | |
78 | - "SUPERHURT", | |
79 | - "INERTIA", | |
80 | - "STUN", | |
81 | - "FLAVOR", | |
82 | - NULL | |
42 | +const std::unordered_map<std::string_view, rbe_type> r_info_blow_effect = { | |
43 | + { "HURT", RBE_HURT }, | |
44 | + { "POISON", RBE_POISON }, | |
45 | + { "UN_BONUS", RBE_UN_BONUS }, | |
46 | + { "UN_POWER", RBE_UN_POWER }, | |
47 | + { "EAT_GOLD", RBE_EAT_GOLD }, | |
48 | + { "EAT_ITEM", RBE_EAT_ITEM }, | |
49 | + { "EAT_FOOD", RBE_EAT_FOOD }, | |
50 | + { "EAT_LITE", RBE_EAT_LITE }, | |
51 | + { "ACID", RBE_ACID }, | |
52 | + { "ELEC", RBE_ELEC }, | |
53 | + { "FIRE", RBE_FIRE }, | |
54 | + { "COLD", RBE_COLD }, | |
55 | + { "BLIND", RBE_BLIND }, | |
56 | + { "CONFUSE", RBE_CONFUSE }, | |
57 | + { "TERRIFY", RBE_TERRIFY }, | |
58 | + { "PARALYZE", RBE_PARALYZE }, | |
59 | + { "LOSE_STR", RBE_LOSE_STR }, | |
60 | + { "LOSE_INT", RBE_LOSE_INT }, | |
61 | + { "LOSE_WIS", RBE_LOSE_WIS }, | |
62 | + { "LOSE_DEX", RBE_LOSE_DEX }, | |
63 | + { "LOSE_CON", RBE_LOSE_CON }, | |
64 | + { "LOSE_CHR", RBE_LOSE_CHR }, | |
65 | + { "LOSE_ALL", RBE_LOSE_ALL }, | |
66 | + { "SHATTER", RBE_SHATTER }, | |
67 | + { "EXP_10", RBE_EXP_10 }, | |
68 | + { "EXP_20", RBE_EXP_20 }, | |
69 | + { "EXP_40", RBE_EXP_40 }, | |
70 | + { "EXP_80", RBE_EXP_80 }, | |
71 | + { "DISEASE", RBE_DISEASE }, | |
72 | + { "TIME", RBE_TIME }, | |
73 | + { "EXP_VAMP", RBE_DR_LIFE }, | |
74 | + { "DR_MANA", RBE_DR_MANA }, | |
75 | + { "SUPERHURT", RBE_SUPERHURT }, | |
76 | + { "INERTIA", RBE_INERTIA }, | |
77 | + { "STUN", RBE_STUN }, | |
78 | + { "FLAVOR", RBE_FLAVOR }, | |
83 | 79 | }; |
84 | 80 | |
85 | 81 | /*! |
86 | 82 | * モンスター特性トークンの定義1 / |
87 | 83 | * Monster race flags |
88 | 84 | */ |
89 | -concptr r_info_flags1[NUM_R_FLAGS_1] = { | |
90 | - "UNIQUE", | |
91 | - "QUESTOR", | |
92 | - "MALE", | |
93 | - "FEMALE", | |
94 | - "CHAR_CLEAR", | |
95 | - "SHAPECHANGER", | |
96 | - "ATTR_CLEAR", | |
97 | - "ATTR_MULTI", | |
98 | - "FORCE_DEPTH", | |
99 | - "FORCE_MAXHP", | |
100 | - "PREVENT_SUDDEN_MAGIC", | |
101 | - "FORCE_EXTRA", | |
102 | - "ATTR_SEMIRAND", | |
103 | - "FRIENDS", | |
104 | - "ESCORT", | |
105 | - "ESCORTS", | |
106 | - "NEVER_BLOW", | |
107 | - "NEVER_MOVE", | |
108 | - "RAND_25", | |
109 | - "RAND_50", | |
110 | - "ONLY_GOLD", | |
111 | - "ONLY_ITEM", | |
112 | - "DROP_60", | |
113 | - "DROP_90", | |
114 | - "DROP_1D2", | |
115 | - "DROP_2D2", | |
116 | - "DROP_3D2", | |
117 | - "DROP_4D2", | |
118 | - "DROP_GOOD", | |
119 | - "DROP_GREAT", | |
120 | - "XXX2", | |
121 | - "XXX3" | |
85 | +const std::unordered_map<std::string_view, race_flags1> r_info_flags1 = { | |
86 | + { "UNIQUE", RF1_UNIQUE }, | |
87 | + { "QUESTOR", RF1_QUESTOR }, | |
88 | + { "MALE", RF1_MALE }, | |
89 | + { "FEMALE", RF1_FEMALE }, | |
90 | + { "CHAR_CLEAR", RF1_CHAR_CLEAR }, | |
91 | + { "SHAPECHANGER", RF1_SHAPECHANGER }, | |
92 | + { "ATTR_CLEAR", RF1_ATTR_CLEAR }, | |
93 | + { "ATTR_MULTI", RF1_ATTR_MULTI }, | |
94 | + { "FORCE_DEPTH", RF1_FORCE_DEPTH }, | |
95 | + { "FORCE_MAXHP", RF1_FORCE_MAXHP }, | |
96 | + { "PREVENT_SUDDEN_MAGIC", RF1_PREVENT_SUDDEN_MAGIC }, | |
97 | + { "FORCE_EXTRA", RF1_FORCE_EXTRA }, | |
98 | + { "ATTR_SEMIRAND", RF1_ATTR_SEMIRAND }, | |
99 | + { "FRIENDS", RF1_FRIENDS }, | |
100 | + { "ESCORT", RF1_ESCORT }, | |
101 | + { "ESCORTS", RF1_ESCORTS }, | |
102 | + { "NEVER_BLOW", RF1_NEVER_BLOW }, | |
103 | + { "NEVER_MOVE", RF1_NEVER_MOVE }, | |
104 | + { "RAND_25", RF1_RAND_25 }, | |
105 | + { "RAND_50", RF1_RAND_50 }, | |
106 | + { "ONLY_GOLD", RF1_ONLY_GOLD }, | |
107 | + { "ONLY_ITEM", RF1_ONLY_ITEM }, | |
108 | + { "DROP_60", RF1_DROP_60 }, | |
109 | + { "DROP_90", RF1_DROP_90 }, | |
110 | + { "DROP_1D2", RF1_DROP_1D2 }, | |
111 | + { "DROP_2D2", RF1_DROP_2D2 }, | |
112 | + { "DROP_3D2", RF1_DROP_3D2 }, | |
113 | + { "DROP_4D2", RF1_DROP_4D2 }, | |
114 | + { "DROP_GOOD", RF1_DROP_GOOD }, | |
115 | + { "DROP_GREAT", RF1_DROP_GREAT }, | |
122 | 116 | }; |
123 | 117 | |
124 | 118 | /*! |
125 | 119 | * モンスター特性トークンの定義2 / |
126 | 120 | * Monster race flags |
127 | 121 | */ |
128 | -concptr r_info_flags2[NUM_R_FLAGS_2] = { | |
129 | - "STUPID", | |
130 | - "SMART", | |
131 | - "CAN_SPEAK", | |
132 | - "REFLECTING", | |
133 | - "INVISIBLE", | |
134 | - "COLD_BLOOD", | |
135 | - "EMPTY_MIND", | |
136 | - "WEIRD_MIND", | |
137 | - "MULTIPLY", | |
138 | - "REGENERATE", | |
139 | - "CHAR_MULTI", | |
140 | - "ATTR_ANY", | |
141 | - "POWERFUL", | |
142 | - "ELDRITCH_HORROR", | |
143 | - "AURA_FIRE", | |
144 | - "AURA_ELEC", | |
145 | - "OPEN_DOOR", | |
146 | - "BASH_DOOR", | |
147 | - "PASS_WALL", | |
148 | - "KILL_WALL", | |
149 | - "MOVE_BODY", | |
150 | - "KILL_BODY", | |
151 | - "TAKE_ITEM", | |
152 | - "KILL_ITEM", | |
153 | - "XXX", | |
154 | - "XXX", | |
155 | - "XXX", | |
156 | - "XXX", | |
157 | - "XXX", | |
158 | - "XXX", | |
159 | - "HUMAN", | |
160 | - "QUANTUM" | |
122 | +const std::unordered_map<std::string_view, race_flags2> r_info_flags2 = { | |
123 | + { "STUPID", RF2_STUPID }, | |
124 | + { "SMART", RF2_SMART }, | |
125 | + { "CAN_SPEAK", RF2_CAN_SPEAK }, | |
126 | + { "REFLECTING", RF2_REFLECTING }, | |
127 | + { "INVISIBLE", RF2_INVISIBLE }, | |
128 | + { "COLD_BLOOD", RF2_COLD_BLOOD }, | |
129 | + { "EMPTY_MIND", RF2_EMPTY_MIND }, | |
130 | + { "WEIRD_MIND", RF2_WEIRD_MIND }, | |
131 | + { "MULTIPLY", RF2_MULTIPLY }, | |
132 | + { "REGENERATE", RF2_REGENERATE }, | |
133 | + { "CHAR_MULTI", RF2_CHAR_MULTI }, | |
134 | + { "ATTR_ANY", RF2_ATTR_ANY }, | |
135 | + { "POWERFUL", RF2_POWERFUL }, | |
136 | + { "ELDRITCH_HORROR", RF2_ELDRITCH_HORROR }, | |
137 | + { "AURA_FIRE", RF2_AURA_FIRE }, | |
138 | + { "AURA_ELEC", RF2_AURA_ELEC }, | |
139 | + { "OPEN_DOOR", RF2_OPEN_DOOR }, | |
140 | + { "BASH_DOOR", RF2_BASH_DOOR }, | |
141 | + { "PASS_WALL", RF2_PASS_WALL }, | |
142 | + { "KILL_WALL", RF2_KILL_WALL }, | |
143 | + { "MOVE_BODY", RF2_MOVE_BODY }, | |
144 | + { "KILL_BODY", RF2_KILL_BODY }, | |
145 | + { "TAKE_ITEM", RF2_TAKE_ITEM }, | |
146 | + { "KILL_ITEM", RF2_KILL_ITEM }, | |
147 | + { "HUMAN", RF2_HUMAN }, | |
148 | + { "QUANTUM", RF2_QUANTUM } | |
161 | 149 | }; |
162 | 150 | |
163 | 151 | /*! |
164 | 152 | * モンスター特性トークンの定義3 / |
165 | 153 | * Monster race flags |
166 | 154 | */ |
167 | -concptr r_info_flags3[NUM_R_FLAGS_3] = { | |
168 | - "ORC", | |
169 | - "TROLL", | |
170 | - "GIANT", | |
171 | - "DRAGON", | |
172 | - "DEMON", | |
173 | - "UNDEAD", | |
174 | - "EVIL", | |
175 | - "ANIMAL", | |
176 | - "AMBERITE", | |
177 | - "GOOD", | |
178 | - "AURA_COLD", | |
179 | - "NONLIVING", | |
180 | - "HURT_LITE", | |
181 | - "HURT_ROCK", | |
182 | - "HURT_FIRE", | |
183 | - "HURT_COLD", | |
184 | - "ANGEL", | |
185 | - "XXX", | |
186 | - "XXX", | |
187 | - "XXX", | |
188 | - "XXX", | |
189 | - "XXX", | |
190 | - "XXX", | |
191 | - "XXX", | |
192 | - "XXX", | |
193 | - "XXX", | |
194 | - "XXX", | |
195 | - "XXX", | |
196 | - "NO_FEAR", | |
197 | - "NO_STUN", | |
198 | - "NO_CONF", | |
199 | - "NO_SLEEP" | |
155 | +const std::unordered_map<std::string_view, race_flags3> r_info_flags3 = { | |
156 | + { "ORC", RF3_ORC }, | |
157 | + { "TROLL", RF3_TROLL }, | |
158 | + { "GIANT", RF3_GIANT }, | |
159 | + { "DRAGON", RF3_DRAGON }, | |
160 | + { "DEMON", RF3_DEMON }, | |
161 | + { "UNDEAD", RF3_UNDEAD }, | |
162 | + { "EVIL", RF3_EVIL }, | |
163 | + { "ANIMAL", RF3_ANIMAL }, | |
164 | + { "AMBERITE", RF3_AMBERITE }, | |
165 | + { "GOOD", RF3_GOOD }, | |
166 | + { "AURA_COLD", RF3_AURA_COLD }, | |
167 | + { "NONLIVING", RF3_NONLIVING }, | |
168 | + { "HURT_LITE", RF3_HURT_LITE }, | |
169 | + { "HURT_ROCK", RF3_HURT_ROCK }, | |
170 | + { "HURT_FIRE", RF3_HURT_FIRE }, | |
171 | + { "HURT_COLD", RF3_HURT_COLD }, | |
172 | + { "ANGEL", RF3_ANGEL }, | |
173 | + { "NO_FEAR", RF3_NO_FEAR }, | |
174 | + { "NO_STUN", RF3_NO_STUN }, | |
175 | + { "NO_CONF", RF3_NO_CONF }, | |
176 | + { "NO_SLEEP", RF3_NO_SLEEP } | |
200 | 177 | }; |
201 | 178 | |
202 | 179 | /*! |
@@ -311,155 +288,109 @@ const std::unordered_map<std::string_view, RF_ABILITY> r_info_ability_flags = { | ||
311 | 288 | * Monster race flags |
312 | 289 | * "GUARDIAN" ... init.c d_infoの FINAL_GUARDIAN_* にて自動指定 |
313 | 290 | */ |
314 | -concptr r_info_flags7[NUM_R_FLAGS_7] = { | |
315 | - "AQUATIC", | |
316 | - "CAN_SWIM", | |
317 | - "CAN_FLY", | |
318 | - "FRIENDLY", | |
319 | - "NAZGUL", | |
320 | - "UNIQUE2", | |
321 | - "RIDING", | |
322 | - "KAGE", | |
323 | - "HAS_LITE_1", | |
324 | - "SELF_LITE_1", | |
325 | - "HAS_LITE_2", | |
326 | - "SELF_LITE_2", | |
327 | - "XXX7X12", | |
328 | - "CHAMELEON", | |
329 | - "XXXX4XXX", | |
330 | - "TANUKI", | |
331 | - "HAS_DARK_1", | |
332 | - "SELF_DARK_1", | |
333 | - "HAS_DARK_2", | |
334 | - "SELF_DARK_2", | |
335 | - "XXX7X20", | |
336 | - "XXX7X21", | |
337 | - "XXX7X22", | |
338 | - "XXX7X23", | |
339 | - "XXX7X24", | |
340 | - "XXX7X25", | |
341 | - "XXX7X26", | |
342 | - "XXX7X27", | |
343 | - "XXX7X28", | |
344 | - "XXX7X29", | |
345 | - "XXX7X30", | |
346 | - "XXX7X31", | |
291 | +const std::unordered_map<std::string_view, race_flags7> r_info_flags7 = { | |
292 | + { "AQUATIC", RF7_AQUATIC }, | |
293 | + { "CAN_SWIM", RF7_CAN_SWIM }, | |
294 | + { "CAN_FLY", RF7_CAN_FLY }, | |
295 | + { "FRIENDLY", RF7_FRIENDLY }, | |
296 | + { "NAZGUL", RF7_NAZGUL }, | |
297 | + { "UNIQUE2", RF7_UNIQUE2 }, | |
298 | + { "RIDING", RF7_RIDING }, | |
299 | + { "KAGE", RF7_KAGE }, | |
300 | + { "HAS_LITE_1", RF7_HAS_LITE_1 }, | |
301 | + { "SELF_LITE_1", RF7_SELF_LITE_1 }, | |
302 | + { "HAS_LITE_2", RF7_HAS_LITE_2 }, | |
303 | + { "SELF_LITE_2", RF7_SELF_LITE_2 }, | |
304 | + { "CHAMELEON", RF7_CHAMELEON }, | |
305 | + { "TANUKI", RF7_TANUKI }, | |
306 | + { "HAS_DARK_1", RF7_HAS_DARK_1 }, | |
307 | + { "SELF_DARK_1", RF7_SELF_DARK_1 }, | |
308 | + { "HAS_DARK_2", RF7_HAS_DARK_2 }, | |
309 | + { "SELF_DARK_2", RF7_SELF_DARK_2 }, | |
347 | 310 | }; |
348 | 311 | |
349 | 312 | /*! |
350 | 313 | * モンスター特性トークンの定義8 / |
351 | 314 | * Monster race flags |
352 | 315 | */ |
353 | -concptr r_info_flags8[NUM_R_FLAGS_8] = { | |
354 | - "WILD_ONLY", | |
355 | - "WILD_TOWN", | |
356 | - "XXX8X02", | |
357 | - "WILD_SHORE", | |
358 | - "WILD_OCEAN", | |
359 | - "WILD_WASTE", | |
360 | - "WILD_WOOD", | |
361 | - "WILD_VOLCANO", | |
362 | - "XXX8X08", | |
363 | - "WILD_MOUNTAIN", | |
364 | - "WILD_GRASS", | |
365 | - "XXX8X11", | |
366 | - "XXX8X12", | |
367 | - "XXX8X13", | |
368 | - "XXX8X14", | |
369 | - "XXX8X15", | |
370 | - "XXX8X16", | |
371 | - "XXX8X17", | |
372 | - "XXX8X18", | |
373 | - "XXX8X19", | |
374 | - "XXX8X20", | |
375 | - "XXX8X21", | |
376 | - "XXX8X22", | |
377 | - "XXX8X23", | |
378 | - "XXX8X24", | |
379 | - "XXX8X25", | |
380 | - "XXX8X26", | |
381 | - "XXX8X27", | |
382 | - "XXX8X28", | |
383 | - "XXX8X29", | |
384 | - "WILD_SWAMP", /* ToDo: Implement Swamp */ | |
385 | - "WILD_ALL", | |
316 | +const std::unordered_map<std::string_view, race_flags8> r_info_flags8 = { | |
317 | + { "WILD_ONLY", RF8_WILD_ONLY }, | |
318 | + { "WILD_TOWN", RF8_WILD_TOWN }, | |
319 | + { "WILD_SHORE", RF8_WILD_SHORE }, | |
320 | + { "WILD_OCEAN", RF8_WILD_OCEAN }, | |
321 | + { "WILD_WASTE", RF8_WILD_WASTE }, | |
322 | + { "WILD_WOOD", RF8_WILD_WOOD }, | |
323 | + { "WILD_VOLCANO", RF8_WILD_VOLCANO }, | |
324 | + { "WILD_MOUNTAIN", RF8_WILD_MOUNTAIN }, | |
325 | + { "WILD_GRASS", RF8_WILD_GRASS }, | |
326 | + { "WILD_SWAMP", RF8_WILD_SWAMP }, | |
327 | + { "WILD_ALL", RF8_WILD_ALL }, | |
386 | 328 | }; |
387 | 329 | |
388 | 330 | /*! |
389 | 331 | * モンスター特性トークンの定義9 / |
390 | 332 | * Monster race flags |
391 | 333 | */ |
392 | -concptr r_info_flags9[NUM_R_FLAGS_9] = { | |
393 | - "DROP_CORPSE", | |
394 | - "DROP_SKELETON", | |
395 | - "EAT_BLIND", | |
396 | - "EAT_CONF", | |
397 | - "EAT_MANA", | |
398 | - "EAT_NEXUS", | |
399 | - "EAT_BLINK", | |
400 | - "EAT_SLEEP", | |
401 | - "EAT_BERSERKER", | |
402 | - "EAT_ACIDIC", | |
403 | - "EAT_SPEED", | |
404 | - "EAT_CURE", | |
405 | - "EAT_FIRE_RES", | |
406 | - "EAT_COLD_RES", | |
407 | - "EAT_ACID_RES", | |
408 | - "EAT_ELEC_RES", | |
409 | - "EAT_POIS_RES", | |
410 | - "EAT_INSANITY", | |
411 | - "EAT_DRAIN_EXP", | |
412 | - "EAT_POISONOUS", | |
413 | - "EAT_GIVE_STR", | |
414 | - "EAT_GIVE_INT", | |
415 | - "EAT_GIVE_WIS", | |
416 | - "EAT_GIVE_DEX", | |
417 | - "EAT_GIVE_CON", | |
418 | - "EAT_GIVE_CHR", | |
419 | - "EAT_LOSE_STR", | |
420 | - "EAT_LOSE_INT", | |
421 | - "EAT_LOSE_WIS", | |
422 | - "EAT_LOSE_DEX", | |
423 | - "EAT_LOSE_CON", | |
424 | - "EAT_LOSE_CHR", | |
425 | - "EAT_DRAIN_MANA", | |
334 | +const std::unordered_map<std::string_view, race_flags9> r_info_flags9 = { | |
335 | + { "DROP_CORPSE", RF9_DROP_CORPSE }, | |
336 | + { "DROP_SKELETON", RF9_DROP_SKELETON }, | |
337 | + { "EAT_BLIND", RF9_EAT_BLIND }, | |
338 | + { "EAT_CONF", RF9_EAT_CONF }, | |
339 | + { "EAT_MANA", RF9_EAT_MANA }, | |
340 | + { "EAT_NEXUS", RF9_EAT_NEXUS }, | |
341 | + // { "EAT_BLINK", RF9_EAT_BLINK }, //<! @note フラグ未定義 | |
342 | + { "EAT_SLEEP", RF9_EAT_SLEEP }, | |
343 | + { "EAT_BERSERKER", RF9_EAT_BERSERKER }, | |
344 | + { "EAT_ACIDIC", RF9_EAT_ACIDIC }, | |
345 | + { "EAT_SPEED", RF9_EAT_SPEED }, | |
346 | + { "EAT_CURE", RF9_EAT_CURE }, | |
347 | + { "EAT_FIRE_RES", RF9_EAT_FIRE_RES }, | |
348 | + { "EAT_COLD_RES", RF9_EAT_COLD_RES }, | |
349 | + { "EAT_ACID_RES", RF9_EAT_ACID_RES }, | |
350 | + { "EAT_ELEC_RES", RF9_EAT_ELEC_RES }, | |
351 | + { "EAT_POIS_RES", RF9_EAT_POIS_RES }, | |
352 | + { "EAT_INSANITY", RF9_EAT_INSANITY }, | |
353 | + { "EAT_DRAIN_EXP", RF9_EAT_DRAIN_EXP }, | |
354 | + { "EAT_POISONOUS", RF9_EAT_POISONOUS }, | |
355 | + { "EAT_GIVE_STR", RF9_EAT_GIVE_STR }, | |
356 | + { "EAT_GIVE_INT", RF9_EAT_GIVE_INT }, | |
357 | + { "EAT_GIVE_WIS", RF9_EAT_GIVE_WIS }, | |
358 | + { "EAT_GIVE_DEX", RF9_EAT_GIVE_DEX }, | |
359 | + { "EAT_GIVE_CON", RF9_EAT_GIVE_CON }, | |
360 | + { "EAT_GIVE_CHR", RF9_EAT_GIVE_CHR }, | |
361 | + { "EAT_LOSE_STR", RF9_EAT_LOSE_STR }, | |
362 | + { "EAT_LOSE_INT", RF9_EAT_LOSE_INT }, | |
363 | + { "EAT_LOSE_WIS", RF9_EAT_LOSE_WIS }, | |
364 | + { "EAT_LOSE_DEX", RF9_EAT_LOSE_DEX }, | |
365 | + { "EAT_LOSE_CON", RF9_EAT_LOSE_CON }, | |
366 | + { "EAT_LOSE_CHR", RF9_EAT_LOSE_CHR }, | |
367 | + { "EAT_DRAIN_MANA", RF9_EAT_DRAIN_MANA }, | |
426 | 368 | }; |
427 | 369 | |
428 | 370 | /*! |
429 | 371 | * モンスター特性トークンの定義R(耐性) / |
430 | 372 | * Monster race flags |
431 | 373 | */ |
432 | -concptr r_info_flagsr[NUM_R_FLAGS_R] = { | |
433 | - "IM_ACID", | |
434 | - "IM_ELEC", | |
435 | - "IM_FIRE", | |
436 | - "IM_COLD", | |
437 | - "IM_POIS", | |
438 | - "RES_LITE", | |
439 | - "RES_DARK", | |
440 | - "RES_NETH", | |
441 | - "RES_WATE", | |
442 | - "RES_PLAS", | |
443 | - "RES_SHAR", | |
444 | - "RES_SOUN", | |
445 | - "RES_CHAO", | |
446 | - "RES_NEXU", | |
447 | - "RES_DISE", | |
448 | - "RES_WALL", | |
449 | - "RES_INER", | |
450 | - "RES_TIME", | |
451 | - "RES_GRAV", | |
452 | - "RES_ALL", | |
453 | - "RES_TELE", | |
454 | - "XXX", | |
455 | - "XXX", | |
456 | - "XXX", | |
457 | - "XXX", | |
458 | - "XXX", | |
459 | - "XXX", | |
460 | - "XXX", | |
461 | - "XXX", | |
462 | - "XXX", | |
463 | - "XXX", | |
464 | - "XXX", | |
374 | +const std::unordered_map<std::string_view, race_flags_resistance> r_info_flagsr = { | |
375 | + { "IM_ACID", RFR_IM_ACID }, | |
376 | + { "IM_ELEC", RFR_IM_ELEC }, | |
377 | + { "IM_FIRE", RFR_IM_FIRE }, | |
378 | + { "IM_COLD", RFR_IM_COLD }, | |
379 | + { "IM_POIS", RFR_IM_POIS }, | |
380 | + { "RES_LITE", RFR_RES_LITE }, | |
381 | + { "RES_DARK", RFR_RES_DARK }, | |
382 | + { "RES_NETH", RFR_RES_NETH }, | |
383 | + { "RES_WATE", RFR_RES_WATE }, | |
384 | + { "RES_PLAS", RFR_RES_PLAS }, | |
385 | + { "RES_SHAR", RFR_RES_SHAR }, | |
386 | + { "RES_SOUN", RFR_RES_SOUN }, | |
387 | + { "RES_CHAO", RFR_RES_CHAO }, | |
388 | + { "RES_NEXU", RFR_RES_NEXU }, | |
389 | + { "RES_DISE", RFR_RES_DISE }, | |
390 | + { "RES_WALL", RFR_RES_WALL }, | |
391 | + { "RES_INER", RFR_RES_INER }, | |
392 | + { "RES_TIME", RFR_RES_TIME }, | |
393 | + { "RES_GRAV", RFR_RES_GRAV }, | |
394 | + { "RES_ALL", RFR_RES_ALL }, | |
395 | + { "RES_TELE", RFR_RES_TELE }, | |
465 | 396 | }; |
@@ -2,31 +2,28 @@ | ||
2 | 2 | |
3 | 3 | #include "monster-attack/monster-attack-effect.h" |
4 | 4 | #include "monster-attack/monster-attack-types.h" |
5 | +#include "monster-race/race-ability-flags.h" | |
6 | +#include "monster-race/race-flags1.h" | |
7 | +#include "monster-race/race-flags2.h" | |
8 | +#include "monster-race/race-flags3.h" | |
9 | +#include "monster-race/race-flags7.h" | |
10 | +#include "monster-race/race-flags8.h" | |
11 | +#include "monster-race/race-flags9.h" | |
12 | +#include "monster-race/race-flags-resistance.h" | |
5 | 13 | #include "system/angband.h" |
6 | 14 | |
7 | 15 | #include <string_view> |
8 | 16 | #include <unordered_map> |
9 | 17 | |
10 | -#define NUM_R_FLAGS_1 32 | |
11 | -#define NUM_R_FLAGS_2 32 | |
12 | -#define NUM_R_FLAGS_3 32 | |
13 | -#define NUM_R_FLAGS_4 32 | |
14 | -#define NUM_R_ABILITY_FLAGS_1 32 | |
15 | -#define NUM_R_ABILITY_FLAGS_2 32 | |
16 | -#define NUM_R_FLAGS_7 32 | |
17 | -#define NUM_R_FLAGS_8 32 | |
18 | -#define NUM_R_FLAGS_9 33 | |
19 | -#define NUM_R_FLAGS_R 32 | |
20 | - | |
21 | 18 | enum class RF_ABILITY; |
22 | 19 | |
23 | -extern concptr r_info_blow_method[NB_RBM_TYPE + 1]; | |
24 | -extern concptr r_info_blow_effect[NB_RBE_TYPE + 1]; | |
25 | -extern concptr r_info_flags1[NUM_R_FLAGS_1]; | |
26 | -extern concptr r_info_flags2[NUM_R_FLAGS_2]; | |
27 | -extern concptr r_info_flags3[NUM_R_FLAGS_3]; | |
20 | +extern const std::unordered_map<std::string_view, rbm_type> r_info_blow_method; | |
21 | +extern const std::unordered_map<std::string_view, rbe_type> r_info_blow_effect; | |
22 | +extern const std::unordered_map<std::string_view, race_flags1> r_info_flags1; | |
23 | +extern const std::unordered_map<std::string_view, race_flags2> r_info_flags2; | |
24 | +extern const std::unordered_map<std::string_view, race_flags3> r_info_flags3; | |
28 | 25 | extern const std::unordered_map<std::string_view, RF_ABILITY> r_info_ability_flags; |
29 | -extern concptr r_info_flags7[NUM_R_FLAGS_7]; | |
30 | -extern concptr r_info_flags8[NUM_R_FLAGS_8]; | |
31 | -extern concptr r_info_flags9[NUM_R_FLAGS_9]; | |
32 | -extern concptr r_info_flagsr[NUM_R_FLAGS_R]; | |
26 | +extern const std::unordered_map<std::string_view, race_flags7> r_info_flags7; | |
27 | +extern const std::unordered_map<std::string_view, race_flags8> r_info_flags8; | |
28 | +extern const std::unordered_map<std::string_view, race_flags9> r_info_flags9; | |
29 | +extern const std::unordered_map<std::string_view, race_flags_resistance> r_info_flagsr; |
@@ -1,4 +1,5 @@ | ||
1 | 1 | #include "info-reader/race-reader.h" |
2 | +#include "info-reader/info-reader-util.h" | |
2 | 3 | #include "info-reader/parse-error-types.h" |
3 | 4 | #include "info-reader/race-info-tokens-table.h" |
4 | 5 | #include "main/angband-headers.h" |
@@ -14,33 +15,33 @@ | ||
14 | 15 | * Grab one (basic) flag in a monster_race from a textual string |
15 | 16 | * @param r_ptr 保管先のモンスター種族構造体参照ポインタ |
16 | 17 | * @param what 参照元の文字列ポインタ |
17 | - * @return エラーコード | |
18 | + * @return 見つけたらtrue | |
18 | 19 | */ |
19 | -static errr grab_one_basic_flag(monster_race *r_ptr, concptr what) | |
20 | +static bool grab_one_basic_flag(monster_race *r_ptr, std::string_view what) | |
20 | 21 | { |
21 | - if (grab_one_flag(&r_ptr->flags1, r_info_flags1, what) == 0) | |
22 | - return PARSE_ERROR_NONE; | |
22 | + if (info_grab_one_flag(r_ptr->flags1, r_info_flags1, what)) | |
23 | + return true; | |
23 | 24 | |
24 | - if (grab_one_flag(&r_ptr->flags2, r_info_flags2, what) == 0) | |
25 | - return PARSE_ERROR_NONE; | |
25 | + if (info_grab_one_flag(r_ptr->flags2, r_info_flags2, what)) | |
26 | + return true; | |
26 | 27 | |
27 | - if (grab_one_flag(&r_ptr->flags3, r_info_flags3, what) == 0) | |
28 | - return PARSE_ERROR_NONE; | |
28 | + if (info_grab_one_flag(r_ptr->flags3, r_info_flags3, what)) | |
29 | + return true; | |
29 | 30 | |
30 | - if (grab_one_flag(&r_ptr->flags7, r_info_flags7, what) == 0) | |
31 | - return PARSE_ERROR_NONE; | |
31 | + if (info_grab_one_flag(r_ptr->flags7, r_info_flags7, what)) | |
32 | + return true; | |
32 | 33 | |
33 | - if (grab_one_flag(&r_ptr->flags8, r_info_flags8, what) == 0) | |
34 | - return PARSE_ERROR_NONE; | |
34 | + if (info_grab_one_flag(r_ptr->flags8, r_info_flags8, what)) | |
35 | + return true; | |
35 | 36 | |
36 | - if (grab_one_flag(&r_ptr->flags9, r_info_flags9, what) == 0) | |
37 | - return PARSE_ERROR_NONE; | |
37 | + if (info_grab_one_flag(r_ptr->flags9, r_info_flags9, what)) | |
38 | + return true; | |
38 | 39 | |
39 | - if (grab_one_flag(&r_ptr->flagsr, r_info_flagsr, what) == 0) | |
40 | - return PARSE_ERROR_NONE; | |
40 | + if (info_grab_one_flag(r_ptr->flagsr, r_info_flagsr, what)) | |
41 | + return true; | |
41 | 42 | |
42 | - msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what); | |
43 | - return PARSE_ERROR_GENERIC; | |
43 | + msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data()); | |
44 | + return false; | |
44 | 45 | } |
45 | 46 | |
46 | 47 | /*! |
@@ -48,15 +49,15 @@ static errr grab_one_basic_flag(monster_race *r_ptr, concptr what) | ||
48 | 49 | * Grab one (spell) flag in a monster_race from a textual string |
49 | 50 | * @param r_ptr 保管先のモンスター種族構造体参照ポインタ |
50 | 51 | * @param what 参照元の文字列ポインタ |
51 | - * @return エラーコード | |
52 | + * @return 見つけたらtrue | |
52 | 53 | */ |
53 | -static errr grab_one_spell_flag(monster_race *r_ptr, concptr what) | |
54 | +static bool grab_one_spell_flag(monster_race *r_ptr, std::string_view what) | |
54 | 55 | { |
55 | 56 | if (EnumClassFlagGroup<RF_ABILITY>::grab_one_flag(r_ptr->ability_flags, r_info_ability_flags, what)) |
56 | - return PARSE_ERROR_NONE; | |
57 | + return true; | |
57 | 58 | |
58 | - msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what); | |
59 | - return PARSE_ERROR_GENERIC; | |
59 | + msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data()); | |
60 | + return false; | |
60 | 61 | } |
61 | 62 | |
62 | 63 | /*! |
@@ -66,223 +67,205 @@ static errr grab_one_spell_flag(monster_race *r_ptr, concptr what) | ||
66 | 67 | * @param head ヘッダ構造体 |
67 | 68 | * @return エラーコード |
68 | 69 | */ |
69 | -errr parse_r_info(char *buf, angband_header *head) | |
70 | +errr parse_r_info(std::string_view buf, angband_header *head) | |
70 | 71 | { |
71 | 72 | static monster_race *r_ptr = NULL; |
72 | - char *s, *t; | |
73 | - if (buf[0] == 'N') { | |
74 | - s = angband_strchr(buf + 2, ':'); | |
75 | - if (!s) | |
76 | - return PARSE_ERROR_GENERIC; | |
73 | + const auto &tokens = str_split(buf, ':', true, 10); | |
77 | 74 | |
78 | - *s++ = '\0'; | |
79 | -#ifdef JP | |
80 | - if (!*s) | |
81 | - return PARSE_ERROR_GENERIC; | |
82 | -#endif | |
75 | + if (tokens[0] == "N") { | |
76 | + // N:index:name_ja | |
77 | + if (tokens.size() < 3 || tokens[1].size() == 0) | |
78 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
83 | 79 | |
84 | - int i = atoi(buf + 2); | |
80 | + auto i = std::stoi(tokens[1]); | |
85 | 81 | if (i < error_idx) |
86 | 82 | return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; |
87 | - | |
88 | 83 | if (i >= head->info_num) |
89 | - return PARSE_ERROR_OBSOLETE_FILE; | |
84 | + return PARSE_ERROR_OUT_OF_BOUNDS; | |
90 | 85 | |
91 | 86 | error_idx = i; |
92 | 87 | r_ptr = &r_info[i]; |
93 | 88 | #ifdef JP |
94 | - r_ptr->name = std::string(s); | |
89 | + r_ptr->name = tokens[2]; | |
95 | 90 | #endif |
96 | - } else if (!r_ptr) { | |
91 | + } else if (!r_ptr) | |
97 | 92 | return PARSE_ERROR_MISSING_RECORD_HEADER; |
98 | - } | |
99 | -#ifdef JP | |
100 | - /* 英語名を読むルーチンを追加 */ | |
101 | - /* 'E' から始まる行は英語名 */ | |
102 | - else if (buf[0] == 'E') { | |
103 | - r_ptr->E_name = std::string(buf + 2); | |
104 | - } | |
105 | -#else | |
106 | - else if (buf[0] == 'E') { | |
107 | - r_ptr->name = std::string(buf + 2); | |
108 | - } | |
93 | + else if (tokens[0] == "E") { | |
94 | + // E:name_en | |
95 | +#ifndef JP | |
96 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
97 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
98 | + r_ptr->name = tokens[1]; | |
109 | 99 | #endif |
110 | - else if (buf[0] == 'D') { | |
100 | + } else if (tokens[0] == "D") { | |
101 | + // D:text_ja | |
102 | + // D:$text_en | |
103 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
104 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
111 | 105 | #ifdef JP |
112 | - if (buf[2] == '$') | |
106 | + if (tokens[1][0] == '$') | |
113 | 107 | return PARSE_ERROR_NONE; |
114 | - | |
115 | - s = buf + 2; | |
108 | + r_ptr->text.append(buf.substr(2)); | |
116 | 109 | #else |
117 | - if (buf[2] != '$') | |
110 | + if (tokens[1][0] != '$') | |
118 | 111 | return PARSE_ERROR_NONE; |
119 | - s = buf + 3; | |
112 | + r_ptr->text.append(buf.substr(3)); | |
120 | 113 | #endif |
121 | - r_ptr->text.append(s); | |
122 | - } else if (buf[0] == 'G') { | |
123 | - if ((buf[1] != ':') || !buf[2] || (buf[3] != ':') || !buf[4]) | |
124 | - return PARSE_ERROR_GENERIC; | |
114 | + } else if (tokens[0] == "G") { | |
115 | + // G:color:symbol | |
116 | + if (tokens.size() < 3 || tokens[1].size() == 0 || tokens[2].size() == 0) | |
117 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
125 | 118 | |
126 | - char sym = buf[2]; | |
127 | - byte tmp = color_char_to_attr(buf[4]); | |
128 | - if (tmp > 127) | |
119 | + auto a = color_char_to_attr(tokens[2][0]); | |
120 | + if (a > 127) | |
129 | 121 | return PARSE_ERROR_GENERIC; |
130 | 122 | |
131 | - r_ptr->d_char = sym; | |
132 | - r_ptr->d_attr = tmp; | |
133 | - } else if (buf[0] == 'I') { | |
134 | - int spd, hp1, hp2, aaf, ac, slp; | |
135 | - if (sscanf(buf + 2, "%d:%dd%d:%d:%d:%d", &spd, &hp1, &hp2, &aaf, &ac, &slp) != 6) | |
136 | - return PARSE_ERROR_GENERIC; | |
123 | + r_ptr->d_attr = a; | |
124 | + r_ptr->d_char = tokens[1][0]; | |
125 | + } else if (tokens[0] == "I") { | |
126 | + // G:speed:hp_dice:affect_range:ac:sleep_degree | |
127 | + if (tokens.size() < 6) | |
128 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
137 | 129 | |
138 | - r_ptr->speed = (SPEED)spd; | |
139 | - r_ptr->hdice = (DICE_NUMBER)MAX(hp1, 1); | |
140 | - r_ptr->hside = (DICE_SID)MAX(hp2, 1); | |
141 | - r_ptr->aaf = (POSITION)aaf; | |
142 | - r_ptr->ac = (ARMOUR_CLASS)ac; | |
143 | - r_ptr->sleep = (SLEEP_DEGREE)slp; | |
144 | - } else if (buf[0] == 'W') { | |
145 | - int lev, rar, pad; | |
146 | - long exp; | |
147 | - long nextexp; | |
148 | - int nextmon; | |
149 | - if (sscanf(buf + 2, "%d:%d:%d:%ld:%ld:%d", &lev, &rar, &pad, &exp, &nextexp, &nextmon) != 6) | |
130 | + const auto &dice = str_split(tokens[2], 'd', false, 2); | |
131 | + if (dice.size() < 2) | |
150 | 132 | return PARSE_ERROR_GENERIC; |
151 | 133 | |
152 | - r_ptr->level = (DEPTH)lev; | |
153 | - r_ptr->rarity = (RARITY)rar; | |
154 | - r_ptr->extra = (BIT_FLAGS16)pad; | |
155 | - r_ptr->mexp = (EXP)exp; | |
156 | - r_ptr->next_exp = (EXP)nextexp; | |
157 | - r_ptr->next_r_idx = (MONRACE_IDX)nextmon; | |
158 | - } else if (buf[0] == 'R') { | |
159 | - int id, ds, dd; | |
160 | - int i = 0; | |
161 | - for (; i < A_MAX; i++) | |
134 | + info_set_value(r_ptr->speed, tokens[1]); | |
135 | + info_set_value(r_ptr->hdice, dice[0]); | |
136 | + info_set_value(r_ptr->hside, dice.size() == 1 ? "1" : dice[1]); | |
137 | + info_set_value(r_ptr->aaf, tokens[3]); | |
138 | + info_set_value(r_ptr->ac, tokens[4]); | |
139 | + info_set_value(r_ptr->sleep, tokens[5]); | |
140 | + } else if (tokens[0] == "W") { | |
141 | + // W:level:ratity:extra:exp:next_exp:next_id | |
142 | + if (tokens.size() < 5 || tokens.size() == 6) | |
143 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
144 | + | |
145 | + info_set_value(r_ptr->level, tokens[1]); | |
146 | + info_set_value(r_ptr->rarity, tokens[2]); | |
147 | + info_set_value(r_ptr->extra, tokens[3]); | |
148 | + info_set_value(r_ptr->mexp, tokens[4]); | |
149 | + | |
150 | + if (tokens.size() < 6) | |
151 | + return PARSE_ERROR_NONE; | |
152 | + | |
153 | + info_set_value(r_ptr->next_exp, tokens[5]); | |
154 | + info_set_value(r_ptr->next_r_idx, tokens[6]); | |
155 | + } else if (tokens[0] == "R") { | |
156 | + // R:reinforcer_idx:number_dice | |
157 | + size_t i = 0; | |
158 | + for (; i < A_MAX; i++) { | |
162 | 159 | if (r_ptr->reinforce_id[i] == 0) |
163 | 160 | break; |
161 | + } | |
164 | 162 | |
165 | - if ((i == 6) || (sscanf(buf + 2, "%d:%dd%d", &id, &dd, &ds) != 3)) | |
163 | + if (i >= 6) | |
166 | 164 | return PARSE_ERROR_GENERIC; |
167 | 165 | |
168 | - r_ptr->reinforce_id[i] = (MONRACE_IDX)id; | |
169 | - r_ptr->reinforce_dd[i] = (DICE_NUMBER)dd; | |
170 | - r_ptr->reinforce_ds[i] = (DICE_SID)ds; | |
171 | - } else if (buf[0] == 'B') { | |
172 | - int n1, n2; | |
173 | - int i = 0; | |
174 | - for (i = 0; i < 4; i++) | |
166 | + if (tokens.size() < 3) | |
167 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
168 | + if (tokens[1].size() == 0 || tokens[2].size() == 0) | |
169 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
170 | + | |
171 | + const auto &dice = str_split(tokens[2], 'd', false, 2); | |
172 | + info_set_value(r_ptr->reinforce_id[i], tokens[1]); | |
173 | + info_set_value(r_ptr->reinforce_dd[i], dice[0]); | |
174 | + info_set_value(r_ptr->reinforce_ds[i], dice[1]); | |
175 | + } else if (tokens[0] == "B") { | |
176 | + // B:blow_type:blow_effect:dice | |
177 | + size_t i = 0; | |
178 | + for (; i < 4; i++) { | |
175 | 179 | if (!r_ptr->blow[i].method) |
176 | 180 | break; |
177 | - | |
178 | - if (i == 4) | |
179 | - return PARSE_ERROR_GENERIC; | |
180 | - | |
181 | - /* loop */ | |
182 | - for (s = t = buf + 2; *t && (*t != ':'); t++) | |
183 | - ; | |
184 | - | |
185 | - if (*t == ':') | |
186 | - *t++ = '\0'; | |
187 | - | |
188 | - for (n1 = 0; r_info_blow_method[n1]; n1++) { | |
189 | - if (streq(s, r_info_blow_method[n1])) | |
190 | - break; | |
191 | 181 | } |
192 | 182 | |
193 | - if (!r_info_blow_method[n1]) | |
183 | + if (i >= 4) | |
194 | 184 | return PARSE_ERROR_GENERIC; |
195 | 185 | |
196 | - /* loop */ | |
197 | - for (s = t; *t && (*t != ':'); t++) | |
198 | - ; | |
186 | + if (tokens.size() < 3) | |
187 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
188 | + if (tokens[1].size() == 0 || tokens[2].size() == 0) | |
189 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
199 | 190 | |
200 | - if (*t == ':') | |
201 | - *t++ = '\0'; | |
191 | + auto rbm = r_info_blow_method.find(tokens[1]); | |
192 | + if (rbm == r_info_blow_method.end()) | |
193 | + return PARSE_ERROR_INVALID_FLAG; | |
202 | 194 | |
203 | - for (n2 = 0; r_info_blow_effect[n2]; n2++) { | |
204 | - if (streq(s, r_info_blow_effect[n2])) | |
205 | - break; | |
206 | - } | |
195 | + auto rbe = r_info_blow_effect.find(tokens[2]); | |
196 | + if (rbe == r_info_blow_effect.end()) | |
197 | + return PARSE_ERROR_INVALID_FLAG; | |
207 | 198 | |
208 | - if (!r_info_blow_effect[n2]) | |
209 | - return PARSE_ERROR_GENERIC; | |
199 | + r_ptr->blow[i].method = rbm->second; | |
200 | + r_ptr->blow[i].effect = rbe->second; | |
210 | 201 | |
211 | - /* loop */ | |
212 | - for (s = t; *t && (*t != 'd'); t++) | |
213 | - ; | |
214 | - | |
215 | - if (*t == 'd') | |
216 | - *t++ = '\0'; | |
217 | - | |
218 | - r_ptr->blow[i].method = (rbm_type)n1; | |
219 | - r_ptr->blow[i].effect = (rbe_type)n2; | |
220 | - r_ptr->blow[i].d_dice = atoi(s); | |
221 | - r_ptr->blow[i].d_side = atoi(t); | |
222 | - } else if (buf[0] == 'F') { | |
223 | - for (s = buf + 2; *s;) { | |
224 | - /* loop */ | |
225 | - for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) | |
226 | - ; | |
227 | - | |
228 | - if (*t) { | |
229 | - *t++ = '\0'; | |
230 | - while (*t == ' ' || *t == '|') | |
231 | - t++; | |
232 | - } | |
202 | + if (tokens.size() < 4) | |
203 | + return PARSE_ERROR_NONE; | |
233 | 204 | |
234 | - if (0 != grab_one_basic_flag(r_ptr, s)) | |
235 | - return PARSE_ERROR_INVALID_FLAG; | |
205 | + const auto &dice = str_split(tokens[3], 'd', false, 2); | |
206 | + info_set_value(r_ptr->blow[i].d_dice, dice[0]); | |
207 | + info_set_value(r_ptr->blow[i].d_side, dice[1]); | |
208 | + } else if (tokens[0] == "F") { | |
209 | + // F:flags | |
210 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
211 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
212 | + | |
213 | + const auto &flags = str_split(tokens[1], '|', true, 10); | |
214 | + for (const auto &f : flags) { | |
215 | + if (f.size() == 0) | |
216 | + continue; | |
236 | 217 | |
237 | - s = t; | |
218 | + if (!grab_one_basic_flag(r_ptr, f)) | |
219 | + return PARSE_ERROR_INVALID_FLAG; | |
238 | 220 | } |
239 | - } else if (buf[0] == 'S') { | |
240 | - for (s = buf + 2; *s;) { | |
241 | - | |
242 | - /* loop */ | |
243 | - for (t = s; *t && (*t != ' ') && (*t != '|'); ++t) | |
244 | - ; | |
245 | - | |
246 | - if (*t) { | |
247 | - *t++ = '\0'; | |
248 | - while ((*t == ' ') || (*t == '|')) | |
249 | - t++; | |
250 | - } | |
221 | + } else if (tokens[0] == "S") { | |
222 | + // S:flags | |
223 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
224 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
225 | + | |
226 | + const auto &flags = str_split(tokens[1], '|', true, 10); | |
227 | + for (const auto &f : flags) { | |
228 | + if (f.size() == 0) | |
229 | + continue; | |
251 | 230 | |
252 | - int i; | |
253 | - if (1 == sscanf(s, "1_IN_%d", &i)) { | |
231 | + const auto &s_tokens = str_split(f, '_', false, 3); | |
232 | + if (s_tokens.size() == 3 && s_tokens[1] == "IN") { | |
233 | + if (s_tokens[0] != "1") | |
234 | + return PARSE_ERROR_GENERIC; | |
235 | + RARITY i; | |
236 | + info_set_value(i, s_tokens[2]); | |
254 | 237 | r_ptr->freq_spell = 100 / i; |
255 | - s = t; | |
256 | - continue; | |
238 | + return PARSE_ERROR_NONE; | |
257 | 239 | } |
258 | 240 | |
259 | - if (grab_one_spell_flag(r_ptr, s) != PARSE_ERROR_NONE) | |
241 | + if (!grab_one_spell_flag(r_ptr, f)) | |
260 | 242 | return PARSE_ERROR_INVALID_FLAG; |
261 | - | |
262 | - s = t; | |
263 | 243 | } |
264 | - } else if (buf[0] == 'A') { | |
265 | - int id, per, rarity; | |
266 | - int i = 0; | |
267 | - for (i = 0; i < 4; i++) | |
244 | + | |
245 | + } else if (tokens[0] == "A") { | |
246 | + // A:artifact_idx:rarity:percent | |
247 | + size_t i = 0; | |
248 | + for (; i < 4; i++) { | |
268 | 249 | if (!r_ptr->artifact_id[i]) |
269 | 250 | break; |
270 | - | |
271 | - if ((i == 4) || (sscanf(buf + 2, "%d:%d:%d", &id, &rarity, &per) != 3)) | |
251 | + } | |
252 | + if (i >= 4) | |
272 | 253 | return PARSE_ERROR_GENERIC; |
273 | 254 | |
274 | - r_ptr->artifact_id[i] = (ARTIFACT_IDX)id; | |
275 | - r_ptr->artifact_rarity[i] = (RARITY)rarity; | |
276 | - r_ptr->artifact_percent[i] = (PERCENTAGE)per; | |
277 | - } else if (buf[0] == 'V') { | |
278 | - int val; | |
279 | - if (sscanf(buf + 2, "%d", &val) != 3) | |
280 | - return 1; | |
255 | + if (tokens.size() < 4) | |
256 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
257 | + | |
258 | + info_set_value(r_ptr->artifact_id[i], tokens[1]); | |
259 | + info_set_value(r_ptr->artifact_rarity[i], tokens[2]); | |
260 | + info_set_value(r_ptr->artifact_percent[i], tokens[3]); | |
261 | + } else if (tokens[0] == "V") { | |
262 | + // V:arena_odds | |
263 | + if (tokens.size() < 2) | |
264 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
281 | 265 | |
282 | - r_ptr->arena_ratio = (PERCENTAGE)val; | |
283 | - } else { | |
266 | + info_set_value(r_ptr->arena_ratio, tokens[1]); | |
267 | + } else | |
284 | 268 | return PARSE_ERROR_UNDEFINED_DIRECTIVE; |
285 | - } | |
286 | 269 | |
287 | 270 | return PARSE_ERROR_NONE; |
288 | 271 | } |
@@ -1,6 +1,7 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | -#include "info-reader/info-reader-util.h" | |
4 | 3 | #include "system/angband.h" |
4 | +#include <string_view> | |
5 | 5 | |
6 | -errr parse_r_info(char *buf, angband_header *head); | |
6 | +struct angband_header; | |
7 | +errr parse_r_info(std::string_view buf, angband_header *head); |
@@ -1,6 +1,20 @@ | ||
1 | 1 | #include "info-reader/skill-reader.h" |
2 | +#include "info-reader/info-reader-util.h" | |
3 | +#include "info-reader/parse-error-types.h" | |
2 | 4 | #include "main/angband-headers.h" |
5 | +#include "object/tval-types.h" | |
3 | 6 | #include "player/player-skill.h" |
7 | +#include "util/string-processor.h" | |
8 | + | |
9 | +namespace { | |
10 | +const std::unordered_map<int, int> level_to_exp = { | |
11 | + { EXP_LEVEL_UNSKILLED, WEAPON_EXP_UNSKILLED }, | |
12 | + { EXP_LEVEL_BEGINNER, WEAPON_EXP_BEGINNER }, | |
13 | + { EXP_LEVEL_SKILLED, WEAPON_EXP_SKILLED }, | |
14 | + { EXP_LEVEL_EXPERT, WEAPON_EXP_EXPERT }, | |
15 | + { EXP_LEVEL_MASTER, WEAPON_EXP_MASTER }, | |
16 | +}; | |
17 | +} | |
4 | 18 | |
5 | 19 | /*! |
6 | 20 | * @brief 職業技能情報(s_info)のパース関数 / |
@@ -9,44 +23,62 @@ | ||
9 | 23 | * @param head ヘッダ構造体 |
10 | 24 | * @return エラーコード |
11 | 25 | */ |
12 | -errr parse_s_info(char *buf, angband_header *head) | |
26 | +errr parse_s_info(std::string_view buf, angband_header *head) | |
13 | 27 | { |
14 | 28 | static skill_table *s_ptr = NULL; |
15 | - if (buf[0] == 'N') { | |
16 | - int i = atoi(buf + 2); | |
17 | - if (i <= error_idx) | |
18 | - return 4; | |
29 | + const auto &tokens = str_split(buf, ':', false, 5); | |
30 | + | |
31 | + if (tokens[0] == "N") { | |
32 | + // N:class-index | |
33 | + if (tokens.size() < 2 && tokens[1].size() == 0) | |
34 | + return PARSE_ERROR_GENERIC; | |
35 | + | |
36 | + auto i = std::stoi(tokens[1]); | |
37 | + if (i < error_idx) | |
38 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
19 | 39 | if (i >= head->info_num) |
20 | - return 2; | |
40 | + return PARSE_ERROR_OUT_OF_BOUNDS; | |
21 | 41 | |
22 | 42 | error_idx = i; |
23 | 43 | s_ptr = &s_info[i]; |
24 | - } else if (!s_ptr) { | |
25 | - return 3; | |
26 | - } else if (buf[0] == 'W') { | |
44 | + } else if (!s_ptr) | |
45 | + return PARSE_ERROR_MISSING_RECORD_HEADER; | |
46 | + else if(tokens[0] == "W") { | |
47 | + if (tokens.size() < 5) | |
48 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
49 | + | |
27 | 50 | int tval, sval, start, max; |
28 | - const s16b exp_conv_table[] = { WEAPON_EXP_UNSKILLED, WEAPON_EXP_BEGINNER, WEAPON_EXP_SKILLED, WEAPON_EXP_EXPERT, WEAPON_EXP_MASTER }; | |
51 | + info_set_value(tval, tokens[1]); | |
52 | + info_set_value(sval, tokens[2]); | |
53 | + info_set_value(start, tokens[3]); | |
54 | + info_set_value(max, tokens[4]); | |
55 | + | |
56 | + auto start_exp = level_to_exp.find(start); | |
57 | + if (start_exp == level_to_exp.end()) | |
58 | + return PARSE_ERROR_INVALID_FLAG; | |
29 | 59 | |
30 | - if (4 != sscanf(buf + 2, "%d:%d:%d:%d", &tval, &sval, &start, &max)) | |
31 | - return 1; | |
60 | + auto max_exp = level_to_exp.find(max); | |
61 | + if (max_exp == level_to_exp.end()) | |
62 | + return PARSE_ERROR_INVALID_FLAG; | |
32 | 63 | |
33 | - if (start < EXP_LEVEL_UNSKILLED || start > EXP_LEVEL_MASTER || max < EXP_LEVEL_UNSKILLED || max > EXP_LEVEL_MASTER) | |
34 | - return 8; | |
64 | + s_ptr->w_start[tval][sval] = (SUB_EXP)start_exp->second; | |
65 | + s_ptr->w_max[tval][sval] = (SUB_EXP)max_exp->second; | |
66 | + } else if (tokens[0] == "S") { | |
67 | + if (tokens.size() < 4) | |
68 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
35 | 69 | |
36 | - s_ptr->w_start[tval][sval] = exp_conv_table[start]; | |
37 | - s_ptr->w_max[tval][sval] = exp_conv_table[max]; | |
38 | - } else if (buf[0] == 'S') { | |
39 | 70 | int num, start, max; |
40 | - if (3 != sscanf(buf + 2, "%d:%d:%d", &num, &start, &max)) | |
41 | - return 1; | |
71 | + info_set_value(num, tokens[1]); | |
72 | + info_set_value(start, tokens[2]); | |
73 | + info_set_value(max, tokens[3]); | |
42 | 74 | |
43 | - if (start < WEAPON_EXP_UNSKILLED || start > WEAPON_EXP_MASTER || max < WEAPON_EXP_UNSKILLED || max > WEAPON_EXP_MASTER) | |
44 | - return 8; | |
75 | + if (start < WEAPON_EXP_UNSKILLED || start > WEAPON_EXP_MASTER || max < WEAPON_EXP_UNSKILLED || max > WEAPON_EXP_MASTER || start > max) | |
76 | + return PARSE_ERROR_INVALID_FLAG; | |
45 | 77 | |
46 | 78 | s_ptr->s_start[num] = (SUB_EXP)start; |
47 | 79 | s_ptr->s_max[num] = (SUB_EXP)max; |
48 | 80 | } else |
49 | - return 6; | |
81 | + return PARSE_ERROR_UNDEFINED_DIRECTIVE; | |
50 | 82 | |
51 | - return 0; | |
83 | + return PARSE_ERROR_NONE; | |
52 | 84 | } |
@@ -1,6 +1,7 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | 3 | #include "system/angband.h" |
4 | -#include "info-reader/info-reader-util.h" | |
4 | +#include <string_view> | |
5 | 5 | |
6 | -errr parse_s_info(char *buf, angband_header *head); | |
6 | +struct angband_header; | |
7 | +errr parse_s_info(std::string_view buf, angband_header *head); |
@@ -1,8 +1,9 @@ | ||
1 | 1 | #include "info-reader/vault-reader.h" |
2 | 2 | #include "main/angband-headers.h" |
3 | +#include "info-reader/info-reader-util.h" | |
4 | +#include "info-reader/parse-error-types.h" | |
3 | 5 | #include "room/rooms-vault.h" |
4 | 6 | #include "util/string-processor.h" |
5 | -#include <string> | |
6 | 7 | |
7 | 8 | /*! |
8 | 9 | * @brief Vault情報(v_info)のパース関数 / |
@@ -11,44 +12,46 @@ | ||
11 | 12 | * @param head ヘッダ構造体 |
12 | 13 | * @return エラーコード |
13 | 14 | */ |
14 | -errr parse_v_info(char *buf, angband_header *head) | |
15 | +errr parse_v_info(std::string_view buf, angband_header *head) | |
15 | 16 | { |
16 | - char *s; | |
17 | 17 | static vault_type *v_ptr = NULL; |
18 | + const auto &tokens = str_split(buf, ':', false, 5); | |
18 | 19 | |
19 | - if (buf[0] == 'N') { | |
20 | - s = angband_strchr(buf + 2, ':'); | |
21 | - if (!s) | |
22 | - return 1; | |
20 | + if (tokens[0] == "N") { | |
21 | + // N:index:name | |
22 | + if (tokens.size() < 3) | |
23 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
24 | + if (tokens[1].size() == 0 || tokens[2].size() == 0) | |
25 | + return PARSE_ERROR_GENERIC; | |
23 | 26 | |
24 | - *s++ = '\0'; | |
25 | - if (!*s) | |
26 | - return 1; | |
27 | - | |
28 | - int i = atoi(buf + 2); | |
29 | - if (i <= error_idx) | |
30 | - return 4; | |
27 | + auto i = std::stoi(tokens[1]); | |
28 | + if (i < error_idx) | |
29 | + return PARSE_ERROR_NON_SEQUENTIAL_RECORDS; | |
31 | 30 | if (i >= head->info_num) |
32 | - return 2; | |
31 | + return PARSE_ERROR_OUT_OF_BOUNDS; | |
33 | 32 | |
34 | 33 | error_idx = i; |
35 | 34 | v_ptr = &v_info[i]; |
36 | - v_ptr->name = std::string(s); | |
35 | + v_ptr->name = std::string(tokens[2]); | |
37 | 36 | } else if (!v_ptr) |
38 | - return 3; | |
39 | - else if (buf[0] == 'D') { | |
40 | - v_ptr->text.append(buf + 2); | |
41 | - } else if (buf[0] == 'X') { | |
42 | - EFFECT_ID typ, rat, hgt, wid; | |
43 | - if (4 != sscanf(buf + 2, "%d:%d:%d:%d", &typ, &rat, &hgt, &wid)) | |
44 | - return 1; | |
37 | + return PARSE_ERROR_MISSING_RECORD_HEADER; | |
38 | + else if (tokens[0] == "D") { | |
39 | + // D:MapText | |
40 | + if (tokens.size() < 2 || tokens[1].size() == 0) | |
41 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
42 | + | |
43 | + v_ptr->text.append(buf.substr(2)); | |
44 | + } else if (tokens[0] == "X") { | |
45 | + // X:type:rate:height:width | |
46 | + if (tokens.size() < 5) | |
47 | + return PARSE_ERROR_TOO_FEW_ARGUMENTS; | |
45 | 48 | |
46 | - v_ptr->typ = (ROOM_IDX)typ; | |
47 | - v_ptr->rat = (PROB)rat; | |
48 | - v_ptr->hgt = (POSITION)hgt; | |
49 | - v_ptr->wid = (POSITION)wid; | |
49 | + info_set_value(v_ptr->typ, tokens[1]); | |
50 | + info_set_value(v_ptr->rat, tokens[2]); | |
51 | + info_set_value(v_ptr->hgt, tokens[3]); | |
52 | + info_set_value(v_ptr->wid, tokens[4]); | |
50 | 53 | } else |
51 | - return 6; | |
54 | + return PARSE_ERROR_UNDEFINED_DIRECTIVE; | |
52 | 55 | |
53 | - return 0; | |
56 | + return PARSE_ERROR_NONE; | |
54 | 57 | } |
@@ -1,6 +1,7 @@ | ||
1 | 1 | #pragma once |
2 | 2 | |
3 | 3 | #include "system/angband.h" |
4 | -#include "info-reader/info-reader-util.h" | |
4 | +#include <string_view> | |
5 | 5 | |
6 | -errr parse_v_info(char *buf, angband_header *head); | |
6 | +struct angband_header; | |
7 | +errr parse_v_info(std::string_view buf, angband_header *head); |
@@ -9,9 +9,6 @@ | ||
9 | 9 | /*! |
10 | 10 | * @brief 各初期データ用ヘッダ構造体 / Template file header information (see "init.c"). |
11 | 11 | */ |
12 | -typedef struct angband_header angband_header; | |
13 | -typedef errr (*parse_info_txt_func)(char *buf, angband_header *head); | |
14 | - | |
15 | 12 | struct angband_header { |
16 | 13 | byte checksum; //!< Checksum of "info" records |
17 | 14 | u16b info_num; //!< このinfoのデータ数 |
@@ -12,6 +12,7 @@ | ||
12 | 12 | #include "info-reader/feature-reader.h" |
13 | 13 | #include "info-reader/fixed-map-parser.h" |
14 | 14 | #include "info-reader/general-parser.h" |
15 | +#include "info-reader/info-reader-util.h" | |
15 | 16 | #include "info-reader/kind-reader.h" |
16 | 17 | #include "info-reader/magic-reader.h" |
17 | 18 | #include "info-reader/race-reader.h" |
@@ -38,6 +39,7 @@ | ||
38 | 39 | #ifndef WINDOWS |
39 | 40 | #include <sys/types.h> |
40 | 41 | #endif |
42 | +#include <string_view> | |
41 | 43 | |
42 | 44 | /*! |
43 | 45 | * @brief 基本情報読み込みのメインルーチン / |
@@ -73,7 +75,8 @@ static void init_header(angband_header *head, IDX num) | ||
73 | 75 | * even if the string happens to be empty (everyone has a unique '\0'). |
74 | 76 | */ |
75 | 77 | template <typename InfoType> |
76 | -static errr init_info(concptr filename, angband_header &head, std::vector<InfoType> &info, parse_info_txt_func parser, void (*retouch)(angband_header *head)) | |
78 | +static errr init_info(concptr filename, angband_header &head, std::vector<InfoType> &info, std::function<errr(std::string_view, angband_header *)> parser, | |
79 | + void (*retouch)(angband_header *head)) | |
77 | 80 | { |
78 | 81 | char buf[1024]; |
79 | 82 | path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, format("%s.txt", filename)); |
@@ -12,5 +12,6 @@ enum race_flags8 : uint32_t { | ||
12 | 12 | RF8_XXX8X08 = 0x00000100, |
13 | 13 | RF8_WILD_MOUNTAIN = 0x00000200, |
14 | 14 | RF8_WILD_GRASS = 0x00000400, |
15 | + RF8_WILD_SWAMP = 0x00000800, //!< 沼地に生息(未使用) | |
15 | 16 | RF8_WILD_ALL = 0x80000000, |
16 | 17 | }; |
@@ -18,12 +18,18 @@ concptr macro_trigger_keycode[2][MAX_MACRO_TRIG]; /*!< マクロの内容 */ | ||
18 | 18 | /* |
19 | 19 | * Convert a decimal to a single digit octal number |
20 | 20 | */ |
21 | -static char octify(uint i) { return (hexsym[i % 8]); } | |
21 | +static char octify(uint i) | |
22 | +{ | |
23 | + return (hexsym[i % 8]); | |
24 | +} | |
22 | 25 | |
23 | 26 | /* |
24 | 27 | * Convert a decimal to a single digit hex number |
25 | 28 | */ |
26 | -static char hexify(uint i) { return (hexsym[i % 16]); } | |
29 | +static char hexify(uint i) | |
30 | +{ | |
31 | + return (hexsym[i % 16]); | |
32 | +} | |
27 | 33 | |
28 | 34 | /* |
29 | 35 | * Convert a octal-digit into a decimal |
@@ -49,7 +55,10 @@ static int dehex(char c) | ||
49 | 55 | return 0; |
50 | 56 | } |
51 | 57 | |
52 | -static char force_upper(char a) { return (islower(a)) ? toupper(a) : a; } | |
58 | +static char force_upper(char a) | |
59 | +{ | |
60 | + return (islower(a)) ? toupper(a) : a; | |
61 | +} | |
53 | 62 | |
54 | 63 | static int angband_stricmp(concptr a, concptr b) |
55 | 64 | { |
@@ -611,11 +620,14 @@ std::string str_ltrim(std::string_view str) | ||
611 | 620 | * @param str 操作の対象とする文字列 |
612 | 621 | * @param delim 文字列を分割する文字 |
613 | 622 | * @param trim trueの場合、分割した文字列の両端の空白を削除する |
623 | + * @param num 1以上の場合、事前にvectorサイズを予約しておく(速度向上) | |
614 | 624 | * @return std::vector<std::string> 分割した文字列を要素とする配列 |
615 | 625 | */ |
616 | -std::vector<std::string> str_split(std::string_view str, char delim, bool trim) | |
626 | +std::vector<std::string> str_split(std::string_view str, char delim, bool trim, int num) | |
617 | 627 | { |
618 | 628 | std::vector<std::string> result; |
629 | + if (num > 0) | |
630 | + result.reserve(num); | |
619 | 631 | |
620 | 632 | auto make_str = [trim](std::string_view sv) { return trim ? str_trim(sv) : std::string(sv); }; |
621 | 633 |
@@ -33,5 +33,5 @@ int strrncmp(const char *s1, const char *s2, int len); | ||
33 | 33 | std::string str_trim(std::string_view str); |
34 | 34 | std::string str_rtrim(std::string_view str); |
35 | 35 | std::string str_ltrim(std::string_view str); |
36 | -std::vector<std::string> str_split(std::string_view str, char delim, bool trim = false); | |
36 | +std::vector<std::string> str_split(std::string_view str, char delim, bool trim = false, int num = 0); | |
37 | 37 | std::string str_erase(std::string str, std::string_view erase_chars); |