2 * @brief ゲームデータ初期化1 / Initialization (part 1) -BEN-
5 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6 * 2014 Deskull rearranged comment for Doxygen
9 #include "info-reader/fixed-map-parser.h"
10 #include "dungeon/quest.h"
11 #include "floor/fixed-map-generator.h"
12 #include "game-option/birth-options.h"
13 #include "game-option/runtime-arguments.h"
14 #include "info-reader/parse-error-types.h"
15 #include "io/files-util.h"
16 #include "main/init-error-messages-table.h"
17 #include "player-info/class-info.h"
18 #include "player-info/race-info.h"
19 #include "realm/realm-names-table.h"
20 #include "system/angband-exceptions.h"
21 #include "system/angband-system.h"
22 #include "system/floor-type-definition.h"
23 #include "system/player-type-definition.h"
24 #include "util/angband-files.h"
25 #include "util/string-processor.h"
26 #include "view/display-messages.h"
30 static concptr variant = "ZANGBAND";
33 * @brief 固定マップ (クエスト&街&広域マップ)生成時の分岐処理
34 * Helper function for "parse_fixed_map()"
35 * @param player_ptr プレイヤーへの参照ポインタ
40 static concptr parse_fixed_map_expression(PlayerType *player_ptr, char **sp, char *fp)
42 static std::string tmp;
51 while (iswspace(*s)) {
62 t = parse_fixed_map_expression(player_ptr, &s, &f);
65 } else if (streq(t, "IOR")) {
67 while (*s && (f != b2)) {
68 t = parse_fixed_map_expression(player_ptr, &s, &f);
69 if (*t && !streq(t, "0")) {
73 } else if (streq(t, "AND")) {
75 while (*s && (f != b2)) {
76 t = parse_fixed_map_expression(player_ptr, &s, &f);
77 if (*t && streq(t, "0")) {
81 } else if (streq(t, "NOT")) {
83 while (*s && (f != b2)) {
84 t = parse_fixed_map_expression(player_ptr, &s, &f);
85 if (*t && streq(t, "1")) {
89 } else if (streq(t, "EQU")) {
91 if (*s && (f != b2)) {
92 t = parse_fixed_map_expression(player_ptr, &s, &f);
95 while (*s && (f != b2)) {
96 p = parse_fixed_map_expression(player_ptr, &s, &f);
101 } else if (streq(t, "LEQ")) {
103 if (*s && (f != b2)) {
104 t = parse_fixed_map_expression(player_ptr, &s, &f);
107 while (*s && (f != b2)) {
109 t = parse_fixed_map_expression(player_ptr, &s, &f);
110 if (*t && atoi(p) > atoi(t)) {
114 } else if (streq(t, "GEQ")) {
116 if (*s && (f != b2)) {
117 t = parse_fixed_map_expression(player_ptr, &s, &f);
120 while (*s && (f != b2)) {
122 t = parse_fixed_map_expression(player_ptr, &s, &f);
123 if (*t && atoi(p) < atoi(t)) {
128 while (*s && (f != b2)) {
129 t = parse_fixed_map_expression(player_ptr, &s, &f);
136 if ((f = *s) != '\0') {
146 while (iskanji(*s) || (isprint(*s) && !angband_strchr(" []", *s))) {
153 while (isprint(*s) && !angband_strchr(" []", *s)) {
157 if ((f = *s) != '\0') {
168 if (streq(b + 1, "SYS")) {
170 } else if (streq(b + 1, "GRAF")) {
172 } else if (streq(b + 1, "MONOCHROME")) {
173 if (arg_monochrome) {
178 } else if (streq(b + 1, "RACE")) {
179 v = _(rp_ptr->E_title, rp_ptr->title);
180 } else if (streq(b + 1, "CLASS")) {
181 v = _(cp_ptr->E_title, cp_ptr->title);
182 } else if (streq(b + 1, "REALM1")) {
183 v = _(E_realm_names[player_ptr->realm1], realm_names[player_ptr->realm1]);
184 } else if (streq(b + 1, "REALM2")) {
185 v = _(E_realm_names[player_ptr->realm2], realm_names[player_ptr->realm2]);
186 } else if (streq(b + 1, "PLAYER")) {
187 static char tmp_player_name[32];
189 for (pn = player_ptr->name, tpn = tmp_player_name; *pn; pn++, tpn++) {
197 *tpn = angband_strchr(" []", *pn) ? '_' : *pn;
202 } else if (streq(b + 1, "TOWN")) {
203 tmp = std::to_string(player_ptr->town_num);
205 } else if (streq(b + 1, "LEVEL")) {
206 tmp = std::to_string(player_ptr->lev);
208 } else if (streq(b + 1, "QUEST_NUMBER")) {
209 tmp = std::to_string(enum2i(player_ptr->current_floor_ptr->quest_number));
211 } else if (streq(b + 1, "LEAVING_QUEST")) {
212 tmp = std::to_string(enum2i(leaving_quest));
214 } else if (prefix(b + 1, "QUEST_TYPE")) {
215 const auto &quest_list = QuestList::get_instance();
216 tmp = std::to_string(enum2i(quest_list[i2enum<QuestId>(atoi(b + 11))].type));
218 } else if (prefix(b + 1, "QUEST")) {
219 const auto &quest_list = QuestList::get_instance();
220 tmp = std::to_string(enum2i(quest_list[i2enum<QuestId>(atoi(b + 6))].status));
222 } else if (prefix(b + 1, "RANDOM")) {
223 const auto &system = AngbandSystem::get_instance();
224 tmp = std::to_string((static_cast<int>(system.get_seed_town()) % std::stoi(b + 7)));
226 } else if (streq(b + 1, "VARIANT")) {
228 } else if (streq(b + 1, "WILDERNESS")) {
231 } else if (lite_town) {
236 } else if (streq(b + 1, "IRONMAN_DOWNWARD")) {
237 v = (ironman_downward ? "1" : "0");
246 * @brief 固定マップ (クエスト&街&広域マップ)をq_info、t_info、w_infoから読み込んでパースする
247 * @param player_ptr プレイヤーへの参照ポインタ
255 parse_error_type parse_fixed_map(PlayerType *player_ptr, std::string_view name, int ymin, int xmin, int ymax, int xmax)
257 const auto &path = path_build(ANGBAND_DIR_EDIT, name);
258 auto *fp = angband_fopen(path, FileOpenMode::READ);
260 return PARSE_ERROR_GENERIC;
264 parse_error_type err = PARSE_ERROR_NONE;
270 qtwg_type *qg_ptr = initialize_quest_generator_type(&tmp_qg, buf, ymin, xmin, ymax, xmax, &y, &x);
271 while (angband_fgets(fp, buf, sizeof(buf)) == 0) {
273 if (!buf[0] || iswspace(buf[0]) || buf[0] == '#') {
277 if ((buf[0] == '?') && (buf[1] == ':')) {
281 concptr v = parse_fixed_map_expression(player_ptr, &s, &f);
282 bypass = streq(v, "0");
290 err = generate_fixed_map_floor(player_ptr, qg_ptr, parse_fixed_map);
291 if (err != PARSE_ERROR_NONE) {
297 concptr oops = (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : "unknown");
298 msg_format("Error %d (%s) at line %d of '%s'.", err, oops, num, name.data());
299 msg_format(_("'%s'を解析中。", "Parsing '%s'."), buf);
307 static QuestId parse_quest_number_n(const std::vector<std::string> &token)
309 auto number = i2enum<QuestId>(atoi(token[1].substr(_(0, 1)).data()));
313 static QuestId parse_quest_number(const std::vector<std::string> &token)
315 auto is_quest_none = _(token[1][0] == '$', token[1][0] != '$');
317 return QuestId::NONE;
320 if (token[2] == "N") {
321 return parse_quest_number_n(token);
323 return QuestId::NONE;
327 * @brief クエスト番号をファイルから読み込んでパースする
328 * @param player_ptr プレイヤーへの参照ポインタ
329 * @param file_name ファイル名
330 * @param key_list キーになるQuestIdの配列
332 static void parse_quest_info_aux(std::string_view file_name, std::set<QuestId> &key_list_ref)
334 auto push_set = [&key_list_ref, &file_name](auto q, auto line) {
335 if (q == QuestId::NONE) {
339 if (key_list_ref.find(q) != key_list_ref.end()) {
340 std::stringstream ss;
341 ss << _("重複したQuestID ", "Duplicated Quest Id ") << enum2i(q) << '(' << file_name << ", L" << line << ')';
342 THROW_EXCEPTION(std::runtime_error, ss.str());
345 key_list_ref.insert(q);
348 const auto &path = path_build(ANGBAND_DIR_EDIT, file_name);
349 auto *fp = angband_fopen(path, FileOpenMode::READ);
351 std::stringstream ss;
352 ss << _("ファイルが見つかりません (", "File is not found (") << file_name << ')';
353 THROW_EXCEPTION(std::runtime_error, ss.str());
358 while (angband_fgets(fp, buf, sizeof(buf)) == 0) {
361 const auto token = str_split(buf, ':', true);
363 switch (token[0][0]) {
365 auto quest_number = parse_quest_number(token);
366 push_set(quest_number, line_num);
370 parse_quest_info_aux(token[1].data(), key_list_ref);
382 * @brief ファイルからパースして作成したクエスト番号配列を返す
383 * @param player_ptr プレイヤーへの参照ポインタ
384 * @param file_name ファイル名
387 std::set<QuestId> parse_quest_info(std::string_view file_name)
389 std::set<QuestId> key_list;
390 parse_quest_info_aux(file_name, key_list);