1 #include "info-reader/general-parser.h"
2 #include "artifact/fixed-art-types.h"
3 #include "dungeon/quest.h"
4 #include "grid/feature.h"
5 #include "info-reader/feature-reader.h"
6 #include "info-reader/info-reader-util.h"
7 #include "info-reader/parse-error-types.h"
8 #include "info-reader/random-grid-effect-types.h"
9 #include "io/tokenizer.h"
10 #include "main/angband-headers.h"
11 #include "object-enchant/trg-types.h"
12 #include "realm/realm-types.h"
13 #include "system/artifact-type-definition.h"
14 #include "system/baseitem-info.h"
15 #include "system/building-type-definition.h"
16 #include "system/floor-type-definition.h"
17 #include "system/system-variables.h"
18 #include "util/angband-files.h"
19 #include "util/string-processor.h"
22 dungeon_grid letter[255];
25 * @brief パース関数に基づいてデータファイルからデータを読み取る /
26 * Initialize an "*_info" array, by parsing an ascii "template" file
27 * @param fp 読み取りに使うファイルポインタ
28 * @param buf 読み取りに使うバッファ領域
30 * @param parse_info_txt_line パース関数
31 * @return エラーコード, エラー行番号
33 std::tuple<errr, int> init_info_txt(FILE *fp, char *buf, angband_header *head, Parser parse_info_txt_line)
41 // init_info_txtの呼び出し側のbufは1024バイト
42 const auto line_str = angband_fgets(fp, 1024);
47 const auto len = line_str->copy(buf, 1024 - 1);
49 const std::string_view line = buf;
50 if (line.empty() || line.starts_with('#')) {
54 if (!line.substr(1).starts_with(':')) {
55 return { PARSE_ERROR_GENERIC, error_line };
58 if (line.starts_with('V')) {
62 // 文字コードの差異を吸収するため、日本語が含まれる可能性のある
63 // 「N:」「D:」「J:」はハッシュ計算から除外する
64 if (!line.starts_with('N') && !line.starts_with('D') && !line.starts_with('J')) {
68 if (auto err = parse_info_txt_line(line, head); err != 0) {
69 return { err, error_line };
73 head->digest = sha256.digest();
75 return { PARSE_ERROR_NONE, error_line };
79 * @brief 地形情報の「F:」情報をパースする
80 * Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid
81 * @param floor_ptr 現在フロアへの参照ポインタ
85 parse_error_type parse_line_feature(FloorType *floor_ptr, char *buf)
87 if (init_flags & INIT_ONLY_BUILDINGS) {
88 return PARSE_ERROR_NONE;
92 int num = tokenize(buf + 2, 9, zz, 0);
94 return PARSE_ERROR_GENERIC;
98 letter[index].feature = feat_none;
99 letter[index].monster = 0;
100 letter[index].object = 0;
101 letter[index].ego = EgoType::NONE;
102 letter[index].artifact = FixedArtifactId::NONE;
103 letter[index].trap = feat_none;
104 letter[index].cave_info = 0;
105 letter[index].special = 0;
106 letter[index].random = RANDOM_NONE;
110 letter[index].special = (int16_t)atoi(zz[8]);
113 if ((zz[7][0] == '*') && !zz[7][1]) {
114 letter[index].random |= RANDOM_TRAP;
116 letter[index].trap = f_tag_to_index(zz[7]);
117 if (letter[index].trap < 0) {
118 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
123 if (zz[6][0] == '*') {
124 letter[index].random |= RANDOM_ARTIFACT;
126 letter[index].artifact = i2enum<FixedArtifactId>(atoi(zz[6] + 1));
128 } else if (zz[6][0] == '!') {
129 if (floor_ptr->is_in_quest()) {
130 const auto &quest_list = QuestList::get_instance();
131 letter[index].artifact = quest_list[floor_ptr->quest_number].reward_fa_id;
134 letter[index].artifact = i2enum<FixedArtifactId>(atoi(zz[6]));
138 if (zz[5][0] == '*') {
139 letter[index].random |= RANDOM_EGO;
141 letter[index].ego = i2enum<EgoType>(atoi(zz[5] + 1));
144 letter[index].ego = i2enum<EgoType>(atoi(zz[5]));
148 if (zz[4][0] == '*') {
149 letter[index].random |= RANDOM_OBJECT;
151 letter[index].object = (OBJECT_IDX)atoi(zz[4] + 1);
153 } else if (zz[4][0] == '!') {
154 if (floor_ptr->is_in_quest()) {
155 const auto &quest = QuestList::get_instance()[floor_ptr->quest_number];
156 if (quest.has_reward()) {
157 const auto &artifact = quest.get_reward();
158 if (artifact.gen_flags.has_not(ItemGenerationTraitType::INSTA_ART)) {
159 letter[index].object = BaseitemList::get_instance().lookup_baseitem_id(artifact.bi_key);
164 letter[index].object = (OBJECT_IDX)atoi(zz[4]);
168 if (zz[3][0] == '*') {
169 letter[index].random |= RANDOM_MONSTER;
171 letter[index].monster = (MONSTER_IDX)atoi(zz[3] + 1);
173 } else if (zz[3][0] == 'c') {
175 return PARSE_ERROR_GENERIC;
177 letter[index].monster = -atoi(zz[3] + 1);
179 letter[index].monster = (MONSTER_IDX)atoi(zz[3]);
183 letter[index].cave_info = atoi(zz[2]);
186 if ((zz[1][0] == '*') && !zz[1][1]) {
187 letter[index].random |= RANDOM_FEATURE;
189 letter[index].feature = f_tag_to_index(zz[1]);
190 if (letter[index].feature < 0) {
191 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
198 return PARSE_ERROR_NONE;
202 * @brief 地形情報の「B:」情報をパースする
203 * Process "B:<Index>:<Command>:..." -- Building definition
207 parse_error_type parse_line_building(char *buf)
214 return PARSE_ERROR_NONE;
219 return PARSE_ERROR_NONE;
224 s = angband_strchr(s, ':');
226 return PARSE_ERROR_GENERIC;
231 return PARSE_ERROR_GENERIC;
236 if (tokenize(s + 2, 3, zz, 0) == 3) {
237 strcpy(buildings[index].name, zz[0]);
238 strcpy(buildings[index].owner_name, zz[1]);
239 strcpy(buildings[index].owner_race, zz[2]);
243 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
246 if (tokenize(s + 2, 8, zz, 0) >= 7) {
247 int action_index = atoi(zz[0]);
248 strcpy(buildings[index].act_names[action_index], zz[1]);
249 buildings[index].member_costs[action_index] = (PRICE)atoi(zz[2]);
250 buildings[index].other_costs[action_index] = (PRICE)atoi(zz[3]);
251 buildings[index].letters[action_index] = zz[4][0];
252 buildings[index].actions[action_index] = static_cast<int16_t>(atoi(zz[5]));
253 buildings[index].action_restr[action_index] = static_cast<int16_t>(atoi(zz[6]));
257 return PARSE_ERROR_TOO_FEW_ARGUMENTS;
260 auto pct_max = PLAYER_CLASS_TYPE_MAX;
261 auto n = tokenize(s + 2, pct_max, zz, 0);
262 for (auto i = 0; i < pct_max; i++) {
263 buildings[index].member_class[i] = (i < n) ? atoi(zz[i]) : 1;
269 auto n = tokenize(s + 2, MAX_RACES, zz, 0);
270 for (int i = 0; i < MAX_RACES; i++) {
271 buildings[index].member_race[i] = (i < n) ? atoi(zz[i]) : 1;
278 n = tokenize(s + 2, MAX_MAGIC, zz, 0);
279 for (int i = 0; i < MAX_MAGIC; i++) {
280 buildings[index].member_realm[i + 1] = ((i < n) ? static_cast<int16_t>(atoi(zz[i])) : 1);
289 return PARSE_ERROR_UNDEFINED_DIRECTIVE;
293 return PARSE_ERROR_NONE;