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/grid.h"
14 #include "main/sound-definitions-table.h"
15 #include "main/sound-of-music.h"
16 #include "object/object-mark-types.h"
17 #include "player-status/player-energy.h"
18 #include "player/player-status-flags.h"
19 #include "player/player-status.h"
20 #include "system/floor-type-definition.h"
21 #include "system/grid-type-definition.h"
22 #include "system/item-entity.h"
23 #include "system/monster-entity.h"
24 #include "system/player-type-definition.h"
25 #include "system/terrain-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 player_ptr プレイヤーへの参照ポインタ
53 * @param dir 想定する移動方向ID
56 * @return 移動先が既知の壁ならばTRUE
58 static bool see_wall(PlayerType *player_ptr, DIRECTION dir, POSITION y, POSITION x)
60 auto *floor_ptr = player_ptr->current_floor_ptr;
61 const Pos2D pos(y + ddy[dir], x + ddx[dir]);
62 if (!in_bounds2(floor_ptr, pos.y, pos.x)) {
66 const auto &grid = floor_ptr->get_grid(pos);
67 if (!grid.is_mark()) {
71 const auto terrain_id = grid.get_feat_mimic();
72 const auto &terrain = grid.get_terrain_mimic();
73 if (!player_can_enter(player_ptr, terrain_id, 0)) {
74 return terrain.flags.has_not(TerrainCharacteristics::DOOR);
77 if (terrain.flags.has(TerrainCharacteristics::AVOID_RUN) && !ignore_avoid_run) {
81 if (terrain.flags.has_none_of({ TerrainCharacteristics::MOVE, TerrainCharacteristics::CAN_FLY })) {
82 return terrain.flags.has_not(TerrainCharacteristics::DOOR);
90 * Initialize the running algorithm for a new direction.
91 * @param player_ptr プレイヤーへの参照ポインタ
94 * Diagonal Corridor -- allow diaginal entry into corridors.\n
96 * Blunt Corridor -- If there is a wall two spaces ahead and\n
97 * we seem to be in a corridor, then force a turn into the side\n
98 * corridor, must be moving straight into a corridor here. ???\n
100 * Diagonal Corridor Blunt Corridor (?)\n
105 static void run_init(PlayerType *player_ptr, DIRECTION dir)
109 find_openarea = true;
110 find_breakright = find_breakleft = false;
111 bool deepleft = false;
112 bool deepright = false;
113 bool shortright = false;
114 bool shortleft = false;
115 player_ptr->run_py = player_ptr->y;
116 player_ptr->run_px = player_ptr->x;
117 int row = player_ptr->y + ddy[dir];
118 int col = player_ptr->x + ddx[dir];
119 ignore_avoid_run = cave_has_flag_bold(player_ptr->current_floor_ptr, row, col, TerrainCharacteristics::AVOID_RUN);
121 if (see_wall(player_ptr, cycle[i + 1], player_ptr->y, player_ptr->x)) {
122 find_breakleft = true;
124 } else if (see_wall(player_ptr, cycle[i + 1], row, col)) {
125 find_breakleft = true;
129 if (see_wall(player_ptr, cycle[i - 1], player_ptr->y, player_ptr->x)) {
130 find_breakright = true;
132 } else if (see_wall(player_ptr, cycle[i - 1], row, col)) {
133 find_breakright = true;
137 if (!find_breakleft || !find_breakright) {
141 find_openarea = false;
143 if (deepleft && !deepright) {
144 find_prevdir = cycle[i - 1];
145 } else if (deepright && !deepleft) {
146 find_prevdir = cycle[i + 1];
152 if (!see_wall(player_ptr, cycle[i], row, col)) {
156 if (shortleft && !shortright) {
157 find_prevdir = cycle[i - 2];
158 } else if (shortright && !shortleft) {
159 find_prevdir = cycle[i + 2];
164 * @brief ダッシュ移動処理中、移動先のマスか未知の地形かどうかを判定する /
165 * Hack -- Check for an "unknown corner" (see below)
166 * @param player_ptr プレイヤーへの参照ポインタ
167 * @param dir 想定する移動方向ID
170 * @return 移動先が未知の地形ならばTRUE
172 static bool see_nothing(PlayerType *player_ptr, DIRECTION dir, POSITION y, POSITION x)
177 auto *floor_ptr = player_ptr->current_floor_ptr;
178 if (!in_bounds2(floor_ptr, y, x)) {
182 if (floor_ptr->grid_array[y][x].is_mark()) {
186 if (player_can_see_bold(player_ptr, y, x)) {
194 * @brief ダッシュ移動が継続できるかどうかの判定 /
195 * Update the current "run" path
196 * @param player_ptr プレイヤーへの参照ポインタ
197 * @return 立ち止まるべき条件が満たされたらTRUE
198 * ダッシュ移動が継続できるならばTRUEを返す。
199 * Return TRUE if the running should be stopped
201 static bool run_test(PlayerType *player_ptr)
203 const auto prev_dir = find_prevdir;
204 const auto max = (prev_dir & 0x01) + 1;
205 const auto &floor = *player_ptr->current_floor_ptr;
206 const auto p_pos = player_ptr->get_position();
207 const auto &p_grid = floor.get_grid(p_pos);
208 if ((disturb_trap_detect || alert_trap_detect) && player_ptr->dtrap && !(p_grid.info & CAVE_IN_DETECT)) {
209 player_ptr->dtrap = false;
210 if (!(p_grid.info & CAVE_UNSAFE)) {
211 if (alert_trap_detect) {
212 msg_print(_("* 注意:この先はトラップの感知範囲外です! *", "*Leaving trap detect region!*"));
215 if (disturb_trap_detect) {
225 for (auto i = -max; i <= max; i++) {
226 int new_dir = cycle[chome[prev_dir] + i];
227 const Pos2D pos(player_ptr->y + ddy[new_dir], player_ptr->x + ddx[new_dir]);
228 const auto &grid = floor.get_grid(pos);
230 const auto &monster = floor.m_list[grid.m_idx];
236 for (const auto this_o_idx : grid.o_idx_list) {
237 const auto &item = floor.o_list[this_o_idx];
238 if (item.marked.has(OmType::FOUND)) {
244 if (grid.is_mark()) {
245 const auto &terrain = grid.get_terrain_mimic();
246 auto notice = terrain.flags.has(TerrainCharacteristics::NOTICE);
247 if (notice && terrain.flags.has(TerrainCharacteristics::MOVE)) {
248 if (find_ignore_doors && terrain.flags.has_all_of({ TerrainCharacteristics::DOOR, TerrainCharacteristics::CLOSE })) {
250 } else if (find_ignore_stairs && terrain.flags.has(TerrainCharacteristics::STAIRS)) {
252 } else if (terrain.flags.has(TerrainCharacteristics::LAVA) && (has_immune_fire(player_ptr) || is_invuln(player_ptr))) {
254 } else if (terrain.flags.has_all_of({ TerrainCharacteristics::WATER, TerrainCharacteristics::DEEP }) && (player_ptr->levitation || player_ptr->can_swim || (calc_inventory_weight(player_ptr) <= calc_weight_limit(player_ptr)))) {
266 if (!inv && see_wall(player_ptr, 0, pos.y, pos.x)) {
269 find_breakright = true;
271 find_breakleft = true;
291 if (option != cycle[chome[prev_dir] + i - 1]) {
295 if (new_dir & 0x01) {
296 check_dir = cycle[chome[prev_dir] + i - 2];
301 check_dir = cycle[chome[prev_dir] + i + 1];
307 for (int i = -max; i < 0; i++) {
308 if (!see_wall(player_ptr, cycle[chome[prev_dir] + i], player_ptr->y, player_ptr->x)) {
309 if (find_breakright) {
313 if (find_breakleft) {
319 for (int i = max; i > 0; i--) {
320 if (!see_wall(player_ptr, cycle[chome[prev_dir] + i], player_ptr->y, player_ptr->x)) {
321 if (find_breakleft) {
325 if (find_breakright) {
331 return see_wall(player_ptr, find_current, player_ptr->y, player_ptr->x);
339 find_current = option;
340 find_prevdir = option;
341 return see_wall(player_ptr, find_current, player_ptr->y, player_ptr->x);
342 } else if (!find_cut) {
343 find_current = option;
344 find_prevdir = option2;
345 return see_wall(player_ptr, find_current, player_ptr->y, player_ptr->x);
348 int row = player_ptr->y + ddy[option];
349 int col = player_ptr->x + ddx[option];
350 if (!see_wall(player_ptr, option, row, col) || !see_wall(player_ptr, check_dir, row, col)) {
351 if (see_nothing(player_ptr, option, row, col) && see_nothing(player_ptr, option2, row, col)) {
352 find_current = option;
353 find_prevdir = option2;
354 return see_wall(player_ptr, find_current, player_ptr->y, player_ptr->x);
361 find_current = option2;
362 find_prevdir = option2;
363 return see_wall(player_ptr, find_current, player_ptr->y, player_ptr->x);
366 find_current = option;
367 find_prevdir = option2;
368 return see_wall(player_ptr, find_current, player_ptr->y, player_ptr->x);
372 * @brief 継続的なダッシュ処理 /
373 * Take one step along the current "run" path
374 * @param player_ptr プレイヤーへの参照ポインタ
375 * @param dir 移動を試みる方向ID
377 void run_step(PlayerType *player_ptr, DIRECTION dir)
380 ignore_avoid_run = true;
381 if (see_wall(player_ptr, dir, player_ptr->y, player_ptr->x)) {
382 sound(SOUND_HITWALL);
383 msg_print(_("その方向には走れません。", "You cannot run in that direction."));
384 disturb(player_ptr, false, false);
388 run_init(player_ptr, dir);
390 if (run_test(player_ptr)) {
391 disturb(player_ptr, false, false);
396 if (--player_ptr->running <= 0) {
400 PlayerEnergy(player_ptr).set_player_turn_energy(100);
401 exe_movement(player_ptr, find_current, false, false);
402 if (player_ptr->is_located_at_running_destination()) {
403 player_ptr->run_py = 0;
404 player_ptr->run_px = 0;
405 disturb(player_ptr, false, false);