2 * @file run-execution.cpp
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"
29 bool ignore_avoid_run;
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 };
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 };
37 /* The direction we are running */
38 static DIRECTION find_current;
40 /* The direction we came from */
41 static DIRECTION find_prevdir;
43 static bool find_openarea;
45 /* We are looking for a break */
46 static bool find_breakright;
47 static bool find_breakleft;
50 * @brief ダッシュ移動処理中、移動先のマスが既知の壁かどうかを判定する /
51 * Hack -- Check for a "known wall" (see below)
52 * @param creature_ptr プレーヤーへの参照ポインタ
53 * @param dir 想定する移動方向ID
56 * @return 移動先が既知の壁ならばTRUE
58 static bool see_wall(player_type *creature_ptr, DIRECTION dir, POSITION y, POSITION x)
62 floor_type *floor_ptr = creature_ptr->current_floor_ptr;
63 if (!in_bounds2(floor_ptr, y, x))
67 g_ptr = &floor_ptr->grid_array[y][x];
68 if (!g_ptr->is_mark())
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);
76 if (f_ptr->flags.has(FF::AVOID_RUN) && !ignore_avoid_run)
79 if (f_ptr->flags.has_none_of({FF::MOVE, FF::CAN_FLY}))
80 return f_ptr->flags.has_not(FF::DOOR);
87 * Initialize the running algorithm for a new direction.
88 * @param creature_ptr プレーヤーへの参照ポインタ
91 * Diagonal Corridor -- allow diaginal entry into corridors.\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
97 * Diagonal Corridor Blunt Corridor (?)\n
102 static void run_init(player_type *creature_ptr, DIRECTION 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);
118 if (see_wall(creature_ptr, cycle[i + 1], creature_ptr->y, creature_ptr->x)) {
119 find_breakleft = true;
121 } else if (see_wall(creature_ptr, cycle[i + 1], row, col)) {
122 find_breakleft = true;
126 if (see_wall(creature_ptr, cycle[i - 1], creature_ptr->y, creature_ptr->x)) {
127 find_breakright = true;
129 } else if (see_wall(creature_ptr, cycle[i - 1], row, col)) {
130 find_breakright = true;
134 if (!find_breakleft || !find_breakright)
137 find_openarea = false;
139 if (deepleft && !deepright) {
140 find_prevdir = cycle[i - 1];
141 } else if (deepright && !deepleft) {
142 find_prevdir = cycle[i + 1];
148 if (!see_wall(creature_ptr, cycle[i], row, col))
151 if (shortleft && !shortright) {
152 find_prevdir = cycle[i - 2];
153 } else if (shortright && !shortleft) {
154 find_prevdir = cycle[i + 2];
159 * @brief ダッシュ移動処理中、移動先のマスか未知の地形かどうかを判定する /
160 * Hack -- Check for an "unknown corner" (see below)
161 * @param creature_ptr プレーヤーへの参照ポインタ
162 * @param dir 想定する移動方向ID
165 * @return 移動先が未知の地形ならばTRUE
167 static bool see_nothing(player_type *creature_ptr, DIRECTION dir, POSITION y, POSITION x)
172 floor_type *floor_ptr = creature_ptr->current_floor_ptr;
173 if (!in_bounds2(floor_ptr, y, x))
176 if (floor_ptr->grid_array[y][x].is_mark())
179 if (player_can_see_bold(creature_ptr, y, x))
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
193 static bool run_test(player_type *creature_ptr)
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!*"));
205 if (disturb_trap_detect) {
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];
219 g_ptr = &floor_ptr->grid_array[row][col];
220 FEAT_IDX feat = g_ptr->get_feat_mimic();
222 f_ptr = &f_info[feat];
224 monster_type *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
229 for (const auto this_o_idx : g_ptr->o_idx_list) {
231 o_ptr = &floor_ptr->o_list[this_o_idx];
232 if (o_ptr->marked & OM_FOUND)
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})) {
242 } else if (find_ignore_stairs && f_ptr->flags.has(FF::STAIRS)) {
244 } else if (f_ptr->flags.has(FF::LAVA) && (has_immune_fire(creature_ptr) || is_invuln(creature_ptr))) {
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)))) {
258 if (!inv && see_wall(creature_ptr, 0, row, col)) {
261 find_breakright = true;
263 find_breakleft = true;
281 if (option != cycle[chome[prev_dir] + i - 1])
284 if (new_dir & 0x01) {
285 check_dir = cycle[chome[prev_dir] + i - 2];
290 check_dir = cycle[chome[prev_dir] + i + 1];
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)) {
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)) {
316 return see_wall(creature_ptr, find_current, creature_ptr->y, creature_ptr->x);
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);
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);
345 find_current = option2;
346 find_prevdir = option2;
347 return see_wall(creature_ptr, find_current, creature_ptr->y, creature_ptr->x);
350 find_current = option;
351 find_prevdir = option2;
352 return see_wall(creature_ptr, find_current, creature_ptr->y, creature_ptr->x);
356 * @brief 継続的なダッシュ処理 /
357 * Take one step along the current "run" path
358 * @param creature_ptr プレーヤーへの参照ポインタ
359 * @param dir 移動を試みる方向ID
361 void run_step(player_type *creature_ptr, DIRECTION 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);
372 run_init(creature_ptr, dir);
374 if (run_test(creature_ptr)) {
375 disturb(creature_ptr, false, false);
380 if (--creature_ptr->running <= 0)
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);