OSDN Git Service

Merge pull request #2013 from sikabane-works/release/3.0.0Alpha51
[hengbandforosx/hengbandosx.git] / src / monster-floor / monster-direction.cpp
1 /*!
2  * @brief モンスターの移動方向を決定する処理
3  * @date 2020/03/08
4  * @author Hourier
5  */
6
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-race-definition.h"
21 #include "system/monster-type-definition.h"
22 #include "system/player-type-definition.h"
23 #include "target/projection-path-calculator.h"
24
25 /*!
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
32  */
33 static bool decide_pet_approch_direction(PlayerType *player_ptr, monster_type *m_ptr, monster_type *t_ptr)
34 {
35     monster_race *r_ptr = &r_info[m_ptr->r_idx];
36     if (!is_pet(m_ptr))
37         return false;
38
39     if (player_ptr->pet_follow_distance < 0) {
40         if (t_ptr->cdis <= (0 - player_ptr->pet_follow_distance)) {
41             return true;
42         }
43     } else if ((m_ptr->cdis < t_ptr->cdis) && (t_ptr->cdis > player_ptr->pet_follow_distance)) {
44         return true;
45     }
46
47     return (r_ptr->aaf < t_ptr->cdis);
48 }
49
50 /*!
51  * @brief モンスターが敵に接近するための方向を決定する
52  * @param player_ptr プレイヤーへの参照ポインタ
53  * @param m_idx モンスターID
54  * @param start モンスターIDの開始
55  * @param plus モンスターIDの増減 (1/2 の確率で+1、1/2の確率で-1)
56  * @param y モンスターの移動方向Y
57  * @param x モンスターの移動方向X
58  */
59 static void decide_enemy_approch_direction(PlayerType *player_ptr, MONSTER_IDX m_idx, int start, int plus, POSITION *y, POSITION *x)
60 {
61     floor_type *floor_ptr = player_ptr->current_floor_ptr;
62     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
63     monster_race *r_ptr = &r_info[m_ptr->r_idx];
64     for (int i = start; ((i < start + floor_ptr->m_max) && (i > start - floor_ptr->m_max)); i += plus) {
65         MONSTER_IDX dummy = (i % floor_ptr->m_max);
66         if (dummy == 0)
67             continue;
68
69         MONSTER_IDX t_idx = dummy;
70         monster_type *t_ptr;
71         t_ptr = &floor_ptr->m_list[t_idx];
72         if (t_ptr == m_ptr)
73             continue;
74         if (!monster_is_valid(t_ptr))
75             continue;
76         if (decide_pet_approch_direction(player_ptr, m_ptr, t_ptr))
77             continue;
78         if (!are_enemies(player_ptr, m_ptr, t_ptr))
79             continue;
80
81         if (((r_ptr->flags2 & RF2_PASS_WALL) && ((m_idx != player_ptr->riding) || has_pass_wall(player_ptr)))
82             || ((r_ptr->flags2 & RF2_KILL_WALL) && (m_idx != player_ptr->riding))) {
83             if (!in_disintegration_range(floor_ptr, m_ptr->fy, m_ptr->fx, t_ptr->fy, t_ptr->fx))
84                 continue;
85         } else {
86             if (!projectable(player_ptr, m_ptr->fy, m_ptr->fx, t_ptr->fy, t_ptr->fx))
87                 continue;
88         }
89
90         *y = t_ptr->fy;
91         *x = t_ptr->fx;
92         return;
93     }
94 }
95
96 /*!
97  * @brief モンスターが敵に接近するための方向を計算するメインルーチン
98  * Calculate the direction to the next enemy
99  * @param player_ptr プレイヤーへの参照ポインタ
100  * @param m_idx モンスターの参照ID
101  * @param mm 移動するべき方角IDを返す参照ポインタ
102  * @return 方向が確定した場合TRUE、接近する敵がそもそもいない場合FALSEを返す
103  */
104 bool get_enemy_dir(PlayerType *player_ptr, MONSTER_IDX m_idx, int *mm)
105 {
106     floor_type *floor_ptr = player_ptr->current_floor_ptr;
107     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
108
109     POSITION x = 0, y = 0;
110     if (player_ptr->riding_t_m_idx && player_bold(player_ptr, m_ptr->fy, m_ptr->fx)) {
111         y = floor_ptr->m_list[player_ptr->riding_t_m_idx].fy;
112         x = floor_ptr->m_list[player_ptr->riding_t_m_idx].fx;
113     } else if (is_pet(m_ptr) && player_ptr->pet_t_m_idx) {
114         y = floor_ptr->m_list[player_ptr->pet_t_m_idx].fy;
115         x = floor_ptr->m_list[player_ptr->pet_t_m_idx].fx;
116     } else {
117         int start;
118         int plus = 1;
119         if (player_ptr->phase_out) {
120             start = randint1(floor_ptr->m_max - 1) + floor_ptr->m_max;
121             if (randint0(2))
122                 plus = -1;
123         } else {
124             start = floor_ptr->m_max + 1;
125         }
126
127         decide_enemy_approch_direction(player_ptr, m_idx, start, plus, &y, &x);
128
129         if ((x == 0) && (y == 0))
130             return false;
131     }
132
133     x -= m_ptr->fx;
134     y -= m_ptr->fy;
135
136     store_enemy_approch_direction(mm, y, x);
137     return true;
138 }
139
140 /*!
141  * @brief 不規則歩行フラグを持つモンスターの移動方向をその確率に基づいて決定する
142  * @param player_ptr プレイヤーへの参照ポインタ
143  * @param mm 移動方向
144  * @param m_ptr モンスターへの参照ポインタ
145  * @return 不規則な方向へ歩くことになったらTRUE
146  * @todo "5"とはもしかして「その場に留まる」という意味か?
147  */
148 static bool random_walk(PlayerType *player_ptr, DIRECTION *mm, monster_type *m_ptr)
149 {
150     monster_race *r_ptr = &r_info[m_ptr->r_idx];
151     if (((r_ptr->flags1 & (RF1_RAND_50 | RF1_RAND_25)) == (RF1_RAND_50 | RF1_RAND_25)) && (randint0(100) < 75)) {
152         if (is_original_ap_and_seen(player_ptr, m_ptr))
153             r_ptr->r_flags1 |= (RF1_RAND_50 | RF1_RAND_25);
154
155         mm[0] = mm[1] = mm[2] = mm[3] = 5;
156         return true;
157     }
158
159     if ((r_ptr->flags1 & RF1_RAND_50) && (randint0(100) < 50)) {
160         if (is_original_ap_and_seen(player_ptr, m_ptr))
161             r_ptr->r_flags1 |= RF1_RAND_50;
162
163         mm[0] = mm[1] = mm[2] = mm[3] = 5;
164         return true;
165     }
166
167     if ((r_ptr->flags1 & RF1_RAND_25) && (randint0(100) < 25)) {
168         if (is_original_ap_and_seen(player_ptr, m_ptr))
169             r_ptr->r_flags1 |= RF1_RAND_25;
170
171         mm[0] = mm[1] = mm[2] = mm[3] = 5;
172         return true;
173     }
174
175     return false;
176 }
177
178 /*!
179  * @brief ペットや友好的なモンスターがフロアから逃げる処理を行う
180  * @param player_ptr プレイヤーへの参照ポインタ
181  * @param mm 移動方向
182  * @param m_idx モンスターID
183  * @return モンスターがペットであればTRUE
184  */
185 static bool decide_pet_movement_direction(MonsterSweepGrid *msd)
186 {
187     monster_type *m_ptr = &msd->player_ptr->current_floor_ptr->m_list[msd->m_idx];
188     if (!is_pet(m_ptr)) {
189         return false;
190     }
191     
192     bool avoid = ((msd->player_ptr->pet_follow_distance < 0) && (m_ptr->cdis <= (0 - msd->player_ptr->pet_follow_distance)));
193     bool lonely = (!avoid && (m_ptr->cdis > msd->player_ptr->pet_follow_distance));
194     bool distant = (m_ptr->cdis > PET_SEEK_DIST);
195     msd->mm[0] = msd->mm[1] = msd->mm[2] = msd->mm[3] = 5;
196     if (get_enemy_dir(msd->player_ptr, msd->m_idx, msd->mm)) {
197         return true;
198     }
199
200     if (!avoid && !lonely && !distant) {
201         return true;
202     }
203     
204     POSITION dis = msd->player_ptr->pet_follow_distance;
205     if (msd->player_ptr->pet_follow_distance > PET_SEEK_DIST) {
206         msd->player_ptr->pet_follow_distance = PET_SEEK_DIST;
207     }
208
209     (void)msd->get_movable_grid();
210     msd->player_ptr->pet_follow_distance = (int16_t)dis;
211     return true;
212 }
213
214 /*!
215  * @brief モンスターの移動パターンを決定する
216  * @param player_ptr プレイヤーへの参照ポインタ
217  * @param mm 移動方向
218  * @param m_idx モンスターID
219  * @param aware モンスターがプレイヤーに気付いているならばTRUE、超隠密状態ならばFALSE
220  * @return 移動先が存在すればTRUE
221  */
222 bool decide_monster_movement_direction(PlayerType *player_ptr, DIRECTION *mm, MONSTER_IDX m_idx, bool aware)
223 {
224     monster_type *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
225     monster_race *r_ptr = &r_info[m_ptr->r_idx];
226
227     if (monster_confused_remaining(m_ptr) || !aware) {
228         mm[0] = mm[1] = mm[2] = mm[3] = 5;
229         return true;
230     }
231
232     if (random_walk(player_ptr, mm, m_ptr)) {
233         return true;
234     }
235     
236     if ((r_ptr->flags1 & RF1_NEVER_MOVE) && (m_ptr->cdis > 1)) {
237         mm[0] = mm[1] = mm[2] = mm[3] = 5;
238         return true;
239     }
240
241     MonsterSweepGrid msd(player_ptr, m_idx, mm);
242     if (decide_pet_movement_direction(&msd)) {
243         return true;
244     }
245     
246     if (!is_hostile(m_ptr)) {
247         mm[0] = mm[1] = mm[2] = mm[3] = 5;
248         get_enemy_dir(player_ptr, m_idx, mm);
249         return true;
250     }
251
252     return msd.get_movable_grid();
253 }