OSDN Git Service

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