OSDN Git Service

[Refactor] #39962 files.c/h から display-player.c/h を分離 / Separated display-player...
[hengband/hengband.git] / src / files.c
1 /*!
2  * @file files.c
3  * @brief ファイル入出力管理 / Purpose: code dealing with files (and death)
4  * @date 2014/01/28
5  * @author
6  * <pre>
7  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
8  * This software may be copied and distributed for educational, research,
9  * and not for profit purposes provided that this copyright and statement
10  * are included in all such copies.  Other copyrights may also apply.
11  * 2014 Deskull rearranged comment for Doxygen.\n
12  * </pre>
13  */
14
15 #include "angband.h"
16 #include "term.h"
17 #include "signal-handlers.h"
18 #include "view/display-player.h" // 暫定。後で消す
19 #include "view/display-util.h"
20 #include "view/status-first-page.h"
21 #include "uid-checker.h"
22 #include "files.h"
23 #include "core.h"
24
25 #include "birth.h"
26 #include "character-dump.h"
27 #include "cmd-dump.h"
28 #include "world.h"
29 #include "player-move.h"
30 #include "player-personality.h"
31 #include "player-effects.h"
32 #include "monster-status.h"
33 #include "view-mainwindow.h"
34 #include "objectkind.h"
35 #include "autopick.h"
36 #include "save.h"
37
38 #define PREF_TYPE_NORMAL   0
39 #define PREF_TYPE_AUTOPICK 1
40 #define PREF_TYPE_HISTPREF 2
41
42 concptr ANGBAND_DIR; //!< Path name: The main "lib" directory This variable is not actually used anywhere in the code
43 concptr ANGBAND_DIR_APEX; //!< High score files (binary) These files may be portable between platforms
44 concptr ANGBAND_DIR_BONE; //!< Bone files for player ghosts (ascii) These files are portable between platforms
45 concptr ANGBAND_DIR_DATA; //!< Binary image files for the "*_info" arrays (binary) These files are not portable between platforms
46 concptr ANGBAND_DIR_EDIT; //!< Textual template files for the "*_info" arrays (ascii) These files are portable between platforms
47 concptr ANGBAND_DIR_SCRIPT; //!< Script files These files are portable between platforms.
48 concptr ANGBAND_DIR_FILE; //!< Various extra files (ascii) These files may be portable between platforms
49 concptr ANGBAND_DIR_HELP; //!< Help files (normal) for the online help (ascii) These files are portable between platforms
50 concptr ANGBAND_DIR_INFO; //!< Help files (spoilers) for the online help (ascii) These files are portable between platforms
51 concptr ANGBAND_DIR_PREF; //!< Default user "preference" files (ascii) These files are rarely portable between platforms
52 concptr ANGBAND_DIR_SAVE; //!< Savefiles for current characters (binary)
53 concptr ANGBAND_DIR_USER; //!< User "preference" files (ascii) These files are rarely portable between platforms
54 concptr ANGBAND_DIR_XTRA; //!< Various extra files (binary) These files are rarely portable between platforms
55
56 /*
57  * Buffer to hold the current savefile name
58  * 'savefile' holds full path name. 'savefile_base' holds only base name.
59  */
60 char savefile[1024];
61 char savefile_base[40];
62
63 /*!
64  * @brief 各種データテキストをトークン単位に分解する / Extract the first few "tokens" from a buffer
65  * @param buf データテキストの参照ポインタ
66  * @param num トークンの数
67  * @param tokens トークンを保管する文字列参照ポインタ配列
68  * @param mode オプション
69  * @return 解釈した文字列数
70  * @details
71  * <pre>
72  * This function uses "colon" and "slash" as the delimeter characters.
73  * We never extract more than "num" tokens.  The "last" token may include
74  * "delimeter" characters, allowing the buffer to include a "string" token.
75  * We save pointers to the tokens in "tokens", and return the number found.
76  * Hack -- Attempt to handle the 'c' character formalism
77  * Hack -- An empty buffer, or a final delimeter, yields an "empty" token.
78  * Hack -- We will always extract at least one token
79  * </pre>
80  */
81 s16b tokenize(char *buf, s16b num, char **tokens, BIT_FLAGS mode)
82 {
83         s16b i = 0;
84         char *s = buf;
85         while (i < num - 1)
86         {
87                 char *t;
88                 for (t = s; *t; t++)
89                 {
90                         if ((*t == ':') || (*t == '/')) break;
91
92                         if ((mode & TOKENIZE_CHECKQUOTE) && (*t == '\''))
93                         {
94                                 t++;
95                                 if (*t == '\\') t++;
96                                 if (!*t) break;
97
98                                 t++;
99                                 if (*t != '\'') *t = '\'';
100                         }
101
102                         if (*t == '\\') t++;
103                 }
104
105                 if (!*t) break;
106
107                 *t++ = '\0';
108                 tokens[i++] = s;
109                 s = t;
110         }
111
112         tokens[i++] = s;
113         return i;
114 }
115
116 /* A number with a name */
117 typedef struct named_num named_num;
118
119 struct named_num
120 {
121         concptr name;           /* The name of this thing */
122         int num;                        /* A number associated with it */
123 };
124
125 /* Index of spell type names */
126 static named_num gf_desc[] =
127 {
128         {"GF_ELEC",                             GF_ELEC                         },
129         {"GF_POIS",                             GF_POIS                         },
130         {"GF_ACID",                             GF_ACID                         },
131         {"GF_COLD",                             GF_COLD                         },
132         {"GF_FIRE",                                     GF_FIRE                         },
133         {"GF_PSY_SPEAR",                        GF_PSY_SPEAR            },
134         {"GF_MISSILE",                          GF_MISSILE                      },
135         {"GF_ARROW",                            GF_ARROW                        },
136         {"GF_PLASMA",                           GF_PLASMA                       },
137         {"GF_WATER",                            GF_WATER                        },
138         {"GF_LITE",                                     GF_LITE                         },
139         {"GF_DARK",                                     GF_DARK                         },
140         {"GF_LITE_WEAK",                        GF_LITE_WEAK            },
141         {"GF_DARK_WEAK",                        GF_DARK_WEAK            },
142         {"GF_SHARDS",                           GF_SHARDS                       },
143         {"GF_SOUND",                            GF_SOUND                        },
144         {"GF_CONFUSION",                        GF_CONFUSION            },
145         {"GF_FORCE",                            GF_FORCE                        },
146         {"GF_INERTIA",                          GF_INERTIAL                     },
147         {"GF_MANA",                                     GF_MANA                         },
148         {"GF_METEOR",                           GF_METEOR                       },
149         {"GF_ICE",                                      GF_ICE                          },
150         {"GF_CHAOS",                            GF_CHAOS                        },
151         {"GF_NETHER",                           GF_NETHER                       },
152         {"GF_DISENCHANT",                       GF_DISENCHANT           },
153         {"GF_NEXUS",                            GF_NEXUS                        },
154         {"GF_TIME",                                     GF_TIME                         },
155         {"GF_GRAVITY",                          GF_GRAVITY                      },
156         {"GF_KILL_WALL",                        GF_KILL_WALL            },
157         {"GF_KILL_DOOR",                        GF_KILL_DOOR            },
158         {"GF_KILL_TRAP",                        GF_KILL_TRAP            },
159         {"GF_MAKE_WALL",                        GF_MAKE_WALL            },
160         {"GF_MAKE_DOOR",                        GF_MAKE_DOOR            },
161         {"GF_MAKE_TRAP",                        GF_MAKE_TRAP            },
162         {"GF_MAKE_TREE",                        GF_MAKE_TREE            },
163         {"GF_OLD_CLONE",                        GF_OLD_CLONE            },
164         {"GF_OLD_POLY",                         GF_OLD_POLY                     },
165         {"GF_OLD_HEAL",                         GF_OLD_HEAL                     },
166         {"GF_OLD_SPEED",                        GF_OLD_SPEED            },
167         {"GF_OLD_SLOW",                         GF_OLD_SLOW                     },
168         {"GF_OLD_CONF",                         GF_OLD_CONF                     },
169         {"GF_OLD_SLEEP",                        GF_OLD_SLEEP            },
170         {"GF_HYPODYNAMIA",                      GF_HYPODYNAMIA          },
171         {"GF_AWAY_UNDEAD",                      GF_AWAY_UNDEAD          },
172         {"GF_AWAY_EVIL",                        GF_AWAY_EVIL            },
173         {"GF_AWAY_ALL",                         GF_AWAY_ALL                     },
174         {"GF_TURN_UNDEAD",                      GF_TURN_UNDEAD          },
175         {"GF_TURN_EVIL",                        GF_TURN_EVIL            },
176         {"GF_TURN_ALL",                         GF_TURN_ALL                     },
177         {"GF_DISP_UNDEAD",                      GF_DISP_UNDEAD          },
178         {"GF_DISP_EVIL",                        GF_DISP_EVIL            },
179         {"GF_DISP_ALL",                         GF_DISP_ALL                     },
180         {"GF_DISP_DEMON",                       GF_DISP_DEMON           },
181         {"GF_DISP_LIVING",                      GF_DISP_LIVING          },
182         {"GF_ROCKET",                           GF_ROCKET                       },
183         {"GF_NUKE",                                     GF_NUKE                         },
184         {"GF_MAKE_GLYPH",                       GF_MAKE_GLYPH           },
185         {"GF_STASIS",                           GF_STASIS                       },
186         {"GF_STONE_WALL",                       GF_STONE_WALL           },
187         {"GF_DEATH_RAY",                        GF_DEATH_RAY            },
188         {"GF_STUN",                                     GF_STUN                         },
189         {"GF_HOLY_FIRE",                        GF_HOLY_FIRE            },
190         {"GF_HELL_FIRE",                        GF_HELL_FIRE            },
191         {"GF_DISINTEGRATE",                     GF_DISINTEGRATE         },
192         {"GF_CHARM",                            GF_CHARM                        },
193         {"GF_CONTROL_UNDEAD",           GF_CONTROL_UNDEAD       },
194         {"GF_CONTROL_ANIMAL",           GF_CONTROL_ANIMAL       },
195         {"GF_PSI",                                      GF_PSI                          },
196         {"GF_PSI_DRAIN",                        GF_PSI_DRAIN            },
197         {"GF_TELEKINESIS",                      GF_TELEKINESIS          },
198         {"GF_JAM_DOOR",                         GF_JAM_DOOR                     },
199         {"GF_DOMINATION",                       GF_DOMINATION           },
200         {"GF_DISP_GOOD",                        GF_DISP_GOOD            },
201         {"GF_DRAIN_MANA",                       GF_DRAIN_MANA           },
202         {"GF_MIND_BLAST",                       GF_MIND_BLAST           },
203         {"GF_BRAIN_SMASH",                      GF_BRAIN_SMASH          },
204         {"GF_CAUSE_1",                          GF_CAUSE_1                      },
205         {"GF_CAUSE_2",                          GF_CAUSE_2                      },
206         {"GF_CAUSE_3",                          GF_CAUSE_3                      },
207         {"GF_CAUSE_4",                          GF_CAUSE_4                      },
208         {"GF_HAND_DOOM",                        GF_HAND_DOOM            },
209         {"GF_CAPTURE",                          GF_CAPTURE                      },
210         {"GF_ANIM_DEAD",                        GF_ANIM_DEAD            },
211         {"GF_CHARM_LIVING",                     GF_CHARM_LIVING         },
212         {"GF_IDENTIFY",                         GF_IDENTIFY                     },
213         {"GF_ATTACK",                           GF_ATTACK                       },
214         {"GF_ENGETSU",                          GF_ENGETSU                      },
215         {"GF_GENOCIDE",                         GF_GENOCIDE                     },
216         {"GF_PHOTO",                            GF_PHOTO                        },
217         {"GF_CONTROL_DEMON",            GF_CONTROL_DEMON        },
218         {"GF_LAVA_FLOW",                        GF_LAVA_FLOW            },
219         {"GF_BLOOD_CURSE",                      GF_BLOOD_CURSE          },
220         {"GF_SEEKER",                           GF_SEEKER                       },
221         {"GF_SUPER_RAY",                        GF_SUPER_RAY            },
222         {"GF_STAR_HEAL",                        GF_STAR_HEAL            },
223         {"GF_WATER_FLOW",                       GF_WATER_FLOW           },
224         {"GF_CRUSADE",                          GF_CRUSADE                      },
225         {"GF_STASIS_EVIL",                      GF_STASIS_EVIL          },
226         {"GF_WOUNDS",                           GF_WOUNDS                       },
227         {NULL,                                          0                                       }
228 };
229
230
231 /*!
232  * @brief 設定ファイルの各行から各種テキスト情報を取得する /
233  * Parse a sub-file of the "extra info" (format shown below)
234  * @param creature_ptr プレーヤーへの参照ポインタ
235  * @param buf データテキストの参照ポインタ
236  * @return エラーコード
237  * @details
238  * <pre>
239  * Each "action" line has an "action symbol" in the first column,
240  * followed by a colon, followed by some command specific info,
241  * usually in the form of "tokens" separated by colons or slashes.
242  * Blank lines, lines starting with white space, and lines starting
243  * with pound signs ("#") are ignored (as comments).
244  * Note the use of "tokenize()" to allow the use of both colons and
245  * slashes as delimeters, while still allowing final tokens which
246  * may contain any characters including "delimiters".
247  * Note the use of "strtol()" to allow all "integers" to be encoded
248  * in decimal, hexidecimal, or octal form.
249  * Note that "monster zero" is used for the "player" attr/char, "object
250  * zero" will be used for the "stack" attr/char, and "feature zero" is
251  * used for the "nothing" attr/char.
252  * Parse another file recursively, see below for details
253  *   %:\<filename\>
254  * Specify the attr/char values for "monsters" by race index
255  *   R:\<num\>:\<a\>:\<c\>
256  * Specify the attr/char values for "objects" by kind index
257  *   K:\<num\>:\<a\>:\<c\>
258  * Specify the attr/char values for "features" by feature index
259  *   F:\<num\>:\<a\>:\<c\>
260  * Specify the attr/char values for unaware "objects" by kind tval
261  *   U:\<tv\>:\<a\>:\<c\>
262  * Specify the attr/char values for inventory "objects" by kind tval
263  *   E:\<tv\>:\<a\>:\<c\>
264  * Define a macro action, given an encoded macro action
265  *   A:\<str\>
266  * Create a normal macro, given an encoded macro trigger
267  *   P:\<str\>
268  * Create a command macro, given an encoded macro trigger
269  *   C:\<str\>
270  * Create a keyset mapping
271  *   S:\<key\>:\<key\>:\<dir\>
272  * Turn an option off, given its name
273  *   X:\<str\>
274  * Turn an option on, given its name
275  *   Y:\<str\>
276  * Specify visual information, given an index, and some data
277  *   V:\<num\>:\<kv\>:\<rv\>:\<gv\>:\<bv\>
278  * Specify the set of colors to use when drawing a zapped spell
279  *   Z:\<type\>:\<str\>
280  * Specify a macro trigger template and macro trigger names.
281  *   T:\<template\>:\<modifier chr\>:\<modifier name1\>:\<modifier name2\>:...
282  *   T:\<trigger\>:\<keycode\>:\<shift-keycode\>
283  * </pre>
284  */
285 errr process_pref_file_command(player_type *creature_ptr, char *buf)
286 {
287         if (buf[1] != ':') return 1;
288
289         char *zz[16];
290         switch (buf[0])
291         {
292         case 'H':
293         {
294                 /* Process "H:<history>" */
295                 add_history_from_pref_line(buf + 2);
296                 return 0;
297         }
298         case 'R':
299         {
300                 /* Process "R:<num>:<a>/<c>" -- attr/char for monster races */
301                 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
302
303                 monster_race *r_ptr;
304                 int i = (huge)strtol(zz[0], NULL, 0);
305                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
306                 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
307                 if (i >= max_r_idx) return 1;
308                 r_ptr = &r_info[i];
309                 if (n1 || (!(n2 & 0x80) && n2)) r_ptr->x_attr = n1; /* Allow TERM_DARK text */
310                 if (n2) r_ptr->x_char = n2;
311                 return 0;
312         }
313         case 'K':
314         {
315                 /* Process "K:<num>:<a>/<c>"  -- attr/char for object kinds */
316                 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
317                 
318                 object_kind *k_ptr;
319                 int i = (huge)strtol(zz[0], NULL, 0);
320                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
321                 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
322                 if (i >= max_k_idx) return 1;
323                 k_ptr = &k_info[i];
324                 if (n1 || (!(n2 & 0x80) && n2)) k_ptr->x_attr = n1; /* Allow TERM_DARK text */
325                 if (n2) k_ptr->x_char = n2;
326                 return 0;
327         }
328         case 'F':
329         {
330                 /* Process "F:<num>:<a>/<c>" -- attr/char for terrain features */
331                 /* "F:<num>:<a>/<c>" */
332                 /* "F:<num>:<a>/<c>:LIT" */
333                 /* "F:<num>:<a>/<c>:<la>/<lc>:<da>/<dc>" */
334                 feature_type *f_ptr;
335                 int num = tokenize(buf + 2, F_LIT_MAX * 2 + 1, zz, TOKENIZE_CHECKQUOTE);
336
337                 if ((num != 3) && (num != 4) && (num != F_LIT_MAX * 2 + 1)) return 1;
338                 else if ((num == 4) && !streq(zz[3], "LIT")) return 1;
339
340                 int i = (huge)strtol(zz[0], NULL, 0);
341                 if (i >= max_f_idx) return 1;
342                 f_ptr = &f_info[i];
343
344                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
345                 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
346                 if (n1 || (!(n2 & 0x80) && n2)) f_ptr->x_attr[F_LIT_STANDARD] = n1; /* Allow TERM_DARK text */
347                 if (n2) f_ptr->x_char[F_LIT_STANDARD] = n2;
348
349                 switch (num)
350                 {
351                 case 3:
352                 {
353                         /* No lighting support */
354                         n1 = f_ptr->x_attr[F_LIT_STANDARD];
355                         n2 = f_ptr->x_char[F_LIT_STANDARD];
356                         for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++)
357                         {
358                                 f_ptr->x_attr[j] = n1;
359                                 f_ptr->x_char[j] = n2;
360                         }
361
362                         return 0;
363                 }
364                 case 4:
365                 {
366                         /* Use default lighting */
367                         apply_default_feat_lighting(f_ptr->x_attr, f_ptr->x_char);
368                         return 0;
369                 }
370                 case F_LIT_MAX * 2 + 1:
371                 {
372                         /* Use desired lighting */
373                         for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++)
374                         {
375                                 n1 = (TERM_COLOR)strtol(zz[j * 2 + 1], NULL, 0);
376                                 n2 = (SYMBOL_CODE)strtol(zz[j * 2 + 2], NULL, 0);
377                                 if (n1 || (!(n2 & 0x80) && n2)) f_ptr->x_attr[j] = n1; /* Allow TERM_DARK text */
378                                 if (n2) f_ptr->x_char[j] = n2;
379                         }
380
381                         return 0;
382                 }
383                 default:
384                         return 0;
385                 }
386         }
387         case 'S':
388         {
389                 /* Process "S:<num>:<a>/<c>" -- attr/char for special things */
390                 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
391
392                 int j = (byte)strtol(zz[0], NULL, 0);
393                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
394                 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
395                 misc_to_attr[j] = n1;
396                 misc_to_char[j] = n2;
397                 return 0;
398         }
399         case 'U':
400         {
401                 /* Process "U:<tv>:<a>/<c>" -- attr/char for unaware items */
402                 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
403
404                 int j = (huge)strtol(zz[0], NULL, 0);
405                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
406                 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
407                 for (int i = 1; i < max_k_idx; i++)
408                 {
409                         object_kind *k_ptr = &k_info[i];
410                         if (k_ptr->tval == j)
411                         {
412                                 if (n1) k_ptr->d_attr = n1;
413                                 if (n2) k_ptr->d_char = n2;
414                         }
415                 }
416
417                 return 0;
418         }
419         case 'E':
420         {
421                 /* Process "E:<tv>:<a>" -- attribute for inventory objects */
422                 if (tokenize(buf + 2, 2, zz, TOKENIZE_CHECKQUOTE) != 2) return 1;
423
424                 int j = (byte)strtol(zz[0], NULL, 0) % 128;
425                 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
426                 if (n1) tval_to_attr[j] = n1;
427                 return 0;
428         }
429         case 'A':
430         {
431                 /* Process "A:<str>" -- save an "action" for later */
432                 text_to_ascii(macro__buf, buf + 2);
433                 return 0;
434         }
435         case 'P':
436         {
437                 /* Process "P:<str>" -- normal macro */
438                 char tmp[1024];
439                 text_to_ascii(tmp, buf + 2);
440                 macro_add(tmp, macro__buf);
441                 return 0;
442         }
443         case 'C':
444         {
445                 /* Process "C:<str>" -- create keymap */
446                 if (tokenize(buf + 2, 2, zz, TOKENIZE_CHECKQUOTE) != 2) return 1;
447
448                 int mode = strtol(zz[0], NULL, 0);
449                 if ((mode < 0) || (mode >= KEYMAP_MODES)) return 1;
450
451                 char tmp[1024];
452                 text_to_ascii(tmp, zz[1]);
453                 if (!tmp[0] || tmp[1]) return 1;
454
455                 int i = (byte)(tmp[0]);
456                 string_free(keymap_act[mode][i]);
457                 keymap_act[mode][i] = string_make(macro__buf);
458                 return 0;
459         }
460         case 'V':
461         {
462                 /* Process "V:<num>:<kv>:<rv>:<gv>:<bv>" -- visual info */
463                 if (tokenize(buf + 2, 5, zz, TOKENIZE_CHECKQUOTE) != 5) return 1;
464
465                 int i = (byte)strtol(zz[0], NULL, 0);
466                 angband_color_table[i][0] = (byte)strtol(zz[1], NULL, 0);
467                 angband_color_table[i][1] = (byte)strtol(zz[2], NULL, 0);
468                 angband_color_table[i][2] = (byte)strtol(zz[3], NULL, 0);
469                 angband_color_table[i][3] = (byte)strtol(zz[4], NULL, 0);
470                 return 0;
471         }
472         case 'X':
473         case 'Y':
474         {
475                 /* Process "X:<str>" -- turn option off */
476                 /* Process "Y:<str>" -- turn option on */
477                 for (int i = 0; option_info[i].o_desc; i++)
478                 {
479                         bool is_option = option_info[i].o_var != NULL;
480                         is_option &= option_info[i].o_text != NULL;
481                         is_option &= streq(option_info[i].o_text, buf + 2);
482                         if (!is_option) continue;
483
484                         int os = option_info[i].o_set;
485                         int ob = option_info[i].o_bit;
486
487                         if ((creature_ptr->playing || current_world_ptr->character_xtra) &&
488                                 (OPT_PAGE_BIRTH == option_info[i].o_page) && !current_world_ptr->wizard)
489                         {
490                                 msg_format(_("初期オプションは変更できません! '%s'", "Birth options can not changed! '%s'"), buf);
491                                 msg_print(NULL);
492                                 return 0;
493                         }
494
495                         if (buf[0] == 'X')
496                         {
497                                 option_flag[os] &= ~(1L << ob);
498                                 (*option_info[i].o_var) = FALSE;
499                                 return 0;
500                         }
501
502                         option_flag[os] |= (1L << ob);
503                         (*option_info[i].o_var) = TRUE;
504                         return 0;
505                 }
506
507                 msg_format(_("オプションの名前が正しくありません: %s", "Ignored invalid option: %s"), buf);
508                 msg_print(NULL);
509                 return 0;
510         }
511         case 'Z':
512         {
513                 /* Process "Z:<type>:<str>" -- set spell color */
514                 char *t = my_strchr(buf + 2, ':');
515                 if (!t) return 1;
516
517                 *(t++) = '\0';
518                 for (int i = 0; gf_desc[i].name; i++)
519                 {
520                         if (!streq(gf_desc[i].name, buf + 2)) continue;
521
522                         gf_color[gf_desc[i].num] = (TERM_COLOR)quark_add(t);
523                         return 0;
524                 }
525
526                 return 1;
527         }
528         case 'T':
529         {
530                 /* Initialize macro trigger names and a template */
531                 /* Process "T:<trigger>:<keycode>:<shift-keycode>" */
532                 /* Process "T:<template>:<modifier chr>:<modifier name>:..." */
533                 int tok = tokenize(buf + 2, 2 + MAX_MACRO_MOD, zz, 0);
534
535                 /* Process "T:<template>:<modifier chr>:<modifier name>:..." */
536                 if (tok >= 4)
537                 {
538                         if (macro_template != NULL)
539                         {
540                                 int macro_modifier_length = strlen(macro_modifier_chr);
541                                 string_free(macro_template);
542                                 macro_template = NULL;
543                                 string_free(macro_modifier_chr);
544                                 for (int i = 0; i < macro_modifier_length; i++)
545                                 {
546                                         string_free(macro_modifier_name[i]);
547                                 }
548
549                                 for (int i = 0; i < max_macrotrigger; i++)
550                                 {
551                                         string_free(macro_trigger_name[i]);
552                                         string_free(macro_trigger_keycode[0][i]);
553                                         string_free(macro_trigger_keycode[1][i]);
554                                 }
555
556                                 max_macrotrigger = 0;
557                         }
558
559                         if (*zz[0] == '\0') return 0;
560
561                         int zz_length = strlen(zz[1]);
562                         zz_length = MIN(MAX_MACRO_MOD, zz_length);
563                         if (2 + zz_length != tok) return 1;
564
565                         macro_template = string_make(zz[0]);
566                         macro_modifier_chr = string_make(zz[1]);
567                         for (int i = 0; i < zz_length; i++)
568                         {
569                                 macro_modifier_name[i] = string_make(zz[2 + i]);
570                         }
571
572                         return 0;
573                 }
574
575                 /* Process "T:<trigger>:<keycode>:<shift-keycode>" */
576                 if (tok < 2) return 0;
577
578                 char buf_aux[1024];
579                 char *t, *s;
580                 if (max_macrotrigger >= MAX_MACRO_TRIG)
581                 {
582                         msg_print(_("マクロトリガーの設定が多すぎます!", "Too many macro triggers!"));
583                         return 1;
584                 }
585
586                 int m = max_macrotrigger;
587                 max_macrotrigger++;
588                 t = buf_aux;
589                 s = zz[0];
590                 while (*s)
591                 {
592                         if ('\\' == *s) s++;
593                         *t++ = *s++;
594                 }
595
596                 *t = '\0';
597                 macro_trigger_name[m] = string_make(buf_aux);
598                 macro_trigger_keycode[0][m] = string_make(zz[1]);
599                 if (tok == 3)
600                 {
601                         macro_trigger_keycode[1][m] = string_make(zz[2]);
602                         return 0;
603                 }
604
605                 macro_trigger_keycode[1][m] = string_make(zz[1]);
606                 return 0;
607         }
608         }
609
610         return 1;
611 }
612
613
614 /*!
615  * @brief process_pref_fileのサブルーチンとして条件分岐処理の解釈と結果を返す /
616  * Helper function for "process_pref_file()"
617  * @param creature_ptr プレーヤーへの参照ポインタ
618  * @param sp テキスト文字列の参照ポインタ
619  * @param fp 再帰中のポインタ参照
620  * @return
621  * @details
622  * <pre>
623  * Input:
624  *   v: output buffer array
625  *   f: final character
626  * Output:
627  *   result
628  * </pre>
629  */
630 concptr process_pref_file_expr(player_type *creature_ptr, char **sp, char *fp)
631 {
632         char *s;
633         s = (*sp);
634         while (iswspace(*s)) s++;
635
636         char *b;
637         b = s;
638
639         concptr v = "?o?o?";
640
641         char b1 = '[';
642         char b2 = ']';
643         char f = ' ';
644         static char tmp[16];
645         if (*s == b1)
646         {
647                 concptr p;
648                 concptr t;
649
650                 /* Skip b1 */
651                 s++;
652
653                 /* First */
654                 t = process_pref_file_expr(creature_ptr, &s, &f);
655
656                 if (!*t)
657                 {
658                 }
659                 else if (streq(t, "IOR"))
660                 {
661                         v = "0";
662                         while (*s && (f != b2))
663                         {
664                                 t = process_pref_file_expr(creature_ptr, &s, &f);
665                                 if (*t && !streq(t, "0")) v = "1";
666                         }
667                 }
668                 else if (streq(t, "AND"))
669                 {
670                         v = "1";
671                         while (*s && (f != b2))
672                         {
673                                 t = process_pref_file_expr(creature_ptr, &s, &f);
674                                 if (*t && streq(t, "0")) v = "0";
675                         }
676                 }
677                 else if (streq(t, "NOT"))
678                 {
679                         v = "1";
680                         while (*s && (f != b2))
681                         {
682                                 t = process_pref_file_expr(creature_ptr, &s, &f);
683                                 if (*t && streq(t, "1")) v = "0";
684                         }
685                 }
686                 else if (streq(t, "EQU"))
687                 {
688                         v = "0";
689                         if (*s && (f != b2))
690                         {
691                                 t = process_pref_file_expr(creature_ptr, &s, &f);
692                         }
693                         while (*s && (f != b2))
694                         {
695                                 p = process_pref_file_expr(creature_ptr, &s, &f);
696                                 if (streq(t, p)) v = "1";
697                         }
698                 }
699                 else if (streq(t, "LEQ"))
700                 {
701                         v = "1";
702                         if (*s && (f != b2))
703                         {
704                                 t = process_pref_file_expr(creature_ptr, &s, &f);
705                         }
706                         while (*s && (f != b2))
707                         {
708                                 p = t;
709                                 t = process_pref_file_expr(creature_ptr, &s, &f);
710                                 if (*t && atoi(p) > atoi(t)) v = "0";
711                         }
712                 }
713                 else if (streq(t, "GEQ"))
714                 {
715                         v = "1";
716                         if (*s && (f != b2))
717                         {
718                                 t = process_pref_file_expr(creature_ptr, &s, &f);
719                         }
720                         while (*s && (f != b2))
721                         {
722                                 p = t;
723                                 t = process_pref_file_expr(creature_ptr, &s, &f);
724                                 if (*t && atoi(p) < atoi(t)) v = "0";
725                         }
726                 }
727                 else
728                 {
729                         while (*s && (f != b2))
730                         {
731                                 t = process_pref_file_expr(creature_ptr, &s, &f);
732                         }
733                 }
734
735                 if (f != b2) v = "?x?x?";
736
737                 if ((f = *s) != '\0') *s++ = '\0';
738
739                 *fp = f;
740                 *sp = s;
741                 return v;
742         }
743
744         /* Accept all printables except spaces and brackets */
745 #ifdef JP
746         while (iskanji(*s) || (isprint(*s) && !my_strchr(" []", *s)))
747         {
748                 if (iskanji(*s)) s++;
749                 s++;
750         }
751 #else
752         while (isprint(*s) && !my_strchr(" []", *s)) ++s;
753 #endif
754
755         if ((f = *s) != '\0') *s++ = '\0';
756
757         if (*b != '$')
758         {
759                 v = b;
760                 *fp = f;
761                 *sp = s;
762                 return v;
763         }
764
765         if (streq(b + 1, "SYS"))
766         {
767                 v = ANGBAND_SYS;
768         }
769         else if (streq(b + 1, "KEYBOARD"))
770         {
771                 v = ANGBAND_KEYBOARD;
772         }
773         else if (streq(b + 1, "GRAF"))
774         {
775                 v = ANGBAND_GRAF;
776         }
777         else if (streq(b + 1, "MONOCHROME"))
778         {
779                 if (arg_monochrome)
780                         v = "ON";
781                 else
782                         v = "OFF";
783         }
784         else if (streq(b + 1, "RACE"))
785         {
786 #ifdef JP
787                 v = rp_ptr->E_title;
788 #else
789                 v = rp_ptr->title;
790 #endif
791         }
792         else if (streq(b + 1, "CLASS"))
793         {
794 #ifdef JP
795                 v = cp_ptr->E_title;
796 #else
797                 v = cp_ptr->title;
798 #endif
799         }
800         else if (streq(b + 1, "PLAYER"))
801         {
802                 static char tmp_player_name[32];
803                 char *pn, *tpn;
804                 for (pn = creature_ptr->name, tpn = tmp_player_name; *pn; pn++, tpn++)
805                 {
806 #ifdef JP
807                         if (iskanji(*pn))
808                         {
809                                 *(tpn++) = *(pn++);
810                                 *tpn = *pn;
811                                 continue;
812                         }
813 #endif
814                         *tpn = my_strchr(" []", *pn) ? '_' : *pn;
815                 }
816
817                 *tpn = '\0';
818                 v = tmp_player_name;
819         }
820         else if (streq(b + 1, "REALM1"))
821         {
822 #ifdef JP
823                 v = E_realm_names[creature_ptr->realm1];
824 #else
825                 v = realm_names[creature_ptr->realm1];
826 #endif
827         }
828         else if (streq(b + 1, "REALM2"))
829         {
830 #ifdef JP
831                 v = E_realm_names[creature_ptr->realm2];
832 #else
833                 v = realm_names[creature_ptr->realm2];
834 #endif
835         }
836         else if (streq(b + 1, "LEVEL"))
837         {
838                 sprintf(tmp, "%02d", creature_ptr->lev);
839                 v = tmp;
840         }
841         else if (streq(b + 1, "AUTOREGISTER"))
842         {
843                 if (creature_ptr->autopick_autoregister)
844                         v = "1";
845                 else
846                         v = "0";
847         }
848         else if (streq(b + 1, "MONEY"))
849         {
850                 sprintf(tmp, "%09ld", (long int)creature_ptr->au);
851                 v = tmp;
852         }
853
854         *fp = f;
855         *sp = s;
856         return v;
857 }
858
859
860 /*!
861  * @brief process_pref_fileのサブルーチン /
862  * Open the "user pref file" and parse it.
863  * @param creature_ptr プレーヤーへの参照ポインタ
864  * @param name 読み込むファイル名
865  * @param preftype prefファイルのタイプ
866  * @return エラーコード
867  * @details
868  * <pre>
869  * Input:
870  *   v: output buffer array
871  *   f: final character
872  * Output:
873  *   result
874  * </pre>
875  */
876 static errr process_pref_file_aux(player_type *creature_ptr, concptr name, int preftype)
877 {
878         FILE *fp;
879         fp = my_fopen(name, "r");
880         if (!fp) return -1;
881
882         char buf[1024];
883         char old[1024];
884         int line = -1;
885         errr err = 0;
886         bool bypass = FALSE;
887         while (my_fgets(fp, buf, sizeof(buf)) == 0)
888         {
889                 line++;
890                 if (!buf[0]) continue;
891
892 #ifdef JP
893                 if (!iskanji(buf[0]))
894 #endif
895                         if (iswspace(buf[0])) continue;
896
897                 if (buf[0] == '#') continue;
898                 strcpy(old, buf);
899
900                 /* Process "?:<expr>" */
901                 if ((buf[0] == '?') && (buf[1] == ':'))
902                 {
903                         char f;
904                         char *s;
905                         s = buf + 2;
906                         concptr v = process_pref_file_expr(creature_ptr, &s, &f);
907                         bypass = streq(v, "0");
908                         continue;
909                 }
910
911                 if (bypass) continue;
912
913                 /* Process "%:<file>" */
914                 if (buf[0] == '%')
915                 {
916                         static int depth_count = 0;
917                         if (depth_count > 20) continue;
918
919                         depth_count++;
920                         switch (preftype)
921                         {
922                         case PREF_TYPE_AUTOPICK:
923                                 (void)process_autopick_file(creature_ptr, buf + 2);
924                                 break;
925                         case PREF_TYPE_HISTPREF:
926                                 (void)process_histpref_file(creature_ptr, buf + 2);
927                                 break;
928                         default:
929                                 (void)process_pref_file(creature_ptr, buf + 2);
930                                 break;
931                         }
932
933                         depth_count--;
934                         continue;
935                 }
936
937                 err = process_pref_file_command(creature_ptr, buf);
938                 if (err != 0)
939                 {
940                         if (preftype != PREF_TYPE_AUTOPICK)
941                                 break;
942                         err = process_autopick_file_command(buf);
943                 }
944         }
945
946         if (err != 0)
947         {
948                 /* Print error message */
949                 /* ToDo: Add better error messages */
950                 msg_format(_("ファイル'%s'の%d行でエラー番号%dのエラー。", "Error %d in line %d of file '%s'."),
951                         _(name, err), line, _(err, name));
952                 msg_format(_("('%s'を解析中)", "Parsing '%s'"), old);
953                 msg_print(NULL);
954         }
955
956         my_fclose(fp);
957         return (err);
958 }
959
960
961 /*!
962  * @brief pref設定ファイルを読み込み設定を反映させる /
963  * Process the "user pref file" with the given name
964  * @param creature_ptr プレーヤーへの参照ポインタ
965  * @param name 読み込むファイル名
966  * @return エラーコード
967  * @details
968  * <pre>
969  * See the functions above for a list of legal "commands".
970  * We also accept the special "?" and "%" directives, which
971  * allow conditional evaluation and filename inclusion.
972  * </pre>
973  */
974 errr process_pref_file(player_type *creature_ptr, concptr name)
975 {
976         char buf[1024];
977         path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, name);
978
979         errr err1 = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_NORMAL);
980         if (err1 > 0) return err1;
981
982         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
983         errr err2 = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_NORMAL);
984         if (err2 < 0 && !err1)
985                 return -2;
986
987         return err2;
988 }
989
990
991 /*!
992  * @brief プレイヤーの装備一覧をシンボルで並べる
993  * Equippy chars
994  * @param creature_ptr プレーヤーへの参照ポインタ
995  * @param y 表示するコンソールの行
996  * @param x 表示するコンソールの列
997  * @param mode オプション
998  * @return なし
999  */
1000 void display_player_equippy(player_type *creature_ptr, TERM_LEN y, TERM_LEN x, BIT_FLAGS16 mode)
1001 {
1002         /* Weapon flags need only two column */
1003         int max_i = (mode & DP_WP) ? INVEN_LARM + 1 : INVEN_TOTAL;
1004
1005         /* Dump equippy chars */
1006         for (int i = INVEN_RARM; i < max_i; i++)
1007         {
1008                 object_type *o_ptr;
1009                 o_ptr = &creature_ptr->inventory_list[i];
1010
1011                 TERM_COLOR a = object_attr(o_ptr);
1012                 char c = object_char(o_ptr);
1013
1014                 if (!equippy_chars || !o_ptr->k_idx)
1015                 {
1016                         c = ' ';
1017                         a = TERM_DARK;
1018                 }
1019
1020                 Term_putch(x + i - INVEN_RARM, y, a, c);
1021         }
1022 }
1023
1024
1025 /*!
1026  * @brief プレイヤーステータスをファイルダンプ出力する
1027  * Hack -- Dump a character description file
1028  * @param creature_ptr プレーヤーへの参照ポインタ
1029  * @param name 出力ファイル名
1030  * @return エラーコード
1031  * @details
1032  * Allow the "full" flag to dump additional info,
1033  * and trigger its usage from various places in the code.
1034  */
1035 errr file_character(player_type *creature_ptr, concptr name)
1036 {
1037         char buf[1024];
1038         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
1039
1040         FILE_TYPE(FILE_TYPE_TEXT);
1041
1042         int     fd = fd_open(buf, O_RDONLY);
1043         if (fd >= 0)
1044         {
1045                 char out_val[160];
1046                 (void)fd_close(fd);
1047                 (void)sprintf(out_val, _("現存するファイル %s に上書きしますか? ", "Replace existing file %s? "), buf);
1048                 if (get_check_strict(out_val, CHECK_NO_HISTORY)) fd = -1;
1049         }
1050
1051         FILE *fff = NULL;
1052         if (fd < 0) fff = my_fopen(buf, "w");
1053
1054         if (!fff)
1055         {
1056                 prt(_("キャラクタ情報のファイルへの書き出しに失敗しました!", "Character dump failed!"), 0, 0);
1057                 (void)inkey();
1058                 return -1;
1059         }
1060
1061         /*
1062         * todo view-mainwindow への依存があるが、file_character() 自体関数ポインタなのでよそから呼び出されるので何とかするのは辛い
1063         * ついでに他の関数でもview(略) は参照されているので、簡単に除去することはできない…
1064         */
1065         make_character_dump(creature_ptr, fff, update_playtime, display_player);
1066         my_fclose(fff);
1067         msg_print(_("キャラクタ情報のファイルへの書き出しに成功しました。", "Character dump successful."));
1068         msg_print(NULL);
1069         return 0;
1070 }
1071
1072
1073 /*!
1074  * @brief ファイル内容の一行をコンソールに出力する
1075  * Display single line of on-line help file
1076  * @param str 出力する文字列
1077  * @param cy コンソールの行
1078  * @param shower 確認中
1079  * @return なし
1080  * @details
1081  * <pre>
1082  * You can insert some special color tag to change text color.
1083  * Such as...
1084  * WHITETEXT [[[[y|SOME TEXT WHICH IS DISPLAYED IN YELLOW| WHITETEXT
1085  * A colored segment is between "[[[[y|" and the last "|".
1086  * You can use any single character in place of the "|".
1087  * </pre>
1088  */
1089 static void show_file_aux_line(concptr str, int cy, concptr shower)
1090 {
1091         char lcstr[1024];
1092         if (shower)
1093         {
1094                 strcpy(lcstr, str);
1095                 str_tolower(lcstr);
1096         }
1097
1098         int cx = 0;
1099         Term_gotoxy(cx, cy);
1100
1101         static const char tag_str[] = "[[[[";
1102         byte color = TERM_WHITE;
1103         char in_tag = '\0';
1104         for (int i = 0; str[i];)
1105         {
1106                 int len = strlen(&str[i]);
1107                 int showercol = len + 1;
1108                 int bracketcol = len + 1;
1109                 int endcol = len;
1110                 concptr ptr;
1111                 if (shower)
1112                 {
1113                         ptr = my_strstr(&lcstr[i], shower);
1114                         if (ptr) showercol = ptr - &lcstr[i];
1115                 }
1116
1117                 ptr = in_tag ? my_strchr(&str[i], in_tag) : my_strstr(&str[i], tag_str);
1118                 if (ptr) bracketcol = ptr - &str[i];
1119                 if (bracketcol < endcol) endcol = bracketcol;
1120                 if (showercol < endcol) endcol = showercol;
1121
1122                 Term_addstr(endcol, color, &str[i]);
1123                 cx += endcol;
1124                 i += endcol;
1125
1126                 if (endcol == showercol)
1127                 {
1128                         int showerlen = strlen(shower);
1129                         Term_addstr(showerlen, TERM_YELLOW, &str[i]);
1130                         cx += showerlen;
1131                         i += showerlen;
1132                         continue;
1133                 }
1134
1135                 if (endcol != bracketcol) continue;
1136
1137                 if (in_tag)
1138                 {
1139                         i++;
1140                         in_tag = '\0';
1141                         color = TERM_WHITE;
1142                         continue;
1143                 }
1144
1145                 i += sizeof(tag_str) - 1;
1146                 color = color_char_to_attr(str[i]);
1147                 if (color == 255 || str[i + 1] == '\0')
1148                 {
1149                         color = TERM_WHITE;
1150                         Term_addstr(-1, TERM_WHITE, tag_str);
1151                         cx += sizeof(tag_str) - 1;
1152                         continue;
1153                 }
1154
1155                 i++;
1156                 in_tag = str[i];
1157                 i++;
1158         }
1159
1160         Term_erase(cx, cy, 255);
1161 }
1162
1163
1164 /*!
1165  * @brief ファイル内容をコンソールに出力する
1166  * Recursive file perusal.
1167  * @param creature_ptr プレーヤーへの参照ポインタ
1168  * @param show_version TRUEならばコンソール上にゲームのバージョンを表示する
1169  * @param name ファイル名の文字列
1170  * @param what 内容キャプションの文字列
1171  * @param line 表示の現在行
1172  * @param mode オプション
1173  * @return なし
1174  * @details
1175  * <pre>
1176  * Process various special text in the input file, including
1177  * the "menu" structures used by the "help file" system.
1178  * Return FALSE on 'q' to exit from a deep, otherwise TRUE.
1179  * </pre>
1180  */
1181 bool show_file(player_type *creature_ptr, bool show_version, concptr name, concptr what, int line, BIT_FLAGS mode)
1182 {
1183         int i, skey;
1184         int next = 0;
1185         int size = 0;
1186         int back = 0;
1187         bool menu = FALSE;
1188         FILE *fff = NULL;
1189         concptr find = NULL;
1190         concptr tag = NULL;
1191         char finder_str[81];
1192         char shower_str[81];
1193         char back_str[81];
1194         concptr shower = NULL;
1195         char filename[1024];
1196         char caption[128];
1197         char path[1024];
1198         char buf[1024];
1199         char hook[68][32];
1200         bool reverse = (line < 0);
1201         int wid, hgt;
1202         Term_get_size(&wid, &hgt);
1203         int rows = hgt - 4;
1204
1205         strcpy(finder_str, "");
1206         strcpy(shower_str, "");
1207         strcpy(caption, "");
1208         for (i = 0; i < 68; i++)
1209         {
1210                 hook[i][0] = '\0';
1211         }
1212
1213         strcpy(filename, name);
1214         int n = strlen(filename);
1215
1216         for (i = 0; i < n; i++)
1217         {
1218                 if (filename[i] == '#')
1219                 {
1220                         filename[i] = '\0';
1221                         tag = filename + i + 1;
1222                         break;
1223                 }
1224         }
1225
1226         name = filename;
1227         if (what)
1228         {
1229                 strcpy(caption, what);
1230                 strcpy(path, name);
1231                 fff = my_fopen(path, "r");
1232         }
1233
1234         if (!fff)
1235         {
1236                 sprintf(caption, _("ヘルプ・ファイル'%s'", "Help file '%s'"), name);
1237                 path_build(path, sizeof(path), ANGBAND_DIR_HELP, name);
1238                 fff = my_fopen(path, "r");
1239         }
1240
1241         if (!fff)
1242         {
1243                 sprintf(caption, _("スポイラー・ファイル'%s'", "Info file '%s'"), name);
1244                 path_build(path, sizeof(path), ANGBAND_DIR_INFO, name);
1245                 fff = my_fopen(path, "r");
1246         }
1247
1248         if (!fff)
1249         {
1250                 path_build(path, sizeof(path), ANGBAND_DIR, name);
1251
1252                 for (i = 0; path[i]; i++)
1253                         if ('\\' == path[i])
1254                                 path[i] = PATH_SEP[0];
1255
1256                 sprintf(caption, _("スポイラー・ファイル'%s'", "Info file '%s'"), name);
1257                 fff = my_fopen(path, "r");
1258         }
1259
1260         if (!fff)
1261         {
1262                 msg_format(_("'%s'をオープンできません。", "Cannot open '%s'."), name);
1263                 msg_print(NULL);
1264
1265                 return TRUE;
1266         }
1267
1268         while (TRUE)
1269         {
1270                 char *str = buf;
1271                 if (my_fgets(fff, buf, sizeof(buf))) break;
1272                 if (!prefix(str, "***** "))
1273                 {
1274                         next++;
1275                         continue;
1276                 }
1277
1278                 if ((str[6] == '[') && isalpha(str[7]))
1279                 {
1280                         int k = str[7] - 'A';
1281                         menu = TRUE;
1282                         if ((str[8] == ']') && (str[9] == ' '))
1283                         {
1284                                 strncpy(hook[k], str + 10, 31);
1285                                 hook[k][31] = '\0';
1286                         }
1287
1288                         continue;
1289                 }
1290
1291                 if (str[6] != '<') continue;
1292
1293                 size_t len = strlen(str);
1294                 if (str[len - 1] == '>')
1295                 {
1296                         str[len - 1] = '\0';
1297                         if (tag && streq(str + 7, tag)) line = next;
1298                 }
1299         }
1300
1301         size = next;
1302         if (line == -1) line = ((size - 1) / rows)*rows;
1303         Term_clear();
1304
1305         while (TRUE)
1306         {
1307                 if (line >= size - rows)
1308                         line = size - rows;
1309                 if (line < 0) line = 0;
1310
1311                 if (next > line)
1312                 {
1313                         my_fclose(fff);
1314                         fff = my_fopen(path, "r");
1315                         if (!fff) return FALSE;
1316
1317                         next = 0;
1318                 }
1319
1320                 while (next < line)
1321                 {
1322                         if (my_fgets(fff, buf, sizeof(buf))) break;
1323                         if (prefix(buf, "***** ")) continue;
1324                         next++;
1325                 }
1326
1327                 for (i = 0; i < rows; )
1328                 {
1329                         concptr str = buf;
1330                         if (!i) line = next;
1331                         if (my_fgets(fff, buf, sizeof(buf))) break;
1332                         if (prefix(buf, "***** ")) continue;
1333                         next++;
1334                         if (find && !i)
1335                         {
1336                                 char lc_buf[1024];
1337                                 strcpy(lc_buf, str);
1338                                 str_tolower(lc_buf);
1339                                 if (!my_strstr(lc_buf, find)) continue;
1340                         }
1341
1342                         find = NULL;
1343                         show_file_aux_line(str, i + 2, shower);
1344                         i++;
1345                 }
1346
1347                 while (i < rows)
1348                 {
1349                         Term_erase(0, i + 2, 255);
1350                         i++;
1351                 }
1352
1353                 if (find)
1354                 {
1355                         bell();
1356                         line = back;
1357                         find = NULL;
1358                         continue;
1359                 }
1360
1361                 if (show_version)
1362                 {
1363                         prt(format(_("[変愚蛮怒 %d.%d.%d, %s, %d/%d]", "[Hengband %d.%d.%d, %s, Line %d/%d]"),
1364                                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH,
1365                                 caption, line, size), 0, 0);
1366                 }
1367                 else
1368                 {
1369                         prt(format(_("[%s, %d/%d]", "[%s, Line %d/%d]"),
1370                                 caption, line, size), 0, 0);
1371                 }
1372
1373                 if (size <= rows)
1374                 {
1375                         prt(_("[キー:(?)ヘルプ (ESC)終了]", "[Press ESC to exit.]"), hgt - 1, 0);
1376                 }
1377                 else
1378                 {
1379 #ifdef JP
1380                         if (reverse)
1381                                 prt("[キー:(RET/スペース)↑ (-)↓ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
1382                         else
1383                                 prt("[キー:(RET/スペース)↓ (-)↑ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
1384 #else
1385                         prt("[Press Return, Space, -, =, /, |, or ESC to exit.]", hgt - 1, 0);
1386 #endif
1387                 }
1388
1389                 skey = inkey_special(TRUE);
1390                 switch (skey)
1391                 {
1392                 case '?':
1393                         if (strcmp(name, _("jhelpinfo.txt", "helpinfo.txt")) != 0)
1394                                 show_file(creature_ptr, TRUE, _("jhelpinfo.txt", "helpinfo.txt"), NULL, 0, mode);
1395                         break;
1396                 case '=':
1397                         prt(_("強調: ", "Show: "), hgt - 1, 0);
1398
1399                         strcpy(back_str, shower_str);
1400                         if (askfor(shower_str, 80))
1401                         {
1402                                 if (shower_str[0])
1403                                 {
1404                                         str_tolower(shower_str);
1405                                         shower = shower_str;
1406                                 }
1407                                 else shower = NULL;
1408                         }
1409                         else strcpy(shower_str, back_str);
1410                         break;
1411
1412                 case '/':
1413                 case KTRL('s'):
1414                         prt(_("検索: ", "Find: "), hgt - 1, 0);
1415                         strcpy(back_str, finder_str);
1416                         if (askfor(finder_str, 80))
1417                         {
1418                                 if (finder_str[0])
1419                                 {
1420                                         find = finder_str;
1421                                         back = line;
1422                                         line = line + 1;
1423                                         str_tolower(finder_str);
1424                                         shower = finder_str;
1425                                 }
1426                                 else shower = NULL;
1427                         }
1428                         else strcpy(finder_str, back_str);
1429                         break;
1430
1431                 case '#':
1432                 {
1433                         char tmp[81];
1434                         prt(_("行: ", "Goto Line: "), hgt - 1, 0);
1435                         strcpy(tmp, "0");
1436
1437                         if (askfor(tmp, 80)) line = atoi(tmp);
1438                         break;
1439                 }
1440
1441                 case SKEY_TOP:
1442                         line = 0;
1443                         break;
1444
1445                 case SKEY_BOTTOM:
1446                         line = ((size - 1) / rows) * rows;
1447                         break;
1448
1449                 case '%':
1450                 {
1451                         char tmp[81];
1452                         prt(_("ファイル・ネーム: ", "Goto File: "), hgt - 1, 0);
1453                         strcpy(tmp, _("jhelp.hlp", "help.hlp"));
1454
1455                         if (askfor(tmp, 80))
1456                         {
1457                                 if (!show_file(creature_ptr, TRUE, tmp, NULL, 0, mode)) skey = 'q';
1458                         }
1459
1460                         break;
1461                 }
1462
1463                 case '-':
1464                         line = line + (reverse ? rows : -rows);
1465                         if (line < 0) line = 0;
1466                         break;
1467
1468                 case SKEY_PGUP:
1469                         line = line - rows;
1470                         if (line < 0) line = 0;
1471                         break;
1472
1473                 case '\n':
1474                 case '\r':
1475                         line = line + (reverse ? -1 : 1);
1476                         if (line < 0) line = 0;
1477                         break;
1478
1479                 case '8':
1480                 case SKEY_UP:
1481                         line--;
1482                         if (line < 0) line = 0;
1483                         break;
1484
1485                 case '2':
1486                 case SKEY_DOWN:
1487                         line++;
1488                         break;
1489
1490                 case ' ':
1491                         line = line + (reverse ? -rows : rows);
1492                         if (line < 0) line = 0;
1493                         break;
1494
1495                 case SKEY_PGDOWN:
1496                         line = line + rows;
1497                         break;
1498                 }
1499
1500                 if (menu)
1501                 {
1502                         int key = -1;
1503                         if (!(skey & SKEY_MASK) && isalpha(skey))
1504                                 key = skey - 'A';
1505
1506                         if ((key > -1) && hook[key][0])
1507                         {
1508                                 /* Recurse on that file */
1509                                 if (!show_file(creature_ptr, TRUE, hook[key], NULL, 0, mode))
1510                                         skey = 'q';
1511                         }
1512                 }
1513
1514                 if (skey == '|')
1515                 {
1516                         FILE *ffp;
1517                         char buff[1024];
1518                         char xtmp[82];
1519
1520                         strcpy(xtmp, "");
1521
1522                         if (!get_string(_("ファイル名: ", "File name: "), xtmp, 80)) continue;
1523                         my_fclose(fff);
1524                         path_build(buff, sizeof(buff), ANGBAND_DIR_USER, xtmp);
1525
1526                         /* Hack -- Re-Open the file */
1527                         fff = my_fopen(path, "r");
1528
1529                         ffp = my_fopen(buff, "w");
1530
1531                         if (!(fff && ffp))
1532                         {
1533                                 msg_print(_("ファイルを開けません。", "Failed to open file."));
1534                                 skey = ESCAPE;
1535                                 break;
1536                         }
1537
1538                         sprintf(xtmp, "%s: %s", creature_ptr->name, what ? what : caption);
1539                         my_fputs(ffp, xtmp, 80);
1540                         my_fputs(ffp, "\n", 80);
1541
1542                         while (!my_fgets(fff, buff, sizeof(buff)))
1543                                 my_fputs(ffp, buff, 80);
1544                         my_fclose(fff);
1545                         my_fclose(ffp);
1546                         fff = my_fopen(path, "r");
1547                 }
1548
1549                 if ((skey == ESCAPE) || (skey == '<')) break;
1550
1551                 if (skey == KTRL('q')) skey = 'q';
1552
1553                 if (skey == 'q') break;
1554         }
1555
1556         my_fclose(fff);
1557         return (skey != 'q');
1558 }
1559
1560
1561 /*!
1562  * @brief ヘルプを表示するコマンドのメインルーチン
1563  * Peruse the On-Line-Help
1564  * @param creature_ptr プレーヤーへの参照ポインタ
1565  * @return なし
1566  * @details
1567  */
1568 void do_cmd_help(player_type *creature_ptr)
1569 {
1570         screen_save();
1571         (void)show_file(creature_ptr, TRUE, _("jhelp.hlp", "help.hlp"), NULL, 0, 0);
1572         screen_load();
1573 }
1574
1575
1576 /*!
1577  * @brief プレイヤーの名前をチェックして修正する
1578  * Process the player name.
1579  * @param player_ptr プレーヤーへの参照ポインタ
1580  * @param sf セーブファイル名に合わせた修正を行うならばTRUE
1581  * @return なし
1582  * @details
1583  * Extract a clean "base name".
1584  * Build the savefile name if needed.
1585  */
1586 void process_player_name(player_type *creature_ptr, bool sf)
1587 {
1588         char old_player_base[32] = "";
1589         if (current_world_ptr->character_generated)
1590                 strcpy(old_player_base, creature_ptr->base_name);
1591
1592         for (int i = 0; creature_ptr->name[i]; i++)
1593         {
1594 #ifdef JP
1595                 if (iskanji(creature_ptr->name[i])) { i++; continue; }
1596                 if (iscntrl((unsigned char)creature_ptr->name[i]))
1597 #else
1598                 if (iscntrl(creature_ptr->name[i]))
1599 #endif
1600                 {
1601                         quit_fmt(_("'%s' という名前は不正なコントロールコードを含んでいます。", "The name '%s' contains control chars!"), creature_ptr->name);
1602                 }
1603         }
1604
1605         int k = 0;
1606         for (int i = 0; creature_ptr->name[i]; i++)
1607         {
1608 #ifdef JP
1609                 unsigned char c = creature_ptr->name[i];
1610 #else
1611                 char c = creature_ptr->name[i];
1612 #endif
1613
1614 #ifdef JP
1615                 if (iskanji(c)) {
1616                         if (k + 2 >= sizeof(creature_ptr->base_name) || !creature_ptr->name[i + 1])
1617                                 break;
1618                         creature_ptr->base_name[k++] = c;
1619                         i++;
1620                         creature_ptr->base_name[k++] = creature_ptr->name[i];
1621                 }
1622 #ifdef SJIS
1623                 else if (iskana(c)) creature_ptr->base_name[k++] = c;
1624 #endif
1625                 else
1626 #endif
1627                         if (!strncmp(PATH_SEP, creature_ptr->name + i, strlen(PATH_SEP)))
1628                         {
1629                                 creature_ptr->base_name[k++] = '_';
1630                                 i += strlen(PATH_SEP);
1631                         }
1632 #if defined(WINDOWS)
1633                         else if (my_strchr("\"*,/:;<>?\\|", c))
1634                                 creature_ptr->base_name[k++] = '_';
1635 #endif
1636                         else if (isprint(c))
1637                                 creature_ptr->base_name[k++] = c;
1638         }
1639
1640         creature_ptr->base_name[k] = '\0';
1641         if (!creature_ptr->base_name[0])
1642                 strcpy(creature_ptr->base_name, "PLAYER");
1643
1644 #ifdef SAVEFILE_MUTABLE
1645         sf = TRUE;
1646 #endif
1647         if (!savefile_base[0] && savefile[0])
1648         {
1649                 concptr s = savefile;
1650                 while (TRUE)
1651                 {
1652                         concptr t;
1653                         t = my_strstr(s, PATH_SEP);
1654                         if (!t)
1655                                 break;
1656                         s = t + 1;
1657                 }
1658
1659                 strcpy(savefile_base, s);
1660         }
1661
1662         if (!savefile_base[0] || !savefile[0])
1663                 sf = TRUE;
1664
1665         if (sf)
1666         {
1667                 char temp[128];
1668                 strcpy(savefile_base, creature_ptr->base_name);
1669
1670 #ifdef SAVEFILE_USE_UID
1671                 /* Rename the savefile, using the creature_ptr->player_uid and creature_ptr->base_name */
1672                 (void)sprintf(temp, "%d.%s", creature_ptr->player_uid, creature_ptr->base_name);
1673 #else
1674                 /* Rename the savefile, using the creature_ptr->base_name */
1675                 (void)sprintf(temp, "%s", creature_ptr->base_name);
1676 #endif
1677                 path_build(savefile, sizeof(savefile), ANGBAND_DIR_SAVE, temp);
1678         }
1679
1680         if (current_world_ptr->character_generated && !streq(old_player_base, creature_ptr->base_name))
1681         {
1682                 autopick_load_pref(creature_ptr, FALSE);
1683         }
1684 }
1685
1686
1687 /*!
1688  * @brief プレイヤーの名前を変更するコマンドのメインルーチン
1689  * Gets a name for the character, reacting to name changes.
1690  * @param creature_ptr プレーヤーへの参照ポインタ
1691  * @return なし
1692  * @details
1693  * <pre>
1694  * Assumes that "display_player()" has just been called
1695  * Perhaps we should NOT ask for a name (at "birth()") on
1696  * Unix machines?  XXX XXX
1697  * What a horrible name for a global function.
1698  * </pre>
1699  */
1700 void get_name(player_type *creature_ptr)
1701 {
1702         char tmp[64];
1703         strcpy(tmp, creature_ptr->name);
1704
1705         if (get_string(_("キャラクターの名前を入力して下さい: ", "Enter a name for your character: "), tmp, 15))
1706         {
1707                 strcpy(creature_ptr->name, tmp);
1708         }
1709
1710         if (strlen(creature_ptr->name) == 0)
1711         {
1712                 strcpy(creature_ptr->name, "PLAYER");
1713         }
1714
1715         strcpy(tmp, ap_ptr->title);
1716 #ifdef JP
1717         if (ap_ptr->no == 1)
1718                 strcat(tmp, "の");
1719 #else
1720         strcat(tmp, " ");
1721 #endif
1722         strcat(tmp, creature_ptr->name);
1723
1724         Term_erase(34, 1, 255);
1725         c_put_str(TERM_L_BLUE, tmp, 1, 34);
1726         clear_from(22);
1727 }
1728
1729
1730 /*!
1731  * @brief セーブするコマンドのメインルーチン
1732  * Save the game
1733  * @param creature_ptr プレーヤーへの参照ポインタ
1734  * @param is_autosave オートセーブ中の処理ならばTRUE
1735  * @return なし
1736  * @details
1737  */
1738 void do_cmd_save_game(player_type *creature_ptr, int is_autosave)
1739 {
1740         if (is_autosave)
1741         {
1742                 msg_print(_("自動セーブ中", "Autosaving the game..."));
1743         }
1744         else
1745         {
1746                 disturb(creature_ptr, TRUE, TRUE);
1747         }
1748
1749         msg_print(NULL);
1750         handle_stuff(creature_ptr);
1751         prt(_("ゲームをセーブしています...", "Saving game..."), 0, 0);
1752         Term_fresh();
1753         (void)strcpy(creature_ptr->died_from, _("(セーブ)", "(saved)"));
1754         signals_ignore_tstp();
1755         if (save_player(creature_ptr))
1756         {
1757                 prt(_("ゲームをセーブしています... 終了", "Saving game... done."), 0, 0);
1758         }
1759         else
1760         {
1761                 prt(_("ゲームをセーブしています... 失敗!", "Saving game... failed!"), 0, 0);
1762         }
1763
1764         signals_handle_tstp();
1765         Term_fresh();
1766         (void)strcpy(creature_ptr->died_from, _("(元気に生きている)", "(alive and well)"));
1767         current_world_ptr->is_loading_now = FALSE;
1768         update_creature(creature_ptr);
1769         mproc_init(creature_ptr->current_floor_ptr);
1770         current_world_ptr->is_loading_now = TRUE;
1771 }
1772
1773
1774 /*!
1775  * @brief セーブ後にゲーム中断フラグを立てる/
1776  * Save the game and exit
1777  * @return なし
1778  * @details
1779  */
1780 void do_cmd_save_and_exit(player_type *creature_ptr)
1781 {
1782         creature_ptr->playing = FALSE;
1783         creature_ptr->leaving = TRUE;
1784         exe_write_diary(creature_ptr, DIARY_GAMESTART, 0, _("----ゲーム中断----", "---- Save and Exit Game ----"));
1785 }
1786
1787
1788 /*!
1789  * @brief 異常発生時のゲーム緊急終了処理 /
1790  * Handle abrupt death of the visual system
1791  * @param creature_ptr プレーヤーへの参照ポインタ
1792  * @return なし
1793  * @details
1794  * This routine is called only in very rare situations, and only
1795  * by certain visual systems, when they experience fatal errors.
1796  */
1797 void exit_game_panic(player_type *creature_ptr)
1798 {
1799         if (!current_world_ptr->character_generated || current_world_ptr->character_saved)
1800                 quit(_("緊急事態", "panic"));
1801         msg_flag = FALSE;
1802
1803         prt("", 0, 0);
1804         disturb(creature_ptr, TRUE, TRUE);
1805         if (creature_ptr->chp < 0) creature_ptr->is_dead = FALSE;
1806
1807         creature_ptr->panic_save = 1;
1808         signals_ignore_tstp();
1809         (void)strcpy(creature_ptr->died_from, _("(緊急セーブ)", "(panic save)"));
1810         if (!save_player(creature_ptr)) quit(_("緊急セーブ失敗!", "panic save failed!"));
1811         quit(_("緊急セーブ成功!", "panic save succeeded!"));
1812 }
1813
1814
1815 /*!
1816  * @brief ファイルからランダムに行を一つ取得する /
1817  * Get a random line from a file
1818  * @param file_name ファイル名
1819  * @param entry 特定条件時のN:タグヘッダID
1820  * @param output 出力先の文字列参照ポインタ
1821  * @return エラーコード
1822  * @details
1823  * <pre>
1824  * Based on the monster speech patch by Matt Graham,
1825  * </pre>
1826  */
1827 errr get_rnd_line(concptr file_name, int entry, char *output)
1828 {
1829         char buf[1024];
1830         path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, file_name);
1831         FILE *fp;
1832         fp = my_fopen(buf, "r");
1833         if (!fp) return -1;
1834
1835         int test;
1836         int line_num = 0;
1837         while (TRUE)
1838         {
1839                 if (my_fgets(fp, buf, sizeof(buf)) != 0)
1840                 {
1841                         my_fclose(fp);
1842                         return -1;
1843                 }
1844
1845                 line_num++;
1846                 if ((buf[0] != 'N') || (buf[1] != ':')) continue;
1847
1848                 if (buf[2] == '*')
1849                 {
1850                         break;
1851                 }
1852                 else if (buf[2] == 'M')
1853                 {
1854                         if (r_info[entry].flags1 & RF1_MALE) break;
1855                 }
1856                 else if (buf[2] == 'F')
1857                 {
1858                         if (r_info[entry].flags1 & RF1_FEMALE) break;
1859                 }
1860                 else if (sscanf(&(buf[2]), "%d", &test) != EOF)
1861                 {
1862                         if (test == entry) break;
1863                 }
1864
1865                 msg_format("Error in line %d of %s!", line_num, file_name);
1866                 my_fclose(fp);
1867                 return -1;
1868         }
1869
1870         int counter;
1871         for (counter = 0; ; counter++)
1872         {
1873                 while (TRUE)
1874                 {
1875                         test = my_fgets(fp, buf, sizeof(buf));
1876                         if (!test)
1877                         {
1878                                 /* Ignore lines starting with 'N:' */
1879                                 if ((buf[0] == 'N') && (buf[1] == ':')) continue;
1880
1881                                 if (buf[0] != '#') break;
1882                         }
1883                         else break;
1884                 }
1885
1886                 if (!buf[0]) break;
1887
1888                 if (one_in_(counter + 1)) strcpy(output, buf);
1889         }
1890
1891         my_fclose(fp);
1892         return counter ? 0 : -1;
1893 }
1894
1895
1896 #ifdef JP
1897 /*!
1898  * @brief ファイルからランダムに行を一つ取得する(日本語文字列のみ) /
1899  * @param file_name ファイル名
1900  * @param entry 特定条件時のN:タグヘッダID
1901  * @param output 出力先の文字列参照ポインタ
1902  * @param count 試行回数
1903  * @return エラーコード
1904  * @details
1905  */
1906 errr get_rnd_line_jonly(concptr file_name, int entry, char *output, int count)
1907 {
1908         errr result = 1;
1909         for (int i = 0; i < count; i++)
1910         {
1911                 result = get_rnd_line(file_name, entry, output);
1912                 if (result) break;
1913                 bool kanji = FALSE;
1914                 for (int j = 0; output[j]; j++) kanji |= iskanji(output[j]);
1915                 if (kanji) break;
1916         }
1917
1918         return result;
1919 }
1920 #endif
1921
1922
1923 /*!
1924  * @brief 自動拾いファイルを読み込む /
1925  * @param creature_ptr プレーヤーへの参照ポインタ
1926  * @param name ファイル名
1927  * @details
1928  */
1929 errr process_autopick_file(player_type *creature_ptr, concptr name)
1930 {
1931         char buf[1024];
1932         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
1933         errr err = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_AUTOPICK);
1934         return err;
1935 }
1936
1937
1938 /*!
1939  * @brief プレイヤーの生い立ちファイルを読み込む /
1940  * Process file for player's history editor.
1941  * @param creature_ptr プレーヤーへの参照ポインタ
1942  * @param name ファイル名
1943  * @return エラーコード
1944  * @details
1945  */
1946 errr process_histpref_file(player_type *creature_ptr, concptr name)
1947 {
1948         bool old_character_xtra = current_world_ptr->character_xtra;
1949         char buf[1024];
1950         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
1951
1952         /* Hack -- prevent modification birth options in this file */
1953         current_world_ptr->character_xtra = TRUE;
1954         errr err = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_HISTPREF);
1955         current_world_ptr->character_xtra = old_character_xtra;
1956         return err;
1957 }
1958
1959
1960 /*!
1961  * @brief ファイル位置をシーク /
1962  * @param creature_ptr プレーヤーへの参照ポインタ
1963  * @param fd ファイルディスクリプタ
1964  * @param where ファイルバイト位置
1965  * @param flag FALSEならば現ファイルを超えた位置へシーク時エラー、TRUEなら足りない間を0で埋め尽くす
1966  * @return エラーコード
1967  * @details
1968  */
1969 static errr counts_seek(player_type *creature_ptr, int fd, u32b where, bool flag)
1970 {
1971         char temp1[128], temp2[128];
1972 #ifdef SAVEFILE_USE_UID
1973         (void)sprintf(temp1, "%d.%s.%d%d%d", creature_ptr->player_uid, savefile_base, creature_ptr->pclass, creature_ptr->pseikaku, creature_ptr->age);
1974 #else
1975         (void)sprintf(temp1, "%s.%d%d%d", savefile_base, creature_ptr->pclass, creature_ptr->pseikaku, creature_ptr->age);
1976 #endif
1977         for (int i = 0; temp1[i]; i++)
1978                 temp1[i] ^= (i + 1) * 63;
1979
1980         int seekpoint = 0;
1981         u32b zero_header[3] = { 0L, 0L, 0L };
1982         while (TRUE)
1983         {
1984                 if (fd_seek(fd, seekpoint + 3 * sizeof(u32b)))
1985                         return 1;
1986                 if (fd_read(fd, (char*)(temp2), sizeof(temp2)))
1987                 {
1988                         if (!flag)
1989                                 return 1;
1990                         /* add new name */
1991                         fd_seek(fd, seekpoint);
1992                         fd_write(fd, (char*)zero_header, 3 * sizeof(u32b));
1993                         fd_write(fd, (char*)(temp1), sizeof(temp1));
1994                         break;
1995                 }
1996
1997                 if (strcmp(temp1, temp2) == 0)
1998                         break;
1999
2000                 seekpoint += 128 + 3 * sizeof(u32b);
2001         }
2002
2003         return fd_seek(fd, seekpoint + where * sizeof(u32b));
2004 }
2005
2006
2007 /*!
2008  * @brief ファイル位置を読み込む
2009  * @param creature_ptr プレーヤーへの参照ポインタ
2010  * @param where ファイルバイト位置
2011  * @return エラーコード
2012  * @details
2013  */
2014 u32b counts_read(player_type *creature_ptr, int where)
2015 {
2016         char buf[1024];
2017         path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
2018         int fd = fd_open(buf, O_RDONLY);
2019
2020         u32b count = 0;
2021         if (counts_seek(creature_ptr, fd, where, FALSE) ||
2022                 fd_read(fd, (char*)(&count), sizeof(u32b)))
2023                 count = 0;
2024
2025         (void)fd_close(fd);
2026
2027         return count;
2028 }
2029
2030
2031 /*!
2032  * @brief ファイル位置に書き込む /
2033  * @param creature_ptr プレーヤーへの参照ポインタ
2034  * @param where ファイルバイト位置
2035  * @param count 書き込む値
2036  * @return エラーコード
2037  * @details
2038  */
2039 errr counts_write(player_type *creature_ptr, int where, u32b count)
2040 {
2041         char buf[1024];
2042         path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
2043
2044         safe_setuid_grab();
2045         int fd = fd_open(buf, O_RDWR);
2046         safe_setuid_drop();
2047         if (fd < 0)
2048         {
2049                 FILE_TYPE(FILE_TYPE_DATA);
2050                 safe_setuid_grab();
2051                 fd = fd_make(buf, 0644);
2052                 safe_setuid_drop();
2053         }
2054
2055         safe_setuid_grab();
2056         errr err = fd_lock(fd, F_WRLCK);
2057         safe_setuid_drop();
2058         if (err) return 1;
2059
2060         counts_seek(creature_ptr, fd, where, TRUE);
2061         fd_write(fd, (char*)(&count), sizeof(u32b));
2062         safe_setuid_grab();
2063         err = fd_lock(fd, F_UNLCK);
2064         safe_setuid_drop();
2065
2066         if (err) return 1;
2067
2068         (void)fd_close(fd);
2069         return 0;
2070 }
2071
2072
2073 /*!
2074  * @brief 墓のアスキーアートテンプレを読み込む
2075  * @param buf テンプレへのバッファ
2076  * @param buf_size バッファの長さ
2077  * @return なし
2078  */
2079 void read_dead_file(char *buf, size_t buf_size)
2080 {
2081         path_build(buf, buf_size, ANGBAND_DIR_FILE, _("dead_j.txt", "dead.txt"));
2082
2083         FILE *fp;
2084         fp = my_fopen(buf, "r");
2085         if (!fp) return;
2086
2087         int i = 0;
2088         while (my_fgets(fp, buf, buf_size) == 0)
2089         {
2090                 put_str(buf, i++, 0);
2091         }
2092
2093         my_fclose(fp);
2094 }