OSDN Git Service

[Fix] クイックメッセージの挙動が以前と異なる
[hengband/hengband.git] / src / main / info-initializer.c
1 #include "main/info-initializer.h"
2 #include "dungeon/dungeon.h"
3 #include "grid/feature.h"
4 #include "info-reader/artifact-reader.h"
5 #include "info-reader/dungeon-reader.h"
6 #include "info-reader/ego-reader.h"
7 #include "info-reader/feature-reader.h"
8 #include "info-reader/fixed-map-parser.h"
9 #include "info-reader/general-parser.h"
10 #include "info-reader/kind-reader.h"
11 #include "info-reader/magic-reader.h"
12 #include "info-reader/race-reader.h"
13 #include "info-reader/skill-reader.h"
14 #include "info-reader/vault-reader.h"
15 #include "io/files-util.h"
16 #include "io/uid-checker.h"
17 #include "main/angband-headers.h"
18 #include "main/init-error-messages-table.h"
19 #include "monster-race/monster-race.h"
20 #include "object-enchant/object-ego.h"
21 #include "object/object-kind.h"
22 #include "player/player-class.h"
23 #include "player/player-skill.h"
24 #include "room/rooms-vault.h"
25 #include "system/angband-version.h"
26 #include "system/artifact-type-definition.h"
27 #include "util/angband-files.h"
28 #include "view/display-messages.h"
29 #include "world/world.h"
30 #include <sys/stat.h>
31 #ifndef WINDOWS
32 #include <sys/types.h>
33 #endif
34
35 /*!
36  * @brief 基本情報読み込みのメインルーチン /
37  * Initialize misc. values
38  * @param player_ptr プレーヤーへの参照ポインタ
39  * @return エラーコード
40  */
41 errr init_misc(player_type *player_ptr) { return parse_fixed_map(player_ptr, "misc.txt", 0, 0, 0, 0); }
42
43 /*!
44  * @brief rawファイルからのデータの読み取り処理
45  * Initialize the "*_info" array, by parsing a binary "image" file
46  * @param fd ファイルディスクリプタ
47  * @param head rawファイルのヘッダ
48  * @return エラーコード
49  */
50 static errr init_info_raw(int fd, angband_header *head)
51 {
52     angband_header test;
53     if (fd_read(fd, (char *)(&test), sizeof(angband_header)) || (test.v_major != head->v_major) || (test.v_minor != head->v_minor)
54         || (test.v_patch != head->v_patch) || (test.info_num != head->info_num) || (test.info_len != head->info_len) || (test.head_size != head->head_size)
55         || (test.info_size != head->info_size)) {
56         return -1;
57     }
58
59     *head = test;
60     C_MAKE(head->info_ptr, head->info_size, char);
61     fd_read(fd, head->info_ptr, head->info_size);
62     if (head->name_size) {
63         C_MAKE(head->name_ptr, head->name_size, char);
64         fd_read(fd, head->name_ptr, head->name_size);
65     }
66
67     if (head->text_size) {
68         C_MAKE(head->text_ptr, head->text_size, char);
69         fd_read(fd, head->text_ptr, head->text_size);
70     }
71
72     if (head->tag_size) {
73         C_MAKE(head->tag_ptr, head->tag_size, char);
74         fd_read(fd, head->tag_ptr, head->tag_size);
75     }
76
77     return 0;
78 }
79
80 static void update_header(angband_header *head, void **info, char **name, char **text, char **tag)
81 {
82     if (info)
83         *info = head->info_ptr;
84
85     if (name)
86         *name = head->name_ptr;
87
88     if (text)
89         *text = head->text_ptr;
90
91     if (tag)
92         *tag = head->tag_ptr;
93 }
94
95 /*!
96  * @brief ヘッダ構造体の更新
97  * Initialize the header of an *_info.raw file.
98  * @param head rawファイルのヘッダ
99  * @param num データ数
100  * @param len データの長さ
101  * @return エラーコード
102  */
103 static void init_header(angband_header *head, IDX num, int len)
104 {
105     head->v_major = FAKE_VER_MAJOR;
106     head->v_minor = FAKE_VER_MINOR;
107     head->v_patch = FAKE_VER_PATCH;
108     head->v_extra = 0;
109
110     head->info_num = (IDX)num;
111     head->info_len = len;
112
113     head->head_size = sizeof(angband_header);
114     head->info_size = head->info_num * head->info_len;
115 }
116
117 /*!
118  * @brief テキストファイルとrawファイルの更新時刻を比較する
119  * Find the default paths to all of our important sub-directories.
120  * @param fd ファイルディスクリプタ
121  * @param template_file ファイル名
122  * @return テキストの方が新しいか、rawファイルがなく更新の必要がある場合-1、更新の必要がない場合0。
123  */
124 static errr check_modification_date(int fd, concptr template_file)
125 {
126     struct stat txt_stat, raw_stat;
127     char buf[1024];
128     path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, template_file);
129     if (stat(buf, &txt_stat))
130         return 0;
131
132     if (fstat(fd, &raw_stat))
133         return -1;
134
135     if (txt_stat.st_mtime > raw_stat.st_mtime)
136         return -1;
137
138     return 0;
139 }
140
141 /*!
142  * @brief ヘッダ構造体の更新
143  * Initialize the "*_info" array
144  * @param filename ファイル名(拡張子txt/raw)
145  * @param head 処理に用いるヘッダ構造体
146  * @param info データ保管先の構造体ポインタ
147  * @param name 名称用可変文字列の保管先
148  * @param text テキスト用可変文字列の保管先
149  * @param tag タグ用可変文字列の保管先
150  * @return エラーコード
151  * @note
152  * Note that we let each entry have a unique "name" and "text" string,
153  * even if the string happens to be empty (everyone has a unique '\0').
154  */
155 static errr init_info(player_type *player_ptr, concptr filename, angband_header *head, void **info, char **name, char **text, char **tag)
156 {
157     char buf[1024];
158     path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, format(_("%s_j.raw", "%s.raw"), filename));
159     int fd = fd_open(buf, O_RDONLY);
160     errr err = 1;
161     if (fd >= 0) {
162         err = check_modification_date(fd, format("%s.txt", filename));
163         if (!err)
164             err = init_info_raw(fd, head);
165
166         (void)fd_close(fd);
167     }
168
169     BIT_FLAGS file_permission = 0644;
170     if (err == 0) {
171         update_header(head, info, name, text, tag);
172         return 0;
173     }
174
175     C_MAKE(head->info_ptr, head->info_size, char);
176     if (name)
177         C_MAKE(head->name_ptr, FAKE_NAME_SIZE, char);
178
179     if (text)
180         C_MAKE(head->text_ptr, FAKE_TEXT_SIZE, char);
181
182     if (tag)
183         C_MAKE(head->tag_ptr, FAKE_TAG_SIZE, char);
184
185     if (info)
186         *info = head->info_ptr;
187
188     if (name)
189         *name = head->name_ptr;
190
191     if (text)
192         *text = head->text_ptr;
193
194     if (tag)
195         *tag = head->tag_ptr;
196
197     path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, format("%s.txt", filename));
198     FILE *fp;
199     fp = angband_fopen(buf, "r");
200     if (!fp)
201         quit(format(_("'%s.txt'ファイルをオープンできません。", "Cannot open '%s.txt' file."), filename));
202
203     err = init_info_txt(fp, buf, head, head->parse_info_txt);
204     angband_fclose(fp);
205     if (err) {
206         concptr oops = (((err > 0) && (err < PARSE_ERROR_MAX)) ? err_str[err] : _("未知の", "unknown"));
207 #ifdef JP
208         msg_format("'%s.txt'ファイルの %d 行目にエラー。", filename, error_line);
209 #else
210         msg_format("Error %d at line %d of '%s.txt'.", err, error_line, filename);
211 #endif
212         msg_format(_("レコード %d は '%s' エラーがあります。", "Record %d contains a '%s' error."), error_idx, oops);
213         msg_format(_("構文 '%s'。", "Parsing '%s'."), buf);
214         msg_print(NULL);
215         quit(format(_("'%s.txt'ファイルにエラー", "Error in '%s.txt' file."), filename));
216     }
217
218     if (head->retouch)
219         (*head->retouch)(head);
220
221     path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, format(_("%s_j.raw", "%s.raw"), filename));
222     safe_setuid_grab(player_ptr);
223     (void)fd_kill(buf);
224     fd = fd_make(buf, file_permission);
225     safe_setuid_drop();
226     if (fd >= 0) {
227         fd_write(fd, (concptr)(head), head->head_size);
228         fd_write(fd, head->info_ptr, head->info_size);
229         fd_write(fd, head->name_ptr, head->name_size);
230         fd_write(fd, head->text_ptr, head->text_size);
231         fd_write(fd, head->tag_ptr, head->tag_size);
232         (void)fd_close(fd);
233     }
234
235     C_KILL(head->info_ptr, head->info_size, char);
236     if (name)
237         C_KILL(head->name_ptr, FAKE_NAME_SIZE, char);
238
239     if (text)
240         C_KILL(head->text_ptr, FAKE_TEXT_SIZE, char);
241
242     if (tag)
243         C_KILL(head->tag_ptr, FAKE_TAG_SIZE, char);
244
245     path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, format(_("%s_j.raw", "%s.raw"), filename));
246     fd = fd_open(buf, O_RDONLY);
247     if (fd < 0)
248         quit(format(_("'%s_j.raw'ファイルをロードできません。", "Cannot load '%s.raw' file."), filename));
249
250     err = init_info_raw(fd, head);
251     (void)fd_close(fd);
252     if (err)
253         quit(format(_("'%s_j.raw'ファイルを解析できません。", "Cannot parse '%s.raw' file."), filename));
254
255     update_header(head, info, name, text, tag);
256     return 0;
257 }
258
259 /*!
260  * @brief 地形情報読み込みのメインルーチン /
261  * Initialize the "f_info" array
262  * @return エラーコード
263  */
264 errr init_f_info(player_type *player_ptr)
265 {
266     init_header(&f_head, max_f_idx, sizeof(feature_type));
267     f_head.parse_info_txt = parse_f_info;
268     f_head.retouch = retouch_f_info;
269     return init_info(player_ptr, "f_info", &f_head, (void *)&f_info, &f_name, NULL, &f_tag);
270 }
271
272 /*!
273  * @brief ベースアイテム情報読み込みのメインルーチン /
274  * Initialize the "k_info" array
275  * @return エラーコード
276  */
277 errr init_k_info(player_type *player_ptr)
278 {
279     init_header(&k_head, max_k_idx, sizeof(object_kind));
280     k_head.parse_info_txt = parse_k_info;
281     return init_info(player_ptr, "k_info", &k_head, (void *)&k_info, &k_name, &k_text, NULL);
282 }
283
284 /*!
285  * @brief 固定アーティファクト情報読み込みのメインルーチン /
286  * Initialize the "a_info" array
287  * @return エラーコード
288  */
289 errr init_a_info(player_type *player_ptr)
290 {
291     init_header(&a_head, max_a_idx, sizeof(artifact_type));
292     a_head.parse_info_txt = parse_a_info;
293     return init_info(player_ptr, "a_info", &a_head, (void *)&a_info, &a_name, &a_text, NULL);
294 }
295
296 /*!
297  * @brief 固定アーティファクト情報読み込みのメインルーチン /
298  * Initialize the "e_info" array
299  * @return エラーコード
300  */
301 errr init_e_info(player_type *player_ptr)
302 {
303     init_header(&e_head, max_e_idx, sizeof(ego_item_type));
304     e_head.parse_info_txt = parse_e_info;
305     return init_info(player_ptr, "e_info", &e_head, (void *)&e_info, &e_name, &e_text, NULL);
306 }
307
308 /*!
309  * @brief モンスター種族情報読み込みのメインルーチン /
310  * Initialize the "r_info" array
311  * @return エラーコード
312  */
313 errr init_r_info(player_type *player_ptr)
314 {
315     init_header(&r_head, max_r_idx, sizeof(monster_race));
316     r_head.parse_info_txt = parse_r_info;
317     return init_info(player_ptr, "r_info", &r_head, (void *)&r_info, &r_name, &r_text, NULL);
318 }
319
320 /*!
321  * @brief ダンジョン情報読み込みのメインルーチン /
322  * Initialize the "d_info" array
323  * @return エラーコード
324  */
325 errr init_d_info(player_type *player_ptr)
326 {
327     init_header(&d_head, current_world_ptr->max_d_idx, sizeof(dungeon_type));
328     d_head.parse_info_txt = parse_d_info;
329     return init_info(player_ptr, "d_info", &d_head, (void *)&d_info, &d_name, &d_text, NULL);
330 }
331
332 /*!
333  * @brief Vault情報読み込みのメインルーチン /
334  * Initialize the "v_info" array
335  * @return エラーコード
336  * @note
337  * Note that we let each entry have a unique "name" and "text" string,
338  * even if the string happens to be empty (everyone has a unique '\0').
339  */
340 errr init_v_info(player_type *player_ptr)
341 {
342     init_header(&v_head, max_v_idx, sizeof(vault_type));
343     v_head.parse_info_txt = parse_v_info;
344     return init_info(player_ptr, "v_info", &v_head, (void *)&v_info, &v_name, &v_text, NULL);
345 }
346
347 /*!
348  * @brief 職業技能情報読み込みのメインルーチン /
349  * Initialize the "s_info" array
350  * @return エラーコード
351  */
352 errr init_s_info(player_type *player_ptr)
353 {
354     init_header(&s_head, MAX_CLASS, sizeof(skill_table));
355     s_head.parse_info_txt = parse_s_info;
356     return init_info(player_ptr, "s_info", &s_head, (void *)&s_info, NULL, NULL, NULL);
357 }
358
359 /*!
360  * @brief 職業魔法情報読み込みのメインルーチン /
361  * Initialize the "m_info" array
362  * @return エラーコード
363  */
364 errr init_m_info(player_type *player_ptr)
365 {
366     init_header(&m_head, MAX_CLASS, sizeof(player_magic));
367     m_head.parse_info_txt = parse_m_info;
368     return init_info(player_ptr, "m_info", &m_head, (void *)&m_info, NULL, NULL, NULL);
369 }