OSDN Git Service

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