OSDN Git Service

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