OSDN Git Service

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