OSDN Git Service

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