OSDN Git Service

[Refactor] #40030 Moved *_door() from monster-process.c to monster-move.c/h
[hengband/hengband.git] / src / monster / monster-move.c
1 /*!
2  * @brief モンスターの移動に関する処理
3  * @date 2020/03/08
4  * @author Hourier
5  */
6
7 #include "monster/monster-move.h"
8 #include "cmd/cmd-pet.h"
9 #include "monster-status.h"
10 #include "player-move.h"
11
12 static bool check_hp_for_feat_destruction(feature_type *f_ptr, monster_type *m_ptr)
13 {
14         return !have_flag(f_ptr->flags, FF_GLASS) ||
15                 (r_info[m_ptr->r_idx].flags2 & RF2_STUPID) ||
16                 (m_ptr->hp >= MAX(m_ptr->maxhp / 3, 200));
17 }
18
19
20 /*!
21   * @brief モンスターによる壁の透過・破壊を行う
22   * @param target_ptr プレーヤーへの参照ポインタ
23   * @param m_ptr モンスターへの参照ポインタ
24   * @param ny モンスターのY座標
25   * @param nx モンスターのX座標
26   * @param can_cross モンスターが地形を踏破できるならばTRUE
27   * @return 透過も破壊もしなかった場合はFALSE、それ以外はTRUE
28   */
29 bool process_wall(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx, bool can_cross)
30 {
31         monster_race *r_ptr = &r_info[m_ptr->r_idx];
32         grid_type *g_ptr;
33         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
34         feature_type *f_ptr;
35         f_ptr = &f_info[g_ptr->feat];
36         if (player_bold(target_ptr, ny, nx))
37         {
38                 turn_flags_ptr->do_move = TRUE;
39                 return TRUE;
40         }
41
42         if (g_ptr->m_idx > 0)
43         {
44                 turn_flags_ptr->do_move = TRUE;
45                 return TRUE;
46         }
47
48         if (((r_ptr->flags2 & RF2_KILL_WALL) != 0) &&
49                 (can_cross ? !have_flag(f_ptr->flags, FF_LOS) : !turn_flags_ptr->is_riding_mon) &&
50                 have_flag(f_ptr->flags, FF_HURT_DISI) && !have_flag(f_ptr->flags, FF_PERMANENT) &&
51                 check_hp_for_feat_destruction(f_ptr, m_ptr))
52         {
53                 turn_flags_ptr->do_move = TRUE;
54                 if (!can_cross) turn_flags_ptr->must_alter_to_move = TRUE;
55
56                 turn_flags_ptr->did_kill_wall = TRUE;
57                 return TRUE;
58         }
59
60         if (!can_cross) return FALSE;
61
62         turn_flags_ptr->do_move = TRUE;
63         if (((r_ptr->flags2 & RF2_PASS_WALL) != 0) && (!turn_flags_ptr->is_riding_mon || target_ptr->pass_wall) &&
64                 have_flag(f_ptr->flags, FF_CAN_PASS))
65         {
66                 turn_flags_ptr->did_pass_wall = TRUE;
67         }
68
69         return TRUE;
70 }
71
72
73 /*!
74  * @brief モンスターが普通のドアを開ける処理
75  * @param target_ptr プレーヤーへの参照ポインタ
76  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
77  * @param m_ptr モンスターへの参照ポインタ
78  * @param ny モンスターのY座標
79  * @param nx モンスターのX座標
80  * @return ここではドアを開けず、ガラスのドアを開ける可能性があるならTRUE
81  */
82 static bool bash_normal_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
83 {
84         monster_race *r_ptr = &r_info[m_ptr->r_idx];
85         grid_type *g_ptr;
86         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
87         feature_type *f_ptr;
88         f_ptr = &f_info[g_ptr->feat];
89         turn_flags_ptr->do_move = FALSE;
90         if (((r_ptr->flags2 & RF2_OPEN_DOOR) == 0) || !have_flag(f_ptr->flags, FF_OPEN) ||
91                 (is_pet(m_ptr) && ((target_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0)))
92                 return TRUE;
93
94         if (f_ptr->power == 0)
95         {
96                 turn_flags_ptr->did_open_door = TRUE;
97                 turn_flags_ptr->do_turn = TRUE;
98                 return FALSE;
99         }
100
101         if (randint0(m_ptr->hp / 10) > f_ptr->power)
102         {
103                 cave_alter_feat(target_ptr, ny, nx, FF_DISARM);
104                 turn_flags_ptr->do_turn = TRUE;
105                 return FALSE;
106         }
107
108         return TRUE;
109 }
110
111
112 /*!
113  * @brief モンスターがガラスのドアを開ける処理
114  * @param target_ptr プレーヤーへの参照ポインタ
115  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
116  * @param m_ptr モンスターへの参照ポインタ
117  * @param g_ptr グリッドへの参照ポインタ
118  * @param f_ptr 地形への参照ポインタ
119  * @return なし
120  */
121 static void bash_glass_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, feature_type *f_ptr, bool may_bash)
122 {
123         monster_race *r_ptr = &r_info[m_ptr->r_idx];
124         if (!may_bash || ((r_ptr->flags2 & RF2_BASH_DOOR) == 0) || !have_flag(f_ptr->flags, FF_BASH) ||
125                 (is_pet(m_ptr) && ((target_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0)))
126                 return;
127
128         if (!check_hp_for_feat_destruction(f_ptr, m_ptr) || (randint0(m_ptr->hp / 10) <= f_ptr->power))
129                 return;
130
131         if (have_flag(f_ptr->flags, FF_GLASS))
132                 msg_print(_("ガラスが砕ける音がした!", "You hear glass breaking!"));
133         else
134                 msg_print(_("ドアを叩き開ける音がした!", "You hear a door burst open!"));
135
136         if (disturb_minor) disturb(target_ptr, FALSE, FALSE);
137
138         turn_flags_ptr->did_bash_door = TRUE;
139         turn_flags_ptr->do_move = TRUE;
140         turn_flags_ptr->must_alter_to_move = TRUE;
141 }
142
143
144 /*!
145  * @brief モンスターによるドアの開放・破壊を行う
146  * @param target_ptr プレーヤーへの参照ポインタ
147  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
148  * @param m_ptr モンスターへの参照ポインタ
149  * @param ny モンスターのY座標
150  * @param nx モンスターのX座標
151  * @return モンスターが死亡した場合のみFALSE
152  */
153 bool process_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
154 {
155         monster_race *r_ptr = &r_info[m_ptr->r_idx];
156         grid_type *g_ptr;
157         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
158         if (!is_closed_door(target_ptr, g_ptr->feat)) return TRUE;
159
160         feature_type *f_ptr;
161         f_ptr = &f_info[g_ptr->feat];
162         bool may_bash = bash_normal_door(target_ptr, turn_flags_ptr, m_ptr, ny, nx);
163         bash_glass_door(target_ptr, turn_flags_ptr, m_ptr, f_ptr, may_bash);
164
165         if (!turn_flags_ptr->did_open_door && !turn_flags_ptr->did_bash_door) return TRUE;
166
167         if (turn_flags_ptr->did_bash_door &&
168                 ((randint0(100) < 50) || (feat_state(target_ptr, g_ptr->feat, FF_OPEN) == g_ptr->feat) || have_flag(f_ptr->flags, FF_GLASS)))
169         {
170                 cave_alter_feat(target_ptr, ny, nx, FF_BASH);
171                 if (!monster_is_valid(m_ptr))
172                 {
173                         target_ptr->update |= (PU_FLOW);
174                         target_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
175                         if (is_original_ap_and_seen(target_ptr, m_ptr)) r_ptr->r_flags2 |= (RF2_BASH_DOOR);
176
177                         return FALSE;
178                 }
179         }
180         else
181         {
182                 cave_alter_feat(target_ptr, ny, nx, FF_OPEN);
183         }
184
185         f_ptr = &f_info[g_ptr->feat];
186         turn_flags_ptr->do_view = TRUE;
187         return TRUE;
188 }
189
190
191 /*!
192  * @brief モンスターが壁を掘った後続処理を実行する
193  * @param target_ptr プレーヤーへの参照ポインタ
194  * @turn_flags_ptr ターン経過処理フラグへの参照ポインタ
195  * @param m_ptr モンスターへの参照ポインタ
196  * @param ny モンスターのY座標
197  * @param nx モンスターのX座標
198  * @return モンスターが死亡した場合のみFALSE
199  */
200 bool process_post_dig_wall(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
201 {
202         monster_race *r_ptr = &r_info[m_ptr->r_idx];
203         grid_type *g_ptr;
204         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
205         feature_type *f_ptr;
206         f_ptr = &f_info[g_ptr->feat];
207         if (!turn_flags_ptr->did_kill_wall || !turn_flags_ptr->do_move) return TRUE;
208
209         if (one_in_(GRINDNOISE))
210         {
211                 if (have_flag(f_ptr->flags, FF_GLASS))
212                         msg_print(_("何かの砕ける音が聞こえる。", "There is a crashing sound."));
213                 else
214                         msg_print(_("ギシギシいう音が聞こえる。", "There is a grinding sound."));
215         }
216
217         cave_alter_feat(target_ptr, ny, nx, FF_HURT_DISI);
218
219         if (!monster_is_valid(m_ptr))
220         {
221                 target_ptr->update |= (PU_FLOW);
222                 target_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
223                 if (is_original_ap_and_seen(target_ptr, m_ptr)) r_ptr->r_flags2 |= (RF2_KILL_WALL);
224
225                 return FALSE;
226         }
227
228         f_ptr = &f_info[g_ptr->feat];
229         turn_flags_ptr->do_view = TRUE;
230         turn_flags_ptr->do_turn = TRUE;
231         return TRUE;
232 }
233
234
235 /*!
236  * @brief 守りのルーンによるモンスターの移動制限を処理する
237  * @param target_ptr プレーヤーへの参照ポインタ
238  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
239  * @param m_ptr モンスターへの参照ポインタ
240  * @param ny モンスターのY座標
241  * @param nx モンスターのX座標
242  * @return ルーンのある/なし
243  */
244 bool process_protection_rune(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
245 {
246         grid_type *g_ptr;
247         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
248         monster_race *r_ptr = &r_info[m_ptr->r_idx];
249         if (!turn_flags_ptr->do_move || !is_glyph_grid(g_ptr) ||
250                 (((r_ptr->flags1 & RF1_NEVER_BLOW) != 0) && player_bold(target_ptr, ny, nx)))
251                 return FALSE;
252
253         turn_flags_ptr->do_move = FALSE;
254         if (is_pet(m_ptr) || (randint1(BREAK_GLYPH) >= r_ptr->level))
255                 return TRUE;
256
257         if (g_ptr->info & CAVE_MARK)
258         {
259                 msg_print(_("守りのルーンが壊れた!", "The rune of protection is broken!"));
260         }
261
262         g_ptr->info &= ~(CAVE_MARK);
263         g_ptr->info &= ~(CAVE_OBJECT);
264         g_ptr->mimic = 0;
265         turn_flags_ptr->do_move = TRUE;
266         note_spot(target_ptr, ny, nx);
267         return TRUE;
268 }
269
270
271 /*!
272  * @brief 爆発のルーンを処理する
273  * @param target_ptr プレーヤーへの参照ポインタ
274  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
275  * @param m_ptr モンスターへの参照ポインタ
276  * @param ny モンスターのY座標
277  * @param nx モンスターのX座標
278  * @return モンスターが死亡した場合のみFALSE
279  */
280 bool process_explosive_rune(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
281 {
282         grid_type *g_ptr;
283         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
284         monster_race *r_ptr = &r_info[m_ptr->r_idx];
285         if (!turn_flags_ptr->do_move || !is_explosive_rune_grid(g_ptr) ||
286                 (((r_ptr->flags1 & RF1_NEVER_BLOW) != 0) && player_bold(target_ptr, ny, nx)))
287                 return TRUE;
288
289         turn_flags_ptr->do_move = FALSE;
290         if (is_pet(m_ptr)) return TRUE;
291
292         if (randint1(BREAK_MINOR_GLYPH) > r_ptr->level)
293         {
294                 if (g_ptr->info & CAVE_MARK)
295                 {
296                         msg_print(_("ルーンが爆発した!", "The rune explodes!"));
297                         BIT_FLAGS project_flags = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI;
298                         project(target_ptr, 0, 2, ny, nx, 2 * (target_ptr->lev + damroll(7, 7)), GF_MANA, project_flags, -1);
299                 }
300         }
301         else
302         {
303                 msg_print(_("爆発のルーンは解除された。", "An explosive rune was disarmed."));
304         }
305
306         g_ptr->info &= ~(CAVE_MARK);
307         g_ptr->info &= ~(CAVE_OBJECT);
308         g_ptr->mimic = 0;
309
310         note_spot(target_ptr, ny, nx);
311         lite_spot(target_ptr, ny, nx);
312
313         if (!monster_is_valid(m_ptr)) return FALSE;
314
315         turn_flags_ptr->do_move = TRUE;
316         return TRUE;
317 }