OSDN Git Service

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