2 * @brief モンスターの移動方向を決定する処理
7 #include "monster-floor/monster-direction.h"
8 #include "floor/cave.h"
9 #include "monster-floor/monster-sweep-grid.h"
10 #include "monster-race/monster-race.h"
11 #include "monster-race/race-flags1.h"
12 #include "monster-race/race-flags2.h"
13 #include "monster/monster-info.h"
14 #include "monster/monster-processor-util.h"
15 #include "monster/monster-status.h"
16 #include "pet/pet-util.h"
17 #include "player/player-status-flags.h"
18 #include "spell/range-calc.h"
19 #include "system/floor-type-definition.h"
20 #include "system/monster-entity.h"
21 #include "system/monster-race-info.h"
22 #include "system/player-type-definition.h"
23 #include "target/projection-path-calculator.h"
26 * @brief ペットが敵に接近するための方向を決定する
27 * @param player_ptr プレイヤーへの参照ポインタ
28 * @param m_ptr 移動を試みているモンスターへの参照ポインタ
29 * @param t_ptr 移動先モンスターへの参照ポインタ
30 * @param plus モンスターIDの増減 (1/2 の確率で+1、1/2の確率で-1)
31 * @return ペットがモンスターに近づくならばTRUE
33 static bool decide_pet_approch_direction(PlayerType *player_ptr, MonsterEntity *m_ptr, MonsterEntity *t_ptr)
35 auto *r_ptr = &monraces_info[m_ptr->r_idx];
36 if (!m_ptr->is_pet()) {
40 if (player_ptr->pet_follow_distance < 0) {
41 if (t_ptr->cdis <= (0 - player_ptr->pet_follow_distance)) {
44 } else if ((m_ptr->cdis < t_ptr->cdis) && (t_ptr->cdis > player_ptr->pet_follow_distance)) {
48 return r_ptr->aaf < t_ptr->cdis;
52 * @brief モンスターが敵に接近するための方向を決定する
53 * @param player_ptr プレイヤーへの参照ポインタ
54 * @param m_idx モンスターID
55 * @param start モンスターIDの開始
56 * @param plus モンスターIDの増減 (1/2 の確率で+1、1/2の確率で-1)
57 * @param y モンスターの移動方向Y
58 * @param x モンスターの移動方向X
60 static void decide_enemy_approch_direction(PlayerType *player_ptr, MONSTER_IDX m_idx, int start, int plus, POSITION *y, POSITION *x)
62 auto *floor_ptr = player_ptr->current_floor_ptr;
63 auto *m_ptr = &floor_ptr->m_list[m_idx];
64 auto *r_ptr = &monraces_info[m_ptr->r_idx];
65 for (int i = start; ((i < start + floor_ptr->m_max) && (i > start - floor_ptr->m_max)); i += plus) {
66 MONSTER_IDX dummy = (i % floor_ptr->m_max);
71 MONSTER_IDX t_idx = dummy;
73 t_ptr = &floor_ptr->m_list[t_idx];
77 if (!t_ptr->is_valid()) {
80 if (decide_pet_approch_direction(player_ptr, m_ptr, t_ptr)) {
83 if (!are_enemies(player_ptr, *m_ptr, *t_ptr)) {
87 const auto can_pass_wall = r_ptr->feature_flags.has(MonsterFeatureType::PASS_WALL) && ((m_idx != player_ptr->riding) || has_pass_wall(player_ptr));
88 const auto can_kill_wall = r_ptr->feature_flags.has(MonsterFeatureType::KILL_WALL) && (m_idx != player_ptr->riding);
89 if (can_pass_wall || can_kill_wall) {
90 if (!in_disintegration_range(floor_ptr, m_ptr->fy, m_ptr->fx, t_ptr->fy, t_ptr->fx)) {
94 if (!projectable(player_ptr, m_ptr->fy, m_ptr->fx, t_ptr->fy, t_ptr->fx)) {
106 * @brief モンスターが敵に接近するための方向を計算するメインルーチン
107 * Calculate the direction to the next enemy
108 * @param player_ptr プレイヤーへの参照ポインタ
109 * @param m_idx モンスターの参照ID
110 * @param mm 移動するべき方角IDを返す参照ポインタ
111 * @return 方向が確定した場合TRUE、接近する敵がそもそもいない場合FALSEを返す
113 bool get_enemy_dir(PlayerType *player_ptr, MONSTER_IDX m_idx, int *mm)
115 auto *floor_ptr = player_ptr->current_floor_ptr;
116 auto *m_ptr = &floor_ptr->m_list[m_idx];
118 POSITION x = 0, y = 0;
119 if (player_ptr->riding_t_m_idx && player_bold(player_ptr, m_ptr->fy, m_ptr->fx)) {
120 y = floor_ptr->m_list[player_ptr->riding_t_m_idx].fy;
121 x = floor_ptr->m_list[player_ptr->riding_t_m_idx].fx;
122 } else if (m_ptr->is_pet() && player_ptr->pet_t_m_idx) {
123 y = floor_ptr->m_list[player_ptr->pet_t_m_idx].fy;
124 x = floor_ptr->m_list[player_ptr->pet_t_m_idx].fx;
128 if (player_ptr->phase_out) {
129 start = randint1(floor_ptr->m_max - 1) + floor_ptr->m_max;
134 start = floor_ptr->m_max + 1;
137 decide_enemy_approch_direction(player_ptr, m_idx, start, plus, &y, &x);
139 if ((x == 0) && (y == 0)) {
147 store_enemy_approch_direction(mm, y, x);
152 * @brief 不規則歩行フラグを持つモンスターの移動方向をその確率に基づいて決定する
153 * @param player_ptr プレイヤーへの参照ポインタ
155 * @param m_ptr モンスターへの参照ポインタ
156 * @return 不規則な方向へ歩くことになったらTRUE
157 * @todo "5"とはもしかして「その場に留まる」という意味か?
159 static bool random_walk(PlayerType *player_ptr, DIRECTION *mm, MonsterEntity *m_ptr)
161 auto *r_ptr = &monraces_info[m_ptr->r_idx];
162 if (r_ptr->behavior_flags.has_all_of({ MonsterBehaviorType::RAND_MOVE_50, MonsterBehaviorType::RAND_MOVE_25 }) && (randint0(100) < 75)) {
163 if (is_original_ap_and_seen(player_ptr, m_ptr)) {
164 r_ptr->r_behavior_flags.set({ MonsterBehaviorType::RAND_MOVE_50, MonsterBehaviorType::RAND_MOVE_25 });
167 mm[0] = mm[1] = mm[2] = mm[3] = 5;
171 if (r_ptr->behavior_flags.has(MonsterBehaviorType::RAND_MOVE_50) && (randint0(100) < 50)) {
172 if (is_original_ap_and_seen(player_ptr, m_ptr)) {
173 r_ptr->r_behavior_flags.set(MonsterBehaviorType::RAND_MOVE_50);
176 mm[0] = mm[1] = mm[2] = mm[3] = 5;
180 if (r_ptr->behavior_flags.has(MonsterBehaviorType::RAND_MOVE_25) && (randint0(100) < 25)) {
181 if (is_original_ap_and_seen(player_ptr, m_ptr)) {
182 r_ptr->r_behavior_flags.set(MonsterBehaviorType::RAND_MOVE_25);
185 mm[0] = mm[1] = mm[2] = mm[3] = 5;
193 * @brief ペットや友好的なモンスターがフロアから逃げる処理を行う
194 * @param player_ptr プレイヤーへの参照ポインタ
196 * @param m_idx モンスターID
197 * @return モンスターがペットであればTRUE
199 static bool decide_pet_movement_direction(MonsterSweepGrid *msd)
201 auto *m_ptr = &msd->player_ptr->current_floor_ptr->m_list[msd->m_idx];
202 if (!m_ptr->is_pet()) {
206 bool avoid = ((msd->player_ptr->pet_follow_distance < 0) && (m_ptr->cdis <= (0 - msd->player_ptr->pet_follow_distance)));
207 bool lonely = (!avoid && (m_ptr->cdis > msd->player_ptr->pet_follow_distance));
208 bool distant = (m_ptr->cdis > PET_SEEK_DIST);
209 msd->mm[0] = msd->mm[1] = msd->mm[2] = msd->mm[3] = 5;
210 if (get_enemy_dir(msd->player_ptr, msd->m_idx, msd->mm)) {
214 if (!avoid && !lonely && !distant) {
218 POSITION dis = msd->player_ptr->pet_follow_distance;
219 if (msd->player_ptr->pet_follow_distance > PET_SEEK_DIST) {
220 msd->player_ptr->pet_follow_distance = PET_SEEK_DIST;
223 (void)msd->get_movable_grid();
224 msd->player_ptr->pet_follow_distance = (int16_t)dis;
229 * @brief モンスターの移動パターンを決定する
230 * @param player_ptr プレイヤーへの参照ポインタ
232 * @param m_idx モンスターID
233 * @param aware モンスターがプレイヤーに気付いているならばTRUE、超隠密状態ならばFALSE
234 * @return 移動先が存在すればTRUE
236 bool decide_monster_movement_direction(PlayerType *player_ptr, DIRECTION *mm, MONSTER_IDX m_idx, bool aware)
238 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
239 auto *r_ptr = &monraces_info[m_ptr->r_idx];
241 if (m_ptr->is_confused() || !aware) {
242 mm[0] = mm[1] = mm[2] = mm[3] = 5;
246 if (random_walk(player_ptr, mm, m_ptr)) {
250 if (r_ptr->behavior_flags.has(MonsterBehaviorType::NEVER_MOVE) && (m_ptr->cdis > 1)) {
251 mm[0] = mm[1] = mm[2] = mm[3] = 5;
255 MonsterSweepGrid msd(player_ptr, m_idx, mm);
256 if (decide_pet_movement_direction(&msd)) {
260 if (!m_ptr->is_hostile()) {
261 mm[0] = mm[1] = mm[2] = mm[3] = 5;
262 get_enemy_dir(player_ptr, m_idx, mm);
266 return msd.get_movable_grid();