OSDN Git Service

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