OSDN Git Service

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