OSDN Git Service

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