OSDN Git Service

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