OSDN Git Service

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