OSDN Git Service

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