3 * @brief ファイル入出力管理 / Purpose: code dealing with files (and death)
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
17 #include "signal-handlers.h"
18 #include "uid-checker.h"
20 #include "core.h" // リファクタリングして後で消す
23 #include "character-dump.h"
26 #include "player-move.h"
27 #include "player-personality.h"
28 #include "player-effects.h"
29 #include "monster-status.h"
30 #include "view-mainwindow.h"
31 #include "objectkind.h"
34 #include "io/gf-descriptions.h"
36 #define PREF_TYPE_NORMAL 0
37 #define PREF_TYPE_AUTOPICK 1
38 #define PREF_TYPE_HISTPREF 2
40 concptr ANGBAND_DIR; //!< Path name: The main "lib" directory This variable is not actually used anywhere in the code
41 concptr ANGBAND_DIR_APEX; //!< High score files (binary) These files may be portable between platforms
42 concptr ANGBAND_DIR_BONE; //!< Bone files for player ghosts (ascii) These files are portable between platforms
43 concptr ANGBAND_DIR_DATA; //!< Binary image files for the "*_info" arrays (binary) These files are not portable between platforms
44 concptr ANGBAND_DIR_EDIT; //!< Textual template files for the "*_info" arrays (ascii) These files are portable between platforms
45 concptr ANGBAND_DIR_SCRIPT; //!< Script files These files are portable between platforms.
46 concptr ANGBAND_DIR_FILE; //!< Various extra files (ascii) These files may be portable between platforms
47 concptr ANGBAND_DIR_HELP; //!< Help files (normal) for the online help (ascii) These files are portable between platforms
48 concptr ANGBAND_DIR_INFO; //!< Help files (spoilers) for the online help (ascii) These files are portable between platforms
49 concptr ANGBAND_DIR_PREF; //!< Default user "preference" files (ascii) These files are rarely portable between platforms
50 concptr ANGBAND_DIR_SAVE; //!< Savefiles for current characters (binary)
51 concptr ANGBAND_DIR_USER; //!< User "preference" files (ascii) These files are rarely portable between platforms
52 concptr ANGBAND_DIR_XTRA; //!< Various extra files (binary) These files are rarely portable between platforms
55 * Buffer to hold the current savefile name
56 * 'savefile' holds full path name. 'savefile_base' holds only base name.
59 char savefile_base[40];
62 * @brief 各種データテキストをトークン単位に分解する / Extract the first few "tokens" from a buffer
63 * @param buf データテキストの参照ポインタ
65 * @param tokens トークンを保管する文字列参照ポインタ配列
70 * This function uses "colon" and "slash" as the delimeter characters.
71 * We never extract more than "num" tokens. The "last" token may include
72 * "delimeter" characters, allowing the buffer to include a "string" token.
73 * We save pointers to the tokens in "tokens", and return the number found.
74 * Hack -- Attempt to handle the 'c' character formalism
75 * Hack -- An empty buffer, or a final delimeter, yields an "empty" token.
76 * Hack -- We will always extract at least one token
79 s16b tokenize(char *buf, s16b num, char **tokens, BIT_FLAGS mode)
88 if ((*t == ':') || (*t == '/')) break;
90 if ((mode & TOKENIZE_CHECKQUOTE) && (*t == '\''))
97 if (*t != '\'') *t = '\'';
116 * @brief 設定ファイルの各行から各種テキスト情報を取得する /
117 * Parse a sub-file of the "extra info" (format shown below)
118 * @param creature_ptr プレーヤーへの参照ポインタ
119 * @param buf データテキストの参照ポインタ
123 * Each "action" line has an "action symbol" in the first column,
124 * followed by a colon, followed by some command specific info,
125 * usually in the form of "tokens" separated by colons or slashes.
126 * Blank lines, lines starting with white space, and lines starting
127 * with pound signs ("#") are ignored (as comments).
128 * Note the use of "tokenize()" to allow the use of both colons and
129 * slashes as delimeters, while still allowing final tokens which
130 * may contain any characters including "delimiters".
131 * Note the use of "strtol()" to allow all "integers" to be encoded
132 * in decimal, hexidecimal, or octal form.
133 * Note that "monster zero" is used for the "player" attr/char, "object
134 * zero" will be used for the "stack" attr/char, and "feature zero" is
135 * used for the "nothing" attr/char.
136 * Parse another file recursively, see below for details
138 * Specify the attr/char values for "monsters" by race index
139 * R:\<num\>:\<a\>:\<c\>
140 * Specify the attr/char values for "objects" by kind index
141 * K:\<num\>:\<a\>:\<c\>
142 * Specify the attr/char values for "features" by feature index
143 * F:\<num\>:\<a\>:\<c\>
144 * Specify the attr/char values for unaware "objects" by kind tval
145 * U:\<tv\>:\<a\>:\<c\>
146 * Specify the attr/char values for inventory "objects" by kind tval
147 * E:\<tv\>:\<a\>:\<c\>
148 * Define a macro action, given an encoded macro action
150 * Create a normal macro, given an encoded macro trigger
152 * Create a command macro, given an encoded macro trigger
154 * Create a keyset mapping
155 * S:\<key\>:\<key\>:\<dir\>
156 * Turn an option off, given its name
158 * Turn an option on, given its name
160 * Specify visual information, given an index, and some data
161 * V:\<num\>:\<kv\>:\<rv\>:\<gv\>:\<bv\>
162 * Specify the set of colors to use when drawing a zapped spell
164 * Specify a macro trigger template and macro trigger names.
165 * T:\<template\>:\<modifier chr\>:\<modifier name1\>:\<modifier name2\>:...
166 * T:\<trigger\>:\<keycode\>:\<shift-keycode\>
169 errr process_pref_file_command(player_type *creature_ptr, char *buf)
171 if (buf[1] != ':') return 1;
178 /* Process "H:<history>" */
179 add_history_from_pref_line(buf + 2);
184 /* Process "R:<num>:<a>/<c>" -- attr/char for monster races */
185 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
188 int i = (huge)strtol(zz[0], NULL, 0);
189 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
190 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
191 if (i >= max_r_idx) return 1;
193 if (n1 || (!(n2 & 0x80) && n2)) r_ptr->x_attr = n1; /* Allow TERM_DARK text */
194 if (n2) r_ptr->x_char = n2;
199 /* Process "K:<num>:<a>/<c>" -- attr/char for object kinds */
200 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
203 int i = (huge)strtol(zz[0], NULL, 0);
204 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
205 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
206 if (i >= max_k_idx) return 1;
208 if (n1 || (!(n2 & 0x80) && n2)) k_ptr->x_attr = n1; /* Allow TERM_DARK text */
209 if (n2) k_ptr->x_char = n2;
214 /* Process "F:<num>:<a>/<c>" -- attr/char for terrain features */
215 /* "F:<num>:<a>/<c>" */
216 /* "F:<num>:<a>/<c>:LIT" */
217 /* "F:<num>:<a>/<c>:<la>/<lc>:<da>/<dc>" */
219 int num = tokenize(buf + 2, F_LIT_MAX * 2 + 1, zz, TOKENIZE_CHECKQUOTE);
221 if ((num != 3) && (num != 4) && (num != F_LIT_MAX * 2 + 1)) return 1;
222 else if ((num == 4) && !streq(zz[3], "LIT")) return 1;
224 int i = (huge)strtol(zz[0], NULL, 0);
225 if (i >= max_f_idx) return 1;
228 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
229 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
230 if (n1 || (!(n2 & 0x80) && n2)) f_ptr->x_attr[F_LIT_STANDARD] = n1; /* Allow TERM_DARK text */
231 if (n2) f_ptr->x_char[F_LIT_STANDARD] = n2;
237 /* No lighting support */
238 n1 = f_ptr->x_attr[F_LIT_STANDARD];
239 n2 = f_ptr->x_char[F_LIT_STANDARD];
240 for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++)
242 f_ptr->x_attr[j] = n1;
243 f_ptr->x_char[j] = n2;
250 /* Use default lighting */
251 apply_default_feat_lighting(f_ptr->x_attr, f_ptr->x_char);
254 case F_LIT_MAX * 2 + 1:
256 /* Use desired lighting */
257 for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++)
259 n1 = (TERM_COLOR)strtol(zz[j * 2 + 1], NULL, 0);
260 n2 = (SYMBOL_CODE)strtol(zz[j * 2 + 2], NULL, 0);
261 if (n1 || (!(n2 & 0x80) && n2)) f_ptr->x_attr[j] = n1; /* Allow TERM_DARK text */
262 if (n2) f_ptr->x_char[j] = n2;
273 /* Process "S:<num>:<a>/<c>" -- attr/char for special things */
274 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
276 int j = (byte)strtol(zz[0], NULL, 0);
277 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
278 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
279 misc_to_attr[j] = n1;
280 misc_to_char[j] = n2;
285 /* Process "U:<tv>:<a>/<c>" -- attr/char for unaware items */
286 if (tokenize(buf + 2, 3, zz, TOKENIZE_CHECKQUOTE) != 3) return 1;
288 int j = (huge)strtol(zz[0], NULL, 0);
289 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
290 SYMBOL_CODE n2 = (SYMBOL_CODE)strtol(zz[2], NULL, 0);
291 for (int i = 1; i < max_k_idx; i++)
293 object_kind *k_ptr = &k_info[i];
294 if (k_ptr->tval == j)
296 if (n1) k_ptr->d_attr = n1;
297 if (n2) k_ptr->d_char = n2;
305 /* Process "E:<tv>:<a>" -- attribute for inventory objects */
306 if (tokenize(buf + 2, 2, zz, TOKENIZE_CHECKQUOTE) != 2) return 1;
308 int j = (byte)strtol(zz[0], NULL, 0) % 128;
309 TERM_COLOR n1 = (TERM_COLOR)strtol(zz[1], NULL, 0);
310 if (n1) tval_to_attr[j] = n1;
315 /* Process "A:<str>" -- save an "action" for later */
316 text_to_ascii(macro__buf, buf + 2);
321 /* Process "P:<str>" -- normal macro */
323 text_to_ascii(tmp, buf + 2);
324 macro_add(tmp, macro__buf);
329 /* Process "C:<str>" -- create keymap */
330 if (tokenize(buf + 2, 2, zz, TOKENIZE_CHECKQUOTE) != 2) return 1;
332 int mode = strtol(zz[0], NULL, 0);
333 if ((mode < 0) || (mode >= KEYMAP_MODES)) return 1;
336 text_to_ascii(tmp, zz[1]);
337 if (!tmp[0] || tmp[1]) return 1;
339 int i = (byte)(tmp[0]);
340 string_free(keymap_act[mode][i]);
341 keymap_act[mode][i] = string_make(macro__buf);
346 /* Process "V:<num>:<kv>:<rv>:<gv>:<bv>" -- visual info */
347 if (tokenize(buf + 2, 5, zz, TOKENIZE_CHECKQUOTE) != 5) return 1;
349 int i = (byte)strtol(zz[0], NULL, 0);
350 angband_color_table[i][0] = (byte)strtol(zz[1], NULL, 0);
351 angband_color_table[i][1] = (byte)strtol(zz[2], NULL, 0);
352 angband_color_table[i][2] = (byte)strtol(zz[3], NULL, 0);
353 angband_color_table[i][3] = (byte)strtol(zz[4], NULL, 0);
359 /* Process "X:<str>" -- turn option off */
360 /* Process "Y:<str>" -- turn option on */
361 for (int i = 0; option_info[i].o_desc; i++)
363 bool is_option = option_info[i].o_var != NULL;
364 is_option &= option_info[i].o_text != NULL;
365 is_option &= streq(option_info[i].o_text, buf + 2);
366 if (!is_option) continue;
368 int os = option_info[i].o_set;
369 int ob = option_info[i].o_bit;
371 if ((creature_ptr->playing || current_world_ptr->character_xtra) &&
372 (OPT_PAGE_BIRTH == option_info[i].o_page) && !current_world_ptr->wizard)
374 msg_format(_("初期オプションは変更できません! '%s'", "Birth options can not changed! '%s'"), buf);
381 option_flag[os] &= ~(1L << ob);
382 (*option_info[i].o_var) = FALSE;
386 option_flag[os] |= (1L << ob);
387 (*option_info[i].o_var) = TRUE;
391 msg_format(_("オプションの名前が正しくありません: %s", "Ignored invalid option: %s"), buf);
397 /* Process "Z:<type>:<str>" -- set spell color */
398 char *t = my_strchr(buf + 2, ':');
402 for (int i = 0; i < MAX_NAMED_NUM; i++)
404 if (!streq(gf_desc[i].name, buf + 2)) continue;
406 gf_color[gf_desc[i].num] = (TERM_COLOR)quark_add(t);
414 /* Initialize macro trigger names and a template */
415 /* Process "T:<trigger>:<keycode>:<shift-keycode>" */
416 /* Process "T:<template>:<modifier chr>:<modifier name>:..." */
417 int tok = tokenize(buf + 2, 2 + MAX_MACRO_MOD, zz, 0);
419 /* Process "T:<template>:<modifier chr>:<modifier name>:..." */
422 if (macro_template != NULL)
424 int macro_modifier_length = strlen(macro_modifier_chr);
425 string_free(macro_template);
426 macro_template = NULL;
427 string_free(macro_modifier_chr);
428 for (int i = 0; i < macro_modifier_length; i++)
430 string_free(macro_modifier_name[i]);
433 for (int i = 0; i < max_macrotrigger; i++)
435 string_free(macro_trigger_name[i]);
436 string_free(macro_trigger_keycode[0][i]);
437 string_free(macro_trigger_keycode[1][i]);
440 max_macrotrigger = 0;
443 if (*zz[0] == '\0') return 0;
445 int zz_length = strlen(zz[1]);
446 zz_length = MIN(MAX_MACRO_MOD, zz_length);
447 if (2 + zz_length != tok) return 1;
449 macro_template = string_make(zz[0]);
450 macro_modifier_chr = string_make(zz[1]);
451 for (int i = 0; i < zz_length; i++)
453 macro_modifier_name[i] = string_make(zz[2 + i]);
459 /* Process "T:<trigger>:<keycode>:<shift-keycode>" */
460 if (tok < 2) return 0;
464 if (max_macrotrigger >= MAX_MACRO_TRIG)
466 msg_print(_("マクロトリガーの設定が多すぎます!", "Too many macro triggers!"));
470 int m = max_macrotrigger;
481 macro_trigger_name[m] = string_make(buf_aux);
482 macro_trigger_keycode[0][m] = string_make(zz[1]);
485 macro_trigger_keycode[1][m] = string_make(zz[2]);
489 macro_trigger_keycode[1][m] = string_make(zz[1]);
499 * @brief process_pref_fileのサブルーチンとして条件分岐処理の解釈と結果を返す /
500 * Helper function for "process_pref_file()"
501 * @param creature_ptr プレーヤーへの参照ポインタ
502 * @param sp テキスト文字列の参照ポインタ
503 * @param fp 再帰中のポインタ参照
508 * v: output buffer array
514 concptr process_pref_file_expr(player_type *creature_ptr, char **sp, char *fp)
518 while (iswspace(*s)) s++;
538 t = process_pref_file_expr(creature_ptr, &s, &f);
543 else if (streq(t, "IOR"))
546 while (*s && (f != b2))
548 t = process_pref_file_expr(creature_ptr, &s, &f);
549 if (*t && !streq(t, "0")) v = "1";
552 else if (streq(t, "AND"))
555 while (*s && (f != b2))
557 t = process_pref_file_expr(creature_ptr, &s, &f);
558 if (*t && streq(t, "0")) v = "0";
561 else if (streq(t, "NOT"))
564 while (*s && (f != b2))
566 t = process_pref_file_expr(creature_ptr, &s, &f);
567 if (*t && streq(t, "1")) v = "0";
570 else if (streq(t, "EQU"))
575 t = process_pref_file_expr(creature_ptr, &s, &f);
577 while (*s && (f != b2))
579 p = process_pref_file_expr(creature_ptr, &s, &f);
580 if (streq(t, p)) v = "1";
583 else if (streq(t, "LEQ"))
588 t = process_pref_file_expr(creature_ptr, &s, &f);
590 while (*s && (f != b2))
593 t = process_pref_file_expr(creature_ptr, &s, &f);
594 if (*t && atoi(p) > atoi(t)) v = "0";
597 else if (streq(t, "GEQ"))
602 t = process_pref_file_expr(creature_ptr, &s, &f);
604 while (*s && (f != b2))
607 t = process_pref_file_expr(creature_ptr, &s, &f);
608 if (*t && atoi(p) < atoi(t)) v = "0";
613 while (*s && (f != b2))
615 t = process_pref_file_expr(creature_ptr, &s, &f);
619 if (f != b2) v = "?x?x?";
621 if ((f = *s) != '\0') *s++ = '\0';
628 /* Accept all printables except spaces and brackets */
630 while (iskanji(*s) || (isprint(*s) && !my_strchr(" []", *s)))
632 if (iskanji(*s)) s++;
636 while (isprint(*s) && !my_strchr(" []", *s)) ++s;
639 if ((f = *s) != '\0') *s++ = '\0';
649 if (streq(b + 1, "SYS"))
653 else if (streq(b + 1, "KEYBOARD"))
655 v = ANGBAND_KEYBOARD;
657 else if (streq(b + 1, "GRAF"))
661 else if (streq(b + 1, "MONOCHROME"))
668 else if (streq(b + 1, "RACE"))
676 else if (streq(b + 1, "CLASS"))
684 else if (streq(b + 1, "PLAYER"))
686 static char tmp_player_name[32];
688 for (pn = creature_ptr->name, tpn = tmp_player_name; *pn; pn++, tpn++)
698 *tpn = my_strchr(" []", *pn) ? '_' : *pn;
704 else if (streq(b + 1, "REALM1"))
707 v = E_realm_names[creature_ptr->realm1];
709 v = realm_names[creature_ptr->realm1];
712 else if (streq(b + 1, "REALM2"))
715 v = E_realm_names[creature_ptr->realm2];
717 v = realm_names[creature_ptr->realm2];
720 else if (streq(b + 1, "LEVEL"))
722 sprintf(tmp, "%02d", creature_ptr->lev);
725 else if (streq(b + 1, "AUTOREGISTER"))
727 if (creature_ptr->autopick_autoregister)
732 else if (streq(b + 1, "MONEY"))
734 sprintf(tmp, "%09ld", (long int)creature_ptr->au);
745 * @brief process_pref_fileのサブルーチン /
746 * Open the "user pref file" and parse it.
747 * @param creature_ptr プレーヤーへの参照ポインタ
748 * @param name 読み込むファイル名
749 * @param preftype prefファイルのタイプ
754 * v: output buffer array
760 static errr process_pref_file_aux(player_type *creature_ptr, concptr name, int preftype)
763 fp = my_fopen(name, "r");
771 while (my_fgets(fp, buf, sizeof(buf)) == 0)
774 if (!buf[0]) continue;
777 if (!iskanji(buf[0]))
779 if (iswspace(buf[0])) continue;
781 if (buf[0] == '#') continue;
784 /* Process "?:<expr>" */
785 if ((buf[0] == '?') && (buf[1] == ':'))
790 concptr v = process_pref_file_expr(creature_ptr, &s, &f);
791 bypass = streq(v, "0");
795 if (bypass) continue;
797 /* Process "%:<file>" */
800 static int depth_count = 0;
801 if (depth_count > 20) continue;
806 case PREF_TYPE_AUTOPICK:
807 (void)process_autopick_file(creature_ptr, buf + 2);
809 case PREF_TYPE_HISTPREF:
810 (void)process_histpref_file(creature_ptr, buf + 2);
813 (void)process_pref_file(creature_ptr, buf + 2);
821 err = process_pref_file_command(creature_ptr, buf);
824 if (preftype != PREF_TYPE_AUTOPICK)
826 err = process_autopick_file_command(buf);
832 /* Print error message */
833 /* ToDo: Add better error messages */
834 msg_format(_("ファイル'%s'の%d行でエラー番号%dのエラー。", "Error %d in line %d of file '%s'."),
835 _(name, err), line, _(err, name));
836 msg_format(_("('%s'を解析中)", "Parsing '%s'"), old);
846 * @brief pref設定ファイルを読み込み設定を反映させる /
847 * Process the "user pref file" with the given name
848 * @param creature_ptr プレーヤーへの参照ポインタ
849 * @param name 読み込むファイル名
853 * See the functions above for a list of legal "commands".
854 * We also accept the special "?" and "%" directives, which
855 * allow conditional evaluation and filename inclusion.
858 errr process_pref_file(player_type *creature_ptr, concptr name)
861 path_build(buf, sizeof(buf), ANGBAND_DIR_PREF, name);
863 errr err1 = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_NORMAL);
864 if (err1 > 0) return err1;
866 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
867 errr err2 = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_NORMAL);
868 if (err2 < 0 && !err1)
876 * @brief プレイヤーステータスをファイルダンプ出力する
877 * Hack -- Dump a character description file
878 * @param creature_ptr プレーヤーへの参照ポインタ
879 * @param name 出力ファイル名
882 * Allow the "full" flag to dump additional info,
883 * and trigger its usage from various places in the code.
885 errr file_character(player_type *creature_ptr, concptr name, display_player_pf display_player, map_name_pf map_name)
888 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
890 FILE_TYPE(FILE_TYPE_TEXT);
892 int fd = fd_open(buf, O_RDONLY);
897 (void)sprintf(out_val, _("現存するファイル %s に上書きしますか? ", "Replace existing file %s? "), buf);
898 if (get_check_strict(out_val, CHECK_NO_HISTORY)) fd = -1;
902 if (fd < 0) fff = my_fopen(buf, "w");
906 prt(_("キャラクタ情報のファイルへの書き出しに失敗しました!", "Character dump failed!"), 0, 0);
911 make_character_dump(creature_ptr, fff, update_playtime, display_player, map_name);
913 msg_print(_("キャラクタ情報のファイルへの書き出しに成功しました。", "Character dump successful."));
920 * @brief ファイル内容の一行をコンソールに出力する
921 * Display single line of on-line help file
928 * You can insert some special color tag to change text color.
930 * WHITETEXT [[[[y|SOME TEXT WHICH IS DISPLAYED IN YELLOW| WHITETEXT
931 * A colored segment is between "[[[[y|" and the last "|".
932 * You can use any single character in place of the "|".
935 static void show_file_aux_line(concptr str, int cy, concptr shower)
947 static const char tag_str[] = "[[[[";
948 byte color = TERM_WHITE;
950 for (int i = 0; str[i];)
952 int len = strlen(&str[i]);
953 int showercol = len + 1;
954 int bracketcol = len + 1;
959 ptr = my_strstr(&lcstr[i], shower);
960 if (ptr) showercol = ptr - &lcstr[i];
963 ptr = in_tag ? my_strchr(&str[i], in_tag) : my_strstr(&str[i], tag_str);
964 if (ptr) bracketcol = ptr - &str[i];
965 if (bracketcol < endcol) endcol = bracketcol;
966 if (showercol < endcol) endcol = showercol;
968 Term_addstr(endcol, color, &str[i]);
972 if (endcol == showercol)
974 int showerlen = strlen(shower);
975 Term_addstr(showerlen, TERM_YELLOW, &str[i]);
981 if (endcol != bracketcol) continue;
991 i += sizeof(tag_str) - 1;
992 color = color_char_to_attr(str[i]);
993 if (color == 255 || str[i + 1] == '\0')
996 Term_addstr(-1, TERM_WHITE, tag_str);
997 cx += sizeof(tag_str) - 1;
1006 Term_erase(cx, cy, 255);
1011 * @brief ファイル内容をコンソールに出力する
1012 * Recursive file perusal.
1013 * @param creature_ptr プレーヤーへの参照ポインタ
1014 * @param show_version TRUEならばコンソール上にゲームのバージョンを表示する
1015 * @param name ファイル名の文字列
1016 * @param what 内容キャプションの文字列
1017 * @param line 表示の現在行
1022 * Process various special text in the input file, including
1023 * the "menu" structures used by the "help file" system.
1024 * Return FALSE on 'q' to exit from a deep, otherwise TRUE.
1027 bool show_file(player_type *creature_ptr, bool show_version, concptr name, concptr what, int line, BIT_FLAGS mode)
1030 Term_get_size(&wid, &hgt);
1032 char finder_str[81];
1033 strcpy(finder_str, "");
1035 char shower_str[81];
1036 strcpy(shower_str, "");
1039 strcpy(caption, "");
1042 for (int i = 0; i < 68; i++)
1047 char filename[1024];
1048 strcpy(filename, name);
1049 int n = strlen(filename);
1052 for (int i = 0; i < n; i++)
1054 if (filename[i] == '#')
1057 tag = filename + i + 1;
1067 strcpy(caption, what);
1069 fff = my_fopen(path, "r");
1074 sprintf(caption, _("ヘルプ・ファイル'%s'", "Help file '%s'"), name);
1075 path_build(path, sizeof(path), ANGBAND_DIR_HELP, name);
1076 fff = my_fopen(path, "r");
1081 sprintf(caption, _("スポイラー・ファイル'%s'", "Info file '%s'"), name);
1082 path_build(path, sizeof(path), ANGBAND_DIR_INFO, name);
1083 fff = my_fopen(path, "r");
1088 path_build(path, sizeof(path), ANGBAND_DIR, name);
1090 for (int i = 0; path[i]; i++)
1091 if ('\\' == path[i])
1092 path[i] = PATH_SEP[0];
1094 sprintf(caption, _("スポイラー・ファイル'%s'", "Info file '%s'"), name);
1095 fff = my_fopen(path, "r");
1100 msg_format(_("'%s'をオープンできません。", "Cannot open '%s'."), name);
1112 bool reverse = (line < 0);
1116 if (my_fgets(fff, buf, sizeof(buf))) break;
1117 if (!prefix(str, "***** "))
1123 if ((str[6] == '[') && isalpha(str[7]))
1125 int k = str[7] - 'A';
1127 if ((str[8] == ']') && (str[9] == ' '))
1129 strncpy(hook[k], str + 10, 31);
1136 if (str[6] != '<') continue;
1138 size_t len = strlen(str);
1139 if (str[len - 1] == '>')
1141 str[len - 1] = '\0';
1142 if (tag && streq(str + 7, tag)) line = next;
1149 line = ((size - 1) / rows)*rows;
1153 concptr find = NULL;
1156 if (line >= size - rows)
1158 if (line < 0) line = 0;
1163 fff = my_fopen(path, "r");
1164 if (!fff) return FALSE;
1171 if (my_fgets(fff, buf, sizeof(buf))) break;
1172 if (prefix(buf, "***** ")) continue;
1177 concptr shower = NULL;
1178 for (int i = 0; i < rows; i++)
1181 if (!i) line = next;
1182 if (my_fgets(fff, buf, sizeof(buf))) break;
1183 if (prefix(buf, "***** ")) continue;
1188 strcpy(lc_buf, str);
1189 str_tolower(lc_buf);
1190 if (!my_strstr(lc_buf, find)) continue;
1194 show_file_aux_line(str, i + 2, shower);
1198 while (row_count < rows)
1200 Term_erase(0, row_count + 2, 255);
1214 prt(format(_("[変愚蛮怒 %d.%d.%d, %s, %d/%d]", "[Hengband %d.%d.%d, %s, Line %d/%d]"),
1215 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH,
1216 caption, line, size), 0, 0);
1220 prt(format(_("[%s, %d/%d]", "[%s, Line %d/%d]"),
1221 caption, line, size), 0, 0);
1226 prt(_("[キー:(?)ヘルプ (ESC)終了]", "[Press ESC to exit.]"), hgt - 1, 0);
1232 prt("[キー:(RET/スペース)↑ (-)↓ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
1234 prt("[キー:(RET/スペース)↓ (-)↑ (?)ヘルプ (ESC)終了]", hgt - 1, 0);
1236 prt("[Press Return, Space, -, =, /, |, or ESC to exit.]", hgt - 1, 0);
1240 skey = inkey_special(TRUE);
1244 if (strcmp(name, _("jhelpinfo.txt", "helpinfo.txt")) != 0)
1245 show_file(creature_ptr, TRUE, _("jhelpinfo.txt", "helpinfo.txt"), NULL, 0, mode);
1248 prt(_("強調: ", "Show: "), hgt - 1, 0);
1251 strcpy(back_str, shower_str);
1252 if (askfor(shower_str, 80))
1256 str_tolower(shower_str);
1257 shower = shower_str;
1261 else strcpy(shower_str, back_str);
1266 prt(_("検索: ", "Find: "), hgt - 1, 0);
1267 strcpy(back_str, finder_str);
1268 if (askfor(finder_str, 80))
1275 str_tolower(finder_str);
1276 shower = finder_str;
1280 else strcpy(finder_str, back_str);
1286 prt(_("行: ", "Goto Line: "), hgt - 1, 0);
1289 if (askfor(tmp, 80)) line = atoi(tmp);
1298 line = ((size - 1) / rows) * rows;
1304 prt(_("ファイル・ネーム: ", "Goto File: "), hgt - 1, 0);
1305 strcpy(tmp, _("jhelp.hlp", "help.hlp"));
1307 if (askfor(tmp, 80))
1309 if (!show_file(creature_ptr, TRUE, tmp, NULL, 0, mode)) skey = 'q';
1316 line = line + (reverse ? rows : -rows);
1317 if (line < 0) line = 0;
1322 if (line < 0) line = 0;
1327 line = line + (reverse ? -1 : 1);
1328 if (line < 0) line = 0;
1334 if (line < 0) line = 0;
1343 line = line + (reverse ? -rows : rows);
1344 if (line < 0) line = 0;
1355 if (!(skey & SKEY_MASK) && isalpha(skey))
1358 if ((key > -1) && hook[key][0])
1360 /* Recurse on that file */
1361 if (!show_file(creature_ptr, TRUE, hook[key], NULL, 0, mode))
1374 if (!get_string(_("ファイル名: ", "File name: "), xtmp, 80)) continue;
1376 path_build(buff, sizeof(buff), ANGBAND_DIR_USER, xtmp);
1378 /* Hack -- Re-Open the file */
1379 fff = my_fopen(path, "r");
1381 ffp = my_fopen(buff, "w");
1385 msg_print(_("ファイルを開けません。", "Failed to open file."));
1390 sprintf(xtmp, "%s: %s", creature_ptr->name, what ? what : caption);
1391 my_fputs(ffp, xtmp, 80);
1392 my_fputs(ffp, "\n", 80);
1394 while (!my_fgets(fff, buff, sizeof(buff)))
1395 my_fputs(ffp, buff, 80);
1398 fff = my_fopen(path, "r");
1401 if ((skey == ESCAPE) || (skey == '<')) break;
1403 if (skey == KTRL('q')) skey = 'q';
1405 if (skey == 'q') break;
1409 return (skey != 'q');
1414 * @brief ヘルプを表示するコマンドのメインルーチン
1415 * Peruse the On-Line-Help
1416 * @param creature_ptr プレーヤーへの参照ポインタ
1420 void do_cmd_help(player_type *creature_ptr)
1423 (void)show_file(creature_ptr, TRUE, _("jhelp.hlp", "help.hlp"), NULL, 0, 0);
1429 * @brief プレイヤーの名前をチェックして修正する
1430 * Process the player name.
1431 * @param player_ptr プレーヤーへの参照ポインタ
1432 * @param sf セーブファイル名に合わせた修正を行うならばTRUE
1435 * Extract a clean "base name".
1436 * Build the savefile name if needed.
1438 void process_player_name(player_type *creature_ptr, bool sf)
1440 char old_player_base[32] = "";
1441 if (current_world_ptr->character_generated)
1442 strcpy(old_player_base, creature_ptr->base_name);
1444 for (int i = 0; creature_ptr->name[i]; i++)
1447 if (iskanji(creature_ptr->name[i]))
1453 if (iscntrl((unsigned char)creature_ptr->name[i]))
1455 if (iscntrl(creature_ptr->name[i]))
1458 quit_fmt(_("'%s' という名前は不正なコントロールコードを含んでいます。", "The name '%s' contains control chars!"), creature_ptr->name);
1463 for (int i = 0; creature_ptr->name[i]; i++)
1466 unsigned char c = creature_ptr->name[i];
1468 char c = creature_ptr->name[i];
1473 if (k + 2 >= sizeof(creature_ptr->base_name) || !creature_ptr->name[i + 1])
1476 creature_ptr->base_name[k++] = c;
1478 creature_ptr->base_name[k++] = creature_ptr->name[i];
1481 else if (iskana(c)) creature_ptr->base_name[k++] = c;
1485 if (!strncmp(PATH_SEP, creature_ptr->name + i, strlen(PATH_SEP)))
1487 creature_ptr->base_name[k++] = '_';
1488 i += strlen(PATH_SEP);
1490 #if defined(WINDOWS)
1491 else if (my_strchr("\"*,/:;<>?\\|", c))
1492 creature_ptr->base_name[k++] = '_';
1494 else if (isprint(c))
1495 creature_ptr->base_name[k++] = c;
1498 creature_ptr->base_name[k] = '\0';
1499 if (!creature_ptr->base_name[0])
1500 strcpy(creature_ptr->base_name, "PLAYER");
1502 #ifdef SAVEFILE_MUTABLE
1505 if (!savefile_base[0] && savefile[0])
1507 concptr s = savefile;
1511 t = my_strstr(s, PATH_SEP);
1517 strcpy(savefile_base, s);
1520 if (!savefile_base[0] || !savefile[0])
1526 strcpy(savefile_base, creature_ptr->base_name);
1528 #ifdef SAVEFILE_USE_UID
1529 /* Rename the savefile, using the creature_ptr->player_uid and creature_ptr->base_name */
1530 (void)sprintf(temp, "%d.%s", creature_ptr->player_uid, creature_ptr->base_name);
1532 /* Rename the savefile, using the creature_ptr->base_name */
1533 (void)sprintf(temp, "%s", creature_ptr->base_name);
1535 path_build(savefile, sizeof(savefile), ANGBAND_DIR_SAVE, temp);
1538 if (current_world_ptr->character_generated && !streq(old_player_base, creature_ptr->base_name))
1540 autopick_load_pref(creature_ptr, FALSE);
1546 * @brief プレイヤーの名前を変更するコマンドのメインルーチン
1547 * Gets a name for the character, reacting to name changes.
1548 * @param creature_ptr プレーヤーへの参照ポインタ
1552 * Assumes that "display_player()" has just been called
1553 * Perhaps we should NOT ask for a name (at "birth()") on
1554 * Unix machines? XXX XXX
1555 * What a horrible name for a global function.
1558 void get_name(player_type *creature_ptr)
1561 strcpy(tmp, creature_ptr->name);
1563 if (get_string(_("キャラクターの名前を入力して下さい: ", "Enter a name for your character: "), tmp, 15))
1565 strcpy(creature_ptr->name, tmp);
1568 if (strlen(creature_ptr->name) == 0)
1570 strcpy(creature_ptr->name, "PLAYER");
1573 strcpy(tmp, ap_ptr->title);
1575 if (ap_ptr->no == 1)
1580 strcat(tmp, creature_ptr->name);
1582 Term_erase(34, 1, 255);
1583 c_put_str(TERM_L_BLUE, tmp, 1, 34);
1589 * @brief セーブするコマンドのメインルーチン
1591 * @param creature_ptr プレーヤーへの参照ポインタ
1592 * @param is_autosave オートセーブ中の処理ならばTRUE
1596 void do_cmd_save_game(player_type *creature_ptr, int is_autosave)
1600 msg_print(_("自動セーブ中", "Autosaving the game..."));
1604 disturb(creature_ptr, TRUE, TRUE);
1608 handle_stuff(creature_ptr);
1609 prt(_("ゲームをセーブしています...", "Saving game..."), 0, 0);
1611 (void)strcpy(creature_ptr->died_from, _("(セーブ)", "(saved)"));
1612 signals_ignore_tstp();
1613 if (save_player(creature_ptr))
1615 prt(_("ゲームをセーブしています... 終了", "Saving game... done."), 0, 0);
1619 prt(_("ゲームをセーブしています... 失敗!", "Saving game... failed!"), 0, 0);
1622 signals_handle_tstp();
1624 (void)strcpy(creature_ptr->died_from, _("(元気に生きている)", "(alive and well)"));
1625 current_world_ptr->is_loading_now = FALSE;
1626 update_creature(creature_ptr);
1627 mproc_init(creature_ptr->current_floor_ptr);
1628 current_world_ptr->is_loading_now = TRUE;
1633 * @brief セーブ後にゲーム中断フラグを立てる/
1634 * Save the game and exit
1638 void do_cmd_save_and_exit(player_type *creature_ptr)
1640 creature_ptr->playing = FALSE;
1641 creature_ptr->leaving = TRUE;
1642 exe_write_diary(creature_ptr, DIARY_GAMESTART, 0, _("----ゲーム中断----", "---- Save and Exit Game ----"));
1647 * @brief 異常発生時のゲーム緊急終了処理 /
1648 * Handle abrupt death of the visual system
1649 * @param creature_ptr プレーヤーへの参照ポインタ
1652 * This routine is called only in very rare situations, and only
1653 * by certain visual systems, when they experience fatal errors.
1655 void exit_game_panic(player_type *creature_ptr)
1657 if (!current_world_ptr->character_generated || current_world_ptr->character_saved)
1658 quit(_("緊急事態", "panic"));
1662 disturb(creature_ptr, TRUE, TRUE);
1663 if (creature_ptr->chp < 0) creature_ptr->is_dead = FALSE;
1665 creature_ptr->panic_save = 1;
1666 signals_ignore_tstp();
1667 (void)strcpy(creature_ptr->died_from, _("(緊急セーブ)", "(panic save)"));
1668 if (!save_player(creature_ptr)) quit(_("緊急セーブ失敗!", "panic save failed!"));
1669 quit(_("緊急セーブ成功!", "panic save succeeded!"));
1674 * @brief ファイルからランダムに行を一つ取得する /
1675 * Get a random line from a file
1676 * @param file_name ファイル名
1677 * @param entry 特定条件時のN:タグヘッダID
1678 * @param output 出力先の文字列参照ポインタ
1682 * Based on the monster speech patch by Matt Graham,
1685 errr get_rnd_line(concptr file_name, int entry, char *output)
1688 path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, file_name);
1690 fp = my_fopen(buf, "r");
1697 if (my_fgets(fp, buf, sizeof(buf)) != 0)
1704 if ((buf[0] != 'N') || (buf[1] != ':')) continue;
1710 else if (buf[2] == 'M')
1712 if (r_info[entry].flags1 & RF1_MALE) break;
1714 else if (buf[2] == 'F')
1716 if (r_info[entry].flags1 & RF1_FEMALE) break;
1718 else if (sscanf(&(buf[2]), "%d", &test) != EOF)
1720 if (test == entry) break;
1723 msg_format("Error in line %d of %s!", line_num, file_name);
1729 for (counter = 0; ; counter++)
1733 test = my_fgets(fp, buf, sizeof(buf));
1736 /* Ignore lines starting with 'N:' */
1737 if ((buf[0] == 'N') && (buf[1] == ':')) continue;
1739 if (buf[0] != '#') break;
1746 if (one_in_(counter + 1)) strcpy(output, buf);
1750 return counter ? 0 : -1;
1756 * @brief ファイルからランダムに行を一つ取得する(日本語文字列のみ) /
1757 * @param file_name ファイル名
1758 * @param entry 特定条件時のN:タグヘッダID
1759 * @param output 出力先の文字列参照ポインタ
1764 errr get_rnd_line_jonly(concptr file_name, int entry, char *output, int count)
1767 for (int i = 0; i < count; i++)
1769 result = get_rnd_line(file_name, entry, output);
1772 for (int j = 0; output[j]; j++) kanji |= iskanji(output[j]);
1782 * @brief 自動拾いファイルを読み込む /
1783 * @param creature_ptr プレーヤーへの参照ポインタ
1787 errr process_autopick_file(player_type *creature_ptr, concptr name)
1790 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
1791 errr err = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_AUTOPICK);
1797 * @brief プレイヤーの生い立ちファイルを読み込む /
1798 * Process file for player's history editor.
1799 * @param creature_ptr プレーヤーへの参照ポインタ
1804 errr process_histpref_file(player_type *creature_ptr, concptr name)
1806 bool old_character_xtra = current_world_ptr->character_xtra;
1808 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, name);
1810 /* Hack -- prevent modification birth options in this file */
1811 current_world_ptr->character_xtra = TRUE;
1812 errr err = process_pref_file_aux(creature_ptr, buf, PREF_TYPE_HISTPREF);
1813 current_world_ptr->character_xtra = old_character_xtra;
1819 * @brief ファイル位置をシーク /
1820 * @param creature_ptr プレーヤーへの参照ポインタ
1821 * @param fd ファイルディスクリプタ
1822 * @param where ファイルバイト位置
1823 * @param flag FALSEならば現ファイルを超えた位置へシーク時エラー、TRUEなら足りない間を0で埋め尽くす
1827 static errr counts_seek(player_type *creature_ptr, int fd, u32b where, bool flag)
1829 char temp1[128], temp2[128];
1830 #ifdef SAVEFILE_USE_UID
1831 (void)sprintf(temp1, "%d.%s.%d%d%d", creature_ptr->player_uid, savefile_base, creature_ptr->pclass, creature_ptr->pseikaku, creature_ptr->age);
1833 (void)sprintf(temp1, "%s.%d%d%d", savefile_base, creature_ptr->pclass, creature_ptr->pseikaku, creature_ptr->age);
1835 for (int i = 0; temp1[i]; i++)
1836 temp1[i] ^= (i + 1) * 63;
1839 u32b zero_header[3] = { 0L, 0L, 0L };
1842 if (fd_seek(fd, seekpoint + 3 * sizeof(u32b)))
1844 if (fd_read(fd, (char*)(temp2), sizeof(temp2)))
1849 fd_seek(fd, seekpoint);
1850 fd_write(fd, (char*)zero_header, 3 * sizeof(u32b));
1851 fd_write(fd, (char*)(temp1), sizeof(temp1));
1855 if (strcmp(temp1, temp2) == 0)
1858 seekpoint += 128 + 3 * sizeof(u32b);
1861 return fd_seek(fd, seekpoint + where * sizeof(u32b));
1866 * @brief ファイル位置を読み込む
1867 * @param creature_ptr プレーヤーへの参照ポインタ
1868 * @param where ファイルバイト位置
1872 u32b counts_read(player_type *creature_ptr, int where)
1875 path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
1876 int fd = fd_open(buf, O_RDONLY);
1879 if (counts_seek(creature_ptr, fd, where, FALSE) ||
1880 fd_read(fd, (char*)(&count), sizeof(u32b)))
1890 * @brief ファイル位置に書き込む /
1891 * @param creature_ptr プレーヤーへの参照ポインタ
1892 * @param where ファイルバイト位置
1893 * @param count 書き込む値
1897 errr counts_write(player_type *creature_ptr, int where, u32b count)
1900 path_build(buf, sizeof(buf), ANGBAND_DIR_DATA, _("z_info_j.raw", "z_info.raw"));
1903 int fd = fd_open(buf, O_RDWR);
1907 FILE_TYPE(FILE_TYPE_DATA);
1909 fd = fd_make(buf, 0644);
1914 errr err = fd_lock(fd, F_WRLCK);
1918 counts_seek(creature_ptr, fd, where, TRUE);
1919 fd_write(fd, (char*)(&count), sizeof(u32b));
1921 err = fd_lock(fd, F_UNLCK);
1932 * @brief 墓のアスキーアートテンプレを読み込む
1933 * @param buf テンプレへのバッファ
1934 * @param buf_size バッファの長さ
1937 void read_dead_file(char *buf, size_t buf_size)
1939 path_build(buf, buf_size, ANGBAND_DIR_FILE, _("dead_j.txt", "dead.txt"));
1942 fp = my_fopen(buf, "r");
1946 while (my_fgets(fp, buf, buf_size) == 0)
1948 put_str(buf, i++, 0);