1 #include "cmd-action/cmd-move.h"
2 #include "action/action-limited.h"
3 #include "action/movement-execution.h"
4 #include "action/run-execution.h"
5 #include "avatar/avatar.h"
6 #include "cmd-io/cmd-save.h"
7 #include "core/asking-player.h"
8 #include "core/disturbance.h"
9 #include "core/stuff-handler.h"
10 #include "dungeon/quest.h"
11 #include "floor/cave.h"
12 #include "floor/floor-mode-changer.h"
13 #include "floor/wild.h"
14 #include "game-option/birth-options.h"
15 #include "game-option/input-options.h"
16 #include "game-option/map-screen-options.h"
17 #include "game-option/play-record-options.h"
18 #include "game-option/special-options.h"
19 #include "info-reader/fixed-map-parser.h"
20 #include "io/input-key-requester.h"
21 #include "io/write-diary.h"
22 #include "main/sound-definitions-table.h"
23 #include "main/sound-of-music.h"
24 #include "mind/mind-ninja.h"
25 #include "player-base/player-class.h"
26 #include "player-info/samurai-data-type.h"
27 #include "player-status/player-energy.h"
28 #include "player/attack-defense-types.h"
29 #include "player/player-move.h"
30 #include "player/player-status.h"
31 #include "player/special-defense-types.h"
32 #include "spell-realm/spells-hex.h"
33 #include "spell-realm/spells-song.h"
34 #include "status/action-setter.h"
35 #include "system/dungeon-info.h"
36 #include "system/floor-type-definition.h"
37 #include "system/grid-type-definition.h"
38 #include "system/player-type-definition.h"
39 #include "system/redrawing-flags-updater.h"
40 #include "system/terrain-type-definition.h"
41 #include "target/target-getter.h"
42 #include "timed-effect/player-cut.h"
43 #include "timed-effect/player-stun.h"
44 #include "timed-effect/timed-effects.h"
45 #include "util/bit-flags-calculator.h"
46 #include "view/display-messages.h"
50 * @brief フロア脱出時に出戻りが不可能だった場合に警告を加える処理
51 * @param down_stair TRUEならば階段を降りる処理、FALSEなら階段を昇る処理による内容
52 * @return フロア移動を実際に行うならTRUE、キャンセルする場合はFALSE
54 static bool confirm_leave_level(PlayerType *player_ptr, bool down_stair)
56 const auto &quest_list = QuestList::get_instance();
57 const auto *q_ptr = &quest_list[player_ptr->current_floor_ptr->quest_number];
59 auto caution_in_tower = any_bits(q_ptr->flags, QUEST_FLAG_TOWER);
60 caution_in_tower &= q_ptr->status != QuestStatusType::STAGE_COMPLETED || (down_stair && (quest_list[QuestId::TOWER1].status != QuestStatusType::COMPLETED));
62 auto caution_in_quest = q_ptr->type == QuestKindType::RANDOM;
63 caution_in_quest |= q_ptr->flags & QUEST_FLAG_ONCE && q_ptr->status != QuestStatusType::COMPLETED;
64 caution_in_quest |= caution_in_tower;
66 if (confirm_quest && inside_quest(player_ptr->current_floor_ptr->quest_number) && caution_in_quest) {
67 msg_print(_("この階を一度去ると二度と戻って来られません。", "You can't come back here once you leave this floor."));
68 return input_check(_("本当にこの階を去りますか?", "Really leave this floor? "));
75 * @brief 階段を使って階層を昇る処理 / Go up one level
77 void do_cmd_go_up(PlayerType *player_ptr)
79 auto &quest_list = QuestList::get_instance();
81 auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
82 auto *f_ptr = &terrains_info[g_ptr->feat];
84 PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
86 if (f_ptr->flags.has_not(TerrainCharacteristics::LESS)) {
87 msg_print(_("ここには上り階段が見当たらない。", "I see no up staircase here."));
91 const auto &floor_ptr = player_ptr->current_floor_ptr;
92 if (f_ptr->flags.has(TerrainCharacteristics::QUEST)) {
93 if (!confirm_leave_level(player_ptr, false)) {
97 if (is_echizen(player_ptr)) {
98 msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
100 msg_print(_("上の階に登った。", "You enter the up staircase."));
103 sound(SOUND_STAIRWAY);
105 leave_quest_check(player_ptr);
106 floor_ptr->quest_number = i2enum<QuestId>(g_ptr->special);
107 const auto quest_number = floor_ptr->quest_number;
108 auto &quest = quest_list[quest_number];
109 if (quest.status == QuestStatusType::UNTAKEN) {
110 if (quest.type != QuestKindType::RANDOM) {
111 init_flags = INIT_ASSIGN;
112 parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
115 quest.status = QuestStatusType::TAKEN;
118 if (!inside_quest(quest_number)) {
119 floor_ptr->dun_level = 0;
120 player_ptr->word_recall = 0;
123 player_ptr->leaving = true;
124 player_ptr->oldpx = 0;
125 player_ptr->oldpy = 0;
126 PlayerEnergy(player_ptr).set_player_turn_energy(100);
130 if (!floor_ptr->is_in_dungeon()) {
133 go_up = confirm_leave_level(player_ptr, false);
140 PlayerEnergy(player_ptr).set_player_turn_energy(100);
143 do_cmd_save_game(player_ptr, true);
146 const auto quest_number = player_ptr->current_floor_ptr->quest_number;
147 auto &quest = quest_list[quest_number];
149 if (inside_quest(quest_number) && quest.type == QuestKindType::RANDOM) {
150 leave_quest_check(player_ptr);
151 player_ptr->current_floor_ptr->quest_number = QuestId::NONE;
154 if (inside_quest(quest_number) && quest.type != QuestKindType::RANDOM) {
155 leave_quest_check(player_ptr);
156 player_ptr->current_floor_ptr->quest_number = i2enum<QuestId>(g_ptr->special);
157 player_ptr->current_floor_ptr->dun_level = 0;
160 if (f_ptr->flags.has(TerrainCharacteristics::SHAFT)) {
161 prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_UP | CFM_SHAFT);
164 prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_UP);
168 if (player_ptr->current_floor_ptr->dun_level - up_num < floor_ptr->get_dungeon_definition().mindepth) {
169 up_num = player_ptr->current_floor_ptr->dun_level;
174 exe_write_diary(player_ptr, DiaryKind::STAIR, 0 - up_num, _("階段を上った", "climbed up the stairs to"));
177 if (up_num == player_ptr->current_floor_ptr->dun_level) {
178 if (is_echizen(player_ptr)) {
179 msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
181 msg_print(_("地上に戻った。", "You go back to the surface."));
183 player_ptr->word_recall = 0;
185 if (is_echizen(player_ptr)) {
186 msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
188 msg_print(_("階段を上って新たなる迷宮へと足を踏み入れた。", "You enter a maze of up staircases."));
192 sound(SOUND_STAIRWAY);
194 player_ptr->leaving = true;
198 * @brief 階段を使って階層を降りる処理 / Go down one level
199 * @param player_ptr プレイヤーへの参照ポインタ
201 void do_cmd_go_down(PlayerType *player_ptr)
203 bool fall_trap = false;
205 PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
207 auto *floor_ptr = player_ptr->current_floor_ptr;
208 auto *g_ptr = &floor_ptr->grid_array[player_ptr->y][player_ptr->x];
209 auto *f_ptr = &terrains_info[g_ptr->feat];
210 if (f_ptr->flags.has_not(TerrainCharacteristics::MORE)) {
211 msg_print(_("ここには下り階段が見当たらない。", "I see no down staircase here."));
215 if (f_ptr->flags.has(TerrainCharacteristics::TRAP)) {
219 if (f_ptr->flags.has(TerrainCharacteristics::QUEST_ENTER)) {
220 do_cmd_quest(player_ptr);
224 if (f_ptr->flags.has(TerrainCharacteristics::QUEST)) {
225 auto &quest_list = QuestList::get_instance();
226 if (!confirm_leave_level(player_ptr, true)) {
230 if (is_echizen(player_ptr)) {
231 msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
233 msg_print(_("下の階に降りた。", "You enter the down staircase."));
236 sound(SOUND_STAIRWAY);
238 leave_quest_check(player_ptr);
239 leave_tower_check(player_ptr);
240 floor_ptr->quest_number = i2enum<QuestId>(g_ptr->special);
242 auto ¤t_quest = quest_list[floor_ptr->quest_number];
243 if (current_quest.status == QuestStatusType::UNTAKEN) {
244 if (current_quest.type != QuestKindType::RANDOM) {
245 init_flags = INIT_ASSIGN;
246 parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
249 current_quest.status = QuestStatusType::TAKEN;
252 if (!inside_quest(floor_ptr->quest_number)) {
253 floor_ptr->dun_level = 0;
254 player_ptr->word_recall = 0;
257 player_ptr->leaving = true;
258 player_ptr->oldpx = 0;
259 player_ptr->oldpy = 0;
260 PlayerEnergy(player_ptr).set_player_turn_energy(100);
264 short target_dungeon = 0;
265 if (!floor_ptr->is_in_dungeon()) {
266 target_dungeon = f_ptr->flags.has(TerrainCharacteristics::ENTRANCE) ? g_ptr->special : DUNGEON_ANGBAND;
267 if (ironman_downward && (target_dungeon != DUNGEON_ANGBAND)) {
268 msg_print(_("ダンジョンの入口は塞がれている!", "The entrance of this dungeon is closed!"));
272 if (!max_dlv[target_dungeon]) {
273 const auto mes = _("ここには%sの入り口(%d階相当)があります", "There is the entrance of %s (Danger level: %d)");
274 const auto &dungeon = dungeons_info[target_dungeon];
275 msg_format(mes, dungeon.name.data(), dungeon.mindepth);
276 if (!input_check(_("本当にこのダンジョンに入りますか?", "Do you really get in this dungeon? "))) {
281 player_ptr->oldpx = player_ptr->x;
282 player_ptr->oldpy = player_ptr->y;
283 floor_ptr->set_dungeon_index(target_dungeon);
284 prepare_change_floor_mode(player_ptr, CFM_FIRST_FLOOR);
287 PlayerEnergy(player_ptr).set_player_turn_energy(100);
289 do_cmd_save_game(player_ptr, true);
292 if (f_ptr->flags.has(TerrainCharacteristics::SHAFT)) {
298 const auto &dungeon = floor_ptr->get_dungeon_definition();
299 if (!floor_ptr->is_in_dungeon()) {
300 player_ptr->enter_dungeon = true;
301 down_num = dungeon.mindepth;
306 exe_write_diary(player_ptr, DiaryKind::STAIR, down_num, _("落とし戸に落ちた", "fell through a trap door"));
308 exe_write_diary(player_ptr, DiaryKind::STAIR, down_num, _("階段を下りた", "climbed down the stairs to"));
313 msg_print(_("わざと落とし戸に落ちた。", "You deliberately jump through the trap door."));
315 if (target_dungeon) {
316 msg_format(_("%sへ入った。", "You entered %s."), dungeon.text.data());
318 if (is_echizen(player_ptr)) {
319 msg_print(_("なんだこの階段は!", "What's this STAIRWAY!"));
321 msg_print(_("階段を下りて新たなる迷宮へと足を踏み入れた。", "You enter a maze of down staircases."));
325 sound(SOUND_STAIRWAY);
328 player_ptr->leaving = true;
331 prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_DOWN | CFM_RAND_PLACE | CFM_RAND_CONNECT);
335 if (f_ptr->flags.has(TerrainCharacteristics::SHAFT)) {
336 prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_DOWN | CFM_SHAFT);
338 prepare_change_floor_mode(player_ptr, CFM_SAVE_FLOORS | CFM_DOWN);
343 * @brief 「歩く」動作コマンドのメインルーチン /
344 * Support code for the "Walk" and "Jump" commands
345 * @param player_ptr プレイヤーへの参照ポインタ
346 * @param pickup アイテムの自動拾いを行うならTRUE
348 void do_cmd_walk(PlayerType *player_ptr, bool pickup)
351 command_rep = command_arg - 1;
352 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
358 if (get_rep_dir(player_ptr, &dir)) {
359 PlayerEnergy energy(player_ptr);
360 energy.set_player_turn_energy(100);
362 PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
365 if (player_ptr->wild_mode) {
366 energy.mul_player_turn_energy((MAX_HGT + MAX_WID) / 2);
369 if (player_ptr->action == ACTION_HAYAGAKE) {
370 auto energy_use = (ENERGY)(player_ptr->energy_use * (45 - (player_ptr->lev / 2)) / 100);
371 energy.set_player_turn_energy(energy_use);
374 exe_movement(player_ptr, dir, pickup, false);
378 if (player_ptr->wild_mode && !cave_has_flag_bold(player_ptr->current_floor_ptr, player_ptr->y, player_ptr->x, TerrainCharacteristics::TOWN)) {
379 int tmp = 120 + player_ptr->lev * 10 - wilderness[player_ptr->y][player_ptr->x].level + 5;
384 if (((wilderness[player_ptr->y][player_ptr->x].level + 5) > (player_ptr->lev / 2)) && randint0(tmp) < (21 - player_ptr->skill_stl)) {
385 msg_print(_("襲撃だ!", "You are ambushed !"));
386 player_ptr->oldpy = randint1(MAX_HGT - 2);
387 player_ptr->oldpx = randint1(MAX_WID - 2);
388 change_wild_mode(player_ptr, true);
389 PlayerEnergy(player_ptr).set_player_turn_energy(100);
394 disturb(player_ptr, false, false);
399 * @brief 「走る」動作コマンドのメインルーチン /
401 * @param player_ptr プレイヤーへの参照ポインタ
403 void do_cmd_run(PlayerType *player_ptr)
406 if (cmd_limit_confused(player_ptr)) {
410 PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
412 if (get_rep_dir(player_ptr, &dir)) {
413 player_ptr->running = (command_arg ? command_arg : 1000);
414 run_step(player_ptr, dir);
419 * @brief 「留まる」動作コマンドのメインルーチン /
420 * Stay still. Search. Enter stores.
421 * Pick up treasure if "pickup" is true.
422 * @param player_ptr プレイヤーへの参照ポインタ
423 * @param pickup アイテムの自動拾いを行うならTRUE
425 void do_cmd_stay(PlayerType *player_ptr, bool pickup)
427 uint32_t mpe_mode = MPE_STAYING | MPE_ENERGY_USE;
429 command_rep = command_arg - 1;
430 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::ACTION);
434 PlayerEnergy(player_ptr).set_player_turn_energy(100);
436 mpe_mode |= MPE_DO_PICKUP;
439 (void)move_player_effect(player_ptr, player_ptr->y, player_ptr->x, mpe_mode);
443 * @brief 休憩ターン数のコマンド受付
445 static bool input_rest_turns()
447 constexpr auto p = _("休憩 (0-9999, '*' で HP/MP全快, '&' で必要なだけ): ", "Rest (0-9999, '*' for HP/SP, '&' as needed): ");
449 const auto rest_turns_opt = input_string(p, 4, "&");
450 if (!rest_turns_opt.has_value()) {
454 const auto &rest_turns = rest_turns_opt.value();
455 if (rest_turns.starts_with('&')) {
456 command_arg = COMMAND_ARG_REST_UNTIL_DONE;
460 if (rest_turns.starts_with('*')) {
461 command_arg = COMMAND_ARG_REST_FULL_HEALING;
466 command_arg = static_cast<short>(std::clamp(std::stoi(rest_turns), 0, 9999));
468 } catch (std::invalid_argument const &) {
469 msg_print(_("数値を入力して下さい。", "Please input numeric value."));
475 * @brief 「休む」動作コマンドのメインルーチン /
476 * Resting allows a player to safely restore his hp -RAK-
477 * @param player_ptr プレイヤーへの参照ポインタ
479 void do_cmd_rest(PlayerType *player_ptr)
481 set_action(player_ptr, ACTION_NONE);
482 if (PlayerClass(player_ptr).equals(PlayerClassType::BARD)) {
483 auto is_singing = get_singing_song_effect(player_ptr) != 0;
484 is_singing |= get_interrupting_song_effect(player_ptr) != 0;
486 stop_singing(player_ptr);
490 SpellHex spell_hex(player_ptr);
491 if (spell_hex.is_spelling_any()) {
492 (void)spell_hex.stop_all_spells();
495 if (!input_rest_turns()) {
499 set_superstealth(player_ptr, false);
501 PlayerEnergy(player_ptr).set_player_turn_energy(100);
502 if (command_arg > 100) {
503 chg_virtue(player_ptr, Virtue::DILIGENCE, -1);
506 if (player_ptr->is_fully_healthy()) {
507 chg_virtue(player_ptr, Virtue::DILIGENCE, -1);
510 player_ptr->resting = command_arg;
511 player_ptr->action = ACTION_REST;
512 auto &rfu = RedrawingFlagsUpdater::get_instance();
513 rfu.set_flag(StatusRecalculatingFlag::BONUS);
514 rfu.set_flag(MainWindowRedrawingFlag::ACTION);
515 handle_stuff(player_ptr);