OSDN Git Service

[Refactor] #1366 Removed type alias 'REALM_IDX'
[hengbandforosx/hengbandosx.git] / src / info-reader / general-parser.cpp
1 #include "info-reader/general-parser.h"
2 #include "dungeon/quest.h"
3 #include "grid/feature.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/random-grid-effect-types.h"
8 #include "io/tokenizer.h"
9 #include "main/angband-headers.h"
10 #include "object-enchant/trg-types.h"
11 #include "object/object-kind-hook.h"
12 #include "realm/realm-types.h"
13 #include "system/artifact-type-definition.h"
14 #include "system/building-type-definition.h"
15 #include "system/floor-type-definition.h"
16 #include "system/system-variables.h"
17 #include "util/angband-files.h"
18 #include "util/string-processor.h"
19 #include <string>
20
21 dungeon_grid letter[255];
22
23 /*!
24  * @brief パース関数に基づいてデータファイルからデータを読み取る /
25  * Initialize an "*_info" array, by parsing an ascii "template" file
26  * @param fp 読み取りに使うファイルポインタ
27  * @param buf 読み取りに使うバッファ領域
28  * @param head ヘッダ構造体
29  * @param parse_info_txt_line パース関数
30  * @return エラーコード
31  */
32 errr init_info_txt(FILE *fp, char *buf, angband_header *head, std::function<errr(std::string_view, angband_header *)> parse_info_txt_line)
33 {
34     error_idx = -1;
35     error_line = 0;
36
37     errr err;
38     while (angband_fgets(fp, buf, 1024) == 0) {
39         error_line++;
40         if (!buf[0] || (buf[0] == '#'))
41             continue;
42
43         if (buf[1] != ':')
44             return (PARSE_ERROR_GENERIC);
45
46         if (buf[0] == 'V') {
47             continue;
48         }
49
50         if (buf[0] != 'N' && buf[0] != 'D') {
51             int i;
52             for (i = 0; buf[i]; i++) {
53                 head->checksum += (byte)buf[i];
54                 head->checksum ^= (1U << (i % 8));
55             }
56         }
57
58         if ((err = parse_info_txt_line(buf, head)) != 0)
59             return (err);
60     }
61
62     return 0;
63 }
64
65 /*!
66  * @brief 地形情報の「F:」情報をパースする
67  * Process "F:<letter>:<terrain>:<cave_info>:<monster>:<object>:<ego>:<artifact>:<trap>:<special>" -- info for dungeon grid
68  * @param floor_ptr 現在フロアへの参照ポインタ
69  * @param buf 解析文字列
70  * @return エラーコード
71  */
72 parse_error_type parse_line_feature(floor_type *floor_ptr, char *buf)
73 {
74     if (init_flags & INIT_ONLY_BUILDINGS)
75         return PARSE_ERROR_NONE;
76
77     char *zz[9];
78     int num = tokenize(buf + 2, 9, zz, 0);
79     if (num <= 1)
80         return PARSE_ERROR_GENERIC;
81
82     int index = zz[0][0];
83     letter[index].feature = feat_none;
84     letter[index].monster = 0;
85     letter[index].object = 0;
86     letter[index].ego = 0;
87     letter[index].artifact = 0;
88     letter[index].trap = feat_none;
89     letter[index].cave_info = 0;
90     letter[index].special = 0;
91     letter[index].random = RANDOM_NONE;
92
93     switch (num) {
94     case 9:
95         letter[index].special = (int16_t)atoi(zz[8]);
96         /* Fall through */
97     case 8:
98         if ((zz[7][0] == '*') && !zz[7][1]) {
99             letter[index].random |= RANDOM_TRAP;
100         } else {
101             letter[index].trap = f_tag_to_index(zz[7]);
102             if (letter[index].trap < 0)
103                 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
104         }
105         /* Fall through */
106     case 7:
107         if (zz[6][0] == '*') {
108             letter[index].random |= RANDOM_ARTIFACT;
109             if (zz[6][1])
110                 letter[index].artifact = (ARTIFACT_IDX)atoi(zz[6] + 1);
111         } else if (zz[6][0] == '!') {
112             if (floor_ptr->inside_quest) {
113                 letter[index].artifact = quest[floor_ptr->inside_quest].k_idx;
114             }
115         } else {
116             letter[index].artifact = (ARTIFACT_IDX)atoi(zz[6]);
117         }
118         /* Fall through */
119     case 6:
120         if (zz[5][0] == '*') {
121             letter[index].random |= RANDOM_EGO;
122             if (zz[5][1])
123                 letter[index].ego = (EGO_IDX)atoi(zz[5] + 1);
124         } else {
125             letter[index].ego = (EGO_IDX)atoi(zz[5]);
126         }
127         /* Fall through */
128     case 5:
129         if (zz[4][0] == '*') {
130             letter[index].random |= RANDOM_OBJECT;
131             if (zz[4][1])
132                 letter[index].object = (OBJECT_IDX)atoi(zz[4] + 1);
133         } else if (zz[4][0] == '!') {
134             if (floor_ptr->inside_quest) {
135                 ARTIFACT_IDX a_idx = quest[floor_ptr->inside_quest].k_idx;
136                 if (a_idx) {
137                     artifact_type *a_ptr = &a_info[a_idx];
138                     if (a_ptr->gen_flags.has_not(TRG::INSTA_ART)) {
139                         letter[index].object = lookup_kind(a_ptr->tval, a_ptr->sval);
140                     }
141                 }
142             }
143         } else {
144             letter[index].object = (OBJECT_IDX)atoi(zz[4]);
145         }
146         /* Fall through */
147     case 4:
148         if (zz[3][0] == '*') {
149             letter[index].random |= RANDOM_MONSTER;
150             if (zz[3][1])
151                 letter[index].monster = (MONSTER_IDX)atoi(zz[3] + 1);
152         } else if (zz[3][0] == 'c') {
153             if (!zz[3][1])
154                 return PARSE_ERROR_GENERIC;
155             letter[index].monster = -atoi(zz[3] + 1);
156         } else {
157             letter[index].monster = (MONSTER_IDX)atoi(zz[3]);
158         }
159         /* Fall through */
160     case 3:
161         letter[index].cave_info = atoi(zz[2]);
162         /* Fall through */
163     case 2:
164         if ((zz[1][0] == '*') && !zz[1][1]) {
165             letter[index].random |= RANDOM_FEATURE;
166         } else {
167             letter[index].feature = f_tag_to_index(zz[1]);
168             if (letter[index].feature < 0)
169                 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
170         }
171
172         break;
173     }
174
175     return PARSE_ERROR_NONE;
176 }
177
178 /*!
179  * @brief 地形情報の「B:」情報をパースする
180  * Process "B:<Index>:<Command>:..." -- Building definition
181  * @param buf 解析文字列
182  * @return エラーコード
183  */
184 parse_error_type parse_line_building(char *buf)
185 {
186     char *zz[1000];
187     char *s;
188
189 #ifdef JP
190     if (buf[2] == '$')
191         return PARSE_ERROR_NONE;
192     s = buf + 2;
193 #else
194     if (buf[2] != '$')
195         return PARSE_ERROR_NONE;
196     s = buf + 3;
197 #endif
198     int index = atoi(s);
199     s = angband_strchr(s, ':');
200     if (!s)
201         return PARSE_ERROR_GENERIC;
202
203     *s++ = '\0';
204     if (!*s)
205         return PARSE_ERROR_GENERIC;
206
207     switch (s[0]) {
208     case 'N': {
209         if (tokenize(s + 2, 3, zz, 0) == 3) {
210             strcpy(building[index].name, zz[0]);
211             strcpy(building[index].owner_name, zz[1]);
212             strcpy(building[index].owner_race, zz[2]);
213             break;
214         }
215
216         return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
217     }
218     case 'A': {
219         if (tokenize(s + 2, 8, zz, 0) >= 7) {
220             int action_index = atoi(zz[0]);
221             strcpy(building[index].act_names[action_index], zz[1]);
222             building[index].member_costs[action_index] = (PRICE)atoi(zz[2]);
223             building[index].other_costs[action_index] = (PRICE)atoi(zz[3]);
224             building[index].letters[action_index] = zz[4][0];
225             building[index].actions[action_index] = static_cast<int16_t>(atoi(zz[5]));
226             building[index].action_restr[action_index] = static_cast<int16_t>(atoi(zz[6]));
227             break;
228         }
229
230         return (PARSE_ERROR_TOO_FEW_ARGUMENTS);
231     }
232     case 'C': {
233         int n;
234         n = tokenize(s + 2, MAX_CLASS, zz, 0);
235         for (int i = 0; i < MAX_CLASS; i++) {
236             building[index].member_class[i] = static_cast<player_class_type>((i < n) ? atoi(zz[i]) : 1);
237         }
238
239         break;
240     }
241     case 'R': {
242         int n;
243         n = tokenize(s + 2, MAX_RACES, zz, 0);
244         for (int i = 0; i < MAX_RACES; i++) {
245             building[index].member_race[i] = static_cast<player_race_type>((i < n) ? atoi(zz[i]) : 1);
246         }
247
248         break;
249     }
250     case 'M': {
251         int n;
252         n = tokenize(s + 2, MAX_MAGIC, zz, 0);
253         for (int i = 0; i < MAX_MAGIC; i++) {
254             building[index].member_realm[i + 1] = ((i < n) ? static_cast<int16_t>(atoi(zz[i])) : 1);
255         }
256
257         break;
258     }
259     case 'Z': {
260         break;
261     }
262     default: {
263         return (PARSE_ERROR_UNDEFINED_DIRECTIVE);
264     }
265     }
266
267     return PARSE_ERROR_NONE;
268 }