OSDN Git Service

[Refactor] #40542 Separated disturbance.c/h from player-move.c/h
[hengband/hengband.git] / src / action / run-execution.c
1 #include "action/run-execution.h"
2 #include "action/movement-execution.h"
3 #include "core/disturbance.h"
4 #include "floor/floor.h"
5 #include "game-option/disturbance-options.h"
6 #include "grid/feature.h"
7 #include "grid/grid.h"
8 #include "main/sound-definitions-table.h"
9 #include "main/sound-of-music.h"
10 #include "object/object-mark-types.h"
11 #include "system/object-type-definition.h"
12 #include "util/bit-flags-calculator.h"
13 #include "view/display-messages.h"
14
15 bool ignore_avoid_run;
16
17 /* Allow quick "cycling" through the legal directions */
18 byte cycle[MAX_RUN_CYCLES] = { 1, 2, 3, 6, 9, 8, 7, 4, 1, 2, 3, 6, 9, 8, 7, 4, 1 };
19
20 /* Map each direction into the "middle" of the "cycle[]" array */
21 byte chome[MAX_RUN_CHOME] = { 0, 8, 9, 10, 7, 0, 11, 6, 5, 4 };
22
23 /* The direction we are running */
24 static DIRECTION find_current;
25
26 /* The direction we came from */
27 static DIRECTION find_prevdir;
28
29 static bool find_openarea;
30
31 /* We are looking for a break */
32 static bool find_breakright;
33 static bool find_breakleft;
34
35 /*!
36  * @brief ダッシュ移動処理中、移動先のマスが既知の壁かどうかを判定する /
37  * Hack -- Check for a "known wall" (see below)
38  * @param creature_ptr  プレーヤーへの参照ポインタ
39  * @param dir 想定する移動方向ID
40  * @param y 移動元のY座標
41  * @param x 移動元のX座標
42  * @return 移動先が既知の壁ならばTRUE
43  */
44 static bool see_wall(player_type *creature_ptr, DIRECTION dir, POSITION y, POSITION x)
45 {
46     y += ddy[dir];
47     x += ddx[dir];
48     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
49     if (!in_bounds2(floor_ptr, y, x))
50         return FALSE;
51
52     grid_type *g_ptr;
53     g_ptr = &floor_ptr->grid_array[y][x];
54     if (!(g_ptr->info & CAVE_MARK))
55         return FALSE;
56
57     s16b feat = get_feat_mimic(g_ptr);
58     feature_type *f_ptr = &f_info[feat];
59     if (!player_can_enter(creature_ptr, feat, 0))
60         return !have_flag(f_ptr->flags, FF_DOOR);
61
62     if (have_flag(f_ptr->flags, FF_AVOID_RUN) && !ignore_avoid_run)
63         return TRUE;
64
65     if (!have_flag(f_ptr->flags, FF_MOVE) && !have_flag(f_ptr->flags, FF_CAN_FLY))
66         return !have_flag(f_ptr->flags, FF_DOOR);
67
68     return FALSE;
69 }
70
71 /*!
72  * @brief ダッシュ処理の導入 /
73  * Initialize the running algorithm for a new direction.
74  * @param creature_ptr  プレーヤーへの参照ポインタ
75  * @param dir 導入の移動先
76  * @details
77  * Diagonal Corridor -- allow diaginal entry into corridors.\n
78  *\n
79  * Blunt Corridor -- If there is a wall two spaces ahead and\n
80  * we seem to be in a corridor, then force a turn into the side\n
81  * corridor, must be moving straight into a corridor here. ???\n
82  *\n
83  * Diagonal Corridor    Blunt Corridor (?)\n
84  *       \# \#                  \#\n
85  *       \#x\#                  \@x\#\n
86  *       \@\@p.                  p\n
87  */
88 static void run_init(player_type *creature_ptr, DIRECTION dir)
89 {
90     find_current = dir;
91     find_prevdir = dir;
92     find_openarea = TRUE;
93     find_breakright = find_breakleft = FALSE;
94     bool deepleft = FALSE;
95     bool deepright = FALSE;
96     bool shortright = FALSE;
97     bool shortleft = FALSE;
98     creature_ptr->run_py = creature_ptr->y;
99     creature_ptr->run_px = creature_ptr->x;
100     int row = creature_ptr->y + ddy[dir];
101     int col = creature_ptr->x + ddx[dir];
102     ignore_avoid_run = cave_have_flag_bold(creature_ptr->current_floor_ptr, row, col, FF_AVOID_RUN);
103     int i = chome[dir];
104     if (see_wall(creature_ptr, cycle[i + 1], creature_ptr->y, creature_ptr->x)) {
105         find_breakleft = TRUE;
106         shortleft = TRUE;
107     } else if (see_wall(creature_ptr, cycle[i + 1], row, col)) {
108         find_breakleft = TRUE;
109         deepleft = TRUE;
110     }
111
112     if (see_wall(creature_ptr, cycle[i - 1], creature_ptr->y, creature_ptr->x)) {
113         find_breakright = TRUE;
114         shortright = TRUE;
115     } else if (see_wall(creature_ptr, cycle[i - 1], row, col)) {
116         find_breakright = TRUE;
117         deepright = TRUE;
118     }
119
120     if (!find_breakleft || !find_breakright)
121         return;
122
123     find_openarea = FALSE;
124     if (dir & 0x01) {
125         if (deepleft && !deepright) {
126             find_prevdir = cycle[i - 1];
127         } else if (deepright && !deepleft) {
128             find_prevdir = cycle[i + 1];
129         }
130
131         return;
132     }
133
134     if (!see_wall(creature_ptr, cycle[i], row, col))
135         return;
136
137     if (shortleft && !shortright) {
138         find_prevdir = cycle[i - 2];
139     } else if (shortright && !shortleft) {
140         find_prevdir = cycle[i + 2];
141     }
142 }
143
144 /*!
145  * @brief ダッシュ移動処理中、移動先のマスか未知の地形かどうかを判定する /
146  * Hack -- Check for an "unknown corner" (see below)
147  * @param creature_ptr  プレーヤーへの参照ポインタ
148  * @param dir 想定する移動方向ID
149  * @param y 移動元のY座標
150  * @param x 移動元のX座標
151  * @return 移動先が未知の地形ならばTRUE
152  */
153 static bool see_nothing(player_type *creature_ptr, DIRECTION dir, POSITION y, POSITION x)
154 {
155     y += ddy[dir];
156     x += ddx[dir];
157
158     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
159     if (!in_bounds2(floor_ptr, y, x))
160         return TRUE;
161
162     if (floor_ptr->grid_array[y][x].info & (CAVE_MARK))
163         return FALSE;
164
165     if (player_can_see_bold(creature_ptr, y, x))
166         return FALSE;
167
168     return TRUE;
169 }
170
171 /*!
172  * @brief ダッシュ移動が継続できるかどうかの判定 /
173  * Update the current "run" path
174  * @param creature_ptr  プレーヤーへの参照ポインタ
175  * @return 立ち止まるべき条件が満たされたらTRUE
176  * ダッシュ移動が継続できるならばTRUEを返す。
177  * Return TRUE if the running should be stopped
178  */
179 static bool run_test(player_type *creature_ptr)
180 {
181     DIRECTION prev_dir = find_prevdir;
182     int max = (prev_dir & 0x01) + 1;
183     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
184     if ((disturb_trap_detect || alert_trap_detect) && creature_ptr->dtrap && !(floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].info & CAVE_IN_DETECT)) {
185         creature_ptr->dtrap = FALSE;
186         if (!(floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].info & CAVE_UNSAFE)) {
187             if (alert_trap_detect) {
188                 msg_print(_("* 注意:この先はトラップの感知範囲外です! *", "*Leaving trap detect region!*"));
189             }
190
191             if (disturb_trap_detect) {
192                 /* Break Run */
193                 return TRUE;
194             }
195         }
196     }
197
198     DIRECTION check_dir = 0;
199     int option = 0, option2 = 0;
200     for (int i = -max; i <= max; i++) {
201         OBJECT_IDX this_o_idx, next_o_idx = 0;
202         DIRECTION new_dir = cycle[chome[prev_dir] + i];
203         int row = creature_ptr->y + ddy[new_dir];
204         int col = creature_ptr->x + ddx[new_dir];
205         grid_type *g_ptr;
206         g_ptr = &floor_ptr->grid_array[row][col];
207         FEAT_IDX feat = get_feat_mimic(g_ptr);
208         feature_type *f_ptr;
209         f_ptr = &f_info[feat];
210         if (g_ptr->m_idx) {
211             monster_type *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
212             if (m_ptr->ml)
213                 return TRUE;
214         }
215
216         for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
217             object_type *o_ptr;
218             o_ptr = &floor_ptr->o_list[this_o_idx];
219             next_o_idx = o_ptr->next_o_idx;
220             if (o_ptr->marked & OM_FOUND)
221                 return TRUE;
222         }
223
224         bool inv = TRUE;
225         if (g_ptr->info & (CAVE_MARK)) {
226             bool notice = have_flag(f_ptr->flags, FF_NOTICE);
227             if (notice && have_flag(f_ptr->flags, FF_MOVE)) {
228                 if (find_ignore_doors && have_flag(f_ptr->flags, FF_DOOR) && have_flag(f_ptr->flags, FF_CLOSE)) {
229                     notice = FALSE;
230                 } else if (find_ignore_stairs && have_flag(f_ptr->flags, FF_STAIRS)) {
231                     notice = FALSE;
232                 } else if (have_flag(f_ptr->flags, FF_LAVA) && (creature_ptr->immune_fire || is_invuln(creature_ptr))) {
233                     notice = FALSE;
234                 } else if (have_flag(f_ptr->flags, FF_WATER) && have_flag(f_ptr->flags, FF_DEEP)
235                     && (creature_ptr->levitation || creature_ptr->can_swim || (creature_ptr->total_weight <= weight_limit(creature_ptr)))) {
236                     notice = FALSE;
237                 }
238             }
239
240             if (notice)
241                 return TRUE;
242
243             inv = FALSE;
244         }
245
246         if (!inv && see_wall(creature_ptr, 0, row, col)) {
247             if (find_openarea) {
248                 if (i < 0) {
249                     find_breakright = TRUE;
250                 } else if (i > 0) {
251                     find_breakleft = TRUE;
252                 }
253             }
254
255             continue;
256         }
257
258         if (find_openarea)
259             continue;
260
261         if (!option) {
262             option = new_dir;
263             continue;
264         }
265
266         if (option2)
267             return TRUE;
268
269         if (option != cycle[chome[prev_dir] + i - 1])
270             return TRUE;
271
272         if (new_dir & 0x01) {
273             check_dir = cycle[chome[prev_dir] + i - 2];
274             option2 = new_dir;
275             continue;
276         }
277
278         check_dir = cycle[chome[prev_dir] + i + 1];
279         option2 = option;
280         option = new_dir;
281     }
282
283     if (find_openarea) {
284         for (int i = -max; i < 0; i++) {
285             if (!see_wall(creature_ptr, cycle[chome[prev_dir] + i], creature_ptr->y, creature_ptr->x)) {
286                 if (find_breakright)
287                     return TRUE;
288             } else {
289                 if (find_breakleft)
290                     return TRUE;
291             }
292         }
293
294         for (int i = max; i > 0; i--) {
295             if (!see_wall(creature_ptr, cycle[chome[prev_dir] + i], creature_ptr->y, creature_ptr->x)) {
296                 if (find_breakleft)
297                     return TRUE;
298             } else {
299                 if (find_breakright)
300                     return TRUE;
301             }
302         }
303
304         return see_wall(creature_ptr, find_current, creature_ptr->y, creature_ptr->x);
305     }
306
307     if (!option)
308         return TRUE;
309
310     if (!option2) {
311         find_current = option;
312         find_prevdir = option;
313         return see_wall(creature_ptr, find_current, creature_ptr->y, creature_ptr->x);
314     } else if (!find_cut) {
315         find_current = option;
316         find_prevdir = option2;
317         return see_wall(creature_ptr, find_current, creature_ptr->y, creature_ptr->x);
318     }
319
320     int row = creature_ptr->y + ddy[option];
321     int col = creature_ptr->x + ddx[option];
322     if (!see_wall(creature_ptr, option, row, col) || !see_wall(creature_ptr, check_dir, row, col)) {
323         if (see_nothing(creature_ptr, option, row, col) && see_nothing(creature_ptr, option2, row, col)) {
324             find_current = option;
325             find_prevdir = option2;
326             return see_wall(creature_ptr, find_current, creature_ptr->y, creature_ptr->x);
327         }
328
329         return TRUE;
330     }
331
332     if (find_cut) {
333         find_current = option2;
334         find_prevdir = option2;
335         return see_wall(creature_ptr, find_current, creature_ptr->y, creature_ptr->x);
336     }
337
338     find_current = option;
339     find_prevdir = option2;
340     return see_wall(creature_ptr, find_current, creature_ptr->y, creature_ptr->x);
341 }
342
343 /*!
344  * @brief 継続的なダッシュ処理 /
345  * Take one step along the current "run" path
346  * @param creature_ptr  プレーヤーへの参照ポインタ
347  * @param dir 移動を試みる方向ID
348  * @return なし
349  */
350 void run_step(player_type *creature_ptr, DIRECTION dir)
351 {
352     if (dir) {
353         ignore_avoid_run = TRUE;
354         if (see_wall(creature_ptr, dir, creature_ptr->y, creature_ptr->x)) {
355             sound(SOUND_HITWALL);
356             msg_print(_("その方向には走れません。", "You cannot run in that direction."));
357             disturb(creature_ptr, FALSE, FALSE);
358             return;
359         }
360
361         run_init(creature_ptr, dir);
362     } else {
363         if (run_test(creature_ptr)) {
364             disturb(creature_ptr, FALSE, FALSE);
365             return;
366         }
367     }
368
369     if (--creature_ptr->running <= 0)
370         return;
371
372     take_turn(creature_ptr, 100);
373     exe_movement(creature_ptr, find_current, FALSE, FALSE);
374     if (player_bold(creature_ptr, creature_ptr->run_py, creature_ptr->run_px)) {
375         creature_ptr->run_py = 0;
376         creature_ptr->run_px = 0;
377         disturb(creature_ptr, FALSE, FALSE);
378     }
379 }