1 #include "info-reader/dungeon-reader.h"
2 #include "grid/feature.h"
3 #include "info-reader/dungeon-info-tokens-table.h"
4 #include "info-reader/feature-reader.h"
5 #include "info-reader/info-reader-util.h"
6 #include "info-reader/parse-error-types.h"
7 #include "info-reader/race-info-tokens-table.h"
8 #include "io/tokenizer.h"
9 #include "main/angband-headers.h"
10 #include "system/dungeon-info.h"
11 #include "util/string-processor.h"
12 #include "view/display-messages.h"
15 * @brief テキストトークンを走査してフラグを一つ得る(ダンジョン用) /
16 * Grab one flag for a dungeon type from a textual string
17 * @param d_ptr 保管先のダンジョン構造体参照ポインタ
18 * @param what 参照元の文字列ポインタ
21 static bool grab_one_dungeon_flag(dungeon_type *d_ptr, std::string_view what)
23 if (EnumClassFlagGroup<DungeonFeatureType>::grab_one_flag(d_ptr->flags, dungeon_flags, what)) {
27 msg_format(_("未知のダンジョン・フラグ '%s'。", "Unknown dungeon type flag '%s'."), what.data());
32 * @brief テキストトークンを走査してフラグを一つ得る(モンスターのダンジョン出現条件用1) /
33 * Grab one (basic) flag in a MonsterRaceInfo from a textual string
34 * @param d_ptr 保管先のダンジョン構造体参照ポインタ
35 * @param what 参照元の文字列ポインタ
38 static bool grab_one_basic_monster_flag(dungeon_type *d_ptr, std::string_view what)
40 if (info_grab_one_flag(d_ptr->mflags1, r_info_flags1, what)) {
44 if (info_grab_one_flag(d_ptr->mflags2, r_info_flags2, what)) {
48 if (info_grab_one_flag(d_ptr->mflags7, r_info_flags7, what)) {
52 if (info_grab_one_flag(d_ptr->mflags8, r_info_flags8, what)) {
56 if (EnumClassFlagGroup<MonsterResistanceType>::grab_one_flag(d_ptr->mon_resistance_flags, r_info_flagsr, what)) {
60 if (EnumClassFlagGroup<MonsterBehaviorType>::grab_one_flag(d_ptr->mon_behavior_flags, r_info_behavior_flags, what)) {
64 if (EnumClassFlagGroup<MonsterVisualType>::grab_one_flag(d_ptr->mon_visual_flags, r_info_visual_flags, what)) {
68 if (EnumClassFlagGroup<MonsterKindType>::grab_one_flag(d_ptr->mon_kind_flags, r_info_kind_flags, what)) {
72 if (EnumClassFlagGroup<MonsterDropType>::grab_one_flag(d_ptr->mon_drop_flags, r_info_drop_flags, what)) {
76 if (EnumClassFlagGroup<MonsterWildernessType>::grab_one_flag(d_ptr->mon_wilderness_flags, r_info_wilderness_flags, what)) {
80 if (EnumClassFlagGroup<MonsterFeatureType>::grab_one_flag(d_ptr->mon_feature_flags, r_info_feature_flags, what)) {
84 if (EnumClassFlagGroup<MonsterPopulationType>::grab_one_flag(d_ptr->mon_population_flags, r_info_population_flags, what)) {
88 if (EnumClassFlagGroup<MonsterSpeakType>::grab_one_flag(d_ptr->mon_speak_flags, r_info_speak_flags, what)) {
92 if (EnumClassFlagGroup<MonsterBrightnessType>::grab_one_flag(d_ptr->mon_brightness_flags, r_info_brightness_flags, what)) {
96 if (EnumClassFlagGroup<MonsterSpecialType>::grab_one_flag(d_ptr->mon_special_flags, r_info_special_flags, what)) {
99 if (EnumClassFlagGroup<MonsterMiscType>::grab_one_flag(d_ptr->mon_misc_flags, r_info_misc_flags, what)) {
103 msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data());
108 * @brief テキストトークンを走査してフラグを一つ得る(モンスターのダンジョン出現条件用2) /
109 * Grab one (spell) flag in a MonsterRaceInfo from a textual string
110 * @param d_ptr 保管先のダンジョン構造体参照ポインタ
111 * @param what 参照元の文字列ポインタ
114 static bool grab_one_spell_monster_flag(dungeon_type *d_ptr, std::string_view what)
116 if (EnumClassFlagGroup<MonsterAbilityType>::grab_one_flag(d_ptr->mon_ability_flags, r_info_ability_flags, what)) {
120 msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data());
125 * @brief ダンジョン情報(DungeonsDefinition)のパース関数 /
130 errr parse_dungeons_info(std::string_view buf, angband_header *)
132 static dungeon_type *d_ptr = nullptr;
133 const auto &tokens = str_split(buf, ':', false);
135 if (tokens[0] == "N") {
137 if (tokens.size() < 3 || tokens[1].size() == 0) {
138 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
141 auto i = std::stoi(tokens[1]);
143 return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
145 if (i >= static_cast<int>(dungeons_info.size())) {
146 dungeons_info.resize(i + 1);
150 d_ptr = &dungeons_info[i];
151 d_ptr->idx = static_cast<DUNGEON_IDX>(i);
153 d_ptr->name = tokens[2];
156 return PARSE_ERROR_MISSING_RECORD_HEADER;
157 } else if (tokens[0] == "E") {
160 if (tokens.size() < 2 || tokens[1].size() == 0) {
161 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
163 d_ptr->name = tokens[1];
165 } else if (tokens[0] == "D") {
168 if (tokens.size() < 2 || buf.length() < 3) {
169 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
173 return PARSE_ERROR_NONE;
175 d_ptr->text.append(buf.substr(2));
178 return PARSE_ERROR_NONE;
180 if (buf.length() == 3) {
181 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
183 append_english_text(d_ptr->text, buf.substr(3));
185 } else if (tokens[0] == "W") {
186 // W:min_level:max_level:(1):mode:(2):(3):(4):(5):prob_pit:prob_nest
187 // (1)minimum player level (unused)
188 // (2)minimum level of allocating monster
189 // (3)maximum probability of level boost of allocation monster
190 // (4)maximum probability of dropping good objects
191 // (5)maximum probability of dropping great objects
192 if (tokens.size() < 11) {
193 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
196 info_set_value(d_ptr->mindepth, tokens[1]);
197 info_set_value(d_ptr->maxdepth, tokens[2]);
198 info_set_value(d_ptr->min_plev, tokens[3]);
199 info_set_value(d_ptr->mode, tokens[4]);
200 info_set_value(d_ptr->min_m_alloc_level, tokens[5]);
201 info_set_value(d_ptr->max_m_alloc_chance, tokens[6]);
202 info_set_value(d_ptr->obj_good, tokens[7]);
203 info_set_value(d_ptr->obj_great, tokens[8]);
204 info_set_value(d_ptr->pit, tokens[9], 16);
205 info_set_value(d_ptr->nest, tokens[10], 16);
206 } else if (tokens[0] == "P") {
208 if (tokens.size() < 3) {
209 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
212 info_set_value(d_ptr->dy, tokens[1]);
213 info_set_value(d_ptr->dx, tokens[2]);
214 } else if (tokens[0] == "L") {
215 // L:floor_1:prob_1:floor_2:prob_2:floor_3:prob_3:tunnel_prob
216 if (tokens.size() < DUNGEON_FEAT_PROB_NUM * 2 + 2) {
217 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
220 for (size_t i = 0; i < DUNGEON_FEAT_PROB_NUM; i++) {
221 auto feat_idx = i * 2 + 1;
222 auto per_idx = feat_idx + 1;
223 d_ptr->floor[i].feat = f_tag_to_index(tokens[feat_idx]);
224 if (d_ptr->floor[i].feat < 0) {
225 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
228 info_set_value(d_ptr->floor[i].percent, tokens[per_idx]);
231 auto tunnel_idx = DUNGEON_FEAT_PROB_NUM * 2 + 1;
232 info_set_value(d_ptr->tunnel_percent, tokens[tunnel_idx]);
233 } else if (tokens[0] == "A") {
234 // A:wall_1:prob_1:wall_2:prob_2:wall_3:prob_3:outer_wall:inner_wall:stream_1:stream_2
235 if (tokens.size() < DUNGEON_FEAT_PROB_NUM * 2 + 5) {
236 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
239 for (int i = 0; i < DUNGEON_FEAT_PROB_NUM; i++) {
240 auto feat_idx = i * 2 + 1;
241 auto prob_idx = feat_idx + 1;
242 d_ptr->fill[i].feat = f_tag_to_index(tokens[feat_idx]);
243 if (d_ptr->fill[i].feat < 0) {
244 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
247 info_set_value(d_ptr->fill[i].percent, tokens[prob_idx]);
250 auto idx = DUNGEON_FEAT_PROB_NUM * 2 + 1;
251 d_ptr->outer_wall = f_tag_to_index(tokens[idx++]);
252 if (d_ptr->outer_wall < 0) {
253 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
256 d_ptr->inner_wall = f_tag_to_index(tokens[idx++]);
257 if (d_ptr->inner_wall < 0) {
258 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
261 d_ptr->stream1 = f_tag_to_index(tokens[idx++]);
262 if (d_ptr->stream1 < 0) {
263 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
266 d_ptr->stream2 = f_tag_to_index(tokens[idx]);
267 if (d_ptr->stream2 < 0) {
268 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
270 } else if (tokens[0] == "F") {
272 if (tokens.size() < 2) {
273 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
276 const auto &flags = str_split(tokens[1], '|', true);
277 for (const auto &f : flags) {
282 const auto &f_tokens = str_split(f, '_');
283 if (f_tokens.size() == 3) {
284 if (f_tokens[0] == "FINAL" && f_tokens[1] == "ARTIFACT") {
285 info_set_value(d_ptr->final_artifact, f_tokens[2]);
288 if (f_tokens[0] == "FINAL" && f_tokens[1] == "OBJECT") {
289 info_set_value(d_ptr->final_object, f_tokens[2]);
292 if (f_tokens[0] == "FINAL" && f_tokens[1] == "GUARDIAN") {
293 info_set_value(d_ptr->final_guardian, f_tokens[2]);
296 if (f_tokens[0] == "MONSTER" && f_tokens[1] == "DIV") {
297 info_set_value(d_ptr->special_div, f_tokens[2]);
302 if (!grab_one_dungeon_flag(d_ptr, f)) {
303 return PARSE_ERROR_INVALID_FLAG;
306 } else if (tokens[0] == "M") {
308 if (tokens[1] == "X") {
309 if (tokens.size() < 3) {
310 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
313 if (!info_grab_one_const(sex, r_info_sex, tokens[2])) {
314 return PARSE_ERROR_INVALID_FLAG;
316 d_ptr->mon_sex = static_cast<MonsterSex>(sex);
319 if (tokens.size() < 2) {
320 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
323 const auto &flags = str_split(tokens[1], '|', true);
324 for (const auto &f : flags) {
329 const auto &m_tokens = str_split(f, '_');
330 if (m_tokens[0] == "R" && m_tokens[1] == "CHAR") {
331 d_ptr->r_chars.insert(d_ptr->r_chars.end(), m_tokens[2].begin(), m_tokens[2].end());
335 if (!grab_one_basic_monster_flag(d_ptr, f)) {
336 return PARSE_ERROR_INVALID_FLAG;
339 } else if (tokens[0] == "S") {
341 if (tokens.size() < 2) {
342 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
345 const auto &flags = str_split(tokens[1], '|', true);
346 for (const auto &f : flags) {
351 const auto &s_tokens = str_split(f, '_');
352 if (s_tokens.size() == 3 && s_tokens[1] == "IN") {
353 if (s_tokens[0] != "1") {
354 return PARSE_ERROR_GENERIC;
356 continue; //!< MonsterRaceDefinitions.txtからのコピペ対策
359 if (!grab_one_spell_monster_flag(d_ptr, f)) {
360 return PARSE_ERROR_INVALID_FLAG;
364 return PARSE_ERROR_UNDEFINED_DIRECTIVE;