OSDN Git Service

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