OSDN Git Service

[Refactor] feature_flag_type の enum class 化
[hengbandforosx/hengbandosx.git] / src / action / movement-execution.cpp
1 /*!
2  * @file movement-execution.cpp
3  * @brief プレイヤーの歩行勝利実行定義
4  */
5
6 #include "action/movement-execution.h"
7 #include "action/open-close-execution.h"
8 #include "artifact/fixed-art-types.h"
9 #include "cmd-action/cmd-attack.h"
10 #include "core/disturbance.h"
11 #include "core/player-update-types.h"
12 #include "core/stuff-handler.h"
13 #include "floor/pattern-walk.h"
14 #include "floor/geometry.h"
15 #include "game-option/input-options.h"
16 #include "grid/feature.h"
17 #include "grid/grid.h"
18 #include "inventory/inventory-slot-types.h"
19 #include "main/sound-definitions-table.h"
20 #include "main/sound-of-music.h"
21 #include "monster-race/monster-race.h"
22 #include "monster-race/race-flags-resistance.h"
23 #include "monster-race/race-flags1.h"
24 #include "monster-race/race-flags2.h"
25 #include "monster-race/race-flags7.h"
26 #include "monster-race/race-flags8.h"
27 #include "monster/monster-describer.h"
28 #include "monster/monster-info.h"
29 #include "monster/monster-status-setter.h"
30 #include "monster/monster-status.h"
31 #include "mutation/mutation-flag-types.h"
32 #include "object/warning.h"
33 #include "player-status/player-energy.h"
34 #include "player/player-move.h"
35 #include "player/player-status-flags.h"
36 #include "player/player-status.h"
37 #include "system/floor-type-definition.h"
38 #include "system/grid-type-definition.h"
39 #include "system/monster-race-definition.h"
40 #include "system/monster-type-definition.h"
41 #include "system/player-type-definition.h"
42 #include "system/object-type-definition.h"
43 #include "util/bit-flags-calculator.h"
44 #include "view/display-messages.h"
45 #ifdef JP
46 #else
47 #include "locale/english.h"
48 #endif
49
50 /*!
51  * Determine if a "boundary" grid is "floor mimic"
52  * @param grid_type *g_ptr
53  * @param feature_type *f_ptr
54  * @param feature_type  *mimic_f_ptr
55  * @return 移動不能であればTRUE
56  * @todo 負論理なので反転させたい
57  */
58 static bool boundary_floor(grid_type *g_ptr, feature_type *f_ptr, feature_type *mimic_f_ptr)
59 {
60     bool is_boundary_floor = g_ptr->mimic > 0;
61     is_boundary_floor &= permanent_wall(f_ptr);
62     is_boundary_floor &= mimic_f_ptr->flags.has_any_of({ FF::MOVE, FF::CAN_FLY });
63     is_boundary_floor &= mimic_f_ptr->flags.has(FF::PROJECT);
64     is_boundary_floor &= mimic_f_ptr->flags.has_not(FF::OPEN);
65     return is_boundary_floor;
66 }
67
68 /*!
69  * @brief 該当地形のトラップがプレイヤーにとって無効かどうかを判定して返す /
70  * Move player in the given direction, with the given "pickup" flag.
71  * @param creature_ptr プレーヤーへの参照ポインタ
72  * @param dir 移動方向ID
73  * @param do_pickup 罠解除を試みながらの移動ならばTRUE
74  * @param break_trap トラップ粉砕処理を行うならばTRUE
75  * @return 実際に移動が行われたならばTRUEを返す。
76  * @note
77  * This routine should (probably) always induce energy expenditure.\n
78  * @details
79  * Note that moving will *always* take a turn, and will *always* hit\n
80  * any monster which might be in the destination grid.  Previously,\n
81  * moving into walls was "free" and did NOT hit invisible monsters.\n
82  */
83 void exe_movement(player_type *creature_ptr, DIRECTION dir, bool do_pickup, bool break_trap)
84 {
85     POSITION y = creature_ptr->y + ddy[dir];
86     POSITION x = creature_ptr->x + ddx[dir];
87     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
88     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
89     bool p_can_enter = player_can_enter(creature_ptr, g_ptr->feat, CEM_P_CAN_ENTER_PATTERN);
90     bool stormbringer = false;
91     if (!floor_ptr->dun_level && !creature_ptr->wild_mode && ((x == 0) || (x == MAX_WID - 1) || (y == 0) || (y == MAX_HGT - 1))) {
92         if (g_ptr->mimic && player_can_enter(creature_ptr, g_ptr->mimic, 0)) {
93             if ((y == 0) && (x == 0)) {
94                 creature_ptr->wilderness_y--;
95                 creature_ptr->wilderness_x--;
96                 creature_ptr->oldpy = floor_ptr->height - 2;
97                 creature_ptr->oldpx = floor_ptr->width - 2;
98                 creature_ptr->ambush_flag = false;
99             } else if ((y == 0) && (x == MAX_WID - 1)) {
100                 creature_ptr->wilderness_y--;
101                 creature_ptr->wilderness_x++;
102                 creature_ptr->oldpy = floor_ptr->height - 2;
103                 creature_ptr->oldpx = 1;
104                 creature_ptr->ambush_flag = false;
105             } else if ((y == MAX_HGT - 1) && (x == 0)) {
106                 creature_ptr->wilderness_y++;
107                 creature_ptr->wilderness_x--;
108                 creature_ptr->oldpy = 1;
109                 creature_ptr->oldpx = floor_ptr->width - 2;
110                 creature_ptr->ambush_flag = false;
111             } else if ((y == MAX_HGT - 1) && (x == MAX_WID - 1)) {
112                 creature_ptr->wilderness_y++;
113                 creature_ptr->wilderness_x++;
114                 creature_ptr->oldpy = 1;
115                 creature_ptr->oldpx = 1;
116                 creature_ptr->ambush_flag = false;
117             } else if (y == 0) {
118                 creature_ptr->wilderness_y--;
119                 creature_ptr->oldpy = floor_ptr->height - 2;
120                 creature_ptr->oldpx = x;
121                 creature_ptr->ambush_flag = false;
122             } else if (y == MAX_HGT - 1) {
123                 creature_ptr->wilderness_y++;
124                 creature_ptr->oldpy = 1;
125                 creature_ptr->oldpx = x;
126                 creature_ptr->ambush_flag = false;
127             } else if (x == 0) {
128                 creature_ptr->wilderness_x--;
129                 creature_ptr->oldpx = floor_ptr->width - 2;
130                 creature_ptr->oldpy = y;
131                 creature_ptr->ambush_flag = false;
132             } else if (x == MAX_WID - 1) {
133                 creature_ptr->wilderness_x++;
134                 creature_ptr->oldpx = 1;
135                 creature_ptr->oldpy = y;
136                 creature_ptr->ambush_flag = false;
137             }
138
139             creature_ptr->leaving = true;
140             PlayerEnergy(creature_ptr).set_player_turn_energy(100);
141             return;
142         }
143
144         p_can_enter = false;
145     }
146
147     monster_type *m_ptr;
148     m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
149     if (creature_ptr->inventory_list[INVEN_MAIN_HAND].name1 == ART_STORMBRINGER)
150         stormbringer = true;
151
152     if (creature_ptr->inventory_list[INVEN_SUB_HAND].name1 == ART_STORMBRINGER)
153         stormbringer = true;
154
155     feature_type *f_ptr = &f_info[g_ptr->feat];
156     bool p_can_kill_walls = has_kill_wall(creature_ptr) && f_ptr->flags.has(FF::HURT_DISI) && (!p_can_enter || f_ptr->flags.has_not(FF::LOS))
157         && f_ptr->flags.has_not(FF::PERMANENT);
158     GAME_TEXT m_name[MAX_NLEN];
159     bool can_move = true;
160     bool do_past = false;
161     if (g_ptr->m_idx && (m_ptr->ml || p_can_enter || p_can_kill_walls)) {
162         monster_race *r_ptr = &r_info[m_ptr->r_idx];
163         if (!is_hostile(m_ptr)
164             && !(creature_ptr->confused || creature_ptr->image || !m_ptr->ml || creature_ptr->stun
165                 || (creature_ptr->muta.has(MUTA::BERS_RAGE) && is_shero(creature_ptr)))
166             && pattern_seq(creature_ptr, creature_ptr->y, creature_ptr->x, y, x) && (p_can_enter || p_can_kill_walls)) {
167             (void)set_monster_csleep(creature_ptr, g_ptr->m_idx, 0);
168             monster_desc(creature_ptr, m_name, m_ptr, 0);
169             if (m_ptr->ml) {
170                 if (!creature_ptr->image)
171                     monster_race_track(creature_ptr, m_ptr->ap_r_idx);
172
173                 health_track(creature_ptr, g_ptr->m_idx);
174             }
175
176             if ((stormbringer && (randint1(1000) > 666)) || (creature_ptr->pclass == CLASS_BERSERKER)) {
177                 do_cmd_attack(creature_ptr, y, x, HISSATSU_NONE);
178                 can_move = false;
179             } else if (monster_can_cross_terrain(creature_ptr, floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].feat, r_ptr, 0)) {
180                 do_past = true;
181             } else {
182                 msg_format(_("%^sが邪魔だ!", "%^s is in your way!"), m_name);
183                 PlayerEnergy(creature_ptr).reset_player_turn();
184                 can_move = false;
185             }
186         } else {
187             do_cmd_attack(creature_ptr, y, x, HISSATSU_NONE);
188             can_move = false;
189         }
190     }
191
192     monster_type *riding_m_ptr = &floor_ptr->m_list[creature_ptr->riding];
193     monster_race *riding_r_ptr = &r_info[creature_ptr->riding ? riding_m_ptr->r_idx : 0];
194     PlayerEnergy energy(creature_ptr);
195     if (can_move && creature_ptr->riding) {
196         if (riding_r_ptr->flags1 & RF1_NEVER_MOVE) {
197             msg_print(_("動けない!", "Can't move!"));
198             energy.reset_player_turn();
199             can_move = false;
200             disturb(creature_ptr, false, true);
201         } else if (monster_fear_remaining(riding_m_ptr)) {
202             GAME_TEXT steed_name[MAX_NLEN];
203             monster_desc(creature_ptr, steed_name, riding_m_ptr, 0);
204             msg_format(_("%sが恐怖していて制御できない。", "%^s is too scared to control."), steed_name);
205             can_move = false;
206             disturb(creature_ptr, false, true);
207         } else if (creature_ptr->riding_ryoute) {
208             can_move = false;
209             disturb(creature_ptr, false, true);
210         } else if (f_ptr->flags.has(FF::CAN_FLY) && (riding_r_ptr->flags7 & RF7_CAN_FLY)) {
211             /* Allow moving */
212         } else if (f_ptr->flags.has(FF::CAN_SWIM) && (riding_r_ptr->flags7 & RF7_CAN_SWIM)) {
213             /* Allow moving */
214         } else if (f_ptr->flags.has(FF::WATER) && !(riding_r_ptr->flags7 & RF7_AQUATIC)
215             && (f_ptr->flags.has(FF::DEEP) || (riding_r_ptr->flags2 & RF2_AURA_FIRE))) {
216             msg_format(_("%sの上に行けない。", "Can't swim."), f_info[g_ptr->get_feat_mimic()].name.c_str());
217             energy.reset_player_turn();
218             can_move = false;
219             disturb(creature_ptr, false, true);
220         } else if (f_ptr->flags.has_not(FF::WATER) && (riding_r_ptr->flags7 & RF7_AQUATIC)) {
221             msg_format(_("%sから上がれない。", "Can't land."), f_info[floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].get_feat_mimic()].name.c_str());
222             energy.reset_player_turn();
223             can_move = false;
224             disturb(creature_ptr, false, true);
225         } else if (f_ptr->flags.has(FF::LAVA) && !(riding_r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK)) {
226             msg_format(_("%sの上に行けない。", "Too hot to go through."), f_info[g_ptr->get_feat_mimic()].name.c_str());
227             energy.reset_player_turn();
228             can_move = false;
229             disturb(creature_ptr, false, true);
230         }
231
232         if (can_move && monster_stunned_remaining(riding_m_ptr) && one_in_(2)) {
233             GAME_TEXT steed_name[MAX_NLEN];
234             monster_desc(creature_ptr, steed_name, riding_m_ptr, 0);
235             msg_format(_("%sが朦朧としていてうまく動けない!", "You cannot control stunned %s!"), steed_name);
236             can_move = false;
237             disturb(creature_ptr, false, true);
238         }
239     }
240
241     if (!can_move) {
242     } else if (f_ptr->flags.has_not(FF::MOVE) && f_ptr->flags.has(FF::CAN_FLY) && !creature_ptr->levitation) {
243         msg_format(_("空を飛ばないと%sの上には行けない。", "You need to fly to go through the %s."), f_info[g_ptr->get_feat_mimic()].name.c_str());
244         energy.reset_player_turn();
245         creature_ptr->running = 0;
246         can_move = false;
247     } else if (f_ptr->flags.has(FF::TREE) && !p_can_kill_walls) {
248         if ((creature_ptr->pclass != CLASS_RANGER) && !creature_ptr->levitation && (!creature_ptr->riding || !(riding_r_ptr->flags8 & RF8_WILD_WOOD))) {
249             energy.mul_player_turn_energy(2);
250         }
251     } else if ((do_pickup != easy_disarm) && f_ptr->flags.has(FF::DISARM) && !g_ptr->mimic) {
252         if (!trap_can_be_ignored(creature_ptr, g_ptr->feat)) {
253             (void)exe_disarm(creature_ptr, y, x, dir);
254             return;
255         }
256     } else if (!p_can_enter && !p_can_kill_walls) {
257         FEAT_IDX feat = g_ptr->get_feat_mimic();
258         feature_type *mimic_f_ptr = &f_info[feat];
259         concptr name = mimic_f_ptr->name.c_str();
260         can_move = false;
261         if (!g_ptr->is_mark() && !player_can_see_bold(creature_ptr, y, x)) {
262             if (boundary_floor(g_ptr, f_ptr, mimic_f_ptr))
263                 msg_print(_("それ以上先には進めないようだ。", "You feel you cannot go any more."));
264             else {
265 #ifdef JP
266                 msg_format("%sが行く手をはばんでいるようだ。", name);
267 #else
268                 msg_format("You feel %s %s blocking your way.", is_a_vowel(name[0]) ? "an" : "a", name);
269 #endif
270                 g_ptr->info |= (CAVE_MARK);
271                 lite_spot(creature_ptr, y, x);
272             }
273         } else {
274             if (boundary_floor(g_ptr, f_ptr, mimic_f_ptr)) {
275                 msg_print(_("それ以上先には進めない。", "You cannot go any more."));
276                 if (!(creature_ptr->confused || creature_ptr->stun || creature_ptr->image))
277                     energy.reset_player_turn();
278             } else {
279                 if (easy_open && is_closed_door(creature_ptr, feat) && easy_open_door(creature_ptr, y, x))
280                     return;
281
282 #ifdef JP
283                 msg_format("%sが行く手をはばんでいる。", name);
284 #else
285                 msg_format("There is %s %s blocking your way.", is_a_vowel(name[0]) ? "an" : "a", name);
286 #endif
287                 if (!(creature_ptr->confused || creature_ptr->stun || creature_ptr->image))
288                     energy.reset_player_turn();
289             }
290         }
291
292         disturb(creature_ptr, false, true);
293         if (!boundary_floor(g_ptr, f_ptr, mimic_f_ptr))
294             sound(SOUND_HITWALL);
295     }
296
297     if (can_move && !pattern_seq(creature_ptr, creature_ptr->y, creature_ptr->x, y, x)) {
298         if (!(creature_ptr->confused || creature_ptr->stun || creature_ptr->image))
299             energy.reset_player_turn();
300
301         disturb(creature_ptr, false, true);
302         can_move = false;
303     }
304
305     if (!can_move)
306         return;
307
308     if (creature_ptr->warning && (!process_warning(creature_ptr, x, y))) {
309         energy.set_player_turn_energy(25);
310         return;
311     }
312
313     if (do_past)
314         msg_format(_("%sを押し退けた。", "You push past %s."), m_name);
315
316     if (creature_ptr->wild_mode) {
317         if (ddy[dir] > 0)
318             creature_ptr->oldpy = 1;
319
320         if (ddy[dir] < 0)
321             creature_ptr->oldpy = MAX_HGT - 2;
322
323         if (ddy[dir] == 0)
324             creature_ptr->oldpy = MAX_HGT / 2;
325
326         if (ddx[dir] > 0)
327             creature_ptr->oldpx = 1;
328
329         if (ddx[dir] < 0)
330             creature_ptr->oldpx = MAX_WID - 2;
331
332         if (ddx[dir] == 0)
333             creature_ptr->oldpx = MAX_WID / 2;
334     }
335
336     if (p_can_kill_walls) {
337         cave_alter_feat(creature_ptr, y, x, FF::HURT_DISI);
338         creature_ptr->update |= PU_FLOW;
339     }
340
341     uint32_t mpe_mode = MPE_ENERGY_USE;
342     if (do_pickup != always_pickup)
343         mpe_mode |= MPE_DO_PICKUP;
344
345     if (break_trap)
346         mpe_mode |= MPE_BREAK_TRAP;
347
348     (void)move_player_effect(creature_ptr, y, x, mpe_mode);
349 }