OSDN Git Service

[Refactor] #40236 Separated do_cmd_knowledge_inventory() from cmd-dump.c to cmd-inven...
[hengband/hengband.git] / src / cmd / cmd-dump.c
1 /*!
2  * @file cmd-dump.c
3  * @brief プレイヤーのインターフェイスに関するコマンドの実装 / Interface commands
4  * @date 2014/01/02
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  * </pre>
12  * @details
13  * <pre>
14  * A set of functions to maintain automatic dumps of various kinds.
15  * The dump commands of original Angband simply add new lines to
16  * existing files; these files will become bigger and bigger unless
17  * an user deletes some or all of these files by hand at some
18  * point.
19  * These three functions automatically delete old dumped lines
20  * before adding new ones.  Since there are various kinds of automatic
21  * dumps in a single file, we add a header and a footer with a type
22  * name for every automatic dump, and kill old lines only when the
23  * lines have the correct type of header and footer.
24  * We need to be quite paranoid about correctness; the user might
25  * (mistakenly) edit the file by hand, and see all their work come
26  * to nothing on the next auto dump otherwise.  The current code only
27  * detects changes by noting inconsistencies between the actual number
28  * of lines and the number written in the footer.  Note that this will
29  * not catch single-line edits.
30  * </pre>
31  */
32
33 #include "angband.h"
34 #include "cmd/cmd-draw.h"
35 #include "cmd/cmd-dump.h"
36 #include "cmd/cmd-inventory.h"
37 #include "cmd/lighting-level-table.h"
38 #include "cmd/cmd-visuals.h"
39 #include "term.h"
40 #include "core.h" // 暫定。後で消す.
41 #include "core/show-file.h"
42 #include "io/read-pref-file.h"
43 #include "io/interpret-pref-file.h"
44 #include "autopick.h"
45 #include "birth.h"
46 #include "dungeon.h"
47 #include "world.h"
48 #include "view/display-player.h" // 暫定。後で消す.
49 #include "player/process-name.h"
50 #include "player-effects.h"
51 #include "player-skill.h"
52 #include "player-personality.h"
53 #include "sort.h"
54 #include "mutation.h"
55 #include "quest.h"
56 #include "store.h"
57 #include "artifact.h"
58 #include "avatar.h"
59 #include "object-flavor.h"
60 #include "object-hook.h"
61 #include "monster-status.h"
62 #include "dungeon-file.h"
63 #include "objectkind.h"
64 #include "floor-town.h"
65 #include "cmd/feeling-table.h"
66 #include "cmd/monster-group-table.h"
67 #include "cmd/object-group-table.h"
68 #include "market/store-util.h"
69 #include "view-mainwindow.h" // 暫定。後で消す
70 #include "english.h"
71
72 #include "diary-subtitle-table.h"
73 #include "io/write-diary.h"
74 #include "chuukei.h"
75
76 // Clipboard variables for copy&paste in visual mode
77 static TERM_COLOR attr_idx = 0;
78 static SYMBOL_CODE char_idx = 0;
79
80 static TERM_COLOR attr_idx_feat[F_LIT_MAX];
81 static SYMBOL_CODE char_idx_feat[F_LIT_MAX];
82
83 // Encode the screen colors
84 static char hack[17] = "dwsorgbuDWvyRGBU";
85
86 /*!
87  * @brief prefファイルを選択して処理する /
88  * Ask for a "user pref line" and process it
89  * @brief prf出力内容を消去する /
90  * Remove old lines automatically generated before.
91  * @param orig_file 消去を行うファイル名
92  */
93 static void remove_auto_dump(concptr orig_file, concptr auto_dump_mark)
94 {
95         FILE *tmp_fff, *orig_fff;
96         char tmp_file[1024];
97         char buf[1024];
98         bool between_mark = FALSE;
99         bool changed = FALSE;
100         int line_num = 0;
101         long header_location = 0;
102         char header_mark_str[80];
103         char footer_mark_str[80];
104
105         sprintf(header_mark_str, auto_dump_header, auto_dump_mark);
106         sprintf(footer_mark_str, auto_dump_footer, auto_dump_mark);
107         size_t mark_len = strlen(footer_mark_str);
108         orig_fff = my_fopen(orig_file, "r");
109         if (!orig_fff) return;
110
111         tmp_fff = my_fopen_temp(tmp_file, 1024);
112         if (!tmp_fff)
113         {
114                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), tmp_file);
115                 msg_print(NULL);
116                 return;
117         }
118
119         while (TRUE)
120         {
121                 if (my_fgets(orig_fff, buf, sizeof(buf)))
122                 {
123                         if (between_mark)
124                         {
125                                 fseek(orig_fff, header_location, SEEK_SET);
126                                 between_mark = FALSE;
127                                 continue;
128                         }
129                         else
130                         {
131                                 break;
132                         }
133                 }
134
135                 if (!between_mark)
136                 {
137                         if (!strcmp(buf, header_mark_str))
138                         {
139                                 header_location = ftell(orig_fff);
140                                 line_num = 0;
141                                 between_mark = TRUE;
142                                 changed = TRUE;
143                         }
144                         else
145                         {
146                                 fprintf(tmp_fff, "%s\n", buf);
147                         }
148
149                         continue;
150                 }
151
152                 if (!strncmp(buf, footer_mark_str, mark_len))
153                 {
154                         int tmp;
155                         if (!sscanf(buf + mark_len, " (%d)", &tmp)
156                                 || tmp != line_num)
157                         {
158                                 fseek(orig_fff, header_location, SEEK_SET);
159                         }
160
161                         between_mark = FALSE;
162                         continue;
163                 }
164
165                 line_num++;
166         }
167
168         my_fclose(orig_fff);
169         my_fclose(tmp_fff);
170
171         if (changed)
172         {
173                 tmp_fff = my_fopen(tmp_file, "r");
174                 orig_fff = my_fopen(orig_file, "w");
175                 while (!my_fgets(tmp_fff, buf, sizeof(buf)))
176                         fprintf(orig_fff, "%s\n", buf);
177
178                 my_fclose(orig_fff);
179                 my_fclose(tmp_fff);
180         }
181
182         fd_kill(tmp_file);
183 }
184
185
186 #ifdef JP
187 #else
188 /*!
189  * @brief Return suffix of ordinal number
190  * @param num number
191  * @return pointer of suffix string.
192  */
193 concptr get_ordinal_number_suffix(int num)
194 {
195         num = ABS(num) % 100;
196         switch (num % 10)
197         {
198         case 1:
199                 return (num == 11) ? "th" : "st";
200         case 2:
201                 return (num == 12) ? "th" : "nd";
202         case 3:
203                 return (num == 13) ? "th" : "rd";
204         default:
205                 return "th";
206         }
207 }
208 #endif
209
210
211 /*!
212  * @brief 画面を再描画するコマンドのメインルーチン
213  * Hack -- redraw the screen
214  * @param creature_ptr プレーヤーへの参照ポインタ
215  * @return なし
216  * @details
217  * Allow absolute file names?
218  */
219 void do_cmd_pref(player_type *creature_ptr)
220 {
221         char buf[80];
222         strcpy(buf, "");
223         if (!get_string(_("設定変更コマンド: ", "Pref: "), buf, 80)) return;
224
225         (void)interpret_pref_file(creature_ptr, buf);
226 }
227
228
229 /*!
230  * @brief 自動拾い設定ファイルをロードするコマンドのメインルーチン /
231  * @param creature_ptr プレーヤーへの参照ポインタ
232  * @return なし
233  */
234 void do_cmd_reload_autopick(player_type *creature_ptr)
235 {
236         if (!get_check(_("自動拾い設定ファイルをロードしますか? ", "Reload auto-pick preference file? ")))
237                 return;
238
239         autopick_load_pref(creature_ptr, TRUE);
240 }
241
242
243 /*
244  * Interact with "colors"
245  */
246 void do_cmd_colors(player_type *creature_ptr)
247 {
248         int i;
249         char tmp[160];
250         char buf[1024];
251         FILE *auto_dump_stream;
252         FILE_TYPE(FILE_TYPE_TEXT);
253         screen_save();
254         while (TRUE)
255         {
256                 Term_clear();
257                 prt(_("[ カラーの設定 ]", "Interact with Colors"), 2, 0);
258                 prt(_("(1) ユーザー設定ファイルのロード", "(1) Load a user pref file"), 4, 5);
259                 prt(_("(2) カラーの設定をファイルに書き出す", "(2) Dump colors"), 5, 5);
260                 prt(_("(3) カラーの設定を変更する", "(3) Modify colors"), 6, 5);
261                 prt(_("コマンド: ", "Command: "), 8, 0);
262                 i = inkey();
263                 if (i == ESCAPE) break;
264
265                 if (i == '1')
266                 {
267                         prt(_("コマンド: ユーザー設定ファイルをロードします", "Command: Load a user pref file"), 8, 0);
268                         prt(_("ファイル: ", "File: "), 10, 0);
269                         sprintf(tmp, "%s.prf", creature_ptr->base_name);
270                         if (!askfor(tmp, 70)) continue;
271
272                         (void)process_pref_file(creature_ptr, tmp);
273                         Term_xtra(TERM_XTRA_REACT, 0);
274                         Term_redraw();
275                 }
276                 else if (i == '2')
277                 {
278                         static concptr mark = "Colors";
279                         prt(_("コマンド: カラーの設定をファイルに書き出します", "Command: Dump colors"), 8, 0);
280                         prt(_("ファイル: ", "File: "), 10, 0);
281                         sprintf(tmp, "%s.prf", creature_ptr->base_name);
282                         if (!askfor(tmp, 70)) continue;
283
284                         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
285                         if (!open_auto_dump(&auto_dump_stream, buf, mark)) continue;
286
287                         auto_dump_printf(auto_dump_stream, _("\n# カラーの設定\n\n", "\n# Color redefinitions\n\n"));
288                         for (i = 0; i < 256; i++)
289                         {
290                                 int kv = angband_color_table[i][0];
291                                 int rv = angband_color_table[i][1];
292                                 int gv = angband_color_table[i][2];
293                                 int bv = angband_color_table[i][3];
294
295                                 concptr name = _("未知", "unknown");
296                                 if (!kv && !rv && !gv && !bv) continue;
297
298                                 if (i < 16) name = color_names[i];
299
300                                 auto_dump_printf(auto_dump_stream, _("# カラー '%s'\n", "# Color '%s'\n"), name);
301                                 auto_dump_printf(auto_dump_stream, "V:%d:0x%02X:0x%02X:0x%02X:0x%02X\n\n",
302                                         i, kv, rv, gv, bv);
303                         }
304
305                         close_auto_dump(&auto_dump_stream, mark);
306                         msg_print(_("カラーの設定をファイルに書き出しました。", "Dumped color redefinitions."));
307                 }
308                 else if (i == '3')
309                 {
310                         static byte a = 0;
311                         prt(_("コマンド: カラーの設定を変更します", "Command: Modify colors"), 8, 0);
312                         while (TRUE)
313                         {
314                                 concptr name;
315                                 clear_from(10);
316                                 for (byte j = 0; j < 16; j++)
317                                 {
318                                         Term_putstr(j * 4, 20, -1, a, "###");
319                                         Term_putstr(j * 4, 22, -1, j, format("%3d", j));
320                                 }
321
322                                 name = ((a < 16) ? color_names[a] : _("未定義", "undefined"));
323                                 Term_putstr(5, 10, -1, TERM_WHITE,
324                                         format(_("カラー = %d, 名前 = %s", "Color = %d, Name = %s"), a, name));
325                                 Term_putstr(5, 12, -1, TERM_WHITE,
326                                         format("K = 0x%02x / R,G,B = 0x%02x,0x%02x,0x%02x",
327                                                 angband_color_table[a][0],
328                                                 angband_color_table[a][1],
329                                                 angband_color_table[a][2],
330                                                 angband_color_table[a][3]));
331                                 Term_putstr(0, 14, -1, TERM_WHITE,
332                                         _("コマンド (n/N/k/K/r/R/g/G/b/B): ", "Command (n/N/k/K/r/R/g/G/b/B): "));
333                                 i = inkey();
334                                 if (i == ESCAPE) break;
335
336                                 if (i == 'n') a = (byte)(a + 1);
337                                 if (i == 'N') a = (byte)(a - 1);
338                                 if (i == 'k') angband_color_table[a][0] = (byte)(angband_color_table[a][0] + 1);
339                                 if (i == 'K') angband_color_table[a][0] = (byte)(angband_color_table[a][0] - 1);
340                                 if (i == 'r') angband_color_table[a][1] = (byte)(angband_color_table[a][1] + 1);
341                                 if (i == 'R') angband_color_table[a][1] = (byte)(angband_color_table[a][1] - 1);
342                                 if (i == 'g') angband_color_table[a][2] = (byte)(angband_color_table[a][2] + 1);
343                                 if (i == 'G') angband_color_table[a][2] = (byte)(angband_color_table[a][2] - 1);
344                                 if (i == 'b') angband_color_table[a][3] = (byte)(angband_color_table[a][3] + 1);
345                                 if (i == 'B') angband_color_table[a][3] = (byte)(angband_color_table[a][3] - 1);
346
347                                 Term_xtra(TERM_XTRA_REACT, 0);
348                                 Term_redraw();
349                         }
350                 }
351                 else
352                 {
353                         bell();
354                 }
355
356                 msg_erase();
357         }
358
359         screen_load();
360 }
361
362
363 /*
364  * Note something in the message recall
365  */
366 void do_cmd_note(void)
367 {
368         char buf[80];
369         strcpy(buf, "");
370         if (!get_string(_("メモ: ", "Note: "), buf, 60)) return;
371         if (!buf[0] || (buf[0] == ' ')) return;
372
373         msg_format(_("メモ: %s", "Note: %s"), buf);
374 }
375
376
377 /*
378  * Mention the current version
379  */
380 void do_cmd_version(void)
381 {
382 #if FAKE_VER_EXTRA > 0
383         msg_format(_("変愚蛮怒(Hengband) %d.%d.%d.%d", "You are playing Hengband %d.%d.%d.%d."),
384                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH, FAKE_VER_EXTRA);
385 #else
386         msg_format(_("変愚蛮怒(Hengband) %d.%d.%d", "You are playing Hengband %d.%d.%d."),
387                 FAKE_VER_MAJOR - 10, FAKE_VER_MINOR, FAKE_VER_PATCH);
388 #endif
389 }
390
391
392 /*
393  * Note that "feeling" is set to zero unless some time has passed.
394  * Note that this is done when the level is GENERATED, not entered.
395  */
396 void do_cmd_feeling(player_type *creature_ptr)
397 {
398         if (creature_ptr->wild_mode) return;
399
400         if (creature_ptr->current_floor_ptr->inside_quest && !random_quest_number(creature_ptr, creature_ptr->current_floor_ptr->dun_level))
401         {
402                 msg_print(_("典型的なクエストのダンジョンのようだ。", "Looks like a typical quest level."));
403                 return;
404         }
405
406         if (creature_ptr->town_num && !creature_ptr->current_floor_ptr->dun_level)
407         {
408                 if (!strcmp(town_info[creature_ptr->town_num].name, _("荒野", "wilderness")))
409                 {
410                         msg_print(_("何かありそうな荒野のようだ。", "Looks like a strange wilderness."));
411                         return;
412                 }
413
414                 msg_print(_("典型的な町のようだ。", "Looks like a typical town."));
415                 return;
416         }
417
418         if (!creature_ptr->current_floor_ptr->dun_level)
419         {
420                 msg_print(_("典型的な荒野のようだ。", "Looks like a typical wilderness."));
421                 return;
422         }
423
424         if (creature_ptr->muta3 & MUT3_GOOD_LUCK)
425                 msg_print(do_cmd_feeling_text_lucky[creature_ptr->feeling]);
426         else if (IS_ECHIZEN(creature_ptr))
427                 msg_print(do_cmd_feeling_text_combat[creature_ptr->feeling]);
428         else
429                 msg_print(do_cmd_feeling_text[creature_ptr->feeling]);
430 }
431
432
433 /*
434  * todo 引数と戻り値について追記求む
435  * Build a list of monster indexes in the given group.
436  *
437  * mode & 0x01 : check for non-empty group
438  * mode & 0x02 : visual operation only
439
440  * @param creature_ptr プレーヤーへの参照ポインタ
441  * @param grp_cur ???
442  * @param mon_idx[] ???
443  * @param mode ???
444  * @return The number of monsters in the group
445  */
446 static IDX collect_monsters(player_type *creature_ptr, IDX grp_cur, IDX mon_idx[], BIT_FLAGS8 mode)
447 {
448         concptr group_char = monster_group_char[grp_cur];
449         bool grp_unique = (monster_group_char[grp_cur] == (char *)-1L);
450         bool grp_riding = (monster_group_char[grp_cur] == (char *)-2L);
451         bool grp_wanted = (monster_group_char[grp_cur] == (char *)-3L);
452         bool grp_amberite = (monster_group_char[grp_cur] == (char *)-4L);
453
454         IDX mon_cnt = 0;
455         for (IDX i = 0; i < max_r_idx; i++)
456         {
457                 monster_race *r_ptr = &r_info[i];
458                 if (!r_ptr->name) continue;
459                 if (!(mode & 0x02) && !cheat_know && !r_ptr->r_sights) continue;
460
461                 if (grp_unique)
462                 {
463                         if (!(r_ptr->flags1 & RF1_UNIQUE)) continue;
464                 }
465                 else if (grp_riding)
466                 {
467                         if (!(r_ptr->flags7 & RF7_RIDING)) continue;
468                 }
469                 else if (grp_wanted)
470                 {
471                         bool wanted = FALSE;
472                         for (int j = 0; j < MAX_BOUNTY; j++)
473                         {
474                                 if (current_world_ptr->bounty_r_idx[j] == i || current_world_ptr->bounty_r_idx[j] - 10000 == i ||
475                                         (creature_ptr->today_mon && creature_ptr->today_mon == i))
476                                 {
477                                         wanted = TRUE;
478                                         break;
479                                 }
480                         }
481
482                         if (!wanted) continue;
483                 }
484                 else if (grp_amberite)
485                 {
486                         if (!(r_ptr->flags3 & RF3_AMBERITE)) continue;
487                 }
488                 else
489                 {
490                         if (!my_strchr(group_char, r_ptr->d_char)) continue;
491                 }
492
493                 mon_idx[mon_cnt++] = i;
494                 if (mode & 0x01) break;
495         }
496
497         mon_idx[mon_cnt] = -1;
498         int dummy_why;
499         ang_sort(mon_idx, &dummy_why, mon_cnt, ang_sort_comp_monster_level, ang_sort_swap_hook);
500         return mon_cnt;
501 }
502
503
504 /*
505  * Build a list of object indexes in the given group. Return the number
506  * of objects in the group.
507  *
508  * mode & 0x01 : check for non-empty group
509  * mode & 0x02 : visual operation only
510  */
511 static KIND_OBJECT_IDX collect_objects(int grp_cur, KIND_OBJECT_IDX object_idx[], BIT_FLAGS8 mode)
512 {
513         KIND_OBJECT_IDX object_cnt = 0;
514         byte group_tval = object_group_tval[grp_cur];
515         for (KIND_OBJECT_IDX i = 0; i < max_k_idx; i++)
516         {
517                 object_kind *k_ptr = &k_info[i];
518                 if (!k_ptr->name) continue;
519
520                 if (!(mode & 0x02))
521                 {
522                         if (!current_world_ptr->wizard)
523                         {
524                                 if (!k_ptr->flavor) continue;
525                                 if (!k_ptr->aware) continue;
526                         }
527
528                         int k = 0;
529                         for (int j = 0; j < 4; j++)
530                                 k += k_ptr->chance[j];
531                         if (!k) continue;
532                 }
533
534                 if (TV_LIFE_BOOK == group_tval)
535                 {
536                         if (TV_LIFE_BOOK <= k_ptr->tval && k_ptr->tval <= TV_HEX_BOOK)
537                         {
538                                 object_idx[object_cnt++] = i;
539                         }
540                         else
541                                 continue;
542                 }
543                 else if (k_ptr->tval == group_tval)
544                 {
545                         object_idx[object_cnt++] = i;
546                 }
547                 else
548                         continue;
549
550                 if (mode & 0x01) break;
551         }
552
553         object_idx[object_cnt] = -1;
554         return object_cnt;
555 }
556
557
558 /*
559  * Description of each feature group.
560  */
561 static concptr feature_group_text[] =
562 {
563         "terrains",
564         NULL
565 };
566
567
568 /*
569  * Build a list of feature indexes in the given group. Return the number
570  * of features in the group.
571  *
572  * mode & 0x01 : check for non-empty group
573  */
574 static FEAT_IDX collect_features(FEAT_IDX *feat_idx, BIT_FLAGS8 mode)
575 {
576         FEAT_IDX feat_cnt = 0;
577         for (FEAT_IDX i = 0; i < max_f_idx; i++)
578         {
579                 feature_type *f_ptr = &f_info[i];
580                 if (!f_ptr->name) continue;
581                 if (f_ptr->mimic != i) continue;
582
583                 feat_idx[feat_cnt++] = i;
584                 if (mode & 0x01) break;
585         }
586
587         feat_idx[feat_cnt] = -1;
588         return feat_cnt;
589 }
590
591
592 /*
593  * Hack -- load a screen dump from a file
594  */
595 void do_cmd_load_screen(void)
596 {
597         TERM_COLOR a = 0;
598         SYMBOL_CODE c = ' ';
599         bool okay = TRUE;
600         FILE *fff;
601         char buf[1024];
602         TERM_LEN wid, hgt;
603         Term_get_size(&wid, &hgt);
604         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "dump.txt");
605         fff = my_fopen(buf, "r");
606         if (!fff)
607         {
608                 msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), buf);
609                 msg_print(NULL);
610                 return;
611         }
612
613         screen_save();
614         Term_clear();
615         for (TERM_LEN y = 0; okay; y++)
616         {
617                 if (!fgets(buf, 1024, fff)) okay = FALSE;
618
619                 if (buf[0] == '\n' || buf[0] == '\0') break;
620                 if (y >= hgt) continue;
621
622                 for (TERM_LEN x = 0; x < wid - 1; x++)
623                 {
624                         if (buf[x] == '\n' || buf[x] == '\0') break;
625
626                         Term_draw(x, y, TERM_WHITE, buf[x]);
627                 }
628         }
629
630         for (TERM_LEN y = 0; okay; y++)
631         {
632                 if (!fgets(buf, 1024, fff)) okay = FALSE;
633
634                 if (buf[0] == '\n' || buf[0] == '\0') break;
635                 if (y >= hgt) continue;
636
637                 for (TERM_LEN x = 0; x < wid - 1; x++)
638                 {
639                         if (buf[x] == '\n' || buf[x] == '\0') break;
640
641                         (void)(Term_what(x, y, &a, &c));
642                         for (int i = 0; i < 16; i++)
643                         {
644                                 if (hack[i] == buf[x]) a = (byte)i;
645                         }
646
647                         Term_draw(x, y, a, c);
648                 }
649         }
650
651         my_fclose(fff);
652         prt(_("ファイルに書き出された画面(記念撮影)をロードしました。", "Screen dump loaded."), 0, 0);
653         flush();
654         inkey();
655         screen_load();
656 }
657
658
659 void do_cmd_save_screen_html_aux(char *filename, int message)
660 {
661         concptr tags[4] = {
662                 "HEADER_START:",
663                 "HEADER_END:",
664                 "FOOTER_START:",
665                 "FOOTER_END:",
666         };
667         concptr html_head[] = {
668                 "<html>\n<body text=\"#ffffff\" bgcolor=\"#000000\">\n",
669                 "<pre>",
670                 0,
671         };
672         concptr html_foot[] = {
673                 "</pre>\n",
674                 "</body>\n</html>\n",
675                 0,
676         };
677
678         TERM_LEN wid, hgt;
679         Term_get_size(&wid, &hgt);
680         FILE_TYPE(FILE_TYPE_TEXT);
681         FILE *fff;
682         fff = my_fopen(filename, "w");
683         if (!fff)
684         {
685                 if (message)
686                 {
687                         msg_format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), filename);
688                         msg_print(NULL);
689                 }
690
691                 return;
692         }
693
694         if (message) screen_save();
695
696         char buf[2048];
697         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "htmldump.prf");
698         FILE *tmpfff;
699         tmpfff = my_fopen(buf, "r");
700         if (!tmpfff)
701         {
702                 for (int i = 0; html_head[i]; i++)
703                         fputs(html_head[i], fff);
704         }
705         else
706         {
707                 bool is_first_line = TRUE;
708                 while (!my_fgets(tmpfff, buf, sizeof(buf)))
709                 {
710                         if (is_first_line)
711                         {
712                                 if (strncmp(buf, tags[0], strlen(tags[0])) == 0)
713                                         is_first_line = FALSE;
714                         }
715                         else
716                         {
717                                 if (strncmp(buf, tags[1], strlen(tags[1])) == 0)
718                                         break;
719                                 fprintf(fff, "%s\n", buf);
720                         }
721                 }
722         }
723
724         for (TERM_LEN y = 0; y < hgt; y++)
725         {
726                 if (y != 0) fprintf(fff, "\n");
727
728                 TERM_COLOR a = 0, old_a = 0;
729                 char c = ' ';
730                 for (TERM_LEN x = 0; x < wid - 1; x++)
731                 {
732                         concptr cc = NULL;
733                         (void)(Term_what(x, y, &a, &c));
734                         switch (c)
735                         {
736                         case '&': cc = "&amp;"; break;
737                         case '<': cc = "&lt;"; break;
738                         case '>': cc = "&gt;"; break;
739 #ifdef WINDOWS
740                         case 0x1f: c = '.'; break;
741                         case 0x7f: c = (a == 0x09) ? '%' : '#'; break;
742 #endif
743                         }
744
745                         a = a & 0x0F;
746                         if ((y == 0 && x == 0) || a != old_a)
747                         {
748                                 int rv = angband_color_table[a][1];
749                                 int gv = angband_color_table[a][2];
750                                 int bv = angband_color_table[a][3];
751                                 fprintf(fff, "%s<font color=\"#%02x%02x%02x\">",
752                                         ((y == 0 && x == 0) ? "" : "</font>"), rv, gv, bv);
753                                 old_a = a;
754                         }
755
756                         if (cc)
757                                 fprintf(fff, "%s", cc);
758                         else
759                                 fprintf(fff, "%c", c);
760                 }
761         }
762
763         fprintf(fff, "</font>");
764         if (!tmpfff)
765         {
766                 for (int i = 0; html_foot[i]; i++)
767                         fputs(html_foot[i], fff);
768         }
769         else
770         {
771                 rewind(tmpfff);
772                 bool is_first_line = TRUE;
773                 while (!my_fgets(tmpfff, buf, sizeof(buf)))
774                 {
775                         if (is_first_line)
776                         {
777                                 if (strncmp(buf, tags[2], strlen(tags[2])) == 0)
778                                         is_first_line = FALSE;
779                         }
780                         else
781                         {
782                                 if (strncmp(buf, tags[3], strlen(tags[3])) == 0)
783                                         break;
784                                 fprintf(fff, "%s\n", buf);
785                         }
786                 }
787
788                 my_fclose(tmpfff);
789         }
790
791         fprintf(fff, "\n");
792         my_fclose(fff);
793         if (message)
794         {
795                 msg_print(_("画面(記念撮影)をファイルに書き出しました。", "Screen dump saved."));
796                 msg_print(NULL);
797         }
798
799         if (message)
800                 screen_load();
801 }
802
803
804 /*
805  * Hack -- save a screen dump to a file
806  */
807 static void do_cmd_save_screen_html(void)
808 {
809         char buf[1024], tmp[256] = "screen.html";
810
811         if (!get_string(_("ファイル名: ", "File name: "), tmp, 80))
812                 return;
813         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
814
815         msg_print(NULL);
816
817         do_cmd_save_screen_html_aux(buf, 1);
818 }
819
820
821 /*
822  * Redefinable "save_screen" action
823  */
824 void(*screendump_aux)(void) = NULL;
825
826
827 /*
828  * Save a screen dump to a file
829  * @param creature_ptr プレーヤーへの参照ポインタ
830  * @return なし
831  */
832 void do_cmd_save_screen(player_type *creature_ptr)
833 {
834         prt(_("記念撮影しますか? [(y)es/(h)tml/(n)o] ", "Save screen dump? [(y)es/(h)tml/(n)o] "), 0, 0);
835         bool html_dump = FALSE;
836         while (TRUE)
837         {
838                 char c = inkey();
839                 if (c == 'Y' || c == 'y')
840                         break;
841                 else if (c == 'H' || c == 'h')
842                 {
843                         html_dump = TRUE;
844                         break;
845                 }
846                 else
847                 {
848                         prt("", 0, 0);
849                         return;
850                 }
851         }
852
853         int wid, hgt;
854         Term_get_size(&wid, &hgt);
855
856         bool old_use_graphics = use_graphics;
857         if (old_use_graphics)
858         {
859                 use_graphics = FALSE;
860                 reset_visuals(creature_ptr);
861                 creature_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
862                 handle_stuff(creature_ptr);
863         }
864
865         if (html_dump)
866         {
867                 do_cmd_save_screen_html();
868                 do_cmd_redraw(creature_ptr);
869         }
870         else if (screendump_aux)
871         {
872                 (*screendump_aux)();
873         }
874         else
875         {
876                 TERM_LEN y, x;
877                 TERM_COLOR a = 0;
878                 SYMBOL_CODE c = ' ';
879                 FILE *fff;
880                 char buf[1024];
881                 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "dump.txt");
882                 FILE_TYPE(FILE_TYPE_TEXT);
883                 fff = my_fopen(buf, "w");
884                 if (!fff)
885                 {
886                         msg_format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), buf);
887                         msg_print(NULL);
888                         return;
889                 }
890
891                 screen_save();
892                 for (y = 0; y < hgt; y++)
893                 {
894                         for (x = 0; x < wid - 1; x++)
895                         {
896                                 (void)(Term_what(x, y, &a, &c));
897                                 buf[x] = c;
898                         }
899
900                         buf[x] = '\0';
901                         fprintf(fff, "%s\n", buf);
902                 }
903
904                 fprintf(fff, "\n");
905                 for (y = 0; y < hgt; y++)
906                 {
907                         for (x = 0; x < wid - 1; x++)
908                         {
909                                 (void)(Term_what(x, y, &a, &c));
910                                 buf[x] = hack[a & 0x0F];
911                         }
912
913                         buf[x] = '\0';
914                         fprintf(fff, "%s\n", buf);
915                 }
916
917                 fprintf(fff, "\n");
918                 my_fclose(fff);
919                 msg_print(_("画面(記念撮影)をファイルに書き出しました。", "Screen dump saved."));
920                 msg_print(NULL);
921                 screen_load();
922         }
923
924         if (!old_use_graphics) return;
925
926         use_graphics = TRUE;
927         reset_visuals(creature_ptr);
928         creature_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
929         handle_stuff(creature_ptr);
930 }
931
932
933 /*
934  * todo okay = 既知のアーティファクト? と思われるが確証がない
935  * 分かりやすい変数名へ変更求む&万が一未知である旨の配列なら負論理なのでゴソッと差し替えるべき
936  * Check the status of "artifacts"
937  * @param player_ptr プレーヤーへの参照ポインタ
938  * @return なし
939  */
940 static void do_cmd_knowledge_artifacts(player_type *player_ptr)
941 {
942         FILE *fff;
943         GAME_TEXT file_name[1024];
944         fff = my_fopen_temp(file_name, 1024);
945         if (!fff)
946         {
947                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
948                 msg_print(NULL);
949                 return;
950         }
951
952         ARTIFACT_IDX *who;
953         C_MAKE(who, max_a_idx, ARTIFACT_IDX);
954         bool *okay;
955         C_MAKE(okay, max_a_idx, bool);
956
957         for (ARTIFACT_IDX k = 0; k < max_a_idx; k++)
958         {
959                 artifact_type *a_ptr = &a_info[k];
960                 okay[k] = FALSE;
961                 if (!a_ptr->name) continue;
962                 if (!a_ptr->cur_num) continue;
963
964                 okay[k] = TRUE;
965         }
966
967         for (POSITION y = 0; y < player_ptr->current_floor_ptr->height; y++)
968         {
969                 for (POSITION x = 0; x < player_ptr->current_floor_ptr->width; x++)
970                 {
971                         grid_type *g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
972                         OBJECT_IDX this_o_idx, next_o_idx = 0;
973                         for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
974                         {
975                                 object_type *o_ptr;
976                                 o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
977                                 next_o_idx = o_ptr->next_o_idx;
978                                 if (!object_is_fixed_artifact(o_ptr)) continue;
979                                 if (object_is_known(o_ptr)) continue;
980
981                                 okay[o_ptr->name1] = FALSE;
982                         }
983                 }
984         }
985
986         for (ARTIFACT_IDX i = 0; i < INVEN_TOTAL; i++)
987         {
988                 object_type *o_ptr = &player_ptr->inventory_list[i];
989                 if (!o_ptr->k_idx) continue;
990                 if (!object_is_fixed_artifact(o_ptr)) continue;
991                 if (object_is_known(o_ptr)) continue;
992
993                 okay[o_ptr->name1] = FALSE;
994         }
995
996         int n = 0;
997         for (ARTIFACT_IDX k = 0; k < max_a_idx; k++)
998         {
999                 if (okay[k]) who[n++] = k;
1000         }
1001
1002         u16b why = 3;
1003         ang_sort(who, &why, n, ang_sort_art_comp, ang_sort_art_swap);
1004         for (ARTIFACT_IDX k = 0; k < n; k++)
1005         {
1006                 artifact_type *a_ptr = &a_info[who[k]];
1007                 GAME_TEXT base_name[MAX_NLEN];
1008                 strcpy(base_name, _("未知の伝説のアイテム", "Unknown Artifact"));
1009                 ARTIFACT_IDX z = lookup_kind(a_ptr->tval, a_ptr->sval);
1010                 if (z)
1011                 {
1012                         object_type forge;
1013                         object_type *q_ptr;
1014                         q_ptr = &forge;
1015                         object_prep(q_ptr, z);
1016                         q_ptr->name1 = (byte)who[k];
1017                         q_ptr->ident |= IDENT_STORE;
1018                         object_desc(player_ptr, base_name, q_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
1019                 }
1020
1021                 fprintf(fff, _("     %s\n", "     The %s\n"), base_name);
1022         }
1023
1024         C_KILL(who, max_a_idx, ARTIFACT_IDX);
1025         C_KILL(okay, max_a_idx, bool);
1026         my_fclose(fff);
1027         (void)show_file(player_ptr, TRUE, file_name, _("既知の伝説のアイテム", "Artifacts Seen"), 0, 0);
1028         fd_kill(file_name);
1029 }
1030
1031
1032 /*
1033  * Display known uniques
1034  * With "XTRA HACK UNIQHIST" (Originally from XAngband)
1035  */
1036 static void do_cmd_knowledge_uniques(player_type *creature_ptr)
1037 {
1038         u16b why = 2;
1039         IDX *who;
1040         GAME_TEXT file_name[1024];
1041         int n_alive[10];
1042         int n_alive_surface = 0;
1043         int n_alive_over100 = 0;
1044         int n_alive_total = 0;
1045         int max_lev = -1;
1046         for (IDX i = 0; i < 10; i++)
1047                 n_alive[i] = 0;
1048
1049         FILE *fff;
1050         fff = my_fopen_temp(file_name, 1024);
1051         if (!fff)
1052         {
1053                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
1054                 msg_print(NULL);
1055                 return;
1056         }
1057
1058         C_MAKE(who, max_r_idx, MONRACE_IDX);
1059         int n = 0;
1060         for (IDX i = 1; i < max_r_idx; i++)
1061         {
1062                 monster_race *r_ptr = &r_info[i];
1063                 if (!r_ptr->name) continue;
1064                 if (!(r_ptr->flags1 & RF1_UNIQUE)) continue;
1065                 if (!cheat_know && !r_ptr->r_sights) continue;
1066                 if (!r_ptr->rarity || ((r_ptr->rarity > 100) && !(r_ptr->flags1 & RF1_QUESTOR))) continue;
1067                 if (r_ptr->max_num == 0) continue;
1068
1069                 if (r_ptr->level)
1070                 {
1071                         int lev = (r_ptr->level - 1) / 10;
1072                         if (lev < 10)
1073                         {
1074                                 n_alive[lev]++;
1075                                 if (max_lev < lev) max_lev = lev;
1076                         }
1077                         else
1078                                 n_alive_over100++;
1079                 }
1080                 else
1081                         n_alive_surface++;
1082
1083                 who[n++] = i;
1084         }
1085
1086         ang_sort(who, &why, n, ang_sort_comp_hook, ang_sort_swap_hook);
1087         if (n_alive_surface)
1088         {
1089                 fprintf(fff, _("     地上  生存: %3d体\n", "      Surface  alive: %3d\n"), n_alive_surface);
1090                 n_alive_total += n_alive_surface;
1091         }
1092
1093         for (IDX i = 0; i <= max_lev; i++)
1094         {
1095                 fprintf(fff, _("%3d-%3d階  生存: %3d体\n", "Level %3d-%3d  alive: %3d\n"), 1 + i * 10, 10 + i * 10, n_alive[i]);
1096                 n_alive_total += n_alive[i];
1097         }
1098
1099         if (n_alive_over100)
1100         {
1101                 fprintf(fff, _("101-   階  生存: %3d体\n", "Level 101-     alive: %3d\n"), n_alive_over100);
1102                 n_alive_total += n_alive_over100;
1103         }
1104
1105         if (n_alive_total)
1106         {
1107                 fputs(_("---------  -----------\n", "-------------  ----------\n"), fff);
1108                 fprintf(fff, _("     合計  生存: %3d体\n\n", "        Total  alive: %3d\n\n"), n_alive_total);
1109         }
1110         else
1111         {
1112                 fputs(_("現在は既知の生存ユニークはいません。\n", "No known uniques alive.\n"), fff);
1113         }
1114
1115         for (int k = 0; k < n; k++)
1116         {
1117                 monster_race *r_ptr = &r_info[who[k]];
1118                 fprintf(fff, _("     %s (レベル%d)\n", "     %s (level %d)\n"), r_name + r_ptr->name, (int)r_ptr->level);
1119         }
1120
1121         C_KILL(who, max_r_idx, s16b);
1122         my_fclose(fff);
1123         (void)show_file(creature_ptr, TRUE, file_name, _("まだ生きているユニーク・モンスター", "Alive Uniques"), 0, 0);
1124         fd_kill(file_name);
1125 }
1126
1127
1128 /*
1129  * Display weapon-exp
1130  */
1131 static void do_cmd_knowledge_weapon_exp(player_type *creature_ptr)
1132 {
1133         FILE *fff;
1134         GAME_TEXT file_name[1024];
1135         fff = my_fopen_temp(file_name, 1024);
1136         if (!fff)
1137         {
1138                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
1139                 msg_print(NULL);
1140                 return;
1141         }
1142
1143         for (int i = 0; i < 5; i++)
1144         {
1145                 for (int num = 0; num < 64; num++)
1146                 {
1147                         SUB_EXP weapon_exp;
1148                         char tmp[30];
1149                         for (KIND_OBJECT_IDX j = 0; j < max_k_idx; j++)
1150                         {
1151                                 object_kind *k_ptr = &k_info[j];
1152
1153                                 if ((k_ptr->tval != TV_SWORD - i) || (k_ptr->sval != num)) continue;
1154                                 if ((k_ptr->tval == TV_BOW) && (k_ptr->sval == SV_CRIMSON || k_ptr->sval == SV_HARP)) continue;
1155
1156                                 weapon_exp = creature_ptr->weapon_exp[4 - i][num];
1157                                 strip_name(tmp, j);
1158                                 fprintf(fff, "%-25s ", tmp);
1159                                 if (weapon_exp >= s_info[creature_ptr->pclass].w_max[4 - i][num]) fprintf(fff, "!");
1160                                 else fprintf(fff, " ");
1161                                 fprintf(fff, "%s", exp_level_str[weapon_exp_level(weapon_exp)]);
1162                                 if (cheat_xtra) fprintf(fff, " %d", weapon_exp);
1163                                 fprintf(fff, "\n");
1164                                 break;
1165                         }
1166                 }
1167         }
1168
1169         my_fclose(fff);
1170         (void)show_file(creature_ptr, TRUE, file_name, _("武器の経験値", "Weapon Proficiency"), 0, 0);
1171         fd_kill(file_name);
1172 }
1173
1174
1175 /*!
1176  * @brief 魔法の経験値を表示するコマンドのメインルーチン
1177  * Display spell-exp
1178  * @return なし
1179  */
1180 static void do_cmd_knowledge_spell_exp(player_type *creature_ptr)
1181 {
1182         FILE *fff;
1183         GAME_TEXT file_name[1024];
1184         fff = my_fopen_temp(file_name, 1024);
1185         if (!fff)
1186         {
1187                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
1188                 msg_print(NULL);
1189                 return;
1190         }
1191
1192         if (creature_ptr->realm1 != REALM_NONE)
1193         {
1194                 fprintf(fff, _("%sの魔法書\n", "%s Spellbook\n"), realm_names[creature_ptr->realm1]);
1195                 for (SPELL_IDX i = 0; i < 32; i++)
1196                 {
1197                         const magic_type *s_ptr;
1198                         if (!is_magic(creature_ptr->realm1))
1199                         {
1200                                 s_ptr = &technic_info[creature_ptr->realm1 - MIN_TECHNIC][i];
1201                         }
1202                         else
1203                         {
1204                                 s_ptr = &mp_ptr->info[creature_ptr->realm1 - 1][i];
1205                         }
1206
1207                         if (s_ptr->slevel >= 99) continue;
1208                         SUB_EXP spell_exp = creature_ptr->spell_exp[i];
1209                         int exp_level = spell_exp_level(spell_exp);
1210                         fprintf(fff, "%-25s ", exe_spell(creature_ptr, creature_ptr->realm1, i, SPELL_NAME));
1211                         if (creature_ptr->realm1 == REALM_HISSATSU)
1212                                 fprintf(fff, "[--]");
1213                         else
1214                         {
1215                                 if (exp_level >= EXP_LEVEL_MASTER) fprintf(fff, "!");
1216                                 else fprintf(fff, " ");
1217                                 fprintf(fff, "%s", exp_level_str[exp_level]);
1218                         }
1219
1220                         if (cheat_xtra) fprintf(fff, " %d", spell_exp);
1221                         fprintf(fff, "\n");
1222                 }
1223         }
1224
1225         if (creature_ptr->realm2 != REALM_NONE)
1226         {
1227                 fprintf(fff, _("%sの魔法書\n", "\n%s Spellbook\n"), realm_names[creature_ptr->realm2]);
1228                 for (SPELL_IDX i = 0; i < 32; i++)
1229                 {
1230                         const magic_type *s_ptr;
1231                         if (!is_magic(creature_ptr->realm1))
1232                         {
1233                                 s_ptr = &technic_info[creature_ptr->realm2 - MIN_TECHNIC][i];
1234                         }
1235                         else
1236                         {
1237                                 s_ptr = &mp_ptr->info[creature_ptr->realm2 - 1][i];
1238                         }
1239
1240                         if (s_ptr->slevel >= 99) continue;
1241
1242                         SUB_EXP spell_exp = creature_ptr->spell_exp[i + 32];
1243                         int exp_level = spell_exp_level(spell_exp);
1244                         fprintf(fff, "%-25s ", exe_spell(creature_ptr, creature_ptr->realm2, i, SPELL_NAME));
1245                         if (exp_level >= EXP_LEVEL_EXPERT) fprintf(fff, "!");
1246                         else fprintf(fff, " ");
1247                         fprintf(fff, "%s", exp_level_str[exp_level]);
1248                         if (cheat_xtra) fprintf(fff, " %d", spell_exp);
1249                         fprintf(fff, "\n");
1250                 }
1251         }
1252
1253         my_fclose(fff);
1254         (void)show_file(creature_ptr, TRUE, file_name, _("魔法の経験値", "Spell Proficiency"), 0, 0);
1255         fd_kill(file_name);
1256 }
1257
1258
1259 /*!
1260  * @brief スキル情報を表示するコマンドのメインルーチン /
1261  * Display skill-exp
1262  * @return なし
1263  */
1264 static void do_cmd_knowledge_skill_exp(player_type *creature_ptr)
1265 {
1266         char skill_name[GINOU_TEMPMAX][20] =
1267         {
1268                 _("マーシャルアーツ", "Martial Arts    "),
1269                 _("二刀流          ", "Dual Wielding   "),
1270                 _("乗馬            ", "Riding          "),
1271                 _("盾              ", "Shield          ")
1272         };
1273
1274         FILE *fff;
1275         char file_name[1024];
1276         fff = my_fopen_temp(file_name, 1024);
1277         if (!fff)
1278         {
1279                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
1280                 msg_print(NULL);
1281                 return;
1282         }
1283
1284         for (int i = 0; i < GINOU_TEMPMAX; i++)
1285         {
1286                 int skill_exp = creature_ptr->skill_exp[i];
1287                 fprintf(fff, "%-20s ", skill_name[i]);
1288                 if (skill_exp >= s_info[creature_ptr->pclass].s_max[i]) fprintf(fff, "!");
1289                 else fprintf(fff, " ");
1290                 fprintf(fff, "%s", exp_level_str[(i == GINOU_RIDING) ? riding_exp_level(skill_exp) : weapon_exp_level(skill_exp)]);
1291                 if (cheat_xtra) fprintf(fff, " %d", skill_exp);
1292                 fprintf(fff, "\n");
1293         }
1294
1295         my_fclose(fff);
1296         (void)show_file(creature_ptr, TRUE, file_name, _("技能の経験値", "Miscellaneous Proficiency"), 0, 0);
1297         fd_kill(file_name);
1298 }
1299
1300
1301 /*!
1302  * @brief 現在のペットを表示するコマンドのメインルーチン /
1303  * Display current pets
1304  * @param creature_ptr プレーヤーへの参照ポインタ
1305  * @return なし
1306  */
1307 static void do_cmd_knowledge_pets(player_type *creature_ptr)
1308 {
1309         GAME_TEXT file_name[1024];
1310         FILE *fff;
1311         fff = my_fopen_temp(file_name, 1024);
1312         if (!fff)
1313         {
1314                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
1315                 msg_print(NULL);
1316                 return;
1317         }
1318
1319         monster_type *m_ptr;
1320         GAME_TEXT pet_name[MAX_NLEN];
1321         int t_friends = 0;
1322         for (int i = creature_ptr->current_floor_ptr->m_max - 1; i >= 1; i--)
1323         {
1324                 m_ptr = &creature_ptr->current_floor_ptr->m_list[i];
1325                 if (!monster_is_valid(m_ptr)) continue;
1326                 if (!is_pet(m_ptr)) continue;
1327
1328                 t_friends++;
1329                 monster_desc(creature_ptr, pet_name, m_ptr, MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE);
1330                 fprintf(fff, "%s (%s)\n", pet_name, look_mon_desc(m_ptr, 0x00));
1331         }
1332
1333         int show_upkeep = calculate_upkeep(creature_ptr);
1334
1335         fprintf(fff, "----------------------------------------------\n");
1336 #ifdef JP
1337         fprintf(fff, "    合計: %d 体のペット\n", t_friends);
1338 #else
1339         fprintf(fff, "   Total: %d pet%s.\n", t_friends, (t_friends == 1 ? "" : "s"));
1340 #endif
1341         fprintf(fff, _(" 維持コスト: %d%% MP\n", "   Upkeep: %d%% mana.\n"), show_upkeep);
1342
1343         my_fclose(fff);
1344         (void)show_file(creature_ptr, TRUE, file_name, _("現在のペット", "Current Pets"), 0, 0);
1345         fd_kill(file_name);
1346 }
1347
1348
1349 /*!
1350  * @brief 現在のペットを表示するコマンドのメインルーチン /
1351  * @param creature_ptr プレーヤーへの参照ポインタ
1352  * Total kill count
1353  * @return なし
1354  * @note the player ghosts are ignored.
1355  */
1356 static void do_cmd_knowledge_kill_count(player_type *creature_ptr)
1357 {
1358         FILE *fff;
1359         GAME_TEXT file_name[1024];
1360         fff = my_fopen_temp(file_name, 1024);
1361         if (!fff)
1362         {
1363                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
1364                 msg_print(NULL);
1365                 return;
1366         }
1367
1368         MONRACE_IDX *who;
1369         C_MAKE(who, max_r_idx, MONRACE_IDX);
1370         s32b total = 0;
1371         for (int kk = 1; kk < max_r_idx; kk++)
1372         {
1373                 monster_race *r_ptr = &r_info[kk];
1374
1375                 if (r_ptr->flags1 & (RF1_UNIQUE))
1376                 {
1377                         bool dead = (r_ptr->max_num == 0);
1378
1379                         if (dead)
1380                         {
1381                                 total++;
1382                         }
1383                 }
1384                 else
1385                 {
1386                         MONSTER_NUMBER this_monster = r_ptr->r_pkills;
1387
1388                         if (this_monster > 0)
1389                         {
1390                                 total += this_monster;
1391                         }
1392                 }
1393         }
1394
1395         if (total < 1)
1396                 fprintf(fff, _("あなたはまだ敵を倒していない。\n\n", "You have defeated no enemies yet.\n\n"));
1397         else
1398 #ifdef JP
1399                 fprintf(fff, "あなたは%ld体の敵を倒している。\n\n", (long int)total);
1400 #else
1401                 fprintf(fff, "You have defeated %ld %s.\n\n", (long int)total, (total == 1) ? "enemy" : "enemies");
1402 #endif
1403
1404         total = 0;
1405         int n = 0;
1406         for (MONRACE_IDX i = 1; i < max_r_idx; i++)
1407         {
1408                 monster_race *r_ptr = &r_info[i];
1409                 if (r_ptr->name) who[n++] = i;
1410         }
1411
1412         u16b why = 2;
1413         ang_sort(who, &why, n, ang_sort_comp_hook, ang_sort_swap_hook);
1414         for (int k = 0; k < n; k++)
1415         {
1416                 monster_race *r_ptr = &r_info[who[k]];
1417                 if (r_ptr->flags1 & (RF1_UNIQUE))
1418                 {
1419                         bool dead = (r_ptr->max_num == 0);
1420                         if (dead)
1421                         {
1422                                 fprintf(fff, "     %s\n", (r_name + r_ptr->name));
1423                                 total++;
1424                         }
1425
1426                         continue;
1427                 }
1428
1429                 MONSTER_NUMBER this_monster = r_ptr->r_pkills;
1430                 if (this_monster <= 0) continue;
1431
1432 #ifdef JP
1433                 if (my_strchr("pt", r_ptr->d_char))
1434                         fprintf(fff, "     %3d 人の %s\n", (int)this_monster, r_name + r_ptr->name);
1435                 else
1436                         fprintf(fff, "     %3d 体の %s\n", (int)this_monster, r_name + r_ptr->name);
1437 #else
1438                 if (this_monster < 2)
1439                 {
1440                         if (my_strstr(r_name + r_ptr->name, "coins"))
1441                         {
1442                                 fprintf(fff, "     1 pile of %s\n", (r_name + r_ptr->name));
1443                         }
1444                         else
1445                         {
1446                                 fprintf(fff, "     1 %s\n", (r_name + r_ptr->name));
1447                         }
1448                 }
1449                 else
1450                 {
1451                         char ToPlural[80];
1452                         strcpy(ToPlural, (r_name + r_ptr->name));
1453                         plural_aux(ToPlural);
1454                         fprintf(fff, "     %d %s\n", this_monster, ToPlural);
1455                 }
1456 #endif
1457                 total += this_monster;
1458         }
1459
1460         fprintf(fff, "----------------------------------------------\n");
1461 #ifdef JP
1462         fprintf(fff, "    合計: %lu 体を倒した。\n", (unsigned long int)total);
1463 #else
1464         fprintf(fff, "   Total: %lu creature%s killed.\n", (unsigned long int)total, (total == 1 ? "" : "s"));
1465 #endif
1466
1467         C_KILL(who, max_r_idx, s16b);
1468         my_fclose(fff);
1469         (void)show_file(creature_ptr, TRUE, file_name, _("倒した敵の数", "Kill Count"), 0, 0);
1470         fd_kill(file_name);
1471 }
1472
1473
1474 /*!
1475  * @brief モンスター情報リスト中のグループを表示する /
1476  * Display the object groups.
1477  * @param col 開始行
1478  * @param row 開始列
1479  * @param wid 表示文字数幅
1480  * @param per_page リストの表示行
1481  * @param grp_idx グループのID配列
1482  * @param group_text グループ名の文字列配列
1483  * @param grp_cur 現在の選択ID
1484  * @param grp_top 現在の選択リスト最上部ID
1485  * @return なし
1486  */
1487 static void display_group_list(int col, int row, int wid, int per_page, IDX grp_idx[], concptr group_text[], int grp_cur, int grp_top)
1488 {
1489         for (int i = 0; i < per_page && (grp_idx[i] >= 0); i++)
1490         {
1491                 int grp = grp_idx[grp_top + i];
1492                 TERM_COLOR attr = (grp_top + i == grp_cur) ? TERM_L_BLUE : TERM_WHITE;
1493                 Term_erase(col, row + i, wid);
1494                 c_put_str(attr, group_text[grp], row + i, col);
1495         }
1496 }
1497
1498
1499 /*
1500  * Move the cursor in a browser window
1501  */
1502 static void browser_cursor(char ch, int *column, IDX *grp_cur, int grp_cnt, IDX *list_cur, int list_cnt)
1503 {
1504         int d;
1505         int col = *column;
1506         IDX grp = *grp_cur;
1507         IDX list = *list_cur;
1508         if (ch == ' ')
1509                 d = 3;
1510         else if (ch == '-')
1511                 d = 9;
1512         else
1513                 d = get_keymap_dir(ch);
1514
1515         if (!d) return;
1516
1517         if ((ddx[d] > 0) && ddy[d])
1518         {
1519                 int browser_rows;
1520                 int wid, hgt;
1521                 Term_get_size(&wid, &hgt);
1522                 browser_rows = hgt - 8;
1523                 if (!col)
1524                 {
1525                         int old_grp = grp;
1526                         grp += ddy[d] * (browser_rows - 1);
1527                         if (grp >= grp_cnt)     grp = grp_cnt - 1;
1528                         if (grp < 0) grp = 0;
1529                         if (grp != old_grp)     list = 0;
1530                 }
1531                 else
1532                 {
1533                         list += ddy[d] * browser_rows;
1534                         if (list >= list_cnt) list = list_cnt - 1;
1535                         if (list < 0) list = 0;
1536                 }
1537
1538                 (*grp_cur) = grp;
1539                 (*list_cur) = list;
1540                 return;
1541         }
1542
1543         if (ddx[d])
1544         {
1545                 col += ddx[d];
1546                 if (col < 0) col = 0;
1547                 if (col > 1) col = 1;
1548
1549                 (*column) = col;
1550                 return;
1551         }
1552
1553         if (!col)
1554         {
1555                 int old_grp = grp;
1556                 grp += (IDX)ddy[d];
1557                 if (grp >= grp_cnt)     grp = grp_cnt - 1;
1558                 if (grp < 0) grp = 0;
1559                 if (grp != old_grp)     list = 0;
1560         }
1561         else
1562         {
1563                 list += (IDX)ddy[d];
1564                 if (list >= list_cnt) list = list_cnt - 1;
1565                 if (list < 0) list = 0;
1566         }
1567
1568         (*grp_cur) = grp;
1569         (*list_cur) = list;
1570 }
1571
1572
1573 /*
1574  * Display visuals.
1575  */
1576 static void display_visual_list(int col, int row, int height, int width, TERM_COLOR attr_top, byte char_left)
1577 {
1578         for (int i = 0; i < height; i++)
1579         {
1580                 Term_erase(col, row + i, width);
1581         }
1582
1583         if (use_bigtile) width /= 2;
1584
1585         for (int i = 0; i < height; i++)
1586         {
1587                 for (int j = 0; j < width; j++)
1588                 {
1589                         TERM_LEN x = col + j;
1590                         TERM_LEN y = row + i;
1591                         if (use_bigtile) x += j;
1592
1593                         TERM_COLOR ia = attr_top + i;
1594                         SYMBOL_CODE ic = char_left + j;
1595                         if (ia > 0x7f || ic > 0xff || ic < ' ' ||
1596                                 (!use_graphics && ic > 0x7f))
1597                                 continue;
1598
1599                         TERM_COLOR a = ia;
1600                         SYMBOL_CODE c = ic;
1601                         if (c & 0x80) a |= 0x80;
1602
1603                         Term_queue_bigchar(x, y, a, c, 0, 0);
1604                 }
1605         }
1606 }
1607
1608
1609 /*
1610  * Place the cursor at the collect position for visual mode
1611  */
1612 static void place_visual_list_cursor(TERM_LEN col, TERM_LEN row, TERM_COLOR a, byte c, TERM_COLOR attr_top, byte char_left)
1613 {
1614         int i = (a & 0x7f) - attr_top;
1615         int j = c - char_left;
1616
1617         TERM_LEN x = col + j;
1618         TERM_LEN y = row + i;
1619         if (use_bigtile) x += j;
1620
1621         Term_gotoxy(x, y);
1622 }
1623
1624
1625 /*
1626  *  Do visual mode command -- Change symbols
1627  */
1628 static bool visual_mode_command(char ch, bool *visual_list_ptr,
1629         int height, int width,
1630         TERM_COLOR *attr_top_ptr, byte *char_left_ptr,
1631         TERM_COLOR *cur_attr_ptr, SYMBOL_CODE *cur_char_ptr, bool *need_redraw)
1632 {
1633         static TERM_COLOR attr_old = 0;
1634         static SYMBOL_CODE char_old = 0;
1635
1636         switch (ch)
1637         {
1638         case ESCAPE:
1639                 if (*visual_list_ptr)
1640                 {
1641                         *cur_attr_ptr = attr_old;
1642                         *cur_char_ptr = char_old;
1643                         *visual_list_ptr = FALSE;
1644
1645                         return TRUE;
1646                 }
1647
1648                 break;
1649
1650         case '\n':
1651         case '\r':
1652                 if (*visual_list_ptr)
1653                 {
1654                         *visual_list_ptr = FALSE;
1655                         *need_redraw = TRUE;
1656
1657                         return TRUE;
1658                 }
1659
1660                 break;
1661
1662         case 'V':
1663         case 'v':
1664                 if (!*visual_list_ptr)
1665                 {
1666                         *visual_list_ptr = TRUE;
1667
1668                         *attr_top_ptr = MAX(0, (*cur_attr_ptr & 0x7f) - 5);
1669                         *char_left_ptr = MAX(0, *cur_char_ptr - 10);
1670
1671                         attr_old = *cur_attr_ptr;
1672                         char_old = *cur_char_ptr;
1673
1674                         return TRUE;
1675                 }
1676
1677                 break;
1678
1679         case 'C':
1680         case 'c':
1681         {
1682                 attr_idx = *cur_attr_ptr;
1683                 char_idx = *cur_char_ptr;
1684                 for (int i = 0; i < F_LIT_MAX; i++)
1685                 {
1686                         attr_idx_feat[i] = 0;
1687                         char_idx_feat[i] = 0;
1688                 }
1689         }
1690
1691         return TRUE;
1692
1693         case 'P':
1694         case 'p':
1695                 if (attr_idx || (!(char_idx & 0x80) && char_idx))
1696                 {
1697                         *cur_attr_ptr = attr_idx;
1698                         *attr_top_ptr = MAX(0, (*cur_attr_ptr & 0x7f) - 5);
1699                         if (!*visual_list_ptr) *need_redraw = TRUE;
1700                 }
1701
1702                 if (char_idx)
1703                 {
1704                         /* Set the char */
1705                         *cur_char_ptr = char_idx;
1706                         *char_left_ptr = MAX(0, *cur_char_ptr - 10);
1707                         if (!*visual_list_ptr) *need_redraw = TRUE;
1708                 }
1709
1710                 return TRUE;
1711
1712         default:
1713                 if (*visual_list_ptr)
1714                 {
1715                         int eff_width;
1716                         int d = get_keymap_dir(ch);
1717                         TERM_COLOR a = (*cur_attr_ptr & 0x7f);
1718                         SYMBOL_CODE c = *cur_char_ptr;
1719
1720                         if (use_bigtile) eff_width = width / 2;
1721                         else eff_width = width;
1722
1723                         if ((a == 0) && (ddy[d] < 0)) d = 0;
1724                         if ((c == 0) && (ddx[d] < 0)) d = 0;
1725                         if ((a == 0x7f) && (ddy[d] > 0)) d = 0;
1726                         if ((c == 0xff) && (ddx[d] > 0)) d = 0;
1727
1728                         a += (TERM_COLOR)ddy[d];
1729                         c += (SYMBOL_CODE)ddx[d];
1730                         if (c & 0x80) a |= 0x80;
1731
1732                         *cur_attr_ptr = a;
1733                         *cur_char_ptr = c;
1734                         if ((ddx[d] < 0) && *char_left_ptr > MAX(0, (int)c - 10)) (*char_left_ptr)--;
1735                         if ((ddx[d] > 0) && *char_left_ptr + eff_width < MIN(0xff, (int)c + 10)) (*char_left_ptr)++;
1736                         if ((ddy[d] < 0) && *attr_top_ptr > MAX(0, (int)(a & 0x7f) - 4)) (*attr_top_ptr)--;
1737                         if ((ddy[d] > 0) && *attr_top_ptr + height < MIN(0x7f, (a & 0x7f) + 4)) (*attr_top_ptr)++;
1738                         return TRUE;
1739                 }
1740
1741                 break;
1742         }
1743
1744         return FALSE;
1745 }
1746
1747
1748 /*
1749  * Display the monsters in a group.
1750  */
1751 static void display_monster_list(int col, int row, int per_page, s16b mon_idx[], int mon_cur, int mon_top, bool visual_only)
1752 {
1753         int i;
1754         for (i = 0; i < per_page && (mon_idx[mon_top + i] >= 0); i++)
1755         {
1756                 TERM_COLOR attr;
1757                 MONRACE_IDX r_idx = mon_idx[mon_top + i];
1758                 monster_race *r_ptr = &r_info[r_idx];
1759                 attr = ((i + mon_top == mon_cur) ? TERM_L_BLUE : TERM_WHITE);
1760                 c_prt(attr, (r_name + r_ptr->name), row + i, col);
1761                 if (per_page == 1)
1762                 {
1763                         c_prt(attr, format("%02x/%02x", r_ptr->x_attr, r_ptr->x_char), row + i, (current_world_ptr->wizard || visual_only) ? 56 : 61);
1764                 }
1765
1766                 if (current_world_ptr->wizard || visual_only)
1767                 {
1768                         c_prt(attr, format("%d", r_idx), row + i, 62);
1769                 }
1770
1771                 Term_erase(69, row + i, 255);
1772                 Term_queue_bigchar(use_bigtile ? 69 : 70, row + i, r_ptr->x_attr, r_ptr->x_char, 0, 0);
1773                 if (!visual_only)
1774                 {
1775                         if (!(r_ptr->flags1 & RF1_UNIQUE))
1776                                 put_str(format("%5d", r_ptr->r_pkills), row + i, 73);
1777                         else
1778                                 c_put_str((r_ptr->max_num == 0 ? TERM_L_DARK : TERM_WHITE),
1779                                 (r_ptr->max_num == 0 ? _("死亡", " dead") : _("生存", "alive")), row + i, 74);
1780                 }
1781         }
1782
1783         for (; i < per_page; i++)
1784         {
1785                 Term_erase(col, row + i, 255);
1786         }
1787 }
1788
1789
1790 /*
1791  * todo 引数の詳細について加筆求む
1792  * Display known monsters.
1793  * @param creature_ptr プレーヤーへの参照ポインタ
1794  * @param need_redraw 画面の再描画が必要な時TRUE
1795  * @param visual_only ???
1796  * @param direct_r_idx モンスターID
1797  * @return なし
1798  */
1799 void do_cmd_knowledge_monsters(player_type *creature_ptr, bool *need_redraw, bool visual_only, IDX direct_r_idx)
1800 {
1801         TERM_LEN wid, hgt;
1802         Term_get_size(&wid, &hgt);
1803         IDX *mon_idx;
1804         C_MAKE(mon_idx, max_r_idx, MONRACE_IDX);
1805
1806         int max = 0;
1807         IDX grp_cnt = 0;
1808         IDX grp_idx[100];
1809         IDX mon_cnt;
1810         bool visual_list = FALSE;
1811         TERM_COLOR attr_top = 0;
1812         byte char_left = 0;
1813         BIT_FLAGS8 mode;
1814         int browser_rows = hgt - 8;
1815         if (direct_r_idx < 0)
1816         {
1817                 mode = visual_only ? 0x03 : 0x01;
1818                 int len;
1819                 for (IDX i = 0; monster_group_text[i] != NULL; i++)
1820                 {
1821                         len = strlen(monster_group_text[i]);
1822                         if (len > max) max = len;
1823
1824                         if ((monster_group_char[i] == ((char *)-1L)) || collect_monsters(creature_ptr, i, mon_idx, mode))
1825                         {
1826                                 grp_idx[grp_cnt++] = i;
1827                         }
1828                 }
1829
1830                 mon_cnt = 0;
1831         }
1832         else
1833         {
1834                 mon_idx[0] = direct_r_idx;
1835                 mon_cnt = 1;
1836                 mon_idx[1] = -1;
1837
1838                 (void)visual_mode_command('v', &visual_list, browser_rows - 1, wid - (max + 3),
1839                         &attr_top, &char_left, &r_info[direct_r_idx].x_attr, &r_info[direct_r_idx].x_char, need_redraw);
1840         }
1841
1842         grp_idx[grp_cnt] = -1;
1843         mode = visual_only ? 0x02 : 0x00;
1844         IDX old_grp_cur = -1;
1845         IDX grp_cur = 0;
1846         IDX grp_top = 0;
1847         IDX mon_cur = 0;
1848         IDX mon_top = 0;
1849         int column = 0;
1850         bool flag = FALSE;
1851         bool redraw = TRUE;
1852         while (!flag)
1853         {
1854                 if (redraw)
1855                 {
1856                         clear_from(0);
1857                         prt(format(_("%s - モンスター", "%s - monsters"), !visual_only ? _("知識", "Knowledge") : _("表示", "Visuals")), 2, 0);
1858                         if (direct_r_idx < 0) prt(_("グループ", "Group"), 4, 0);
1859                         prt(_("名前", "Name"), 4, max + 3);
1860                         if (current_world_ptr->wizard || visual_only) prt("Idx", 4, 62);
1861                         prt(_("文字", "Sym"), 4, 67);
1862                         if (!visual_only) prt(_("殺害数", "Kills"), 4, 72);
1863
1864                         for (IDX i = 0; i < 78; i++)
1865                         {
1866                                 Term_putch(i, 5, TERM_WHITE, '=');
1867                         }
1868
1869                         if (direct_r_idx < 0)
1870                         {
1871                                 for (IDX i = 0; i < browser_rows; i++)
1872                                 {
1873                                         Term_putch(max + 1, 6 + i, TERM_WHITE, '|');
1874                                 }
1875                         }
1876
1877                         redraw = FALSE;
1878                 }
1879
1880                 if (direct_r_idx < 0)
1881                 {
1882                         if (grp_cur < grp_top) grp_top = grp_cur;
1883                         if (grp_cur >= grp_top + browser_rows) grp_top = grp_cur - browser_rows + 1;
1884
1885                         display_group_list(0, 6, max, browser_rows, grp_idx, monster_group_text, grp_cur, grp_top);
1886                         if (old_grp_cur != grp_cur)
1887                         {
1888                                 old_grp_cur = grp_cur;
1889                                 mon_cnt = collect_monsters(creature_ptr, grp_idx[grp_cur], mon_idx, mode);
1890                         }
1891
1892                         while (mon_cur < mon_top)
1893                                 mon_top = MAX(0, mon_top - browser_rows / 2);
1894                         while (mon_cur >= mon_top + browser_rows)
1895                                 mon_top = MIN(mon_cnt - browser_rows, mon_top + browser_rows / 2);
1896                 }
1897
1898                 if (!visual_list)
1899                 {
1900                         display_monster_list(max + 3, 6, browser_rows, mon_idx, mon_cur, mon_top, visual_only);
1901                 }
1902                 else
1903                 {
1904                         mon_top = mon_cur;
1905                         display_monster_list(max + 3, 6, 1, mon_idx, mon_cur, mon_top, visual_only);
1906                         display_visual_list(max + 3, 7, browser_rows - 1, wid - (max + 3), attr_top, char_left);
1907                 }
1908
1909                 prt(format(_("<方向>%s%s%s, ESC", "<dir>%s%s%s, ESC"),
1910                         (!visual_list && !visual_only) ? _(", 'r'で思い出を見る", ", 'r' to recall") : "",
1911                         visual_list ? _(", ENTERで決定", ", ENTER to accept") : _(", 'v'でシンボル変更", ", 'v' for visuals"),
1912                         (attr_idx || char_idx) ? _(", 'c', 'p'でペースト", ", 'c', 'p' to paste") : _(", 'c'でコピー", ", 'c' to copy")),
1913                         hgt - 1, 0);
1914
1915                 monster_race *r_ptr;
1916                 r_ptr = &r_info[mon_idx[mon_cur]];
1917
1918                 if (!visual_only)
1919                 {
1920                         if (mon_cnt) monster_race_track(creature_ptr, mon_idx[mon_cur]);
1921                         handle_stuff(creature_ptr);
1922                 }
1923
1924                 if (visual_list)
1925                 {
1926                         place_visual_list_cursor(max + 3, 7, r_ptr->x_attr, r_ptr->x_char, attr_top, char_left);
1927                 }
1928                 else if (!column)
1929                 {
1930                         Term_gotoxy(0, 6 + (grp_cur - grp_top));
1931                 }
1932                 else
1933                 {
1934                         Term_gotoxy(max + 3, 6 + (mon_cur - mon_top));
1935                 }
1936
1937                 char ch = inkey();
1938                 if (visual_mode_command(ch, &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, &r_ptr->x_attr, &r_ptr->x_char, need_redraw))
1939                 {
1940                         if (direct_r_idx >= 0)
1941                         {
1942                                 switch (ch)
1943                                 {
1944                                 case '\n':
1945                                 case '\r':
1946                                 case ESCAPE:
1947                                         flag = TRUE;
1948                                         break;
1949                                 }
1950                         }
1951
1952                         continue;
1953                 }
1954
1955                 switch (ch)
1956                 {
1957                 case ESCAPE:
1958                 {
1959                         flag = TRUE;
1960                         break;
1961                 }
1962
1963                 case 'R':
1964                 case 'r':
1965                 {
1966                         if (!visual_list && !visual_only && (mon_idx[mon_cur] > 0))
1967                         {
1968                                 screen_roff(creature_ptr, mon_idx[mon_cur], 0);
1969
1970                                 (void)inkey();
1971
1972                                 redraw = TRUE;
1973                         }
1974
1975                         break;
1976                 }
1977
1978                 default:
1979                 {
1980                         browser_cursor(ch, &column, &grp_cur, grp_cnt, &mon_cur, mon_cnt);
1981
1982                         break;
1983                 }
1984                 }
1985         }
1986
1987         C_KILL(mon_idx, max_r_idx, MONRACE_IDX);
1988 }
1989
1990
1991 /*
1992  * Display the objects in a group.
1993  */
1994 static void display_object_list(int col, int row, int per_page, IDX object_idx[],
1995         int object_cur, int object_top, bool visual_only)
1996 {
1997         int i;
1998         for (i = 0; i < per_page && (object_idx[object_top + i] >= 0); i++)
1999         {
2000                 GAME_TEXT o_name[MAX_NLEN];
2001                 TERM_COLOR a;
2002                 SYMBOL_CODE c;
2003                 object_kind *flavor_k_ptr;
2004                 KIND_OBJECT_IDX k_idx = object_idx[object_top + i];
2005                 object_kind *k_ptr = &k_info[k_idx];
2006                 TERM_COLOR attr = ((k_ptr->aware || visual_only) ? TERM_WHITE : TERM_SLATE);
2007                 byte cursor = ((k_ptr->aware || visual_only) ? TERM_L_BLUE : TERM_BLUE);
2008                 if (!visual_only && k_ptr->flavor)
2009                 {
2010                         flavor_k_ptr = &k_info[k_ptr->flavor];
2011                 }
2012                 else
2013                 {
2014                         flavor_k_ptr = k_ptr;
2015                 }
2016
2017                 attr = ((i + object_top == object_cur) ? cursor : attr);
2018                 if (!k_ptr->flavor || (!visual_only && k_ptr->aware))
2019                 {
2020                         strip_name(o_name, k_idx);
2021                 }
2022                 else
2023                 {
2024                         strcpy(o_name, k_name + flavor_k_ptr->flavor_name);
2025                 }
2026
2027                 c_prt(attr, o_name, row + i, col);
2028                 if (per_page == 1)
2029                 {
2030                         c_prt(attr, format("%02x/%02x", flavor_k_ptr->x_attr, flavor_k_ptr->x_char), row + i, (current_world_ptr->wizard || visual_only) ? 64 : 68);
2031                 }
2032
2033                 if (current_world_ptr->wizard || visual_only)
2034                 {
2035                         c_prt(attr, format("%d", k_idx), row + i, 70);
2036                 }
2037
2038                 a = flavor_k_ptr->x_attr;
2039                 c = flavor_k_ptr->x_char;
2040
2041                 Term_queue_bigchar(use_bigtile ? 76 : 77, row + i, a, c, 0, 0);
2042         }
2043
2044         for (; i < per_page; i++)
2045         {
2046                 Term_erase(col, row + i, 255);
2047         }
2048 }
2049
2050
2051 /*
2052  * Describe fake object
2053  */
2054 static void desc_obj_fake(player_type *creature_ptr, KIND_OBJECT_IDX k_idx)
2055 {
2056         object_type *o_ptr;
2057         object_type object_type_body;
2058         o_ptr = &object_type_body;
2059         object_wipe(o_ptr);
2060         object_prep(o_ptr, k_idx);
2061
2062         o_ptr->ident |= IDENT_KNOWN;
2063         handle_stuff(creature_ptr);
2064
2065         if (screen_object(creature_ptr, o_ptr, SCROBJ_FAKE_OBJECT | SCROBJ_FORCE_DETAIL)) return;
2066
2067         msg_print(_("特に変わったところはないようだ。", "You see nothing special."));
2068         msg_print(NULL);
2069 }
2070
2071
2072 /*
2073  * Display known objects
2074  */
2075 void do_cmd_knowledge_objects(player_type *creature_ptr, bool *need_redraw, bool visual_only, IDX direct_k_idx)
2076 {
2077         IDX object_old, object_top;
2078         IDX grp_idx[100];
2079         int object_cnt;
2080         OBJECT_IDX *object_idx;
2081
2082         bool visual_list = FALSE;
2083         TERM_COLOR attr_top = 0;
2084         byte char_left = 0;
2085         byte mode;
2086
2087         TERM_LEN wid, hgt;
2088         Term_get_size(&wid, &hgt);
2089
2090         int browser_rows = hgt - 8;
2091         C_MAKE(object_idx, max_k_idx, KIND_OBJECT_IDX);
2092
2093         int len;
2094         int max = 0;
2095         int grp_cnt = 0;
2096         if (direct_k_idx < 0)
2097         {
2098                 mode = visual_only ? 0x03 : 0x01;
2099                 for (IDX i = 0; object_group_text[i] != NULL; i++)
2100                 {
2101                         len = strlen(object_group_text[i]);
2102                         if (len > max) max = len;
2103
2104                         if (collect_objects(i, object_idx, mode))
2105                         {
2106                                 grp_idx[grp_cnt++] = i;
2107                         }
2108                 }
2109
2110                 object_old = -1;
2111                 object_cnt = 0;
2112         }
2113         else
2114         {
2115                 object_kind *k_ptr = &k_info[direct_k_idx];
2116                 object_kind *flavor_k_ptr;
2117
2118                 if (!visual_only && k_ptr->flavor)
2119                 {
2120                         flavor_k_ptr = &k_info[k_ptr->flavor];
2121                 }
2122                 else
2123                 {
2124                         flavor_k_ptr = k_ptr;
2125                 }
2126
2127                 object_idx[0] = direct_k_idx;
2128                 object_old = direct_k_idx;
2129                 object_cnt = 1;
2130                 object_idx[1] = -1;
2131                 (void)visual_mode_command('v', &visual_list, browser_rows - 1, wid - (max + 3),
2132                         &attr_top, &char_left, &flavor_k_ptr->x_attr, &flavor_k_ptr->x_char, need_redraw);
2133         }
2134
2135         grp_idx[grp_cnt] = -1;
2136         mode = visual_only ? 0x02 : 0x00;
2137         IDX old_grp_cur = -1;
2138         IDX grp_cur = 0;
2139         IDX grp_top = 0;
2140         IDX object_cur = object_top = 0;
2141         bool flag = FALSE;
2142         bool redraw = TRUE;
2143         int column = 0;
2144         while (!flag)
2145         {
2146                 object_kind *k_ptr, *flavor_k_ptr;
2147
2148                 if (redraw)
2149                 {
2150                         clear_from(0);
2151
2152 #ifdef JP
2153                         prt(format("%s - アイテム", !visual_only ? "知識" : "表示"), 2, 0);
2154                         if (direct_k_idx < 0) prt("グループ", 4, 0);
2155                         prt("名前", 4, max + 3);
2156                         if (current_world_ptr->wizard || visual_only) prt("Idx", 4, 70);
2157                         prt("文字", 4, 74);
2158 #else
2159                         prt(format("%s - objects", !visual_only ? "Knowledge" : "Visuals"), 2, 0);
2160                         if (direct_k_idx < 0) prt("Group", 4, 0);
2161                         prt("Name", 4, max + 3);
2162                         if (current_world_ptr->wizard || visual_only) prt("Idx", 4, 70);
2163                         prt("Sym", 4, 75);
2164 #endif
2165
2166                         for (IDX i = 0; i < 78; i++)
2167                         {
2168                                 Term_putch(i, 5, TERM_WHITE, '=');
2169                         }
2170
2171                         if (direct_k_idx < 0)
2172                         {
2173                                 for (IDX i = 0; i < browser_rows; i++)
2174                                 {
2175                                         Term_putch(max + 1, 6 + i, TERM_WHITE, '|');
2176                                 }
2177                         }
2178
2179                         redraw = FALSE;
2180                 }
2181
2182                 if (direct_k_idx < 0)
2183                 {
2184                         if (grp_cur < grp_top) grp_top = grp_cur;
2185                         if (grp_cur >= grp_top + browser_rows) grp_top = grp_cur - browser_rows + 1;
2186
2187                         display_group_list(0, 6, max, browser_rows, grp_idx, object_group_text, grp_cur, grp_top);
2188                         if (old_grp_cur != grp_cur)
2189                         {
2190                                 old_grp_cur = grp_cur;
2191                                 object_cnt = collect_objects(grp_idx[grp_cur], object_idx, mode);
2192                         }
2193
2194                         while (object_cur < object_top)
2195                                 object_top = MAX(0, object_top - browser_rows / 2);
2196                         while (object_cur >= object_top + browser_rows)
2197                                 object_top = MIN(object_cnt - browser_rows, object_top + browser_rows / 2);
2198                 }
2199
2200                 if (!visual_list)
2201                 {
2202                         display_object_list(max + 3, 6, browser_rows, object_idx, object_cur, object_top, visual_only);
2203                 }
2204                 else
2205                 {
2206                         object_top = object_cur;
2207                         display_object_list(max + 3, 6, 1, object_idx, object_cur, object_top, visual_only);
2208                         display_visual_list(max + 3, 7, browser_rows - 1, wid - (max + 3), attr_top, char_left);
2209                 }
2210
2211                 k_ptr = &k_info[object_idx[object_cur]];
2212
2213                 if (!visual_only && k_ptr->flavor)
2214                 {
2215                         flavor_k_ptr = &k_info[k_ptr->flavor];
2216                 }
2217                 else
2218                 {
2219                         flavor_k_ptr = k_ptr;
2220                 }
2221
2222 #ifdef JP
2223                 prt(format("<方向>%s%s%s, ESC",
2224                         (!visual_list && !visual_only) ? ", 'r'で詳細を見る" : "",
2225                         visual_list ? ", ENTERで決定" : ", 'v'でシンボル変更",
2226                         (attr_idx || char_idx) ? ", 'c', 'p'でペースト" : ", 'c'でコピー"),
2227                         hgt - 1, 0);
2228 #else
2229                 prt(format("<dir>%s%s%s, ESC",
2230                         (!visual_list && !visual_only) ? ", 'r' to recall" : "",
2231                         visual_list ? ", ENTER to accept" : ", 'v' for visuals",
2232                         (attr_idx || char_idx) ? ", 'c', 'p' to paste" : ", 'c' to copy"),
2233                         hgt - 1, 0);
2234 #endif
2235
2236                 if (!visual_only)
2237                 {
2238                         if (object_cnt) object_kind_track(creature_ptr, object_idx[object_cur]);
2239
2240                         if (object_old != object_idx[object_cur])
2241                         {
2242                                 handle_stuff(creature_ptr);
2243                                 object_old = object_idx[object_cur];
2244                         }
2245                 }
2246
2247                 if (visual_list)
2248                 {
2249                         place_visual_list_cursor(max + 3, 7, flavor_k_ptr->x_attr, flavor_k_ptr->x_char, attr_top, char_left);
2250                 }
2251                 else if (!column)
2252                 {
2253                         Term_gotoxy(0, 6 + (grp_cur - grp_top));
2254                 }
2255                 else
2256                 {
2257                         Term_gotoxy(max + 3, 6 + (object_cur - object_top));
2258                 }
2259
2260                 char ch = inkey();
2261                 if (visual_mode_command(ch, &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, &flavor_k_ptr->x_attr, &flavor_k_ptr->x_char, need_redraw))
2262                 {
2263                         if (direct_k_idx >= 0)
2264                         {
2265                                 switch (ch)
2266                                 {
2267                                 case '\n':
2268                                 case '\r':
2269                                 case ESCAPE:
2270                                         flag = TRUE;
2271                                         break;
2272                                 }
2273                         }
2274                         continue;
2275                 }
2276
2277                 switch (ch)
2278                 {
2279                 case ESCAPE:
2280                 {
2281                         flag = TRUE;
2282                         break;
2283                 }
2284
2285                 case 'R':
2286                 case 'r':
2287                 {
2288                         if (!visual_list && !visual_only && (grp_cnt > 0))
2289                         {
2290                                 desc_obj_fake(creature_ptr, object_idx[object_cur]);
2291                                 redraw = TRUE;
2292                         }
2293
2294                         break;
2295                 }
2296
2297                 default:
2298                 {
2299                         browser_cursor(ch, &column, &grp_cur, grp_cnt, &object_cur, object_cnt);
2300                         break;
2301                 }
2302                 }
2303         }
2304
2305         C_KILL(object_idx, max_k_idx, KIND_OBJECT_IDX);
2306 }
2307
2308
2309 /*
2310  * Display the features in a group.
2311  */
2312 static void display_feature_list(int col, int row, int per_page, FEAT_IDX *feat_idx,
2313         FEAT_IDX feat_cur, FEAT_IDX feat_top, bool visual_only, int lighting_level)
2314 {
2315         int lit_col[F_LIT_MAX], i;
2316         int f_idx_col = use_bigtile ? 62 : 64;
2317
2318         lit_col[F_LIT_STANDARD] = use_bigtile ? (71 - F_LIT_MAX) : 71;
2319         for (i = F_LIT_NS_BEGIN; i < F_LIT_MAX; i++)
2320                 lit_col[i] = lit_col[F_LIT_STANDARD] + 2 + (i - F_LIT_NS_BEGIN) * 2 + (use_bigtile ? i : 0);
2321
2322         for (i = 0; i < per_page && (feat_idx[feat_top + i] >= 0); i++)
2323         {
2324                 TERM_COLOR attr;
2325                 FEAT_IDX f_idx = feat_idx[feat_top + i];
2326                 feature_type *f_ptr = &f_info[f_idx];
2327                 int row_i = row + i;
2328                 attr = ((i + feat_top == feat_cur) ? TERM_L_BLUE : TERM_WHITE);
2329                 c_prt(attr, f_name + f_ptr->name, row_i, col);
2330                 if (per_page == 1)
2331                 {
2332                         c_prt(attr, format("(%s)", lighting_level_str[lighting_level]), row_i, col + 1 + strlen(f_name + f_ptr->name));
2333                         c_prt(attr, format("%02x/%02x", f_ptr->x_attr[lighting_level], f_ptr->x_char[lighting_level]), row_i, f_idx_col - ((current_world_ptr->wizard || visual_only) ? 6 : 2));
2334                 }
2335                 if (current_world_ptr->wizard || visual_only)
2336                 {
2337                         c_prt(attr, format("%d", f_idx), row_i, f_idx_col);
2338                 }
2339
2340                 Term_queue_bigchar(lit_col[F_LIT_STANDARD], row_i, f_ptr->x_attr[F_LIT_STANDARD], f_ptr->x_char[F_LIT_STANDARD], 0, 0);
2341                 Term_putch(lit_col[F_LIT_NS_BEGIN], row_i, TERM_SLATE, '(');
2342                 for (int j = F_LIT_NS_BEGIN + 1; j < F_LIT_MAX; j++)
2343                 {
2344                         Term_putch(lit_col[j], row_i, TERM_SLATE, '/');
2345                 }
2346
2347                 Term_putch(lit_col[F_LIT_MAX - 1] + (use_bigtile ? 3 : 2), row_i, TERM_SLATE, ')');
2348                 for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++)
2349                 {
2350                         Term_queue_bigchar(lit_col[j] + 1, row_i, f_ptr->x_attr[j], f_ptr->x_char[j], 0, 0);
2351                 }
2352         }
2353
2354         for (; i < per_page; i++)
2355         {
2356                 Term_erase(col, row + i, 255);
2357         }
2358 }
2359
2360
2361 /*
2362  * Interact with feature visuals.
2363  */
2364 void do_cmd_knowledge_features(bool *need_redraw, bool visual_only, IDX direct_f_idx, IDX *lighting_level)
2365 {
2366         TERM_COLOR attr_old[F_LIT_MAX];
2367         (void)C_WIPE(attr_old, F_LIT_MAX, TERM_COLOR);
2368         SYMBOL_CODE char_old[F_LIT_MAX];
2369         (void)C_WIPE(char_old, F_LIT_MAX, SYMBOL_CODE);
2370
2371         TERM_LEN wid, hgt;
2372         Term_get_size(&wid, &hgt);
2373
2374         FEAT_IDX *feat_idx;
2375         C_MAKE(feat_idx, max_f_idx, FEAT_IDX);
2376
2377         int len;
2378         int max = 0;
2379         int grp_cnt = 0;
2380         int feat_cnt;
2381         FEAT_IDX grp_idx[100];
2382         TERM_COLOR attr_top = 0;
2383         bool visual_list = FALSE;
2384         byte char_left = 0;
2385         TERM_LEN browser_rows = hgt - 8;
2386         if (direct_f_idx < 0)
2387         {
2388                 for (FEAT_IDX i = 0; feature_group_text[i] != NULL; i++)
2389                 {
2390                         len = strlen(feature_group_text[i]);
2391                         if (len > max) max = len;
2392
2393                         if (collect_features(feat_idx, 0x01))
2394                         {
2395                                 grp_idx[grp_cnt++] = i;
2396                         }
2397                 }
2398
2399                 feat_cnt = 0;
2400         }
2401         else
2402         {
2403                 feature_type *f_ptr = &f_info[direct_f_idx];
2404
2405                 feat_idx[0] = direct_f_idx;
2406                 feat_cnt = 1;
2407                 feat_idx[1] = -1;
2408
2409                 (void)visual_mode_command('v', &visual_list, browser_rows - 1, wid - (max + 3),
2410                         &attr_top, &char_left, &f_ptr->x_attr[*lighting_level], &f_ptr->x_char[*lighting_level], need_redraw);
2411
2412                 for (FEAT_IDX i = 0; i < F_LIT_MAX; i++)
2413                 {
2414                         attr_old[i] = f_ptr->x_attr[i];
2415                         char_old[i] = f_ptr->x_char[i];
2416                 }
2417         }
2418
2419         grp_idx[grp_cnt] = -1;
2420
2421         FEAT_IDX old_grp_cur = -1;
2422         FEAT_IDX grp_cur = 0;
2423         FEAT_IDX grp_top = 0;
2424         FEAT_IDX feat_cur = 0;
2425         FEAT_IDX feat_top = 0;
2426         TERM_LEN column = 0;
2427         bool flag = FALSE;
2428         bool redraw = TRUE;
2429         TERM_COLOR *cur_attr_ptr;
2430         SYMBOL_CODE *cur_char_ptr;
2431         while (!flag)
2432         {
2433                 char ch;
2434                 feature_type *f_ptr;
2435
2436                 if (redraw)
2437                 {
2438                         clear_from(0);
2439
2440                         prt(_("表示 - 地形", "Visuals - features"), 2, 0);
2441                         if (direct_f_idx < 0) prt(_("グループ", "Group"), 4, 0);
2442                         prt(_("名前", "Name"), 4, max + 3);
2443                         if (use_bigtile)
2444                         {
2445                                 if (current_world_ptr->wizard || visual_only) prt("Idx", 4, 62);
2446                                 prt(_("文字 ( l/ d)", "Sym ( l/ d)"), 4, 66);
2447                         }
2448                         else
2449                         {
2450                                 if (current_world_ptr->wizard || visual_only) prt("Idx", 4, 64);
2451                                 prt(_("文字 (l/d)", "Sym (l/d)"), 4, 68);
2452                         }
2453
2454                         for (FEAT_IDX i = 0; i < 78; i++)
2455                         {
2456                                 Term_putch(i, 5, TERM_WHITE, '=');
2457                         }
2458
2459                         if (direct_f_idx < 0)
2460                         {
2461                                 for (FEAT_IDX i = 0; i < browser_rows; i++)
2462                                 {
2463                                         Term_putch(max + 1, 6 + i, TERM_WHITE, '|');
2464                                 }
2465                         }
2466
2467                         redraw = FALSE;
2468                 }
2469
2470                 if (direct_f_idx < 0)
2471                 {
2472                         if (grp_cur < grp_top) grp_top = grp_cur;
2473                         if (grp_cur >= grp_top + browser_rows) grp_top = grp_cur - browser_rows + 1;
2474
2475                         display_group_list(0, 6, max, browser_rows, grp_idx, feature_group_text, grp_cur, grp_top);
2476                         if (old_grp_cur != grp_cur)
2477                         {
2478                                 old_grp_cur = grp_cur;
2479                                 feat_cnt = collect_features(feat_idx, 0x00);
2480                         }
2481
2482                         while (feat_cur < feat_top)
2483                                 feat_top = MAX(0, feat_top - browser_rows / 2);
2484                         while (feat_cur >= feat_top + browser_rows)
2485                                 feat_top = MIN(feat_cnt - browser_rows, feat_top + browser_rows / 2);
2486                 }
2487
2488                 if (!visual_list)
2489                 {
2490                         display_feature_list(max + 3, 6, browser_rows, feat_idx, feat_cur, feat_top, visual_only, F_LIT_STANDARD);
2491                 }
2492                 else
2493                 {
2494                         feat_top = feat_cur;
2495                         display_feature_list(max + 3, 6, 1, feat_idx, feat_cur, feat_top, visual_only, *lighting_level);
2496                         display_visual_list(max + 3, 7, browser_rows - 1, wid - (max + 3), attr_top, char_left);
2497                 }
2498
2499                 prt(format(_("<方向>%s, 'd'で標準光源効果%s, ESC", "<dir>%s, 'd' for default lighting%s, ESC"),
2500                         visual_list ? _(", ENTERで決定, 'a'で対象明度変更", ", ENTER to accept, 'a' for lighting level") : _(", 'v'でシンボル変更", ", 'v' for visuals"),
2501                         (attr_idx || char_idx) ? _(", 'c', 'p'でペースト", ", 'c', 'p' to paste") : _(", 'c'でコピー", ", 'c' to copy")),
2502                         hgt - 1, 0);
2503
2504                 f_ptr = &f_info[feat_idx[feat_cur]];
2505                 cur_attr_ptr = &f_ptr->x_attr[*lighting_level];
2506                 cur_char_ptr = &f_ptr->x_char[*lighting_level];
2507
2508                 if (visual_list)
2509                 {
2510                         place_visual_list_cursor(max + 3, 7, *cur_attr_ptr, *cur_char_ptr, attr_top, char_left);
2511                 }
2512                 else if (!column)
2513                 {
2514                         Term_gotoxy(0, 6 + (grp_cur - grp_top));
2515                 }
2516                 else
2517                 {
2518                         Term_gotoxy(max + 3, 6 + (feat_cur - feat_top));
2519                 }
2520
2521                 ch = inkey();
2522                 if (visual_list && ((ch == 'A') || (ch == 'a')))
2523                 {
2524                         int prev_lighting_level = *lighting_level;
2525
2526                         if (ch == 'A')
2527                         {
2528                                 if (*lighting_level <= 0) *lighting_level = F_LIT_MAX - 1;
2529                                 else (*lighting_level)--;
2530                         }
2531                         else
2532                         {
2533                                 if (*lighting_level >= F_LIT_MAX - 1) *lighting_level = 0;
2534                                 else (*lighting_level)++;
2535                         }
2536
2537                         if (f_ptr->x_attr[prev_lighting_level] != f_ptr->x_attr[*lighting_level])
2538                                 attr_top = MAX(0, (f_ptr->x_attr[*lighting_level] & 0x7f) - 5);
2539
2540                         if (f_ptr->x_char[prev_lighting_level] != f_ptr->x_char[*lighting_level])
2541                                 char_left = MAX(0, f_ptr->x_char[*lighting_level] - 10);
2542
2543                         continue;
2544                 }
2545                 else if ((ch == 'D') || (ch == 'd'))
2546                 {
2547                         TERM_COLOR prev_x_attr = f_ptr->x_attr[*lighting_level];
2548                         byte prev_x_char = f_ptr->x_char[*lighting_level];
2549
2550                         apply_default_feat_lighting(f_ptr->x_attr, f_ptr->x_char);
2551
2552                         if (visual_list)
2553                         {
2554                                 if (prev_x_attr != f_ptr->x_attr[*lighting_level])
2555                                         attr_top = MAX(0, (f_ptr->x_attr[*lighting_level] & 0x7f) - 5);
2556
2557                                 if (prev_x_char != f_ptr->x_char[*lighting_level])
2558                                         char_left = MAX(0, f_ptr->x_char[*lighting_level] - 10);
2559                         }
2560                         else *need_redraw = TRUE;
2561
2562                         continue;
2563                 }
2564                 else if (visual_mode_command(ch, &visual_list, browser_rows - 1, wid - (max + 3), &attr_top, &char_left, cur_attr_ptr, cur_char_ptr, need_redraw))
2565                 {
2566                         switch (ch)
2567                         {
2568                         case ESCAPE:
2569                                 for (FEAT_IDX i = 0; i < F_LIT_MAX; i++)
2570                                 {
2571                                         f_ptr->x_attr[i] = attr_old[i];
2572                                         f_ptr->x_char[i] = char_old[i];
2573                                 }
2574
2575                                 /* Fall through */
2576                         case '\n':
2577                         case '\r':
2578                                 if (direct_f_idx >= 0) flag = TRUE;
2579                                 else *lighting_level = F_LIT_STANDARD;
2580                                 break;
2581                         case 'V':
2582                         case 'v':
2583                                 for (FEAT_IDX i = 0; i < F_LIT_MAX; i++)
2584                                 {
2585                                         attr_old[i] = f_ptr->x_attr[i];
2586                                         char_old[i] = f_ptr->x_char[i];
2587                                 }
2588                                 *lighting_level = F_LIT_STANDARD;
2589                                 break;
2590
2591                         case 'C':
2592                         case 'c':
2593                                 if (!visual_list)
2594                                 {
2595                                         for (FEAT_IDX i = 0; i < F_LIT_MAX; i++)
2596                                         {
2597                                                 attr_idx_feat[i] = f_ptr->x_attr[i];
2598                                                 char_idx_feat[i] = f_ptr->x_char[i];
2599                                         }
2600                                 }
2601                                 break;
2602
2603                         case 'P':
2604                         case 'p':
2605                                 if (!visual_list)
2606                                 {
2607                                         for (FEAT_IDX i = F_LIT_NS_BEGIN; i < F_LIT_MAX; i++)
2608                                         {
2609                                                 if (attr_idx_feat[i] || (!(char_idx_feat[i] & 0x80) && char_idx_feat[i])) f_ptr->x_attr[i] = attr_idx_feat[i];
2610                                                 if (char_idx_feat[i]) f_ptr->x_char[i] = char_idx_feat[i];
2611                                         }
2612                                 }
2613                                 break;
2614                         }
2615                         continue;
2616                 }
2617
2618                 switch (ch)
2619                 {
2620                 case ESCAPE:
2621                 {
2622                         flag = TRUE;
2623                         break;
2624                 }
2625
2626                 default:
2627                 {
2628                         browser_cursor(ch, &column, &grp_cur, grp_cnt, &feat_cur, feat_cnt);
2629                         break;
2630                 }
2631                 }
2632         }
2633
2634         C_KILL(feat_idx, max_f_idx, FEAT_IDX);
2635 }
2636
2637
2638 /*
2639  * List wanted monsters
2640  * @param creature_ptr プレーヤーへの参照ポインタ
2641  * @return なし
2642  */
2643 static void do_cmd_knowledge_bounty(player_type *creature_ptr)
2644 {
2645         FILE *fff;
2646         GAME_TEXT file_name[1024];
2647         fff = my_fopen_temp(file_name, 1024);
2648         if (!fff)
2649         {
2650                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
2651                 msg_print(NULL);
2652                 return;
2653         }
2654
2655         fprintf(fff, _("今日のターゲット : %s\n", "Today's target : %s\n"),
2656                 (creature_ptr->today_mon ? r_name + r_info[creature_ptr->today_mon].name : _("不明", "unknown")));
2657         fprintf(fff, "\n");
2658         fprintf(fff, _("賞金首リスト\n", "List of wanted monsters\n"));
2659         fprintf(fff, "----------------------------------------------\n");
2660
2661         bool listed = FALSE;
2662         for (int i = 0; i < MAX_BOUNTY; i++)
2663         {
2664                 if (current_world_ptr->bounty_r_idx[i] <= 10000)
2665                 {
2666                         fprintf(fff, "%s\n", r_name + r_info[current_world_ptr->bounty_r_idx[i]].name);
2667                         listed = TRUE;
2668                 }
2669         }
2670
2671         if (!listed)
2672         {
2673                 fprintf(fff, "\n%s\n", _("賞金首はもう残っていません。", "There are no more wanted monster."));
2674         }
2675
2676         my_fclose(fff);
2677         (void)show_file(creature_ptr, TRUE, file_name, _("賞金首の一覧", "Wanted monsters"), 0, 0);
2678         fd_kill(file_name);
2679 }
2680
2681 /*
2682  * List virtues & status
2683  */
2684 static void do_cmd_knowledge_virtues(player_type *creature_ptr)
2685 {
2686         FILE *fff;
2687         GAME_TEXT file_name[1024];
2688         fff = my_fopen_temp(file_name, 1024);
2689         if (!fff)
2690         {
2691                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
2692                 msg_print(NULL);
2693                 return;
2694         }
2695
2696         fprintf(fff, _("現在の属性 : %s\n\n", "Your alignment : %s\n\n"), your_alignment(creature_ptr));
2697         dump_virtues(creature_ptr, fff);
2698         my_fclose(fff);
2699         (void)show_file(creature_ptr, TRUE, file_name, _("八つの徳", "Virtues"), 0, 0);
2700         fd_kill(file_name);
2701 }
2702
2703 /*
2704  * Dungeon
2705  */
2706 static void do_cmd_knowledge_dungeon(player_type *creature_ptr)
2707 {
2708         FILE *fff;
2709         GAME_TEXT file_name[1024];
2710         fff = my_fopen_temp(file_name, 1024);
2711         if (!fff)
2712         {
2713                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
2714                 msg_print(NULL);
2715                 return;
2716         }
2717
2718         for (int i = 1; i < current_world_ptr->max_d_idx; i++)
2719         {
2720                 bool seiha = FALSE;
2721
2722                 if (!d_info[i].maxdepth) continue;
2723                 if (!max_dlv[i]) continue;
2724                 if (d_info[i].final_guardian)
2725                 {
2726                         if (!r_info[d_info[i].final_guardian].max_num) seiha = TRUE;
2727                 }
2728                 else if (max_dlv[i] == d_info[i].maxdepth) seiha = TRUE;
2729
2730                 fprintf(fff, _("%c%-12s :  %3d 階\n", "%c%-16s :  level %3d\n"), seiha ? '!' : ' ', d_name + d_info[i].name, (int)max_dlv[i]);
2731         }
2732
2733         my_fclose(fff);
2734         (void)show_file(creature_ptr, TRUE, file_name, _("今までに入ったダンジョン", "Dungeon"), 0, 0);
2735         fd_kill(file_name);
2736 }
2737
2738
2739 /*
2740 * List virtues & status
2741 *
2742 */
2743 static void do_cmd_knowledge_stat(player_type *creature_ptr)
2744 {
2745         FILE *fff;
2746         GAME_TEXT file_name[1024];
2747         fff = my_fopen_temp(file_name, 1024);
2748         if (!fff)
2749         {
2750                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
2751                 msg_print(NULL);
2752                 return;
2753         }
2754
2755         int percent = (int)(((long)creature_ptr->player_hp[PY_MAX_LEVEL - 1] * 200L) /
2756                 (2 * creature_ptr->hitdie +
2757                 ((PY_MAX_LEVEL - 1 + 3) * (creature_ptr->hitdie + 1))));
2758
2759         if (creature_ptr->knowledge & KNOW_HPRATE)
2760                 fprintf(fff, _("現在の体力ランク : %d/100\n\n", "Your current Life Rating is %d/100.\n\n"), percent);
2761         else fprintf(fff, _("現在の体力ランク : ???\n\n", "Your current Life Rating is ???.\n\n"));
2762
2763         fprintf(fff, _("能力の最大値\n\n", "Limits of maximum stats\n\n"));
2764         for (int v_nr = 0; v_nr < A_MAX; v_nr++)
2765         {
2766                 if ((creature_ptr->knowledge & KNOW_STAT) || creature_ptr->stat_max[v_nr] == creature_ptr->stat_max_max[v_nr]) fprintf(fff, "%s 18/%d\n", stat_names[v_nr], creature_ptr->stat_max_max[v_nr] - 18);
2767                 else fprintf(fff, "%s ???\n", stat_names[v_nr]);
2768         }
2769
2770         dump_yourself(creature_ptr, fff);
2771         my_fclose(fff);
2772         (void)show_file(creature_ptr, TRUE, file_name, _("自分に関する情報", "HP-rate & Max stat"), 0, 0);
2773         fd_kill(file_name);
2774 }
2775
2776
2777 /*
2778  * todo player_typeではなくQUEST_IDXを引数にすべきかもしれない
2779  * Print all active quests
2780  * @param creature_ptr プレーヤーへの参照ポインタ
2781  * @return なし
2782  */
2783 static void do_cmd_knowledge_quests_current(player_type *creature_ptr, FILE *fff)
2784 {
2785         char tmp_str[120];
2786         char rand_tmp_str[120] = "\0";
2787         GAME_TEXT name[MAX_NLEN];
2788         monster_race *r_ptr;
2789         int rand_level = 100;
2790         int total = 0;
2791
2792         fprintf(fff, _("《遂行中のクエスト》\n", "< Current Quest >\n"));
2793
2794         for (QUEST_IDX i = 1; i < max_q_idx; i++)
2795         {
2796                 bool is_print = quest[i].status == QUEST_STATUS_TAKEN;
2797                 is_print |= (quest[i].status == QUEST_STATUS_STAGE_COMPLETED) && (quest[i].type == QUEST_TYPE_TOWER);
2798                 is_print |= quest[i].status == QUEST_STATUS_COMPLETED;
2799                 if (!is_print)
2800                         continue;
2801
2802                 QUEST_IDX old_quest = creature_ptr->current_floor_ptr->inside_quest;
2803                 for (int j = 0; j < 10; j++)
2804                         quest_text[j][0] = '\0';
2805
2806                 quest_text_line = 0;
2807                 creature_ptr->current_floor_ptr->inside_quest = i;
2808                 init_flags = INIT_SHOW_TEXT;
2809                 process_dungeon_file(creature_ptr, "q_info.txt", 0, 0, 0, 0);
2810                 creature_ptr->current_floor_ptr->inside_quest = old_quest;
2811                 if (quest[i].flags & QUEST_FLAG_SILENT) continue;
2812
2813                 total++;
2814                 if (quest[i].type != QUEST_TYPE_RANDOM)
2815                 {
2816                         char note[80] = "\0";
2817
2818                         if (quest[i].status == QUEST_STATUS_TAKEN || quest[i].status == QUEST_STATUS_STAGE_COMPLETED)
2819                         {
2820                                 switch (quest[i].type)
2821                                 {
2822                                 case QUEST_TYPE_KILL_LEVEL:
2823                                 case QUEST_TYPE_KILL_ANY_LEVEL:
2824                                         r_ptr = &r_info[quest[i].r_idx];
2825                                         strcpy(name, r_name + r_ptr->name);
2826                                         if (quest[i].max_num > 1)
2827                                         {
2828 #ifdef JP
2829                                                 sprintf(note, " - %d 体の%sを倒す。(あと %d 体)",
2830                                                         (int)quest[i].max_num, name, (int)(quest[i].max_num - quest[i].cur_num));
2831 #else
2832                                                 plural_aux(name);
2833                                                 sprintf(note, " - kill %d %s, have killed %d.",
2834                                                         (int)quest[i].max_num, name, (int)quest[i].cur_num);
2835 #endif
2836                                         }
2837                                         else
2838                                                 sprintf(note, _(" - %sを倒す。", " - kill %s."), name);
2839                                         break;
2840
2841                                 case QUEST_TYPE_FIND_ARTIFACT:
2842                                         if (quest[i].k_idx)
2843                                         {
2844                                                 artifact_type *a_ptr = &a_info[quest[i].k_idx];
2845                                                 object_type forge;
2846                                                 object_type *q_ptr = &forge;
2847                                                 KIND_OBJECT_IDX k_idx = lookup_kind(a_ptr->tval, a_ptr->sval);
2848                                                 object_prep(q_ptr, k_idx);
2849                                                 q_ptr->name1 = quest[i].k_idx;
2850                                                 q_ptr->ident = IDENT_STORE;
2851                                                 object_desc(creature_ptr, name, q_ptr, OD_NAME_ONLY);
2852                                         }
2853                                         sprintf(note, _("\n   - %sを見つけ出す。", "\n   - Find %s."), name);
2854                                         break;
2855                                 case QUEST_TYPE_FIND_EXIT:
2856                                         sprintf(note, _(" - 出口に到達する。", " - Reach exit."));
2857                                         break;
2858
2859                                 case QUEST_TYPE_KILL_NUMBER:
2860 #ifdef JP
2861                                         sprintf(note, " - %d 体のモンスターを倒す。(あと %d 体)",
2862                                                 (int)quest[i].max_num, (int)(quest[i].max_num - quest[i].cur_num));
2863 #else
2864                                         sprintf(note, " - Kill %d monsters, have killed %d.",
2865                                                 (int)quest[i].max_num, (int)quest[i].cur_num);
2866 #endif
2867                                         break;
2868
2869                                 case QUEST_TYPE_KILL_ALL:
2870                                 case QUEST_TYPE_TOWER:
2871                                         sprintf(note, _(" - 全てのモンスターを倒す。", " - Kill all monsters."));
2872                                         break;
2873                                 }
2874                         }
2875
2876                         sprintf(tmp_str, _("  %s (危険度:%d階相当)%s\n", "  %s (Danger level: %d)%s\n"),
2877                                 quest[i].name, (int)quest[i].level, note);
2878                         fputs(tmp_str, fff);
2879                         if (quest[i].status == QUEST_STATUS_COMPLETED)
2880                         {
2881                                 sprintf(tmp_str, _("    クエスト達成 - まだ報酬を受けとってない。\n", "    Quest Completed - Unrewarded\n"));
2882                                 fputs(tmp_str, fff);
2883                                 continue;
2884                         }
2885
2886                         int k = 0;
2887                         while (quest_text[k][0] && k < 10)
2888                         {
2889                                 fprintf(fff, "    %s\n", quest_text[k]);
2890                                 k++;
2891                         }
2892
2893                         continue;
2894                 }
2895
2896                 if (quest[i].level >= rand_level)
2897                         continue;
2898
2899                 rand_level = quest[i].level;
2900                 if (max_dlv[DUNGEON_ANGBAND] < rand_level) continue;
2901
2902                 r_ptr = &r_info[quest[i].r_idx];
2903                 strcpy(name, r_name + r_ptr->name);
2904                 if (quest[i].max_num <= 1)
2905                 {
2906                         sprintf(rand_tmp_str, _("  %s (%d 階) - %sを倒す。\n", "  %s (Dungeon level: %d)\n  Kill %s.\n"),
2907                                 quest[i].name, (int)quest[i].level, name);
2908                         continue;
2909                 }
2910
2911 #ifdef JP
2912                 sprintf(rand_tmp_str, "  %s (%d 階) - %d 体の%sを倒す。(あと %d 体)\n",
2913                         quest[i].name, (int)quest[i].level,
2914                         (int)quest[i].max_num, name, (int)(quest[i].max_num - quest[i].cur_num));
2915 #else
2916                 plural_aux(name);
2917
2918                 sprintf(rand_tmp_str, "  %s (Dungeon level: %d)\n  Kill %d %s, have killed %d.\n",
2919                         quest[i].name, (int)quest[i].level,
2920                         (int)quest[i].max_num, name, (int)quest[i].cur_num);
2921 #endif
2922         }
2923
2924         if (rand_tmp_str[0]) fputs(rand_tmp_str, fff);
2925
2926         if (!total) fprintf(fff, _("  なし\n", "  Nothing.\n"));
2927 }
2928
2929
2930 static bool do_cmd_knowledge_quests_aux(player_type *player_ptr, FILE *fff, IDX q_idx)
2931 {
2932         char tmp_str[120];
2933         char playtime_str[16];
2934         quest_type* const q_ptr = &quest[q_idx];
2935
2936         floor_type *floor_ptr = player_ptr->current_floor_ptr;
2937         if (is_fixed_quest_idx(q_idx))
2938         {
2939                 IDX old_quest = floor_ptr->inside_quest;
2940                 floor_ptr->inside_quest = q_idx;
2941                 init_flags = INIT_NAME_ONLY;
2942                 process_dungeon_file(player_ptr, "q_info.txt", 0, 0, 0, 0);
2943                 floor_ptr->inside_quest = old_quest;
2944                 if (q_ptr->flags & QUEST_FLAG_SILENT) return FALSE;
2945         }
2946
2947         strnfmt(playtime_str, sizeof(playtime_str), "%02d:%02d:%02d",
2948                 q_ptr->comptime / (60 * 60), (q_ptr->comptime / 60) % 60, q_ptr->comptime % 60);
2949
2950         if (is_fixed_quest_idx(q_idx) || (q_ptr->r_idx == 0))
2951         {
2952                 sprintf(tmp_str,
2953                         _("  %-35s (危険度:%3d階相当) - レベル%2d - %s\n",
2954                                 "  %-35s (Danger  level: %3d) - level %2d - %s\n"),
2955                         q_ptr->name, (int)q_ptr->level, q_ptr->complev, playtime_str);
2956                 fputs(tmp_str, fff);
2957                 return TRUE;
2958         }
2959
2960         if (q_ptr->complev == 0)
2961         {
2962                 sprintf(tmp_str,
2963                         _("  %-35s (%3d階)            -   不戦勝 - %s\n",
2964                                 "  %-35s (Dungeon level: %3d) - Unearned - %s\n"),
2965                         r_name + r_info[q_ptr->r_idx].name,
2966                         (int)q_ptr->level, playtime_str);
2967                 fputs(tmp_str, fff);
2968                 return TRUE;
2969         }
2970
2971         sprintf(tmp_str,
2972                 _("  %-35s (%3d階)            - レベル%2d - %s\n",
2973                         "  %-35s (Dungeon level: %3d) - level %2d - %s\n"),
2974                 r_name + r_info[q_ptr->r_idx].name,
2975                 (int)q_ptr->level,
2976                 q_ptr->complev,
2977                 playtime_str);
2978         fputs(tmp_str, fff);
2979         return TRUE;
2980 }
2981
2982
2983 /*
2984  * Print all finished quests
2985  * @param creature_ptr プレーヤーへの参照ポインタ
2986  * @param fff セーブファイル (展開済?)
2987  * @param quest_num[] 受注したことのあるクエスト群
2988  * @return なし
2989  */
2990 void do_cmd_knowledge_quests_completed(player_type *creature_ptr, FILE *fff, QUEST_IDX quest_num[])
2991 {
2992         fprintf(fff, _("《達成したクエスト》\n", "< Completed Quest >\n"));
2993         QUEST_IDX total = 0;
2994         for (QUEST_IDX i = 1; i < max_q_idx; i++)
2995         {
2996                 QUEST_IDX q_idx = quest_num[i];
2997                 quest_type* const q_ptr = &quest[q_idx];
2998
2999                 if (q_ptr->status == QUEST_STATUS_FINISHED && do_cmd_knowledge_quests_aux(creature_ptr, fff, q_idx))
3000                 {
3001                         ++total;
3002                 }
3003         }
3004
3005         if (!total) fprintf(fff, _("  なし\n", "  Nothing.\n"));
3006 }
3007
3008
3009 /*
3010  * Print all failed quests
3011  * @param creature_ptr プレーヤーへの参照ポインタ
3012  * @param fff セーブファイル (展開済?)
3013  * @param quest_num[] 受注したことのあるクエスト群
3014  * @return なし
3015 */
3016 void do_cmd_knowledge_quests_failed(player_type *creature_ptr, FILE *fff, QUEST_IDX quest_num[])
3017 {
3018         fprintf(fff, _("《失敗したクエスト》\n", "< Failed Quest >\n"));
3019         QUEST_IDX total = 0;
3020         for (QUEST_IDX i = 1; i < max_q_idx; i++)
3021         {
3022                 QUEST_IDX q_idx = quest_num[i];
3023                 quest_type* const q_ptr = &quest[q_idx];
3024
3025                 if (((q_ptr->status == QUEST_STATUS_FAILED_DONE) || (q_ptr->status == QUEST_STATUS_FAILED)) &&
3026                         do_cmd_knowledge_quests_aux(creature_ptr, fff, q_idx))
3027                 {
3028                         ++total;
3029                 }
3030         }
3031
3032         if (!total) fprintf(fff, _("  なし\n", "  Nothing.\n"));
3033 }
3034
3035
3036 /*
3037  * Print all random quests
3038  */
3039 static void do_cmd_knowledge_quests_wiz_random(FILE *fff)
3040 {
3041         fprintf(fff, _("《残りのランダムクエスト》\n", "< Remaining Random Quest >\n"));
3042         GAME_TEXT tmp_str[120];
3043         QUEST_IDX total = 0;
3044         for (QUEST_IDX i = 1; i < max_q_idx; i++)
3045         {
3046                 if (quest[i].flags & QUEST_FLAG_SILENT) continue;
3047
3048                 if ((quest[i].type == QUEST_TYPE_RANDOM) && (quest[i].status == QUEST_STATUS_TAKEN))
3049                 {
3050                         total++;
3051                         sprintf(tmp_str, _("  %s (%d階, %s)\n", "  %s (%d, %s)\n"),
3052                                 quest[i].name, (int)quest[i].level, r_name + r_info[quest[i].r_idx].name);
3053                         fputs(tmp_str, fff);
3054                 }
3055         }
3056
3057         if (!total) fprintf(fff, _("  なし\n", "  Nothing.\n"));
3058 }
3059
3060 /*
3061  * Print quest status of all active quests
3062  * @param creature_ptr プレーヤーへの参照ポインタ
3063  * @return なし
3064  */
3065 static void do_cmd_knowledge_quests(player_type *creature_ptr)
3066 {
3067         FILE *fff;
3068         GAME_TEXT file_name[1024];
3069         fff = my_fopen_temp(file_name, 1024);
3070         if (!fff)
3071         {
3072                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
3073                 msg_print(NULL);
3074                 return;
3075         }
3076
3077         IDX *quest_num;
3078         C_MAKE(quest_num, max_q_idx, QUEST_IDX);
3079
3080         for (IDX i = 1; i < max_q_idx; i++)
3081                 quest_num[i] = i;
3082
3083         int dummy;
3084         ang_sort(quest_num, &dummy, max_q_idx, ang_sort_comp_quest_num, ang_sort_swap_quest_num);
3085
3086         do_cmd_knowledge_quests_current(creature_ptr, fff);
3087         fputc('\n', fff);
3088         do_cmd_knowledge_quests_completed(creature_ptr, fff, quest_num);
3089         fputc('\n', fff);
3090         do_cmd_knowledge_quests_failed(creature_ptr, fff, quest_num);
3091         if (current_world_ptr->wizard)
3092         {
3093                 fputc('\n', fff);
3094                 do_cmd_knowledge_quests_wiz_random(fff);
3095         }
3096
3097         my_fclose(fff);
3098         (void)show_file(creature_ptr, TRUE, file_name, _("クエスト達成状況", "Quest status"), 0, 0);
3099         fd_kill(file_name);
3100         C_KILL(quest_num, max_q_idx, QUEST_IDX);
3101 }
3102
3103
3104 /*
3105  * List my home
3106  * @param player_ptr プレーヤーへの参照ポインタ
3107  * @return なし
3108  */
3109 static void do_cmd_knowledge_home(player_type *player_ptr)
3110 {
3111         process_dungeon_file(player_ptr, "w_info.txt", 0, 0, current_world_ptr->max_wild_y, current_world_ptr->max_wild_x);
3112
3113         /* Open a new file */
3114         FILE *fff;
3115         GAME_TEXT file_name[1024];
3116         fff = my_fopen_temp(file_name, 1024);
3117         if (!fff)
3118         {
3119                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
3120                 msg_print(NULL);
3121                 return;
3122         }
3123
3124         store_type *store_ptr;
3125         store_ptr = &town_info[1].store[STORE_HOME];
3126
3127         if (store_ptr->stock_num)
3128         {
3129 #ifdef JP
3130                 TERM_LEN x = 1;
3131 #endif
3132                 fprintf(fff, _("  [ 我が家のアイテム ]\n", "  [Home Inventory]\n"));
3133                 concptr paren = ")";
3134                 GAME_TEXT o_name[MAX_NLEN];
3135                 for (int i = 0; i < store_ptr->stock_num; i++)
3136                 {
3137 #ifdef JP
3138                         if ((i % 12) == 0) fprintf(fff, "\n ( %d ページ )\n", x++);
3139                         object_desc(player_ptr, o_name, &store_ptr->stock[i], 0);
3140                         if (strlen(o_name) <= 80 - 3)
3141                         {
3142                                 fprintf(fff, "%c%s %s\n", I2A(i % 12), paren, o_name);
3143                         }
3144                         else
3145                         {
3146                                 int n;
3147                                 char *t;
3148                                 for (n = 0, t = o_name; n < 80 - 3; n++, t++)
3149                                         if (iskanji(*t)) { t++; n++; }
3150                                 if (n == 81 - 3) n = 79 - 3; /* 最後が漢字半分 */
3151
3152                                 fprintf(fff, "%c%s %.*s\n", I2A(i % 12), paren, n, o_name);
3153                                 fprintf(fff, "   %.77s\n", o_name + n);
3154                         }
3155 #else
3156                         object_desc(player_ptr, o_name, &store_ptr->stock[i], 0);
3157                         fprintf(fff, "%c%s %s\n", I2A(i % 12), paren, o_name);
3158 #endif
3159                 }
3160
3161                 fprintf(fff, "\n\n");
3162         }
3163
3164         my_fclose(fff);
3165         (void)show_file(player_ptr, TRUE, file_name, _("我が家のアイテム", "Home Inventory"), 0, 0);
3166         fd_kill(file_name);
3167 }
3168
3169
3170 /*
3171  * Check the status of "autopick"
3172  */
3173 static void do_cmd_knowledge_autopick(player_type *creature_ptr)
3174 {
3175         /* Open a new file */
3176         FILE *fff;
3177         GAME_TEXT file_name[1024];
3178         fff = my_fopen_temp(file_name, 1024);
3179         if (!fff)
3180         {
3181                 msg_format(_("一時ファイル %s を作成できませんでした。", "Failed to create temporary file %s."), file_name);
3182                 msg_print(NULL);
3183                 return;
3184         }
3185
3186         if (!max_autopick)
3187         {
3188                 fprintf(fff, _("自動破壊/拾いには何も登録されていません。", "No preference for auto picker/destroyer."));
3189         }
3190         else
3191         {
3192                 fprintf(fff, _("   自動拾い/破壊には現在 %d行登録されています。\n\n",
3193                         "   There are %d registered lines for auto picker/destroyer.\n\n"), max_autopick);
3194         }
3195
3196         for (int k = 0; k < max_autopick; k++)
3197         {
3198                 concptr tmp;
3199                 byte act = autopick_list[k].action;
3200                 if (act & DONT_AUTOPICK)
3201                 {
3202                         tmp = _("放置", "Leave");
3203                 }
3204                 else if (act & DO_AUTODESTROY)
3205                 {
3206                         tmp = _("破壊", "Destroy");
3207                 }
3208                 else if (act & DO_AUTOPICK)
3209                 {
3210                         tmp = _("拾う", "Pickup");
3211                 }
3212                 else
3213                 {
3214                         tmp = _("確認", "Query");
3215                 }
3216
3217                 if (act & DO_DISPLAY)
3218                         fprintf(fff, "%11s", format("[%s]", tmp));
3219                 else
3220                         fprintf(fff, "%11s", format("(%s)", tmp));
3221
3222                 tmp = autopick_line_from_entry(&autopick_list[k]);
3223                 fprintf(fff, " %s", tmp);
3224                 string_free(tmp);
3225                 fprintf(fff, "\n");
3226         }
3227
3228         my_fclose(fff);
3229
3230         (void)show_file(creature_ptr, TRUE, file_name, _("自動拾い/破壊 設定リスト", "Auto-picker/Destroyer"), 0, 0);
3231         fd_kill(file_name);
3232 }
3233
3234
3235 /*
3236  * Interact with "knowledge"
3237  */
3238 void do_cmd_knowledge(player_type *creature_ptr)
3239 {
3240         int i, p = 0;
3241         bool need_redraw = FALSE;
3242         FILE_TYPE(FILE_TYPE_TEXT);
3243         screen_save();
3244         while (TRUE)
3245         {
3246                 Term_clear();
3247                 prt(format(_("%d/2 ページ", "page %d/2"), (p + 1)), 2, 65);
3248                 prt(_("現在の知識を確認する", "Display current knowledge"), 3, 0);
3249
3250 #ifdef JP
3251                 if (p == 0)
3252                 {
3253                         prt("(1) 既知の伝説のアイテム                 の一覧", 6, 5);
3254                         prt("(2) 既知のアイテム                       の一覧", 7, 5);
3255                         prt("(3) 既知の生きているユニーク・モンスター の一覧", 8, 5);
3256                         prt("(4) 既知のモンスター                     の一覧", 9, 5);
3257                         prt("(5) 倒した敵の数                         の一覧", 10, 5);
3258                         if (!vanilla_town) prt("(6) 賞金首                               の一覧", 11, 5);
3259                         prt("(7) 現在のペット                         の一覧", 12, 5);
3260                         prt("(8) 我が家のアイテム                     の一覧", 13, 5);
3261                         prt("(9) *鑑定*済み装備の耐性                 の一覧", 14, 5);
3262                         prt("(0) 地形の表示文字/タイル                の一覧", 15, 5);
3263                 }
3264                 else
3265                 {
3266                         prt("(a) 自分に関する情報                     の一覧", 6, 5);
3267                         prt("(b) 突然変異                             の一覧", 7, 5);
3268                         prt("(c) 武器の経験値                         の一覧", 8, 5);
3269                         prt("(d) 魔法の経験値                         の一覧", 9, 5);
3270                         prt("(e) 技能の経験値                         の一覧", 10, 5);
3271                         prt("(f) プレイヤーの徳                       の一覧", 11, 5);
3272                         prt("(g) 入ったダンジョン                     の一覧", 12, 5);
3273                         prt("(h) 実行中のクエスト                     の一覧", 13, 5);
3274                         prt("(i) 現在の自動拾い/破壊設定              の一覧", 14, 5);
3275                 }
3276 #else
3277                 if (p == 0)
3278                 {
3279                         prt("(1) Display known artifacts", 6, 5);
3280                         prt("(2) Display known objects", 7, 5);
3281                         prt("(3) Display remaining uniques", 8, 5);
3282                         prt("(4) Display known monster", 9, 5);
3283                         prt("(5) Display kill count", 10, 5);
3284                         if (!vanilla_town) prt("(6) Display wanted monsters", 11, 5);
3285                         prt("(7) Display current pets", 12, 5);
3286                         prt("(8) Display home inventory", 13, 5);
3287                         prt("(9) Display *identified* equip.", 14, 5);
3288                         prt("(0) Display terrain symbols.", 15, 5);
3289                 }
3290                 else
3291                 {
3292                         prt("(a) Display about yourself", 6, 5);
3293                         prt("(b) Display mutations", 7, 5);
3294                         prt("(c) Display weapon proficiency", 8, 5);
3295                         prt("(d) Display spell proficiency", 9, 5);
3296                         prt("(e) Display misc. proficiency", 10, 5);
3297                         prt("(f) Display virtues", 11, 5);
3298                         prt("(g) Display dungeons", 12, 5);
3299                         prt("(h) Display current quests", 13, 5);
3300                         prt("(i) Display auto pick/destroy", 14, 5);
3301                 }
3302 #endif
3303                 prt(_("-続く-", "-more-"), 17, 8);
3304                 prt(_("ESC) 抜ける", "ESC) Exit menu"), 21, 1);
3305                 prt(_("SPACE) 次ページ", "SPACE) Next page"), 21, 30);
3306                 prt(_("コマンド:", "Command: "), 20, 0);
3307                 i = inkey();
3308
3309                 if (i == ESCAPE) break;
3310                 switch (i)
3311                 {
3312                 case ' ': /* Page change */
3313                 case '-':
3314                         p = 1 - p;
3315                         break;
3316                 case '1': /* Artifacts */
3317                         do_cmd_knowledge_artifacts(creature_ptr);
3318                         break;
3319                 case '2': /* Objects */
3320                         do_cmd_knowledge_objects(creature_ptr, &need_redraw, FALSE, -1);
3321                         break;
3322                 case '3': /* Uniques */
3323                         do_cmd_knowledge_uniques(creature_ptr);
3324                         break;
3325                 case '4': /* Monsters */
3326                         do_cmd_knowledge_monsters(creature_ptr, &need_redraw, FALSE, -1);
3327                         break;
3328                 case '5': /* Kill count  */
3329                         do_cmd_knowledge_kill_count(creature_ptr);
3330                         break;
3331                 case '6': /* wanted */
3332                         if (!vanilla_town) do_cmd_knowledge_bounty(creature_ptr);
3333                         break;
3334                 case '7': /* Pets */
3335                         do_cmd_knowledge_pets(creature_ptr);
3336                         break;
3337                 case '8': /* Home */
3338                         do_cmd_knowledge_home(creature_ptr);
3339                         break;
3340                 case '9': /* Resist list */
3341                         do_cmd_knowledge_inventory(creature_ptr);
3342                         break;
3343                 case '0': /* Feature list */
3344                 {
3345                         IDX lighting_level = F_LIT_STANDARD;
3346                         do_cmd_knowledge_features(&need_redraw, FALSE, -1, &lighting_level);
3347                 }
3348                 break;
3349                 /* Next page */
3350                 case 'a': /* Max stat */
3351                         do_cmd_knowledge_stat(creature_ptr);
3352                         break;
3353                 case 'b': /* Mutations */
3354                         do_cmd_knowledge_mutations(creature_ptr);
3355                         break;
3356                 case 'c': /* weapon-exp */
3357                         do_cmd_knowledge_weapon_exp(creature_ptr);
3358                         break;
3359                 case 'd': /* spell-exp */
3360                         do_cmd_knowledge_spell_exp(creature_ptr);
3361                         break;
3362                 case 'e': /* skill-exp */
3363                         do_cmd_knowledge_skill_exp(creature_ptr);
3364                         break;
3365                 case 'f': /* Virtues */
3366                         do_cmd_knowledge_virtues(creature_ptr);
3367                         break;
3368                 case 'g': /* Dungeon */
3369                         do_cmd_knowledge_dungeon(creature_ptr);
3370                         break;
3371                 case 'h': /* Quests */
3372                         do_cmd_knowledge_quests(creature_ptr);
3373                         break;
3374                 case 'i': /* Autopick */
3375                         do_cmd_knowledge_autopick(creature_ptr);
3376                         break;
3377                 default: /* Unknown option */
3378                         bell();
3379                 }
3380
3381                 msg_erase();
3382         }
3383
3384         screen_load();
3385         if (need_redraw) do_cmd_redraw(creature_ptr);
3386 }
3387
3388
3389 /*
3390  * Check on the status of an active quest
3391  * @param creature_ptr プレーヤーへの参照ポインタ
3392  * @return なし
3393  */
3394 void do_cmd_checkquest(player_type *creature_ptr)
3395 {
3396         FILE_TYPE(FILE_TYPE_TEXT);
3397         screen_save();
3398         do_cmd_knowledge_quests(creature_ptr);
3399         screen_load();
3400 }
3401
3402
3403 /*
3404  * Display the time and date
3405  * @param creature_ptr プレーヤーへの参照ポインタ
3406  * @return なし
3407  */
3408 void do_cmd_time(player_type *creature_ptr)
3409 {
3410         int day, hour, min;
3411         extract_day_hour_min(creature_ptr, &day, &hour, &min);
3412
3413         char desc[1024];
3414         strcpy(desc, _("変な時刻だ。", "It is a strange time."));
3415
3416         char day_buf[10];
3417         if (day < MAX_DAYS) sprintf(day_buf, "%d", day);
3418         else strcpy(day_buf, "*****");
3419
3420         msg_format(_("%s日目, 時刻は%d:%02d %sです。", "This is day %s. The time is %d:%02d %s."),
3421                 day_buf, (hour % 12 == 0) ? 12 : (hour % 12), min, (hour < 12) ? "AM" : "PM");
3422
3423         char buf[1024];
3424         if (!randint0(10) || creature_ptr->image)
3425         {
3426                 path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, _("timefun_j.txt", "timefun.txt"));
3427         }
3428         else
3429         {
3430                 path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, _("timenorm_j.txt", "timenorm.txt"));
3431         }
3432
3433         FILE *fff;
3434         fff = my_fopen(buf, "rt");
3435
3436         if (!fff) return;
3437
3438         int full = hour * 100 + min;
3439         int start = 9999;
3440         int end = -9999;
3441         int num = 0;
3442         while (!my_fgets(fff, buf, sizeof(buf)))
3443         {
3444                 if (!buf[0] || (buf[0] == '#')) continue;
3445                 if (buf[1] != ':') continue;
3446
3447                 if (buf[0] == 'S')
3448                 {
3449                         start = atoi(buf + 2);
3450                         end = start + 59;
3451                         continue;
3452                 }
3453
3454                 if (buf[0] == 'E')
3455                 {
3456                         end = atoi(buf + 2);
3457                         continue;
3458                 }
3459
3460                 if ((start > full) || (full > end)) continue;
3461
3462                 if (buf[0] == 'D')
3463                 {
3464                         num++;
3465                         if (!randint0(num)) strcpy(desc, buf + 2);
3466
3467                         continue;
3468                 }
3469         }
3470
3471         msg_print(desc);
3472         my_fclose(fff);
3473 }