OSDN Git Service

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