OSDN Git Service

[Refactor] #3286 PlayerType::redraw に関わる処理を、RedrawingFlagsUpdaterに集約した
[hengbandforosx/hengbandosx.git] / src / io / input-key-processor.cpp
1 /*!
2  * @brief キー入力に応じてゲーム内コマンドを実行する
3  * @date 2022/02/20
4  * @author Hourier
5  */
6
7 #include "io/input-key-processor.h"
8 #include "autopick/autopick-pref-processor.h"
9 #include "cmd-action/cmd-hissatsu.h"
10 #include "cmd-action/cmd-mane.h"
11 #include "cmd-action/cmd-mind.h"
12 #include "cmd-action/cmd-move.h"
13 #include "cmd-action/cmd-open-close.h"
14 #include "cmd-action/cmd-others.h"
15 #include "cmd-action/cmd-pet.h"
16 #include "cmd-action/cmd-racial.h"
17 #include "cmd-action/cmd-shoot.h"
18 #include "cmd-action/cmd-spell.h"
19 #include "cmd-action/cmd-travel.h"
20 #include "cmd-action/cmd-tunnel.h"
21 #include "cmd-building/cmd-building.h"
22 #include "cmd-io/cmd-autopick.h"
23 #include "cmd-io/cmd-diary.h"
24 #include "cmd-io/cmd-dump.h"
25 #include "cmd-io/cmd-floor.h"
26 #include "cmd-io/cmd-gameoption.h"
27 #include "cmd-io/cmd-help.h"
28 #include "cmd-io/cmd-knowledge.h"
29 #include "cmd-io/cmd-lore.h"
30 #include "cmd-io/cmd-macro.h"
31 #include "cmd-io/cmd-process-screen.h"
32 #include "cmd-io/cmd-save.h"
33 #include "cmd-item/cmd-destroy.h"
34 #include "cmd-item/cmd-eat.h"
35 #include "cmd-item/cmd-equipment.h"
36 #include "cmd-item/cmd-item.h"
37 #include "cmd-item/cmd-magiceat.h"
38 #include "cmd-item/cmd-quaff.h"
39 #include "cmd-item/cmd-read.h"
40 #include "cmd-item/cmd-refill.h"
41 #include "cmd-item/cmd-throw.h"
42 #include "cmd-item/cmd-usestaff.h"
43 #include "cmd-item/cmd-zaprod.h"
44 #include "cmd-item/cmd-zapwand.h"
45 #include "cmd-visual/cmd-draw.h"
46 #include "cmd-visual/cmd-map.h"
47 #include "cmd-visual/cmd-visuals.h"
48 #include "core/asking-player.h"
49 #include "core/player-redraw-types.h"
50 #include "core/special-internal-keys.h"
51 #include "dungeon/dungeon-flag-types.h"
52 #include "dungeon/quest.h" //!< @do_cmd_quest() がある。後で移設する.
53 #include "effect/spells-effect-util.h"
54 #include "floor/wild.h"
55 #include "game-option/birth-options.h"
56 #include "game-option/disturbance-options.h"
57 #include "game-option/game-play-options.h"
58 #include "game-option/input-options.h"
59 #include "io-dump/random-art-info-dumper.h"
60 #include "io/command-repeater.h"
61 #include "io/files-util.h"
62 #include "io/input-key-requester.h" //!< @todo 相互依存している、後で何とかする.
63 #include "io/record-play-movie.h"
64 #include "io/write-diary.h"
65 #include "knowledge/knowledge-autopick.h"
66 #include "knowledge/knowledge-quests.h"
67 #include "main/sound-definitions-table.h"
68 #include "main/sound-of-music.h"
69 #include "mind/mind-blue-mage.h"
70 #include "mind/mind-elementalist.h"
71 #include "mind/mind-magic-eater.h"
72 #include "mind/mind-sniper.h"
73 #include "mind/mind-weaponsmith.h"
74 #include "mind/snipe-types.h"
75 #include "player-base/player-class.h"
76 #include "player-info/class-info.h"
77 #include "player-info/samurai-data-type.h"
78 #include "player-info/sniper-data-type.h"
79 #include "player-status/player-energy.h"
80 #include "player/attack-defense-types.h"
81 #include "player/digestion-processor.h"
82 #include "player/player-status.h"
83 #include "player/special-defense-types.h"
84 #include "status/action-setter.h"
85 #include "store/cmd-store.h"
86 #include "store/home.h"
87 #include "store/store-util.h"
88 #include "system/dungeon-info.h"
89 #include "system/floor-type-definition.h"
90 #include "system/player-type-definition.h"
91 #include "system/redrawing-flags-updater.h"
92 #include "term/screen-processor.h"
93 #include "util/int-char-converter.h"
94 #include "view/display-messages.h"
95 #include "window/display-sub-windows.h"
96 #include "wizard/cmd-wizard.h"
97 #include "world/world.h"
98 #include <optional>
99 #include <string>
100
101 /*!
102  * @brief ウィザードモードへの導入処理
103  * / Verify use of "wizard" mode
104  * @param player_ptr プレイヤーへの参照ポインタ
105  * @return 実際にウィザードモードへ移行したらTRUEを返す。
106  */
107 bool enter_wizard_mode(PlayerType *player_ptr)
108 {
109     if (!w_ptr->noscore) {
110         if (!allow_debug_opts) {
111             msg_print(_("ウィザードモードは許可されていません。 ", "Wizard mode is not permitted."));
112             return false;
113         }
114
115         msg_print(_("ウィザードモードはデバッグと実験のためのモードです。 ", "Wizard mode is for debugging and experimenting."));
116         msg_print(_("一度ウィザードモードに入るとスコアは記録されません。", "The game will not be scored if you enter wizard mode."));
117         msg_print(nullptr);
118         if (!get_check(_("本当にウィザードモードに入りたいのですか? ", "Are you sure you want to enter wizard mode? "))) {
119             return false;
120         }
121
122         exe_write_diary(
123             player_ptr, DIARY_DESCRIPTION, 0, _("ウィザードモードに突入してスコアを残せなくなった。", "gave up recording score to enter wizard mode."));
124         w_ptr->noscore |= 0x0002;
125     }
126
127     return true;
128 }
129
130 /*!
131  * @brief デバッグコマンドへの導入処理
132  * / Verify use of "debug" commands
133  * @param player_ptr プレイヤーへの参照ポインタ
134  * @return 実際にデバッグコマンドへ移行したらTRUEを返す。
135  */
136 static bool enter_debug_mode(PlayerType *player_ptr)
137 {
138     if (!w_ptr->noscore) {
139         if (!allow_debug_opts) {
140             msg_print(_("デバッグコマンドは許可されていません。 ", "Use of debug command is not permitted."));
141             return false;
142         }
143
144         msg_print(_("デバッグ・コマンドはデバッグと実験のためのコマンドです。 ", "The debug commands are for debugging and experimenting."));
145         msg_print(_("デバッグ・コマンドを使うとスコアは記録されません。", "The game will not be scored if you use debug commands."));
146         msg_print(nullptr);
147         if (!get_check(_("本当にデバッグ・コマンドを使いますか? ", "Are you sure you want to use debug commands? "))) {
148             return false;
149         }
150
151         exe_write_diary(
152             player_ptr, DIARY_DESCRIPTION, 0, _("デバッグモードに突入してスコアを残せなくなった。", "gave up sending score to use debug commands."));
153         w_ptr->noscore |= 0x0008;
154     }
155
156     return true;
157 }
158
159 /*!
160  * @brief プレイヤーから受けた入力コマンドの分岐処理。
161  * / Parse and execute the current command Give "Warning" on illegal commands.
162  * @todo Make some "blocks"
163  */
164 void process_command(PlayerType *player_ptr)
165 {
166     COMMAND_CODE old_now_message = now_message;
167     repeat_check();
168     now_message = 0;
169     auto sniper_data = PlayerClass(player_ptr).get_specific_data<sniper_data_type>();
170     if (sniper_data && sniper_data->concent > 0) {
171         sniper_data->reset_concent = true;
172     }
173
174     auto *floor_ptr = player_ptr->current_floor_ptr;
175     switch (command_cmd) {
176     case ESCAPE:
177     case ' ':
178     case '\r':
179     case '\n': {
180         /* Ignore */
181         break;
182     }
183     case KTRL('W'): {
184         if (w_ptr->wizard) {
185             w_ptr->wizard = false;
186             msg_print(_("ウィザードモード解除。", "Wizard mode off."));
187         } else if (enter_wizard_mode(player_ptr)) {
188             w_ptr->wizard = true;
189             msg_print(_("ウィザードモード突入。", "Wizard mode on."));
190         }
191
192         auto &rfu = RedrawingFlagsUpdater::get_instance();
193         rfu.set_flag(StatusRedrawingFlag::MONSTER_STATUSES);
194         rfu.set_flag(MainWindowRedrawingFlag::TITLE);
195         break;
196     }
197     case KTRL('A'): {
198         if (enter_debug_mode(player_ptr)) {
199             do_cmd_debug(player_ptr);
200         }
201
202         break;
203     }
204     case 'w': {
205         if (!player_ptr->wild_mode) {
206             do_cmd_wield(player_ptr);
207         }
208
209         break;
210     }
211     case 't': {
212         if (!player_ptr->wild_mode) {
213             do_cmd_takeoff(player_ptr);
214         }
215
216         break;
217     }
218     case 'd': {
219         if (!player_ptr->wild_mode) {
220             do_cmd_drop(player_ptr);
221         }
222
223         break;
224     }
225     case 'k': {
226         do_cmd_destroy(player_ptr);
227         break;
228     }
229     case 'e': {
230         do_cmd_equip(player_ptr);
231         break;
232     }
233     case 'i': {
234         do_cmd_inven(player_ptr);
235         break;
236     }
237     case 'I': {
238         do_cmd_observe(player_ptr);
239         break;
240     }
241
242     case KTRL('I'): {
243         toggle_inventory_equipment(player_ptr);
244         break;
245     }
246     case '+': {
247         if (!player_ptr->wild_mode) {
248             do_cmd_alter(player_ptr);
249         }
250
251         break;
252     }
253     case 'T': {
254         if (!player_ptr->wild_mode) {
255             do_cmd_tunnel(player_ptr);
256         }
257
258         break;
259     }
260     case ';': {
261         do_cmd_walk(player_ptr, false);
262         break;
263     }
264     case '-': {
265         do_cmd_walk(player_ptr, true);
266         break;
267     }
268     case '.': {
269         if (!player_ptr->wild_mode) {
270             do_cmd_run(player_ptr);
271         }
272
273         break;
274     }
275     case ',': {
276         do_cmd_stay(player_ptr, always_pickup);
277         break;
278     }
279     case 'g': {
280         do_cmd_stay(player_ptr, !always_pickup);
281         break;
282     }
283     case 'R': {
284         do_cmd_rest(player_ptr);
285         break;
286     }
287     case 's': {
288         do_cmd_search(player_ptr);
289         break;
290     }
291     case 'S': {
292         if (player_ptr->action == ACTION_SEARCH) {
293             set_action(player_ptr, ACTION_NONE);
294         } else {
295             set_action(player_ptr, ACTION_SEARCH);
296         }
297
298         break;
299     }
300     case SPECIAL_KEY_STORE: {
301         do_cmd_store(player_ptr);
302         break;
303     }
304     case SPECIAL_KEY_BUILDING: {
305         do_cmd_building(player_ptr);
306         break;
307     }
308     case SPECIAL_KEY_QUEST: {
309         do_cmd_quest(player_ptr);
310         break;
311     }
312     case '<': {
313         if (!player_ptr->wild_mode && !floor_ptr->dun_level && !floor_ptr->inside_arena && !inside_quest(floor_ptr->quest_number)) {
314             if (vanilla_town) {
315                 break;
316             }
317
318             if (player_ptr->ambush_flag) {
319                 msg_print(_("襲撃から逃げるにはマップの端まで移動しなければならない。", "To flee the ambush you have to reach the edge of the map."));
320                 break;
321             }
322
323             if (player_ptr->food < PY_FOOD_WEAK) {
324                 msg_print(_("その前に食事をとらないと。", "You must eat something here."));
325                 break;
326             }
327
328             change_wild_mode(player_ptr, false);
329         } else {
330             do_cmd_go_up(player_ptr);
331         }
332
333         break;
334     }
335     case '>': {
336         if (player_ptr->wild_mode) {
337             change_wild_mode(player_ptr, false);
338         } else {
339             do_cmd_go_down(player_ptr);
340         }
341
342         break;
343     }
344     case 'o': {
345         do_cmd_open(player_ptr);
346         break;
347     }
348     case 'c': {
349         do_cmd_close(player_ptr);
350         break;
351     }
352     case 'j': {
353         do_cmd_spike(player_ptr);
354         break;
355     }
356     case 'B': {
357         do_cmd_bash(player_ptr);
358         break;
359     }
360     case 'D': {
361         do_cmd_disarm(player_ptr);
362         break;
363     }
364     case 'G': {
365         PlayerClass pc(player_ptr);
366         if (pc.is_every_magic() || pc.equals(PlayerClassType::ELEMENTALIST)) {
367             msg_print(_("呪文を学習する必要はない!", "You don't have to learn spells!"));
368         } else if (pc.equals(PlayerClassType::SAMURAI)) {
369             do_cmd_gain_hissatsu(player_ptr);
370         } else if (pc.equals(PlayerClassType::MAGIC_EATER)) {
371             import_magic_device(player_ptr);
372         } else {
373             do_cmd_study(player_ptr);
374         }
375
376         break;
377     }
378     case 'b': {
379         PlayerClass pc(player_ptr);
380         if (pc.can_browse()) {
381             do_cmd_mind_browse(player_ptr);
382         } else if (pc.equals(PlayerClassType::ELEMENTALIST)) {
383             do_cmd_element_browse(player_ptr);
384         } else if (pc.equals(PlayerClassType::SMITH)) {
385             do_cmd_kaji(player_ptr, true);
386         } else if (pc.equals(PlayerClassType::MAGIC_EATER)) {
387             do_cmd_magic_eater(player_ptr, true, false);
388         } else if (pc.equals(PlayerClassType::SNIPER)) {
389             do_cmd_snipe_browse(player_ptr);
390         } else {
391             do_cmd_browse(player_ptr);
392         }
393
394         break;
395     }
396     case 'm': {
397         if (player_ptr->wild_mode) {
398             break;
399         }
400
401         PlayerClass pc(player_ptr);
402         if (pc.equals(PlayerClassType::WARRIOR) || pc.equals(PlayerClassType::ARCHER) || pc.equals(PlayerClassType::CAVALRY)) {
403             msg_print(_("呪文を唱えられない!", "You cannot cast spells!"));
404             break;
405         }
406
407         const auto &dungeon = dungeons_info[player_ptr->dungeon_idx];
408         auto non_magic_class = pc.equals(PlayerClassType::BERSERKER);
409         non_magic_class |= pc.equals(PlayerClassType::SMITH);
410         if (floor_ptr->dun_level && dungeon.flags.has(DungeonFeatureType::NO_MAGIC) && !non_magic_class) {
411             msg_print(_("ダンジョンが魔法を吸収した!", "The dungeon absorbs all attempted magic!"));
412             msg_print(nullptr);
413             break;
414         }
415
416         if (player_ptr->anti_magic && !non_magic_class) {
417             concptr which_power = _("魔法", "magic");
418             switch (player_ptr->pclass) {
419             case PlayerClassType::MINDCRAFTER:
420                 which_power = _("超能力", "psionic powers");
421                 break;
422             case PlayerClassType::IMITATOR:
423                 which_power = _("ものまね", "imitation");
424                 break;
425             case PlayerClassType::SAMURAI:
426                 which_power = _("必殺剣", "hissatsu");
427                 break;
428             case PlayerClassType::MIRROR_MASTER:
429                 which_power = _("鏡魔法", "mirror magic");
430                 break;
431             case PlayerClassType::NINJA:
432                 which_power = _("忍術", "ninjutsu");
433                 break;
434             case PlayerClassType::ELEMENTALIST:
435                 which_power = _("元素魔法", "magic");
436                 break;
437             default:
438                 if (mp_ptr->spell_book == ItemKindType::LIFE_BOOK) {
439                     which_power = _("祈り", "prayer");
440                 }
441                 break;
442             }
443
444             msg_format(_("反魔法バリアが%sを邪魔した!", "An anti-magic shell disrupts your %s!"), which_power);
445             PlayerEnergy(player_ptr).reset_player_turn();
446             break;
447         }
448
449         if (is_shero(player_ptr) && !pc.equals(PlayerClassType::BERSERKER)) {
450             msg_format(_("狂戦士化していて頭が回らない!", "You cannot think directly!"));
451             PlayerEnergy(player_ptr).reset_player_turn();
452             break;
453         }
454
455         if (pc.can_browse()) {
456             do_cmd_mind(player_ptr);
457         } else if (pc.equals(PlayerClassType::ELEMENTALIST)) {
458             do_cmd_element(player_ptr);
459         } else if (pc.equals(PlayerClassType::IMITATOR)) {
460             do_cmd_mane(player_ptr, false);
461         } else if (pc.equals(PlayerClassType::MAGIC_EATER)) {
462             do_cmd_magic_eater(player_ptr, false, false);
463         } else if (pc.equals(PlayerClassType::SAMURAI)) {
464             do_cmd_hissatsu(player_ptr);
465         } else if (pc.equals(PlayerClassType::BLUE_MAGE)) {
466             do_cmd_cast_learned(player_ptr);
467         } else if (pc.equals(PlayerClassType::SMITH)) {
468             do_cmd_kaji(player_ptr, false);
469         } else if (pc.equals(PlayerClassType::SNIPER)) {
470             do_cmd_snipe(player_ptr);
471         } else {
472             (void)do_cmd_cast(player_ptr);
473         }
474
475         break;
476     }
477     case 'p': {
478         do_cmd_pet(player_ptr);
479         break;
480     }
481     case '{': {
482         do_cmd_inscribe(player_ptr);
483         break;
484     }
485     case '}': {
486         do_cmd_uninscribe(player_ptr);
487         break;
488     }
489     case 'A': {
490         do_cmd_activate(player_ptr);
491         break;
492     }
493     case 'E': {
494         do_cmd_eat_food(player_ptr);
495         break;
496     }
497     case 'F': {
498         do_cmd_refill(player_ptr);
499         break;
500     }
501     case 'f': {
502         do_cmd_fire(player_ptr, SP_NONE);
503         break;
504     }
505     case 'v': {
506         (void)ThrowCommand(player_ptr).do_cmd_throw(1, false, -1);
507         break;
508     }
509     case 'a': {
510         do_cmd_aim_wand(player_ptr);
511         break;
512     }
513     case 'z': {
514         if (use_command && rogue_like_commands) {
515             do_cmd_use(player_ptr);
516         } else {
517             do_cmd_zap_rod(player_ptr);
518         }
519
520         break;
521     }
522     case 'q': {
523         do_cmd_quaff_potion(player_ptr);
524         break;
525     }
526     case 'r': {
527         do_cmd_read_scroll(player_ptr);
528         break;
529     }
530     case 'u': {
531         if (use_command && !rogue_like_commands) {
532             do_cmd_use(player_ptr);
533         } else {
534             do_cmd_use_staff(player_ptr);
535         }
536
537         break;
538     }
539     case 'U': {
540         do_cmd_racial_power(player_ptr);
541         break;
542     }
543     case 'M': {
544         do_cmd_view_map(player_ptr);
545         break;
546     }
547     case 'L': {
548         do_cmd_locate(player_ptr);
549         break;
550     }
551     case 'l': {
552         do_cmd_look(player_ptr);
553         break;
554     }
555     case '*': {
556         do_cmd_target(player_ptr);
557         break;
558     }
559     case '?': {
560         do_cmd_help(player_ptr);
561         break;
562     }
563     case '/': {
564         do_cmd_query_symbol(player_ptr);
565         break;
566     }
567     case 'C': {
568         do_cmd_player_status(player_ptr);
569         break;
570     }
571     case '!': {
572         (void)term_user(0);
573         break;
574     }
575     case '"': {
576         do_cmd_pref(player_ptr);
577         break;
578     }
579     case '$': {
580         do_cmd_reload_autopick(player_ptr);
581         break;
582     }
583     case '_': {
584         do_cmd_edit_autopick(player_ptr);
585         break;
586     }
587     case '@': {
588         do_cmd_macros(player_ptr);
589         break;
590     }
591     case '%': {
592         do_cmd_visuals(player_ptr);
593         do_cmd_redraw(player_ptr);
594         break;
595     }
596     case '&': {
597         do_cmd_colors(player_ptr);
598         do_cmd_redraw(player_ptr);
599         break;
600     }
601     case '=': {
602         do_cmd_options(player_ptr);
603         (void)combine_and_reorder_home(player_ptr, StoreSaleType::HOME);
604         do_cmd_redraw(player_ptr);
605         break;
606     }
607     case ':': {
608         do_cmd_note();
609         break;
610     }
611     case 'V': {
612         do_cmd_version();
613         break;
614     }
615     case KTRL('F'): {
616         do_cmd_feeling(player_ptr);
617         break;
618     }
619     case KTRL('O'): {
620         do_cmd_message_one();
621         break;
622     }
623     case KTRL('P'): {
624         do_cmd_messages(old_now_message);
625         break;
626     }
627     case KTRL('Q'): {
628         do_cmd_checkquest(player_ptr);
629         break;
630     }
631     case KTRL('R'): {
632         now_message = old_now_message;
633         do_cmd_redraw(player_ptr);
634         break;
635     }
636     case KTRL('S'): {
637         do_cmd_save_game(player_ptr, false);
638         break;
639     }
640     case KTRL('T'): {
641         do_cmd_time(player_ptr);
642         break;
643     }
644     case KTRL('X'):
645     case SPECIAL_KEY_QUIT: {
646         do_cmd_save_and_exit(player_ptr);
647         break;
648     }
649     case 'Q': {
650         do_cmd_suicide(player_ptr);
651         break;
652     }
653     case '|': {
654         do_cmd_diary(player_ptr);
655         break;
656     }
657     case '~': {
658         do_cmd_knowledge(player_ptr);
659         break;
660     }
661     case '(': {
662         do_cmd_load_screen();
663         break;
664     }
665     case ')': {
666         do_cmd_save_screen(player_ptr);
667         break;
668     }
669     case ']': {
670         prepare_movie_hooks(player_ptr);
671         break;
672     }
673     case KTRL('V'): {
674         spoil_random_artifact(player_ptr, "randifact.txt");
675         break;
676     }
677     case '`': {
678         if (!player_ptr->wild_mode) {
679             do_cmd_travel(player_ptr);
680         }
681         PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
682
683         break;
684     }
685     default: {
686         if (flush_failure) {
687             flush();
688         }
689         if (one_in_(2)) {
690             sound(SOUND_ILLEGAL);
691             const auto error_mes = get_random_line(_("error_j.txt", "error.txt"), 0);
692             if (error_mes.has_value()) {
693                 msg_print(error_mes.value());
694             }
695         } else {
696             prt(_(" '?' でヘルプが表示されます。", "Type '?' for help."), 0, 0);
697         }
698
699         break;
700     }
701     }
702
703     if (!player_ptr->energy_use && !now_message) {
704         now_message = old_now_message;
705     }
706 }