OSDN Git Service

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