2 * @brief モンスターの移動方向を走査する処理
7 #include "monster-floor/monster-sweep-grid.h"
8 #include "floor/cave.h"
9 #include "floor/line-of-sight.h"
10 #include "grid/feature.h"
11 #include "grid/grid.h"
12 #include "monster-floor/monster-safety-hiding.h"
13 #include "monster-race/monster-race.h"
14 #include "monster-race/race-flags-ability1.h"
15 #include "monster-race/race-flags-ability2.h"
16 #include "monster-race/race-flags1.h"
17 #include "monster-race/race-flags2.h"
18 #include "monster-race/race-flags3.h"
19 #include "monster-race/race-flags4.h"
20 #include "monster/monster-flag-types.h"
21 #include "monster/monster-info.h"
22 #include "monster/monster-status.h"
23 #include "mspell/mspell-mask-definitions.h"
24 #include "player/player-status-flags.h"
25 #include "system/floor-type-definition.h"
26 #include "target/projection-path-calculator.h"
29 * @brief モンスターがプレイヤーから逃走するかどうかを返す /
30 * Returns whether a given monster will try to run from the player.
31 * @param m_idx 逃走するモンスターの参照ID
32 * @return モンスターがプレイヤーから逃走するならばTRUEを返す。
34 * Monsters will attempt to avoid very powerful players. See below.\n
36 * Because this function is called so often, little details are important\n
37 * for efficiency. Like not using "mod" or "div" when possible. And\n
38 * attempting to check the conditions in an optimal order. Note that\n
39 * "(x << 2) == (x * 4)" if "x" has enough bits to hold the result.\n
41 * Note that this function is responsible for about one to five percent\n
42 * of the processor use in normal conditions...\n
44 static bool mon_will_run(player_type *target_ptr, MONSTER_IDX m_idx)
46 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
47 monster_race *r_ptr = &r_info[m_ptr->r_idx];
50 return ((target_ptr->pet_follow_distance < 0) && (m_ptr->cdis <= (0 - target_ptr->pet_follow_distance)));
53 if (m_ptr->cdis > MAX_SIGHT + 5)
55 if (monster_fear_remaining(m_ptr))
60 PLAYER_LEVEL p_lev = target_ptr->lev;
61 DEPTH m_lev = r_ptr->level + (m_idx & 0x08) + 25;
62 if (m_lev > p_lev + 4)
64 if (m_lev + 4 <= p_lev)
67 HIT_POINT p_chp = target_ptr->chp;
68 HIT_POINT p_mhp = target_ptr->mhp;
69 HIT_POINT m_chp = m_ptr->hp;
70 HIT_POINT m_mhp = m_ptr->maxhp;
71 u32b p_val = (p_lev * p_mhp) + (p_chp << 2);
72 u32b m_val = (m_lev * m_mhp) + (m_chp << 2);
73 if (p_val * m_mhp > m_val * p_mhp)
80 * @brief モンスターがプレイヤーに向けて遠距離攻撃を行うことが可能なマスを走査する /
81 * Search spell castable grid
82 * @param target_ptr プレーヤーへの参照ポインタ
83 * @param m_idx モンスターの参照ID
84 * @param yp 適したマスのY座標を返す参照ポインタ
85 * @param xp 適したマスのX座標を返す参照ポインタ
86 * @return 有効なマスがあった場合TRUEを返す
88 static bool sweep_ranged_attack_grid(player_type *target_ptr, MONSTER_IDX m_idx, POSITION *yp, POSITION *xp)
90 floor_type *floor_ptr = target_ptr->current_floor_ptr;
91 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
92 monster_race *r_ptr = &r_info[m_ptr->r_idx];
94 POSITION y1 = m_ptr->fy;
95 POSITION x1 = m_ptr->fx;
97 if (projectable(target_ptr, y1, x1, target_ptr->y, target_ptr->x))
100 int now_cost = grid_cost(&floor_ptr->grid_array[y1][x1], r_ptr);
104 bool can_open_door = FALSE;
105 if (r_ptr->flags2 & (RF2_BASH_DOOR | RF2_OPEN_DOOR)) {
106 can_open_door = TRUE;
110 for (int i = 7; i >= 0; i--) {
111 POSITION y = y1 + ddy_ddd[i];
112 POSITION x = x1 + ddx_ddd[i];
113 if (!in_bounds2(floor_ptr, y, x))
115 if (player_bold(target_ptr, y, x))
119 g_ptr = &floor_ptr->grid_array[y][x];
120 int cost = grid_cost(g_ptr, r_ptr);
121 if (!(((r_ptr->flags2 & RF2_PASS_WALL) && ((m_idx != target_ptr->riding) || has_pass_wall(target_ptr)))
122 || ((r_ptr->flags2 & RF2_KILL_WALL) && (m_idx != target_ptr->riding)))) {
125 if (!can_open_door && is_closed_door(target_ptr, g_ptr->feat))
134 if (!projectable(target_ptr, y, x, target_ptr->y, target_ptr->x))
140 *yp = y1 + ddy_ddd[i];
141 *xp = x1 + ddx_ddd[i];
151 * @brief モンスターがプレイヤーに向けて接近することが可能なマスを走査する /
152 * Choose the "best" direction for "flowing"
153 * @param m_idx モンスターの参照ID
154 * @param yp 移動先のマスのY座標を返す参照ポインタ
155 * @param xp 移動先のマスのX座標を返す参照ポインタ
156 * @param no_flow モンスターにFLOWフラグが経っていない状態でTRUE
159 * Note that ghosts and rock-eaters are never allowed to "flow",\n
160 * since they should move directly towards the player.\n
162 * Prefer "non-diagonal" directions, but twiddle them a little\n
163 * to angle slightly towards the player's actual location.\n
165 * Allow very perceptive monsters to track old "spoor" left by\n
166 * previous locations occupied by the player. This will tend\n
167 * to have monsters end up either near the player or on a grid\n
168 * recently occupied by the player (and left via "teleport").\n
170 * Note that if "smell" is turned on, all monsters get vicious.\n
172 * Also note that teleporting away from a location will cause\n
173 * the monsters who were chasing you to converge on that location\n
174 * as long as you are still near enough to "annoy" them without\n
175 * being close enough to chase directly. I have no idea what will\n
176 * happen if you combine "smell" with low "aaf" values.\n
178 static void sweep_movable_grid(player_type *target_ptr, MONSTER_IDX m_idx, POSITION *yp, POSITION *xp, bool no_flow)
181 floor_type *floor_ptr = target_ptr->current_floor_ptr;
182 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
183 monster_race *r_ptr = &r_info[m_ptr->r_idx];
185 if (r_ptr->flags4 & (RF4_ATTACK_MASK) || r_ptr->a_ability_flags1 & (RF5_ATTACK_MASK) || r_ptr->a_ability_flags2 & (RF6_ATTACK_MASK)) {
186 if (sweep_ranged_attack_grid(target_ptr, m_idx, yp, xp))
192 if ((r_ptr->flags2 & RF2_PASS_WALL) && ((m_idx != target_ptr->riding) || has_pass_wall(target_ptr)))
194 if ((r_ptr->flags2 & RF2_KILL_WALL) && (m_idx != target_ptr->riding))
197 POSITION y1 = m_ptr->fy;
198 POSITION x1 = m_ptr->fx;
199 g_ptr = &floor_ptr->grid_array[y1][x1];
200 if (player_has_los_bold(target_ptr, y1, x1) && projectable(target_ptr, target_ptr->y, target_ptr->x, y1, x1)) {
201 if (distance(y1, x1, target_ptr->y, target_ptr->x) == 1)
203 if (r_ptr->freq_spell > 0)
205 if (grid_cost(g_ptr, r_ptr) > 5)
210 bool use_scent = FALSE;
211 if (grid_cost(g_ptr, r_ptr)) {
213 } else if (g_ptr->when) {
214 if (floor_ptr->grid_array[target_ptr->y][target_ptr->x].when - g_ptr->when > 127)
223 for (int i = 7; i >= 0; i--) {
224 POSITION y = y1 + ddy_ddd[i];
225 POSITION x = x1 + ddx_ddd[i];
227 if (!in_bounds2(floor_ptr, y, x))
230 g_ptr = &floor_ptr->grid_array[y][x];
232 int when = g_ptr->when;
239 if (r_ptr->flags2 & (RF2_BASH_DOOR | RF2_OPEN_DOOR)) {
240 cost = grid_dist(g_ptr, r_ptr);
242 cost = grid_cost(g_ptr, r_ptr);
245 if ((cost == 0) || (best < cost))
251 *yp = target_ptr->y + 16 * ddy_ddd[i];
252 *xp = target_ptr->x + 16 * ddx_ddd[i];
257 * @brief モンスターがプレイヤーから逃走することが可能なマスを走査する /
258 * Provide a location to flee to, but give the player a wide berth.
259 * @param m_idx モンスターの参照ID
260 * @param yp 移動先のマスのY座標を返す参照ポインタ
261 * @param xp 移動先のマスのX座標を返す参照ポインタ
262 * @return 有効なマスがあった場合TRUEを返す
264 * A monster may wish to flee to a location that is behind the player,\n
265 * but instead of heading directly for it, the monster should "swerve"\n
266 * around the player so that he has a smaller chance of getting hit.\n
268 static bool sweep_runnable_away_grid(floor_type *floor_ptr, MONSTER_IDX m_idx, POSITION *yp, POSITION *xp)
270 POSITION gy = 0, gx = 0;
272 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
273 monster_race *r_ptr = &r_info[m_ptr->r_idx];
274 POSITION fy = m_ptr->fy;
275 POSITION fx = m_ptr->fx;
277 POSITION y1 = fy - (*yp);
278 POSITION x1 = fx - (*xp);
281 for (int i = 7; i >= 0; i--) {
282 POSITION y = fy + ddy_ddd[i];
283 POSITION x = fx + ddx_ddd[i];
284 if (!in_bounds2(floor_ptr, y, x))
287 POSITION dis = distance(y, x, y1, x1);
288 POSITION s = 5000 / (dis + 3) - 500 / (grid_dist(&floor_ptr->grid_array[y][x], r_ptr) + 1);
310 * @brief モンスターの移動方向を返す /
311 * Choose "logical" directions for monster movement
312 * @param target_ptr プレーヤーへの参照ポインタ
313 * @param m_idx モンスターの参照ID
314 * @param mm 移動方向を返す方向IDの参照ポインタ
315 * @return 有効方向があった場合TRUEを返す
316 * @todo 分割したいが条件が多すぎて適切な関数名と詳細処理を追いきれない……
318 bool get_movable_grid(player_type *target_ptr, MONSTER_IDX m_idx, DIRECTION *mm)
320 floor_type *floor_ptr = target_ptr->current_floor_ptr;
321 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
322 monster_race *r_ptr = &r_info[m_ptr->r_idx];
323 POSITION y = 0, x = 0;
324 POSITION y2 = target_ptr->y;
325 POSITION x2 = target_ptr->x;
327 bool will_run = mon_will_run(target_ptr, m_idx);
329 bool no_flow = m_ptr->mflag2.has(MFLAG2::NOFLOW) && grid_cost(&floor_ptr->grid_array[m_ptr->fy][m_ptr->fx], r_ptr) > 2;
330 bool can_pass_wall = ((r_ptr->flags2 & RF2_PASS_WALL) != 0) && ((m_idx != target_ptr->riding) || has_pass_wall(target_ptr));
332 if (!will_run && m_ptr->target_y) {
333 int t_m_idx = floor_ptr->grid_array[m_ptr->target_y][m_ptr->target_x].m_idx;
334 if ((t_m_idx > 0) && are_enemies(target_ptr, m_ptr, &floor_ptr->m_list[t_m_idx])
335 && los(target_ptr, m_ptr->fy, m_ptr->fx, m_ptr->target_y, m_ptr->target_x)
336 && projectable(target_ptr, m_ptr->fy, m_ptr->fx, m_ptr->target_y, m_ptr->target_x)) {
337 y = m_ptr->fy - m_ptr->target_y;
338 x = m_ptr->fx - m_ptr->target_x;
343 if (!done && !will_run && is_hostile(m_ptr) && (r_ptr->flags1 & RF1_FRIENDS)
344 && ((los(target_ptr, m_ptr->fy, m_ptr->fx, target_ptr->y, target_ptr->x) && projectable(target_ptr, m_ptr->fy, m_ptr->fx, target_ptr->y, target_ptr->x))
345 || (grid_dist(&floor_ptr->grid_array[m_ptr->fy][m_ptr->fx], r_ptr) < MAX_SIGHT / 2))) {
346 if ((r_ptr->flags3 & RF3_ANIMAL) && !can_pass_wall && !(r_ptr->flags2 & RF2_KILL_WALL)) {
348 for (int i = 0; i < 8; i++) {
349 int xx = target_ptr->x + ddx_ddd[i];
350 int yy = target_ptr->y + ddy_ddd[i];
352 if (!in_bounds2(floor_ptr, yy, xx))
355 g_ptr = &floor_ptr->grid_array[yy][xx];
356 if (monster_can_cross_terrain(target_ptr, g_ptr->feat, r_ptr, 0)) {
361 if (floor_ptr->grid_array[target_ptr->y][target_ptr->x].info & CAVE_ROOM)
363 if (!r_ptr->flags4 && !r_ptr->a_ability_flags1 && !r_ptr->a_ability_flags2)
366 if (room < (8 * (target_ptr->chp + target_ptr->csp)) / (target_ptr->mhp + target_ptr->msp)) {
367 if (find_hiding(target_ptr, m_idx, &y, &x))
372 if (!done && grid_dist(&floor_ptr->grid_array[m_ptr->fy][m_ptr->fx], r_ptr) < 3) {
373 for (int i = 0; i < 8; i++) {
374 y2 = target_ptr->y + ddy_ddd[(m_idx + i) & 7];
375 x2 = target_ptr->x + ddx_ddd[(m_idx + i) & 7];
376 if ((m_ptr->fy == y2) && (m_ptr->fx == x2)) {
382 if (!in_bounds2(floor_ptr, y2, x2))
384 if (!monster_can_enter(target_ptr, y2, x2, r_ptr, 0))
397 sweep_movable_grid(target_ptr, m_idx, &y2, &x2, no_flow);
402 if (is_pet(m_ptr) && will_run) {
405 if (!done && will_run) {
408 if (find_safety(target_ptr, m_idx, &y, &x) && !no_flow) {
409 if (sweep_runnable_away_grid(target_ptr->current_floor_ptr, m_idx, &y, &x))
423 store_moves_val(mm, y, x);