OSDN Git Service

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