OSDN Git Service

[Refactor] #40030 Separated monster-runaway.c/h from monster-process.c
[hengband/hengband.git] / src / monster / monster-attack.c
1 /*!
2  * @brief モンスターの攻撃に関する処理
3  * @date 2020/03/08
4  * @author Hourier
5  */
6
7 #include "monster/monster-attack.h"
8 #include "monster-status.h"
9 #include "dungeon.h"
10 #include "combat/melee.h" // 暫定。後で引っ越し.
11
12  /*!
13   * @brief モンスターが移動した結果、そこにプレーヤーがいたら直接攻撃を行う
14   * @param target_ptr プレーヤーへの参照ポインタ
15   * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
16   * @param m_idx モンスターID
17   * @param ny 移動後の、モンスターのY座標
18   * @param nx 移動後の、モンスターのX座標
19   * @return なし
20   * @details
21   * 反攻撃の洞窟など、直接攻撃ができない場所では処理をスキップする
22   */
23 void exe_monster_attack_to_player(player_type *target_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, POSITION ny, POSITION nx)
24 {
25         monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
26         monster_race *r_ptr = &r_info[m_ptr->r_idx];
27         if (!turn_flags_ptr->do_move || !player_bold(target_ptr, ny, nx))
28                 return;
29
30         if (r_ptr->flags1 & RF1_NEVER_BLOW)
31         {
32                 if (is_original_ap_and_seen(target_ptr, m_ptr))
33                         r_ptr->r_flags1 |= (RF1_NEVER_BLOW);
34
35                 turn_flags_ptr->do_move = FALSE;
36         }
37
38         if (turn_flags_ptr->do_move && ((d_info[target_ptr->dungeon_idx].flags1 & DF1_NO_MELEE) != 0) && !MON_CONFUSED(m_ptr))
39         {
40                 if (!(r_ptr->flags2 & RF2_STUPID))
41                         turn_flags_ptr->do_move = FALSE;
42                 else if (is_original_ap_and_seen(target_ptr, m_ptr))
43                         r_ptr->r_flags2 |= (RF2_STUPID);
44         }
45
46         if (!turn_flags_ptr->do_move) return;
47
48         if (!target_ptr->riding || one_in_(2))
49         {
50                 (void)make_attack_normal(target_ptr, m_idx);
51                 turn_flags_ptr->do_move = FALSE;
52                 turn_flags_ptr->do_turn = TRUE;
53         }
54 }
55
56
57 /*!
58  * @brief モンスターからモンスターへの直接攻撃を実行する
59  * @param target_ptr プレーヤーへの参照ポインタ
60  * @param m_idx モンスターID
61  * @param g_ptr グリッドへの参照ポインタ
62  */
63 static bool exe_monster_attack_to_monster(player_type *target_ptr, MONSTER_IDX m_idx, grid_type *g_ptr)
64 {
65         monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
66         monster_race *r_ptr = &r_info[m_ptr->r_idx];
67         monster_type *y_ptr;
68         y_ptr = &target_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
69         if ((r_ptr->flags1 & RF1_NEVER_BLOW) != 0) return FALSE;
70
71         if (((r_ptr->flags2 & RF2_KILL_BODY) == 0) && is_original_ap_and_seen(target_ptr, m_ptr))
72                 r_ptr->r_flags2 |= (RF2_KILL_BODY);
73
74         if ((y_ptr->r_idx == 0) || (y_ptr->hp < 0)) return FALSE;
75         if (monst_attack_monst(target_ptr, m_idx, g_ptr->m_idx)) return TRUE;
76         if ((d_info[target_ptr->dungeon_idx].flags1 & DF1_NO_MELEE) == 0) return FALSE;
77         if (MON_CONFUSED(m_ptr)) return TRUE;
78         if ((r_ptr->flags2 & RF2_STUPID) == 0) return FALSE;
79
80         if (is_original_ap_and_seen(target_ptr, m_ptr))
81                 r_ptr->r_flags2 |= (RF2_STUPID);
82
83         return TRUE;
84 }
85
86
87 /*!
88   * @brief モンスターからモンスターへの攻撃処理
89   * @param target_ptr プレーヤーへの参照ポインタ
90   * @param turn_flags_ptr ターン経過処理フラグへの参照ポインタ
91   * @param m_idx モンスターID
92   * @param g_ptr グリッドへの参照ポインタ
93   * @param can_cross モンスターが地形を踏破できるならばTRUE
94   * @return ターン消費が発生したらTRUE
95   */
96 bool process_monster_attack_to_monster(player_type *target_ptr, turn_flags *turn_flags_ptr, MONSTER_IDX m_idx, grid_type *g_ptr, bool can_cross)
97 {
98         monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
99         monster_race *r_ptr = &r_info[m_ptr->r_idx];
100         monster_type *y_ptr;
101         y_ptr = &target_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
102         if (!turn_flags_ptr->do_move || (g_ptr->m_idx == 0)) return FALSE;
103
104         monster_race *z_ptr = &r_info[y_ptr->r_idx];
105         turn_flags_ptr->do_move = FALSE;
106         if ((((r_ptr->flags2 & RF2_KILL_BODY) != 0) && ((r_ptr->flags1 & RF1_NEVER_BLOW) == 0) &&
107                 (r_ptr->mexp * r_ptr->level > z_ptr->mexp * z_ptr->level) &&
108                 can_cross && (g_ptr->m_idx != target_ptr->riding)) ||
109                 are_enemies(target_ptr, m_ptr, y_ptr) || MON_CONFUSED(m_ptr))
110         {
111                 return exe_monster_attack_to_monster(target_ptr, m_idx, g_ptr);
112         }
113
114         if (((r_ptr->flags2 & RF2_MOVE_BODY) != 0) && ((r_ptr->flags1 & RF1_NEVER_MOVE) == 0) &&
115                 (r_ptr->mexp > z_ptr->mexp) &&
116                 can_cross && (g_ptr->m_idx != target_ptr->riding) &&
117                 monster_can_cross_terrain(target_ptr, target_ptr->current_floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, z_ptr, 0))
118         {
119                 turn_flags_ptr->do_move = TRUE;
120                 turn_flags_ptr->did_move_body = TRUE;
121                 (void)set_monster_csleep(target_ptr, g_ptr->m_idx, 0);
122         }
123
124         return FALSE;
125 }