2 * @brief モンスターの移動方向を走査する処理
7 #include "monster-floor/monster-sweep-grid.h"
8 #include "floor/cave.h"
9 #include "floor/geometry.h"
10 #include "floor/line-of-sight.h"
11 #include "grid/feature.h"
12 #include "grid/grid.h"
13 #include "monster-floor/monster-safety-hiding.h"
14 #include "monster-race/monster-race.h"
15 #include "monster-race/race-ability-mask.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/monster-flag-types.h"
20 #include "monster/monster-info.h"
21 #include "monster/monster-processor-util.h"
22 #include "monster/monster-status.h"
23 #include "player/player-status-flags.h"
24 #include "system/floor-type-definition.h"
25 #include "system/grid-type-definition.h"
26 #include "system/monster-race-definition.h"
27 #include "system/monster-type-definition.h"
28 #include "system/player-type-definition.h"
29 #include "target/projection-path-calculator.h"
32 * @brief モンスターがプレイヤーから逃走するかどうかを返す /
33 * Returns whether a given monster will try to run from the player.
34 * @param m_idx 逃走するモンスターの参照ID
35 * @return モンスターがプレイヤーから逃走するならばTRUEを返す。
37 * Monsters will attempt to avoid very powerful players. See below.\n
39 * Because this function is called so often, little details are important\n
40 * for efficiency. Like not using "mod" or "div" when possible. And\n
41 * attempting to check the conditions in an optimal order. Note that\n
42 * "(x << 2) == (x * 4)" if "x" has enough bits to hold the result.\n
44 * Note that this function is responsible for about one to five percent\n
45 * of the processor use in normal conditions...\n
47 static bool mon_will_run(player_type *target_ptr, MONSTER_IDX m_idx)
49 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
50 monster_race *r_ptr = &r_info[m_ptr->r_idx];
53 return ((target_ptr->pet_follow_distance < 0) && (m_ptr->cdis <= (0 - target_ptr->pet_follow_distance)));
56 if (m_ptr->cdis > MAX_SIGHT + 5)
58 if (monster_fear_remaining(m_ptr))
63 PLAYER_LEVEL p_lev = target_ptr->lev;
64 DEPTH m_lev = r_ptr->level + (m_idx & 0x08) + 25;
65 if (m_lev > p_lev + 4)
67 if (m_lev + 4 <= p_lev)
70 HIT_POINT p_chp = target_ptr->chp;
71 HIT_POINT p_mhp = target_ptr->mhp;
72 HIT_POINT m_chp = m_ptr->hp;
73 HIT_POINT m_mhp = m_ptr->maxhp;
74 u32b p_val = (p_lev * p_mhp) + (p_chp << 2);
75 u32b m_val = (m_lev * m_mhp) + (m_chp << 2);
76 if (p_val * m_mhp > m_val * p_mhp)
83 * @brief モンスターがプレイヤーに向けて遠距離攻撃を行うことが可能なマスを走査する /
84 * Search spell castable grid
85 * @param target_ptr プレーヤーへの参照ポインタ
86 * @param m_idx モンスターの参照ID
87 * @param yp 適したマスのY座標を返す参照ポインタ
88 * @param xp 適したマスのX座標を返す参照ポインタ
89 * @return 有効なマスがあった場合TRUEを返す
91 static bool sweep_ranged_attack_grid(player_type *target_ptr, MONSTER_IDX m_idx, POSITION *yp, POSITION *xp)
93 floor_type *floor_ptr = target_ptr->current_floor_ptr;
94 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
95 monster_race *r_ptr = &r_info[m_ptr->r_idx];
97 POSITION y1 = m_ptr->fy;
98 POSITION x1 = m_ptr->fx;
100 if (projectable(target_ptr, y1, x1, target_ptr->y, target_ptr->x))
103 int now_cost = grid_cost(&floor_ptr->grid_array[y1][x1], r_ptr);
107 bool can_open_door = false;
108 if (r_ptr->flags2 & (RF2_BASH_DOOR | RF2_OPEN_DOOR)) {
109 can_open_door = true;
113 for (int i = 7; i >= 0; i--) {
114 POSITION y = y1 + ddy_ddd[i];
115 POSITION x = x1 + ddx_ddd[i];
116 if (!in_bounds2(floor_ptr, y, x))
118 if (player_bold(target_ptr, y, x))
122 g_ptr = &floor_ptr->grid_array[y][x];
123 int cost = grid_cost(g_ptr, r_ptr);
124 if (!(((r_ptr->flags2 & RF2_PASS_WALL) && ((m_idx != target_ptr->riding) || has_pass_wall(target_ptr)))
125 || ((r_ptr->flags2 & RF2_KILL_WALL) && (m_idx != target_ptr->riding)))) {
128 if (!can_open_door && is_closed_door(target_ptr, g_ptr->feat))
137 if (!projectable(target_ptr, y, x, target_ptr->y, target_ptr->x))
143 *yp = y1 + ddy_ddd[i];
144 *xp = x1 + ddx_ddd[i];
154 * @brief モンスターがプレイヤーに向けて接近することが可能なマスを走査する /
155 * Choose the "best" direction for "flowing"
156 * @param m_idx モンスターの参照ID
157 * @param yp 移動先のマスのY座標を返す参照ポインタ
158 * @param xp 移動先のマスのX座標を返す参照ポインタ
159 * @param no_flow モンスターにFLOWフラグが経っていない状態でTRUE
161 * Note that ghosts and rock-eaters are never allowed to "flow",\n
162 * since they should move directly towards the player.\n
164 * Prefer "non-diagonal" directions, but twiddle them a little\n
165 * to angle slightly towards the player's actual location.\n
167 * Allow very perceptive monsters to track old "spoor" left by\n
168 * previous locations occupied by the player. This will tend\n
169 * to have monsters end up either near the player or on a grid\n
170 * recently occupied by the player (and left via "teleport").\n
172 * Note that if "smell" is turned on, all monsters get vicious.\n
174 * Also note that teleporting away from a location will cause\n
175 * the monsters who were chasing you to converge on that location\n
176 * as long as you are still near enough to "annoy" them without\n
177 * being close enough to chase directly. I have no idea what will\n
178 * happen if you combine "smell" with low "aaf" values.\n
180 static void sweep_movable_grid(player_type *target_ptr, MONSTER_IDX m_idx, POSITION *yp, POSITION *xp, bool no_flow)
183 floor_type *floor_ptr = target_ptr->current_floor_ptr;
184 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
185 monster_race *r_ptr = &r_info[m_ptr->r_idx];
187 if (r_ptr->ability_flags.has_any_of(RF_ABILITY_ATTACK_MASK)) {
188 if (sweep_ranged_attack_grid(target_ptr, m_idx, yp, xp))
194 if ((r_ptr->flags2 & RF2_PASS_WALL) && ((m_idx != target_ptr->riding) || has_pass_wall(target_ptr)))
196 if ((r_ptr->flags2 & RF2_KILL_WALL) && (m_idx != target_ptr->riding))
199 POSITION y1 = m_ptr->fy;
200 POSITION x1 = m_ptr->fx;
201 g_ptr = &floor_ptr->grid_array[y1][x1];
202 if (player_has_los_bold(target_ptr, y1, x1) && projectable(target_ptr, target_ptr->y, target_ptr->x, y1, x1)) {
203 if (distance(y1, x1, target_ptr->y, target_ptr->x) == 1)
205 if (r_ptr->freq_spell > 0)
207 if (grid_cost(g_ptr, r_ptr) > 5)
212 bool use_scent = false;
213 if (grid_cost(g_ptr, r_ptr)) {
215 } else if (g_ptr->when) {
216 if (floor_ptr->grid_array[target_ptr->y][target_ptr->x].when - g_ptr->when > 127)
225 for (int i = 7; i >= 0; i--) {
226 POSITION y = y1 + ddy_ddd[i];
227 POSITION x = x1 + ddx_ddd[i];
229 if (!in_bounds2(floor_ptr, y, x))
232 g_ptr = &floor_ptr->grid_array[y][x];
234 int when = g_ptr->when;
241 if (r_ptr->flags2 & (RF2_BASH_DOOR | RF2_OPEN_DOOR)) {
242 cost = grid_dist(g_ptr, r_ptr);
244 cost = grid_cost(g_ptr, r_ptr);
247 if ((cost == 0) || (best < cost))
253 *yp = target_ptr->y + 16 * ddy_ddd[i];
254 *xp = target_ptr->x + 16 * ddx_ddd[i];
259 * @brief モンスターがプレイヤーから逃走することが可能なマスを走査する /
260 * Provide a location to flee to, but give the player a wide berth.
261 * @param m_idx モンスターの参照ID
262 * @param yp 移動先のマスのY座標を返す参照ポインタ
263 * @param xp 移動先のマスのX座標を返す参照ポインタ
264 * @return 有効なマスがあった場合TRUEを返す
266 * A monster may wish to flee to a location that is behind the player,\n
267 * but instead of heading directly for it, the monster should "swerve"\n
268 * around the player so that he has a smaller chance of getting hit.\n
270 static bool sweep_runnable_away_grid(floor_type *floor_ptr, MONSTER_IDX m_idx, POSITION *yp, POSITION *xp)
272 POSITION gy = 0, gx = 0;
274 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
275 monster_race *r_ptr = &r_info[m_ptr->r_idx];
276 POSITION fy = m_ptr->fy;
277 POSITION fx = m_ptr->fx;
279 POSITION y1 = fy - (*yp);
280 POSITION x1 = fx - (*xp);
283 for (int i = 7; i >= 0; i--) {
284 POSITION y = fy + ddy_ddd[i];
285 POSITION x = fx + ddx_ddd[i];
286 if (!in_bounds2(floor_ptr, y, x))
289 POSITION dis = distance(y, x, y1, x1);
290 POSITION s = 5000 / (dis + 3) - 500 / (grid_dist(&floor_ptr->grid_array[y][x], r_ptr) + 1);
312 * @brief モンスターの移動方向を返す /
313 * Choose "logical" directions for monster movement
314 * @param target_ptr プレーヤーへの参照ポインタ
315 * @param m_idx モンスターの参照ID
316 * @param mm 移動方向を返す方向IDの参照ポインタ
317 * @return 有効方向があった場合TRUEを返す
318 * @todo 分割したいが条件が多すぎて適切な関数名と詳細処理を追いきれない……
320 bool get_movable_grid(player_type *target_ptr, MONSTER_IDX m_idx, DIRECTION *mm)
322 floor_type *floor_ptr = target_ptr->current_floor_ptr;
323 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
324 monster_race *r_ptr = &r_info[m_ptr->r_idx];
325 POSITION y = 0, x = 0;
326 POSITION y2 = target_ptr->y;
327 POSITION x2 = target_ptr->x;
329 bool will_run = mon_will_run(target_ptr, m_idx);
331 bool no_flow = m_ptr->mflag2.has(MFLAG2::NOFLOW) && grid_cost(&floor_ptr->grid_array[m_ptr->fy][m_ptr->fx], r_ptr) > 2;
332 bool can_pass_wall = ((r_ptr->flags2 & RF2_PASS_WALL) != 0) && ((m_idx != target_ptr->riding) || has_pass_wall(target_ptr));
334 if (!will_run && m_ptr->target_y) {
335 int t_m_idx = floor_ptr->grid_array[m_ptr->target_y][m_ptr->target_x].m_idx;
336 if ((t_m_idx > 0) && are_enemies(target_ptr, m_ptr, &floor_ptr->m_list[t_m_idx])
337 && los(target_ptr, m_ptr->fy, m_ptr->fx, m_ptr->target_y, m_ptr->target_x)
338 && projectable(target_ptr, m_ptr->fy, m_ptr->fx, m_ptr->target_y, m_ptr->target_x)) {
339 y = m_ptr->fy - m_ptr->target_y;
340 x = m_ptr->fx - m_ptr->target_x;
345 if (!done && !will_run && is_hostile(m_ptr) && (r_ptr->flags1 & RF1_FRIENDS)
346 && ((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))
347 || (grid_dist(&floor_ptr->grid_array[m_ptr->fy][m_ptr->fx], r_ptr) < MAX_SIGHT / 2))) {
348 if ((r_ptr->flags3 & RF3_ANIMAL) && !can_pass_wall && !(r_ptr->flags2 & RF2_KILL_WALL)) {
350 for (int i = 0; i < 8; i++) {
351 int xx = target_ptr->x + ddx_ddd[i];
352 int yy = target_ptr->y + ddy_ddd[i];
354 if (!in_bounds2(floor_ptr, yy, xx))
357 g_ptr = &floor_ptr->grid_array[yy][xx];
358 if (monster_can_cross_terrain(target_ptr, g_ptr->feat, r_ptr, 0)) {
363 if (floor_ptr->grid_array[target_ptr->y][target_ptr->x].is_room())
365 if (r_ptr->ability_flags.none())
368 if (room < (8 * (target_ptr->chp + target_ptr->csp)) / (target_ptr->mhp + target_ptr->msp)) {
369 if (find_hiding(target_ptr, m_idx, &y, &x))
374 if (!done && grid_dist(&floor_ptr->grid_array[m_ptr->fy][m_ptr->fx], r_ptr) < 3) {
375 for (int i = 0; i < 8; i++) {
376 y2 = target_ptr->y + ddy_ddd[(m_idx + i) & 7];
377 x2 = target_ptr->x + ddx_ddd[(m_idx + i) & 7];
378 if ((m_ptr->fy == y2) && (m_ptr->fx == x2)) {
384 if (!in_bounds2(floor_ptr, y2, x2))
386 if (!monster_can_enter(target_ptr, y2, x2, r_ptr, 0))
399 sweep_movable_grid(target_ptr, m_idx, &y2, &x2, no_flow);
404 if (is_pet(m_ptr) && will_run) {
407 if (!done && will_run) {
410 if (find_safety(target_ptr, m_idx, &y, &x) && !no_flow) {
411 if (sweep_runnable_away_grid(target_ptr->current_floor_ptr, m_idx, &y, &x))
425 store_moves_val(mm, y, x);