OSDN Git Service

b92def1abc474efe4932b7a91f4c63826907f531
[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 "monster/monster-attack.h"
9 #include "monster/monster-object.h"
10 #include "monster/monster-update.h"
11 #include "cmd/cmd-pet.h"
12 #include "creature.h"
13 #include "files.h"
14 #include "monster/monster-status.h"
15 #include "player/player-move.h"
16 #include "spell/spells-type.h"
17 #include "spell/process-effect.h"
18 #include "effect/effect-characteristics.h"
19
20 static bool check_hp_for_feat_destruction(feature_type *f_ptr, monster_type *m_ptr)
21 {
22         return !have_flag(f_ptr->flags, FF_GLASS) ||
23                 (r_info[m_ptr->r_idx].flags2 & RF2_STUPID) ||
24                 (m_ptr->hp >= MAX(m_ptr->maxhp / 3, 200));
25 }
26
27
28 /*!
29   * @brief モンスターによる壁の透過・破壊を行う
30   * @param target_ptr プレーヤーへの参照ポインタ
31   * @param m_ptr モンスターへの参照ポインタ
32   * @param ny モンスターのY座標
33   * @param nx モンスターのX座標
34   * @param can_cross モンスターが地形を踏破できるならばTRUE
35   * @return 透過も破壊もしなかった場合はFALSE、それ以外はTRUE
36   */
37 static bool process_wall(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx, bool can_cross)
38 {
39         monster_race *r_ptr = &r_info[m_ptr->r_idx];
40         grid_type *g_ptr;
41         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
42         feature_type *f_ptr;
43         f_ptr = &f_info[g_ptr->feat];
44         if (player_bold(target_ptr, ny, nx))
45         {
46                 turn_flags_ptr->do_move = TRUE;
47                 return TRUE;
48         }
49
50         if (g_ptr->m_idx > 0)
51         {
52                 turn_flags_ptr->do_move = TRUE;
53                 return TRUE;
54         }
55
56         if (((r_ptr->flags2 & RF2_KILL_WALL) != 0) &&
57                 (can_cross ? !have_flag(f_ptr->flags, FF_LOS) : !turn_flags_ptr->is_riding_mon) &&
58                 have_flag(f_ptr->flags, FF_HURT_DISI) && !have_flag(f_ptr->flags, FF_PERMANENT) &&
59                 check_hp_for_feat_destruction(f_ptr, m_ptr))
60         {
61                 turn_flags_ptr->do_move = TRUE;
62                 if (!can_cross) turn_flags_ptr->must_alter_to_move = TRUE;
63
64                 turn_flags_ptr->did_kill_wall = TRUE;
65                 return TRUE;
66         }
67
68         if (!can_cross) return FALSE;
69
70         turn_flags_ptr->do_move = TRUE;
71         if (((r_ptr->flags2 & RF2_PASS_WALL) != 0) && (!turn_flags_ptr->is_riding_mon || target_ptr->pass_wall) &&
72                 have_flag(f_ptr->flags, FF_CAN_PASS))
73         {
74                 turn_flags_ptr->did_pass_wall = TRUE;
75         }
76
77         return TRUE;
78 }
79
80
81 /*!
82  * @brief モンスターが普通のドアを開ける処理
83  * @param target_ptr プレーヤーへの参照ポインタ
84  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
85  * @param m_ptr モンスターへの参照ポインタ
86  * @param ny モンスターのY座標
87  * @param nx モンスターのX座標
88  * @return ここではドアを開けず、ガラスのドアを開ける可能性があるならTRUE
89  */
90 static bool bash_normal_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
91 {
92         monster_race *r_ptr = &r_info[m_ptr->r_idx];
93         grid_type *g_ptr;
94         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
95         feature_type *f_ptr;
96         f_ptr = &f_info[g_ptr->feat];
97         turn_flags_ptr->do_move = FALSE;
98         if (((r_ptr->flags2 & RF2_OPEN_DOOR) == 0) || !have_flag(f_ptr->flags, FF_OPEN) ||
99                 (is_pet(m_ptr) && ((target_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0)))
100                 return TRUE;
101
102         if (f_ptr->power == 0)
103         {
104                 turn_flags_ptr->did_open_door = TRUE;
105                 turn_flags_ptr->do_turn = TRUE;
106                 return FALSE;
107         }
108
109         if (randint0(m_ptr->hp / 10) > f_ptr->power)
110         {
111                 cave_alter_feat(target_ptr, ny, nx, FF_DISARM);
112                 turn_flags_ptr->do_turn = TRUE;
113                 return FALSE;
114         }
115
116         return TRUE;
117 }
118
119
120 /*!
121  * @brief モンスターがガラスのドアを開ける処理
122  * @param target_ptr プレーヤーへの参照ポインタ
123  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
124  * @param m_ptr モンスターへの参照ポインタ
125  * @param g_ptr グリッドへの参照ポインタ
126  * @param f_ptr 地形への参照ポインタ
127  * @return なし
128  */
129 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)
130 {
131         monster_race *r_ptr = &r_info[m_ptr->r_idx];
132         if (!may_bash || ((r_ptr->flags2 & RF2_BASH_DOOR) == 0) || !have_flag(f_ptr->flags, FF_BASH) ||
133                 (is_pet(m_ptr) && ((target_ptr->pet_extra_flags & PF_OPEN_DOORS) == 0)))
134                 return;
135
136         if (!check_hp_for_feat_destruction(f_ptr, m_ptr) || (randint0(m_ptr->hp / 10) <= f_ptr->power))
137                 return;
138
139         if (have_flag(f_ptr->flags, FF_GLASS))
140                 msg_print(_("ガラスが砕ける音がした!", "You hear glass breaking!"));
141         else
142                 msg_print(_("ドアを叩き開ける音がした!", "You hear a door burst open!"));
143
144         if (disturb_minor) disturb(target_ptr, FALSE, FALSE);
145
146         turn_flags_ptr->did_bash_door = TRUE;
147         turn_flags_ptr->do_move = TRUE;
148         turn_flags_ptr->must_alter_to_move = TRUE;
149 }
150
151
152 /*!
153  * @brief モンスターによるドアの開放・破壊を行う
154  * @param target_ptr プレーヤーへの参照ポインタ
155  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
156  * @param m_ptr モンスターへの参照ポインタ
157  * @param ny モンスターのY座標
158  * @param nx モンスターのX座標
159  * @return モンスターが死亡した場合のみFALSE
160  */
161 static bool process_door(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
162 {
163         monster_race *r_ptr = &r_info[m_ptr->r_idx];
164         grid_type *g_ptr;
165         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
166         if (!is_closed_door(target_ptr, g_ptr->feat)) return TRUE;
167
168         feature_type *f_ptr;
169         f_ptr = &f_info[g_ptr->feat];
170         bool may_bash = bash_normal_door(target_ptr, turn_flags_ptr, m_ptr, ny, nx);
171         bash_glass_door(target_ptr, turn_flags_ptr, m_ptr, f_ptr, may_bash);
172
173         if (!turn_flags_ptr->did_open_door && !turn_flags_ptr->did_bash_door) return TRUE;
174
175         if (turn_flags_ptr->did_bash_door &&
176                 ((randint0(100) < 50) || (feat_state(target_ptr, g_ptr->feat, FF_OPEN) == g_ptr->feat) || have_flag(f_ptr->flags, FF_GLASS)))
177         {
178                 cave_alter_feat(target_ptr, ny, nx, FF_BASH);
179                 if (!monster_is_valid(m_ptr))
180                 {
181                         target_ptr->update |= (PU_FLOW);
182                         target_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
183                         if (is_original_ap_and_seen(target_ptr, m_ptr)) r_ptr->r_flags2 |= (RF2_BASH_DOOR);
184
185                         return FALSE;
186                 }
187         }
188         else
189         {
190                 cave_alter_feat(target_ptr, ny, nx, FF_OPEN);
191         }
192
193         f_ptr = &f_info[g_ptr->feat];
194         turn_flags_ptr->do_view = TRUE;
195         return TRUE;
196 }
197
198
199 /*!
200  * @brief 守りのルーンによるモンスターの移動制限を処理する
201  * @param target_ptr プレーヤーへの参照ポインタ
202  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
203  * @param m_ptr モンスターへの参照ポインタ
204  * @param ny モンスターのY座標
205  * @param nx モンスターのX座標
206  * @return ルーンのある/なし
207  */
208 static bool process_protection_rune(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
209 {
210         grid_type *g_ptr;
211         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
212         monster_race *r_ptr = &r_info[m_ptr->r_idx];
213         if (!turn_flags_ptr->do_move || !is_glyph_grid(g_ptr) ||
214                 (((r_ptr->flags1 & RF1_NEVER_BLOW) != 0) && player_bold(target_ptr, ny, nx)))
215                 return FALSE;
216
217         turn_flags_ptr->do_move = FALSE;
218         if (is_pet(m_ptr) || (randint1(BREAK_GLYPH) >= r_ptr->level))
219                 return TRUE;
220
221         if (g_ptr->info & CAVE_MARK)
222         {
223                 msg_print(_("守りのルーンが壊れた!", "The rune of protection is broken!"));
224         }
225
226         g_ptr->info &= ~(CAVE_MARK);
227         g_ptr->info &= ~(CAVE_OBJECT);
228         g_ptr->mimic = 0;
229         turn_flags_ptr->do_move = TRUE;
230         note_spot(target_ptr, ny, nx);
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 モンスターが死亡した場合のみFALSE
243  */
244 static bool process_explosive_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_explosive_rune_grid(g_ptr) ||
250                 (((r_ptr->flags1 & RF1_NEVER_BLOW) != 0) && player_bold(target_ptr, ny, nx)))
251                 return TRUE;
252
253         turn_flags_ptr->do_move = FALSE;
254         if (is_pet(m_ptr)) return TRUE;
255
256         if (randint1(BREAK_MINOR_GLYPH) > r_ptr->level)
257         {
258                 if (g_ptr->info & CAVE_MARK)
259                 {
260                         msg_print(_("ルーンが爆発した!", "The rune explodes!"));
261                         BIT_FLAGS project_flags = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI;
262                         project(target_ptr, 0, 2, ny, nx, 2 * (target_ptr->lev + damroll(7, 7)), GF_MANA, project_flags, -1);
263                 }
264         }
265         else
266         {
267                 msg_print(_("爆発のルーンは解除された。", "An explosive rune was disarmed."));
268         }
269
270         g_ptr->info &= ~(CAVE_MARK);
271         g_ptr->info &= ~(CAVE_OBJECT);
272         g_ptr->mimic = 0;
273
274         note_spot(target_ptr, ny, nx);
275         lite_spot(target_ptr, ny, nx);
276
277         if (!monster_is_valid(m_ptr)) return FALSE;
278
279         turn_flags_ptr->do_move = TRUE;
280         return TRUE;
281 }
282
283
284 /*!
285  * @brief モンスターが壁を掘った後続処理を実行する
286  * @param target_ptr プレーヤーへの参照ポインタ
287  * @turn_flags_ptr ターン経過処理フラグへの参照ポインタ
288  * @param m_ptr モンスターへの参照ポインタ
289  * @param ny モンスターのY座標
290  * @param nx モンスターのX座標
291  * @return モンスターが死亡した場合のみFALSE
292  */
293 static bool process_post_dig_wall(player_type *target_ptr, turn_flags *turn_flags_ptr, monster_type *m_ptr, POSITION ny, POSITION nx)
294 {
295         monster_race *r_ptr = &r_info[m_ptr->r_idx];
296         grid_type *g_ptr;
297         g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
298         feature_type *f_ptr;
299         f_ptr = &f_info[g_ptr->feat];
300         if (!turn_flags_ptr->did_kill_wall || !turn_flags_ptr->do_move) return TRUE;
301
302         if (one_in_(GRINDNOISE))
303         {
304                 if (have_flag(f_ptr->flags, FF_GLASS))
305                         msg_print(_("何かの砕ける音が聞こえる。", "There is a crashing sound."));
306                 else
307                         msg_print(_("ギシギシいう音が聞こえる。", "There is a grinding sound."));
308         }
309
310         cave_alter_feat(target_ptr, ny, nx, FF_HURT_DISI);
311
312         if (!monster_is_valid(m_ptr))
313         {
314                 target_ptr->update |= (PU_FLOW);
315                 target_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
316                 if (is_original_ap_and_seen(target_ptr, m_ptr)) r_ptr->r_flags2 |= (RF2_KILL_WALL);
317
318                 return FALSE;
319         }
320
321         f_ptr = &f_info[g_ptr->feat];
322         turn_flags_ptr->do_view = TRUE;
323         turn_flags_ptr->do_turn = TRUE;
324         return TRUE;
325 }
326
327
328 /*!
329  * todo 少し長いが、これといってブロックとしてまとまった部分もないので暫定でこのままとする
330  * @brief モンスターの移動に関するメインルーチン
331  * @param target_ptr プレーヤーへの参照ポインタ
332  * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
333  * @param m_idx モンスターID
334  * @param mm モンスターの移動方向
335  * @param oy 移動前の、モンスターのY座標
336  * @param ox 移動前の、モンスターのX座標
337  * @param count 移動回数 (のはず todo)
338  * @return 移動が阻害される何か (ドア等)があったらFALSE
339  */
340 bool process_monster_movement(player_type *target_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, DIRECTION *mm, POSITION oy, POSITION ox, int *count)
341 {
342         for (int i = 0; mm[i]; i++)
343         {
344                 int d = mm[i];
345                 if (d == 5) d = ddd[randint0(8)];
346
347                 POSITION ny = oy + ddy[d];
348                 POSITION nx = ox + ddx[d];
349                 if (!in_bounds2(target_ptr->current_floor_ptr, ny, nx)) continue;
350
351                 grid_type *g_ptr;
352                 g_ptr = &target_ptr->current_floor_ptr->grid_array[ny][nx];
353                 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
354                 monster_race *r_ptr = &r_info[m_ptr->r_idx];
355                 bool can_cross = monster_can_cross_terrain(target_ptr, g_ptr->feat, r_ptr, turn_flags_ptr->is_riding_mon ? CEM_RIDING : 0);
356
357                 if (!process_wall(target_ptr, turn_flags_ptr, m_ptr, ny, nx, can_cross))
358                 {
359                         if (!process_door(target_ptr, turn_flags_ptr, m_ptr, ny, nx))
360                                 return FALSE;
361                 }
362
363                 if (!process_protection_rune(target_ptr, turn_flags_ptr, m_ptr, ny, nx))
364                 {
365                         if (!process_explosive_rune(target_ptr, turn_flags_ptr, m_ptr, ny, nx))
366                                 return FALSE;
367                 }
368
369                 exe_monster_attack_to_player(target_ptr, turn_flags_ptr, m_idx, ny, nx);
370                 if (process_monster_attack_to_monster(target_ptr, turn_flags_ptr, m_idx, g_ptr, can_cross)) return FALSE;
371
372                 if (turn_flags_ptr->is_riding_mon)
373                 {
374                         if (!target_ptr->riding_ryoute && !MON_MONFEAR(&target_ptr->current_floor_ptr->m_list[target_ptr->riding])) turn_flags_ptr->do_move = FALSE;
375                 }
376
377                 if (!process_post_dig_wall(target_ptr, turn_flags_ptr, m_ptr, ny, nx)) return FALSE;
378
379                 if (turn_flags_ptr->must_alter_to_move && (r_ptr->flags7 & RF7_AQUATIC))
380                 {
381                         if (!monster_can_cross_terrain(target_ptr, g_ptr->feat, r_ptr, turn_flags_ptr->is_riding_mon ? CEM_RIDING : 0))
382                                 turn_flags_ptr->do_move = FALSE;
383                 }
384
385                 if (turn_flags_ptr->do_move && !can_cross && !turn_flags_ptr->did_kill_wall && !turn_flags_ptr->did_bash_door)
386                         turn_flags_ptr->do_move = FALSE;
387
388                 if (turn_flags_ptr->do_move && (r_ptr->flags1 & RF1_NEVER_MOVE))
389                 {
390                         if (is_original_ap_and_seen(target_ptr, m_ptr))
391                                 r_ptr->r_flags1 |= (RF1_NEVER_MOVE);
392
393                         turn_flags_ptr->do_move = FALSE;
394                 }
395
396                 if (!turn_flags_ptr->do_move)
397                 {
398                         if (turn_flags_ptr->do_turn) break;
399
400                         continue;
401                 }
402
403                 turn_flags_ptr->do_turn = TRUE;
404                 feature_type *f_ptr;
405                 f_ptr = &f_info[g_ptr->feat];
406                 if (have_flag(f_ptr->flags, FF_TREE))
407                 {
408                         if (!(r_ptr->flags7 & RF7_CAN_FLY) && !(r_ptr->flags8 & RF8_WILD_WOOD))
409                         {
410                                 m_ptr->energy_need += ENERGY_NEED();
411                         }
412                 }
413
414                 if (!update_riding_monster(target_ptr, turn_flags_ptr, m_idx, oy, ox, ny, nx)) break;
415
416                 monster_race *ap_r_ptr = &r_info[m_ptr->ap_r_idx];
417                 if (m_ptr->ml &&
418                         (disturb_move ||
419                         (disturb_near && (m_ptr->mflag & MFLAG_VIEW) && projectable(target_ptr, target_ptr->y, target_ptr->x, m_ptr->fy, m_ptr->fx)) ||
420                                 (disturb_high && ap_r_ptr->r_tkills && ap_r_ptr->level >= target_ptr->lev)))
421                 {
422                         if (is_hostile(m_ptr))
423                                 disturb(target_ptr, FALSE, TRUE);
424                 }
425
426                 bool is_takable_or_killable = g_ptr->o_idx > 0;
427                 is_takable_or_killable &= (r_ptr->flags2 & (RF2_TAKE_ITEM | RF2_KILL_ITEM)) != 0;
428
429                 bool is_pickup_items = (target_ptr->pet_extra_flags & PF_PICKUP_ITEMS) != 0;
430                 is_pickup_items &= (r_ptr->flags2 & RF2_TAKE_ITEM) != 0;
431
432                 is_takable_or_killable &= !is_pet(m_ptr) || is_pickup_items;
433                 if (!is_takable_or_killable)
434                 {
435                         if (turn_flags_ptr->do_turn) break;
436
437                         continue;
438                 }
439
440                 update_object_by_monster_movement(target_ptr, turn_flags_ptr, m_idx, ny, nx);
441                 if (turn_flags_ptr->do_turn) break;
442
443                 (*count)++;
444         }
445
446         return TRUE;
447 }
448
449
450 /*!
451  * @brief モンスターを喋らせたり足音を立てたりする
452  * @param target_ptr プレーヤーへの参照ポインタ
453  * @param m_idx モンスターID
454  * @param oy モンスターが元々いたY座標
455  * @param ox モンスターが元々いたX座標
456  * @param aware モンスターがプレーヤーに気付いているならばTRUE、超隠密状態ならばFALSE
457  * @return なし
458  */
459 void process_speak_sound(player_type *target_ptr, MONSTER_IDX m_idx, POSITION oy, POSITION ox, bool aware)
460 {
461         if (target_ptr->phase_out) return;
462
463         monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
464         monster_race *ap_r_ptr = &r_info[m_ptr->ap_r_idx];
465         if (m_ptr->ap_r_idx == MON_CYBER &&
466                 one_in_(CYBERNOISE) &&
467                 !m_ptr->ml && (m_ptr->cdis <= MAX_SIGHT))
468         {
469                 if (disturb_minor) disturb(target_ptr, FALSE, FALSE);
470                 msg_print(_("重厚な足音が聞こえた。", "You hear heavy steps."));
471         }
472
473         if (((ap_r_ptr->flags2 & RF2_CAN_SPEAK) == 0) || !aware ||
474                 !one_in_(SPEAK_CHANCE) ||
475                 !player_has_los_bold(target_ptr, oy, ox) ||
476                 !projectable(target_ptr, oy, ox, target_ptr->y, target_ptr->x))
477                 return;
478
479         GAME_TEXT m_name[MAX_NLEN];
480         char monmessage[1024];
481         concptr filename;
482
483         if (m_ptr->ml)
484                 monster_desc(target_ptr, m_name, m_ptr, 0);
485         else
486                 strcpy(m_name, _("それ", "It"));
487
488         if (MON_MONFEAR(m_ptr))
489                 filename = _("monfear_j.txt", "monfear.txt");
490         else if (is_pet(m_ptr))
491                 filename = _("monpet_j.txt", "monpet.txt");
492         else if (is_friendly(m_ptr))
493                 filename = _("monfrien_j.txt", "monfrien.txt");
494         else
495                 filename = _("monspeak_j.txt", "monspeak.txt");
496
497         if (get_rnd_line(filename, m_ptr->ap_r_idx, monmessage) == 0)
498         {
499                 msg_format(_("%^s%s", "%^s %s"), m_name, monmessage);
500         }
501 }