OSDN Git Service

[Refactor] #1366 Removed type alias 'u32b' and replaced them all to 'uint32_t'
[hengbandforosx/hengbandosx.git] / src / cmd-io / cmd-gameoption.cpp
1 #include "cmd-io/cmd-gameoption.h"
2 #include "autopick/autopick.h"
3 #include "cmd-io/cmd-autopick.h"
4 #include "cmd-io/cmd-dump.h"
5 #include "core/player-redraw-types.h"
6 #include "core/show-file.h"
7 #include "core/window-redrawer.h"
8 #include "floor/geometry.h"
9 #include "game-option/game-play-options.h"
10 #include "game-option/keymap-directory-getter.h"
11 #include "game-option/option-flags.h"
12 #include "game-option/option-types-table.h"
13 #include "game-option/special-options.h"
14 #include "io/input-key-acceptor.h"
15 #include "io/write-diary.h"
16 #include "main/sound-of-music.h"
17 #include "system/game-option-types.h"
18 #include "system/player-type-definition.h"
19 #include "term/gameterm.h"
20 #include "term/screen-processor.h"
21 #include "term/term-color-types.h"
22 #include "util/bit-flags-calculator.h"
23 #include "util/int-char-converter.h"
24 #include "util/string-processor.h"
25 #include "view/display-messages.h"
26 #include "world/world.h"
27
28 #define OPT_NUM 15
29
30 typedef struct {
31     char key;
32     concptr name;
33     int row;
34 } opts;
35
36 static opts option_fields[OPT_NUM] = {
37     { '1', _("    キー入力     オプション", "Input Options"), 3 },
38     { '2', _("   マップ画面    オプション", "Map Screen Options"), 4 },
39     { '3', _("  テキスト表示   オプション", "Text Display Options"), 5 },
40     { '4', _("  ゲームプレイ   オプション", "Game-Play Options"), 6 },
41     { '5', _("  行動中止関係   オプション", "Disturbance Options"), 7 },
42     { '6', _("  簡易自動破壊   オプション", "Easy Auto-Destroyer Options"), 8 },
43     { 'r', _("   プレイ記録    オプション", "Play record Options"), 9 },
44
45     { 'p', _("自動拾いエディタ", "Auto-picker/destroyer editor"), 11 },
46     { 'd', _(" 基本ウェイト量 ", "Base Delay Factor"), 12 },
47     { 'h', _("低ヒットポイント", "Hitpoint Warning"), 13 },
48     { 'm', _("  低魔力色閾値  ", "Mana Color Threshold"), 14 },
49     { 'a', _("   自動セーブ    オプション", "Autosave Options"), 15 },
50     { 'w', _("ウインドウフラグ", "Window Flags"), 16 },
51
52     { 'b', _("      初期       オプション (参照のみ)", "Birth Options (Browse Only)"), 18 },
53     { 'c', _("      詐欺       オプション", "Cheat Options"), 19 },
54 };
55
56 /*!
57  * @brief セーブ頻度ターンの次の値を返す
58  * @param current 現在のセーブ頻度ターン値
59  * @return 次のセーブ頻度ターン値
60  */
61 static int16_t toggle_frequency(int16_t current)
62 {
63     switch (current) {
64     case 0:
65         return 50;
66     case 50:
67         return 100;
68     case 100:
69         return 250;
70     case 250:
71         return 500;
72     case 500:
73         return 1000;
74     case 1000:
75         return 2500;
76     case 2500:
77         return 5000;
78     case 5000:
79         return 10000;
80     case 10000:
81         return 25000;
82     default:
83         return 0;
84     }
85 }
86
87 /*!
88  * @brief 自動セーブオプションを変更するコマンドのメインルーチン
89  * @param info 表示メッセージ
90  */
91 static void do_cmd_options_autosave(player_type *player_ptr, concptr info)
92 {
93     char ch;
94     int i, k = 0, n = 2;
95     char buf[80];
96     term_clear();
97     while (true) {
98         sprintf(buf,
99             _("%s ( リターンで次へ, y/n でセット, F で頻度を入力, ESC で決定 ) ", "%s (RET to advance, y/n to set, 'F' for frequency, ESC to accept) "), info);
100         prt(buf, 0, 0);
101         for (i = 0; i < n; i++) {
102             byte a = TERM_WHITE;
103             if (i == k)
104                 a = TERM_L_BLUE;
105
106             sprintf(
107                 buf, "%-48s: %s (%s)", autosave_info[i].o_desc, (*autosave_info[i].o_var ? _("はい  ", "yes") : _("いいえ", "no ")), autosave_info[i].o_text);
108             c_prt(a, buf, i + 2, 0);
109         }
110
111         prt(format(_("自動セーブの頻度: %d ターン毎", "Timed autosave frequency: every %d turns"), autosave_freq), 5, 0);
112         move_cursor(k + 2, 50);
113         ch = inkey();
114         switch (ch) {
115         case ESCAPE: {
116             return;
117         }
118
119         case '-':
120         case '8': {
121             k = (n + k - 1) % n;
122             break;
123         }
124
125         case ' ':
126         case '\n':
127         case '\r':
128         case '2': {
129             k = (k + 1) % n;
130             break;
131         }
132
133         case 'y':
134         case 'Y':
135         case '6': {
136
137             (*autosave_info[k].o_var) = true;
138             k = (k + 1) % n;
139             break;
140         }
141
142         case 'n':
143         case 'N':
144         case '4': {
145             (*autosave_info[k].o_var) = false;
146             k = (k + 1) % n;
147             break;
148         }
149
150         case 'f':
151         case 'F': {
152             autosave_freq = toggle_frequency(autosave_freq);
153             prt(format(_("自動セーブの頻度: %d ターン毎", "Timed autosave frequency: every %d turns"), autosave_freq), 5, 0);
154             break;
155         }
156
157         case '?': {
158             (void)show_file(player_ptr, true, _("joption.txt#Autosave", "option.txt#Autosave"), NULL, 0, 0);
159             term_clear();
160             break;
161         }
162
163         default: {
164             bell();
165             break;
166         }
167         }
168     }
169 }
170
171 /*!
172  * @brief 指定のサブウィンドウが指定のウィンドウフラグを持つか調べる
173  * @param x ウィンドウ番号
174  * @param y ウィンドウフラグ番号
175  * @return 持つならTRUE、持たないならFALSE
176  */
177 static bool has_window_flag(int x, int y)
178 {
179     auto flag = static_cast<window_redraw_type>(1UL << y);
180     return any_bits(window_flag[x], flag);
181 }
182
183 /*!
184  * @brief 指定のサブウィンドウに指定のウィンドウフラグをセットする
185  * @param x ウィンドウ番号
186  * @param y ウィンドウフラグ番号
187  * @details
188  * 未使用フラグはセットしない。
189  */
190 static void set_window_flag(int x, int y)
191 {
192     auto flag = static_cast<window_redraw_type>(1UL << y);
193     if (any_bits(PW_ALL, flag))
194         set_bits(window_flag[x], flag);
195 }
196
197 /*!
198  * @brief 指定のウィンドウフラグをサブウィンドウからクリアする
199  * @param y ウィンドウフラグ番号
200  */
201 static void clear_window_flag(int x, int y)
202 {
203     window_flag[x] = 0;
204
205     auto flag = static_cast<window_redraw_type>(1UL << y);
206     for (int i = 0; i < 8; i++) {
207         reset_bits(window_flag[i], flag);
208     }
209 }
210
211 /*!
212  * @brief ウィンドウオプションを変更するコマンドのメインルーチン /
213  * Modify the "window" options
214  */
215 static void do_cmd_options_win(player_type *player_ptr)
216 {
217     int i, j, d;
218     TERM_LEN y = 0;
219     TERM_LEN x = 0;
220     char ch;
221     bool go = true;
222     uint32_t old_flag[8];
223
224     for (j = 0; j < 8; j++) {
225         old_flag[j] = window_flag[j];
226     }
227
228     term_clear();
229     while (go) {
230         prt(_("ウィンドウ・フラグ (<方向>で移動, 't'でON/OFF,'s'でON(他窓OFF), ESC)", "Window Flags (<dir>, <t>oggle, <s>et, ESC) "), 0, 0);
231         for (j = 0; j < 8; j++) {
232             byte a = TERM_WHITE;
233             concptr s = angband_term_name[j];
234             if (j == x)
235                 a = TERM_L_BLUE;
236
237             term_putstr(35 + j * 5 - strlen(s) / 2, 2 + j % 2, -1, a, s);
238         }
239
240         for (i = 0; i < 16; i++) {
241             byte a = TERM_WHITE;
242             concptr str = window_flag_desc[i];
243             if (i == y)
244                 a = TERM_L_BLUE;
245
246             if (!str)
247                 str = _("(未使用)", "(Unused option)");
248
249             term_putstr(0, i + 5, -1, a, str);
250             for (j = 0; j < 8; j++) {
251                 char c = '.';
252                 a = TERM_WHITE;
253                 if ((i == y) && (j == x))
254                     a = TERM_L_BLUE;
255
256                 if (window_flag[j] & (1UL << i))
257                     c = 'X';
258
259                 term_putch(35 + j * 5, i + 5, a, c);
260             }
261         }
262
263         bool has_flag = false;
264         term_gotoxy(35 + x * 5, y + 5);
265         ch = inkey();
266         switch (ch) {
267         case ESCAPE:
268             go = false;
269             break;
270         case ' ':
271         case 't':
272         case 'T':
273             has_flag = has_window_flag(x, y);
274             window_flag[x] = 0;
275             if (x > 0 && !has_flag)
276                 set_window_flag(x, y);
277             break;
278         case 's':
279         case 'S':
280             if (x == 0)
281                 break;
282             window_flag[x] = 0;
283             clear_window_flag(x, y);
284             set_window_flag(x, y);
285             break;
286         case '?':
287             (void)show_file(player_ptr, true, _("joption.txt#Window", "option.txt#Window"), NULL, 0, 0);
288             term_clear();
289             break;
290         default:
291             d = get_keymap_dir(ch);
292             x = (x + ddx[d] + 8) % 8;
293             y = (y + ddy[d] + 16) % 16;
294             if (!d)
295                 bell();
296             break;
297         }
298     }
299
300     for (j = 0; j < 8; j++) {
301         term_type *old = Term;
302         if (!angband_term[j])
303             continue;
304
305         if (window_flag[j] == old_flag[j])
306             continue;
307
308         term_activate(angband_term[j]);
309         term_clear();
310         term_fresh();
311         term_activate(old);
312     }
313 }
314
315 /*!
316  * @brief チートオプションを変更するコマンドのメインルーチン
317  * Interact with some options for cheating
318  * @param info 表示メッセージ
319  */
320 static void do_cmd_options_cheat(player_type *player_ptr, concptr info)
321 {
322     char ch;
323     int i, k = 0, n = MAX_CHEAT_OPTIONS;
324     char buf[80];
325     term_clear();
326     while (true) {
327         DIRECTION dir;
328         sprintf(buf, _("%s ( リターンで次へ, y/n でセット, ESC で決定 )", "%s (RET to advance, y/n to set, ESC to accept) "), info);
329         prt(buf, 0, 0);
330
331 #ifdef JP
332         /* 詐欺オプションをうっかりいじってしまう人がいるようなので注意 */
333         prt("                                 <<  注意  >>", 11, 0);
334         prt("      詐欺オプションを一度でも設定すると、スコア記録が残らなくなります!", 12, 0);
335         prt("      後に解除してもダメですので、勝利者を目指す方はここのオプションはい", 13, 0);
336         prt("      じらないようにして下さい。", 14, 0);
337 #endif
338         for (i = 0; i < n; i++) {
339             byte a = TERM_WHITE;
340             if (i == k)
341                 a = TERM_L_BLUE;
342
343             sprintf(buf, "%-48s: %s (%s)", cheat_info[i].o_desc, (*cheat_info[i].o_var ? _("はい  ", "yes") : _("いいえ", "no ")), cheat_info[i].o_text);
344             c_prt(a, buf, i + 2, 0);
345         }
346
347         move_cursor(k + 2, 50);
348         ch = inkey();
349         dir = get_keymap_dir(ch);
350         if ((dir == 2) || (dir == 4) || (dir == 6) || (dir == 8))
351             ch = I2D(dir);
352
353         switch (ch) {
354         case ESCAPE: {
355             return;
356         }
357         case '-':
358         case '8': {
359             k = (n + k - 1) % n;
360             break;
361         }
362         case ' ':
363         case '\n':
364         case '\r':
365         case '2': {
366             k = (k + 1) % n;
367             break;
368         }
369         case 'y':
370         case 'Y':
371         case '6': {
372             if (!current_world_ptr->noscore)
373                 exe_write_diary(player_ptr, DIARY_DESCRIPTION, 0,
374                     _("詐欺オプションをONにして、スコアを残せなくなった。", "gave up sending score to use cheating options."));
375
376             current_world_ptr->noscore |= (cheat_info[k].o_set * 256 + cheat_info[k].o_bit);
377             (*cheat_info[k].o_var) = true;
378             k = (k + 1) % n;
379             break;
380         }
381         case 'n':
382         case 'N':
383         case '4': {
384             (*cheat_info[k].o_var) = false;
385             k = (k + 1) % n;
386             break;
387         }
388         case '?': {
389             strnfmt(buf, sizeof(buf), _("joption.txt#%s", "option.txt#%s"), cheat_info[k].o_text);
390             (void)show_file(player_ptr, true, buf, NULL, 0, 0);
391             term_clear();
392             break;
393         }
394         default: {
395             bell();
396             break;
397         }
398         }
399     }
400 }
401
402 /*!
403  * @brief ビットセットからゲームオプションを展開する / Extract option variables from bit sets
404  */
405 void extract_option_vars(void)
406 {
407     for (int i = 0; option_info[i].o_desc; i++) {
408         int os = option_info[i].o_set;
409         int ob = option_info[i].o_bit;
410         if (option_info[i].o_var) {
411             if (option_flag[os] & (1UL << ob)) {
412                 (*option_info[i].o_var) = true;
413             } else {
414                 (*option_info[i].o_var) = false;
415             }
416         }
417     }
418 }
419
420 /*!
421  * @brief 標準オプションを変更するコマンドのメインルーチン /
422  * Set or unset various options.
423  * @details
424  * <pre>
425  * The user must use the "Ctrl-R" command to "adapt" to changes
426  * in any options which control "visual" aspects of the game.
427  * </pre>
428  */
429 void do_cmd_options(player_type *player_ptr)
430 {
431     char k;
432     int d, skey;
433     TERM_LEN i, y = 0;
434     screen_save();
435     while (true) {
436         int n = OPT_NUM;
437         if (!current_world_ptr->noscore && !allow_debug_opts)
438             n--;
439
440         term_clear();
441         prt(_("[ オプションの設定 ]", "Game options"), 1, 0);
442         while (true) {
443             for (i = 0; i < n; i++) {
444                 byte a = TERM_WHITE;
445                 if (i == y)
446                     a = TERM_L_BLUE;
447                 term_putstr(5, option_fields[i].row, -1, a, format("(%c) %s", toupper(option_fields[i].key), option_fields[i].name));
448             }
449
450             prt(_("<方向>で移動, Enterで決定, ESCでキャンセル, ?でヘルプ: ", "Move to <dir>, Select to Enter, Cancel to ESC, ? to help: "), 21, 0);
451             skey = inkey_special(true);
452             if (!(skey & SKEY_MASK))
453                 k = (char)skey;
454             else
455                 k = 0;
456
457             if (k == ESCAPE)
458                 break;
459
460             if (angband_strchr("\n\r ", k)) {
461                 k = option_fields[y].key;
462                 break;
463             }
464
465             for (i = 0; i < n; i++) {
466                 if (tolower(k) == option_fields[i].key)
467                     break;
468             }
469
470             if (i < n)
471                 break;
472
473             if (k == '?')
474                 break;
475
476             d = 0;
477             if (skey == SKEY_UP)
478                 d = 8;
479             if (skey == SKEY_DOWN)
480                 d = 2;
481             y = (y + ddy[d] + n) % n;
482             if (!d)
483                 bell();
484         }
485
486         if (k == ESCAPE)
487             break;
488
489         switch (k) {
490         case '1': {
491             do_cmd_options_aux(player_ptr, OPT_PAGE_INPUT, _("キー入力オプション", "Input Options"));
492             break;
493         }
494         case '2': {
495             do_cmd_options_aux(player_ptr, OPT_PAGE_MAPSCREEN, _("マップ画面オプション", "Map Screen Options"));
496             break;
497         }
498         case '3': {
499             do_cmd_options_aux(player_ptr, OPT_PAGE_TEXT, _("テキスト表示オプション", "Text Display Options"));
500             break;
501         }
502         case '4': {
503             do_cmd_options_aux(player_ptr, OPT_PAGE_GAMEPLAY, _("ゲームプレイ・オプション", "Game-Play Options"));
504             break;
505         }
506         case '5': {
507             do_cmd_options_aux(player_ptr, OPT_PAGE_DISTURBANCE, _("行動中止関係のオプション", "Disturbance Options"));
508             break;
509         }
510         case '6': {
511             do_cmd_options_aux(player_ptr, OPT_PAGE_AUTODESTROY, _("簡易自動破壊オプション", "Easy Auto-Destroyer Options"));
512             break;
513         }
514         case 'R':
515         case 'r': {
516             do_cmd_options_aux(player_ptr, OPT_PAGE_PLAYRECORD, _("プレイ記録オプション", "Play-record Options"));
517             break;
518         }
519         case 'B':
520         case 'b': {
521             do_cmd_options_aux(player_ptr, OPT_PAGE_BIRTH,
522                 (!current_world_ptr->wizard || !allow_debug_opts) ? _("初期オプション(参照のみ)", "Birth Options(browse only)")
523                                                                   : _("初期オプション((*)はスコアに影響)", "Birth Options ((*)) affect score"));
524             break;
525         }
526         case 'C': {
527             if (!current_world_ptr->noscore && !allow_debug_opts) {
528                 bell();
529                 break;
530             }
531
532             do_cmd_options_cheat(player_ptr, _("詐欺師は決して勝利できない!", "Cheaters never win"));
533             break;
534         }
535         case 'a':
536         case 'A': {
537             do_cmd_options_autosave(player_ptr, _("自動セーブ", "Autosave"));
538             break;
539         }
540         case 'W':
541         case 'w': {
542             do_cmd_options_win(player_ptr);
543             player_ptr->window_flags = PW_ALL;
544             break;
545         }
546         case 'P':
547         case 'p': {
548             do_cmd_edit_autopick(player_ptr);
549             break;
550         }
551         case 'D':
552         case 'd': {
553             clear_from(18);
554             prt(_("コマンド: 基本ウェイト量", "Command: Base Delay Factor"), 19, 0);
555             while (true) {
556                 int msec = delay_factor * delay_factor * delay_factor;
557                 prt(format(_("現在のウェイト: %d (%dミリ秒)", "Current base delay factor: %d (%d msec)"), delay_factor, msec), 22, 0);
558                 prt(_("ウェイト (0-9) ESCで決定: ", "Delay Factor (0-9 or ESC to accept): "), 20, 0);
559                 k = inkey();
560                 if (k == ESCAPE)
561                     break;
562                 else if (k == '?') {
563                     (void)show_file(player_ptr, true, _("joption.txt#BaseDelay", "option.txt#BaseDelay"), NULL, 0, 0);
564                     term_clear();
565                 } else if (isdigit(k))
566                     delay_factor = D2I(k);
567                 else
568                     bell();
569             }
570
571             break;
572         }
573         case 'H':
574         case 'h': {
575             clear_from(18);
576             prt(_("コマンド: 低ヒットポイント警告", "Command: Hitpoint Warning"), 19, 0);
577             while (true) {
578                 prt(format(_("現在の低ヒットポイント警告: %d0%%", "Current hitpoint warning: %d0%%"), hitpoint_warn), 22, 0);
579                 prt(_("低ヒットポイント警告 (0-9) ESCで決定: ", "Hitpoint Warning (0-9 or ESC to accept): "), 20, 0);
580                 k = inkey();
581                 if (k == ESCAPE)
582                     break;
583                 else if (k == '?') {
584                     (void)show_file(player_ptr, true, _("joption.txt#Hitpoint", "option.txt#Hitpoint"), NULL, 0, 0);
585                     term_clear();
586                 } else if (isdigit(k))
587                     hitpoint_warn = D2I(k);
588                 else
589                     bell();
590             }
591
592             break;
593         }
594         case 'M':
595         case 'm': {
596             clear_from(18);
597             prt(_("コマンド: 低魔力色閾値", "Command: Mana Color Threshold"), 19, 0);
598             while (true) {
599                 prt(format(_("現在の低魔力色閾値: %d0%%", "Current mana color threshold: %d0%%"), mana_warn), 22, 0);
600                 prt(_("低魔力閾値 (0-9) ESCで決定: ", "Mana color Threshold (0-9 or ESC to accept): "), 20, 0);
601                 k = inkey();
602                 if (k == ESCAPE)
603                     break;
604                 else if (k == '?') {
605                     (void)show_file(player_ptr, true, _("joption.txt#Manapoint", "option.txt#Manapoint"), NULL, 0, 0);
606                     term_clear();
607                 } else if (isdigit(k))
608                     mana_warn = D2I(k);
609                 else
610                     bell();
611             }
612
613             break;
614         }
615         case '?':
616             (void)show_file(player_ptr, true, _("joption.txt", "option.txt"), NULL, 0, 0);
617             term_clear();
618             break;
619         default: {
620             bell();
621             break;
622         }
623         }
624
625         msg_erase();
626     }
627
628     screen_load();
629     player_ptr->redraw |= (PR_EQUIPPY);
630 }
631
632 /*!
633  * @brief 標準オプションを変更するコマンドのサブルーチン /
634  * Interact with some options
635  * @param page オプションページ番号
636  * @param info 表示メッセージ
637  */
638 void do_cmd_options_aux(player_type *player_ptr, game_option_types page, concptr info)
639 {
640     char ch;
641     int i, k = 0, n = 0, l;
642     int opt[24];
643     char buf[80];
644     bool browse_only = (page == OPT_PAGE_BIRTH) && current_world_ptr->character_generated && (!current_world_ptr->wizard || !allow_debug_opts);
645
646     for (i = 0; i < 24; i++)
647         opt[i] = 0;
648
649     for (i = 0; option_info[i].o_desc; i++) {
650         if (option_info[i].o_page == page)
651             opt[n++] = i;
652     }
653
654     term_clear();
655     while (true) {
656         DIRECTION dir;
657         sprintf(buf, _("%s (リターン:次, %sESC:終了, ?:ヘルプ) ", "%s (RET:next, %s, ?:help) "), info,
658             browse_only ? _("", "ESC:exit") : _("y/n:変更, ", "y/n:change, ESC:accept"));
659         prt(buf, 0, 0);
660         if (page == OPT_PAGE_AUTODESTROY)
661             c_prt(TERM_YELLOW, _("以下のオプションは、簡易自動破壊を使用するときのみ有効", "Following options will protect items from easy auto-destroyer."), 6,
662                 _(6, 3));
663
664         for (i = 0; i < n; i++) {
665             byte a = TERM_WHITE;
666             if (i == k)
667                 a = TERM_L_BLUE;
668
669             sprintf(buf, "%-48s: %s (%.19s)", option_info[opt[i]].o_desc, (*option_info[opt[i]].o_var ? _("はい  ", "yes") : _("いいえ", "no ")),
670                 option_info[opt[i]].o_text);
671             if ((page == OPT_PAGE_AUTODESTROY) && i > 2)
672                 c_prt(a, buf, i + 5, 0);
673             else
674                 c_prt(a, buf, i + 2, 0);
675         }
676
677         if ((page == OPT_PAGE_AUTODESTROY) && (k > 2))
678             l = 3;
679         else
680             l = 0;
681
682         move_cursor(k + 2 + l, 50);
683         ch = inkey();
684         dir = get_keymap_dir(ch);
685         if ((dir == 2) || (dir == 4) || (dir == 6) || (dir == 8))
686             ch = I2D(dir);
687
688         switch (ch) {
689         case ESCAPE: {
690             return;
691         }
692         case '-':
693         case '8': {
694             k = (n + k - 1) % n;
695             break;
696         }
697         case ' ':
698         case '\n':
699         case '\r':
700         case '2': {
701             k = (k + 1) % n;
702             break;
703         }
704         case 'y':
705         case 'Y':
706         case '6': {
707             if (browse_only)
708                 break;
709             (*option_info[opt[k]].o_var) = true;
710             k = (k + 1) % n;
711             break;
712         }
713         case 'n':
714         case 'N':
715         case '4': {
716             if (browse_only)
717                 break;
718             (*option_info[opt[k]].o_var) = false;
719             k = (k + 1) % n;
720             break;
721         }
722         case 't':
723         case 'T': {
724             if (!browse_only)
725                 (*option_info[opt[k]].o_var) = !(*option_info[opt[k]].o_var);
726             break;
727         }
728         case '?': {
729             strnfmt(buf, sizeof(buf), _("joption.txt#%s", "option.txt#%s"), option_info[opt[k]].o_text);
730             (void)show_file(player_ptr, true, buf, NULL, 0, 0);
731             term_clear();
732             break;
733         }
734         default: {
735             bell();
736             break;
737         }
738         }
739     }
740 }