2 * @brief プレイヤーの移動処理 / Movement commands
5 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
8 #include "player/player-move.h"
9 #include "core/disturbance.h"
10 #include "core/player-redraw-types.h"
11 #include "core/player-update-types.h"
12 #include "core/special-internal-keys.h"
13 #include "core/stuff-handler.h"
14 #include "core/window-redrawer.h"
15 #include "dungeon/dungeon-flag-types.h"
16 #include "dungeon/dungeon.h"
17 #include "dungeon/quest.h"
18 #include "effect/attribute-types.h"
19 #include "effect/effect-characteristics.h"
20 #include "effect/effect-processor.h"
21 #include "floor/cave.h"
22 #include "floor/floor-util.h"
23 #include "floor/geometry.h"
24 #include "game-option/disturbance-options.h"
25 #include "grid/feature.h"
26 #include "grid/grid.h"
27 #include "grid/trap.h"
28 #include "inventory/player-inventory.h"
29 #include "io/input-key-requester.h"
30 #include "mind/mind-ninja.h"
31 #include "monster/monster-update.h"
32 #include "perception/object-perception.h"
33 #include "player-base/player-class.h"
34 #include "player-base/player-race.h"
35 #include "player-status/player-energy.h"
36 #include "player/attack-defense-types.h"
37 #include "player/player-status-flags.h"
38 #include "player/player-status.h"
39 #include "realm/realm-song-numbers.h"
40 #include "spell-kind/spells-floor.h"
41 #include "spell-realm/spells-song.h"
42 #include "status/action-setter.h"
43 #include "system/floor-type-definition.h"
44 #include "system/grid-type-definition.h"
45 #include "system/monster-type-definition.h"
46 #include "system/object-type-definition.h"
47 #include "system/player-type-definition.h"
48 #include "target/target-checker.h"
49 #include "timed-effect/player-confusion.h"
50 #include "timed-effect/player-hallucination.h"
51 #include "timed-effect/timed-effects.h"
52 #include "util/bit-flags-calculator.h"
53 #include "util/enum-converter.h"
54 #include "view/display-messages.h"
58 POSITION temp2_x[MAX_SHORT];
59 POSITION temp2_y[MAX_SHORT];
62 * @brief 地形やその上のアイテムの隠された要素を全て明かす /
63 * Search for hidden things
64 * @param player_ptr プレイヤーへの参照ポインタ
65 * @param y 対象となるマスのY座標
66 * @param x 対象となるマスのX座標
68 static void discover_hidden_things(PlayerType *player_ptr, POSITION y, POSITION x)
71 auto *floor_ptr = player_ptr->current_floor_ptr;
72 g_ptr = &floor_ptr->grid_array[y][x];
73 if (g_ptr->mimic && is_trap(player_ptr, g_ptr->feat)) {
74 disclose_grid(player_ptr, y, x);
75 msg_print(_("トラップを発見した。", "You have found a trap."));
76 disturb(player_ptr, false, true);
79 if (is_hidden_door(player_ptr, g_ptr)) {
80 msg_print(_("隠しドアを発見した。", "You have found a secret door."));
81 disclose_grid(player_ptr, y, x);
82 disturb(player_ptr, false, false);
85 for (const auto this_o_idx : g_ptr->o_idx_list) {
87 o_ptr = &floor_ptr->o_list[this_o_idx];
88 if (o_ptr->tval != ItemKindType::CHEST) {
92 if (o_ptr->pval <= 0 || chest_traps[o_ptr->pval].none()) {
96 if (!o_ptr->is_known()) {
97 msg_print(_("箱に仕掛けられたトラップを発見した!", "You have discovered a trap on the chest!"));
99 disturb(player_ptr, false, false);
105 * @brief プレイヤーの探索処理判定
106 * @param player_ptr プレイヤーへの参照ポインタ
108 void search(PlayerType *player_ptr)
110 PERCENTAGE chance = player_ptr->skill_srh;
111 if (player_ptr->blind || no_lite(player_ptr)) {
112 chance = chance / 10;
115 auto effects = player_ptr->effects();
116 if (effects->confusion()->is_confused() || effects->hallucination()->is_hallucinated()) {
117 chance = chance / 10;
120 for (DIRECTION i = 0; i < 9; ++i) {
121 if (randint0(100) < chance) {
122 discover_hidden_things(player_ptr, player_ptr->y + ddy_ddd[i], player_ptr->x + ddx_ddd[i]);
128 * @brief 移動に伴うプレイヤーのステータス変化処理
129 * @param player_ptr プレイヤーへの参照ポインタ
132 * @param mpe_mode 移動オプションフラグ
133 * @return プレイヤーが死亡やフロア離脱を行わず、実際に移動が可能ならばTRUEを返す。
135 bool move_player_effect(PlayerType *player_ptr, POSITION ny, POSITION nx, BIT_FLAGS mpe_mode)
137 POSITION oy = player_ptr->y;
138 POSITION ox = player_ptr->x;
139 auto *floor_ptr = player_ptr->current_floor_ptr;
140 auto *g_ptr = &floor_ptr->grid_array[ny][nx];
141 grid_type *oc_ptr = &floor_ptr->grid_array[oy][ox];
142 auto *f_ptr = &f_info[g_ptr->feat];
143 feature_type *of_ptr = &f_info[oc_ptr->feat];
145 if (!(mpe_mode & MPE_STAYING)) {
146 MONSTER_IDX om_idx = oc_ptr->m_idx;
147 MONSTER_IDX nm_idx = g_ptr->m_idx;
150 if (!(mpe_mode & MPE_DONT_SWAP_MON)) {
151 g_ptr->m_idx = om_idx;
152 oc_ptr->m_idx = nm_idx;
154 monster_type *om_ptr = &floor_ptr->m_list[om_idx];
157 update_monster(player_ptr, om_idx, true);
161 monster_type *nm_ptr = &floor_ptr->m_list[nm_idx];
164 update_monster(player_ptr, nm_idx, true);
168 lite_spot(player_ptr, oy, ox);
169 lite_spot(player_ptr, ny, nx);
170 verify_panel(player_ptr);
171 if (mpe_mode & MPE_FORGET_FLOW) {
172 forget_flow(floor_ptr);
173 player_ptr->update |= PU_UN_VIEW;
174 player_ptr->redraw |= PR_MAP;
177 player_ptr->update |= PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_DISTANCE;
178 player_ptr->window_flags |= PW_OVERHEAD | PW_DUNGEON;
179 if ((!player_ptr->blind && !no_lite(player_ptr)) || !is_trap(player_ptr, g_ptr->feat)) {
180 g_ptr->info &= ~(CAVE_UNSAFE);
183 if (floor_ptr->dun_level && d_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::FORGET)) {
184 wiz_dark(player_ptr);
187 if (mpe_mode & MPE_HANDLE_STUFF) {
188 handle_stuff(player_ptr);
191 if (PlayerClass(player_ptr).equals(PlayerClassType::NINJA)) {
192 if (g_ptr->info & (CAVE_GLOW)) {
193 set_superstealth(player_ptr, false);
194 } else if (player_ptr->cur_lite <= 0) {
195 set_superstealth(player_ptr, true);
199 if ((player_ptr->action == ACTION_HAYAGAKE) && (f_ptr->flags.has_not(FloorFeatureType::PROJECT) || (!player_ptr->levitation && f_ptr->flags.has(FloorFeatureType::DEEP)))) {
200 msg_print(_("ここでは素早く動けない。", "You cannot run in here."));
201 set_action(player_ptr, ACTION_NONE);
204 if (PlayerRace(player_ptr).equals(PlayerRaceType::MERFOLK)) {
205 if (f_ptr->flags.has(FloorFeatureType::WATER) ^ of_ptr->flags.has(FloorFeatureType::WATER)) {
206 player_ptr->update |= PU_BONUS;
207 update_creature(player_ptr);
212 if (mpe_mode & MPE_ENERGY_USE) {
213 if (music_singing(player_ptr, MUSIC_WALL)) {
214 (void)project(player_ptr, 0, 0, player_ptr->y, player_ptr->x, (60 + player_ptr->lev), AttributeType::DISINTEGRATE, PROJECT_KILL | PROJECT_ITEM);
215 if (!player_bold(player_ptr, ny, nx) || player_ptr->is_dead || player_ptr->leaving) {
220 if ((player_ptr->skill_fos >= 50) || (0 == randint0(50 - player_ptr->skill_fos))) {
224 if (player_ptr->action == ACTION_SEARCH) {
229 if (!(mpe_mode & MPE_DONT_PICKUP)) {
230 carry(player_ptr, any_bits(mpe_mode, MPE_DO_PICKUP));
233 if (!player_ptr->running) {
234 // 自動拾い/自動破壊により床上のアイテムリストが変化した可能性があるので表示を更新
235 set_bits(player_ptr->window_flags, PW_FLOOR_ITEM_LIST);
236 window_stuff(player_ptr);
239 PlayerEnergy energy(player_ptr);
240 if (f_ptr->flags.has(FloorFeatureType::STORE)) {
241 disturb(player_ptr, false, true);
242 energy.reset_player_turn();
243 command_new = SPECIAL_KEY_STORE;
244 } else if (f_ptr->flags.has(FloorFeatureType::BLDG)) {
245 disturb(player_ptr, false, true);
246 energy.reset_player_turn();
247 command_new = SPECIAL_KEY_BUILDING;
248 } else if (f_ptr->flags.has(FloorFeatureType::QUEST_ENTER)) {
249 disturb(player_ptr, false, true);
250 energy.reset_player_turn();
251 command_new = SPECIAL_KEY_QUEST;
252 } else if (f_ptr->flags.has(FloorFeatureType::QUEST_EXIT)) {
253 const auto &quest_list = QuestList::get_instance();
254 if (quest_list[floor_ptr->quest_number].type == QuestKindType::FIND_EXIT) {
255 complete_quest(player_ptr, floor_ptr->quest_number);
257 leave_quest_check(player_ptr);
258 floor_ptr->quest_number = i2enum<QuestId>(g_ptr->special);
259 floor_ptr->dun_level = 0;
260 if (!inside_quest(floor_ptr->quest_number)) {
261 player_ptr->word_recall = 0;
263 player_ptr->oldpx = 0;
264 player_ptr->oldpy = 0;
265 player_ptr->leaving = true;
266 } else if (f_ptr->flags.has(FloorFeatureType::HIT_TRAP) && !(mpe_mode & MPE_STAYING)) {
267 disturb(player_ptr, false, true);
268 if (g_ptr->mimic || f_ptr->flags.has(FloorFeatureType::SECRET)) {
269 msg_print(_("トラップだ!", "You found a trap!"));
270 disclose_grid(player_ptr, player_ptr->y, player_ptr->x);
273 hit_trap(player_ptr, any_bits(mpe_mode, MPE_BREAK_TRAP));
274 if (!player_bold(player_ptr, ny, nx) || player_ptr->is_dead || player_ptr->leaving) {
279 if (!(mpe_mode & MPE_STAYING) && (disturb_trap_detect || alert_trap_detect) && player_ptr->dtrap && !(g_ptr->info & CAVE_IN_DETECT)) {
280 player_ptr->dtrap = false;
281 if (!(g_ptr->info & CAVE_UNSAFE)) {
282 if (alert_trap_detect) {
283 msg_print(_("* 注意:この先はトラップの感知範囲外です! *", "*Leaving trap detect region!*"));
286 if (disturb_trap_detect) {
287 disturb(player_ptr, false, true);
292 return player_bold(player_ptr, ny, nx) && !player_ptr->is_dead && !player_ptr->leaving;
296 * @brief 該当地形のトラップがプレイヤーにとって無効かどうかを判定して返す
297 * @param player_ptr プレイヤーへの参照ポインタ
299 * @return トラップが自動的に無効ならばTRUEを返す
301 bool trap_can_be_ignored(PlayerType *player_ptr, FEAT_IDX feat)
303 auto *f_ptr = &f_info[feat];
304 if (f_ptr->flags.has_not(FloorFeatureType::TRAP)) {
308 switch (i2enum<TrapType>(f_ptr->subtype)) {
309 case TrapType::TRAPDOOR:
311 case TrapType::SPIKED_PIT:
312 case TrapType::POISON_PIT:
313 if (player_ptr->levitation) {
317 case TrapType::TELEPORT:
318 if (player_ptr->anti_tele) {
323 if (has_immune_fire(player_ptr)) {
328 if (has_immune_acid(player_ptr)) {
332 case TrapType::BLIND:
333 if (has_resist_blind(player_ptr)) {
337 case TrapType::CONFUSE:
338 if (has_resist_conf(player_ptr)) {
342 case TrapType::POISON:
343 if (has_resist_pois(player_ptr)) {
347 case TrapType::SLEEP:
348 if (player_ptr->free_act) {