OSDN Git Service

[Refactor] #40413 Separated sound-of-music.c/h from util.c/h
[hengband/hengband.git] / src / melee / melee-postprocess.c
1 /*!
2  * @brief モンスター同士の打撃後処理 / Melee post-process.
3  * @date 2014/01/17
4  * @author
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n
6  * This software may be copied and distributed for educational, research,\n
7  * and not for profit purposes provided that this copyright and statement\n
8  * are included in all such copies.  Other copyrights may also apply.\n
9  * 2014 Deskull rearranged comment for Doxygen.\n
10  * @details
11  */
12
13 #include "melee/melee-postprocess.h"
14 #include "monster-attack/monster-attack-types.h"
15 #include "floor/floor.h"
16 #include "grid/grid.h"
17 #include "main/sound-definitions-table.h"
18 #include "main/sound-of-music.h"
19 #include "monster-race/race-flags-resistance.h"
20 #include "monster-race/race-flags1.h"
21 #include "monster-race/race-flags3.h"
22 #include "monster-race/race-flags7.h"
23 #include "monster-race/monster-race-hook.h"
24 #include "monster/monster-describer.h"
25 #include "monster/monster-description-types.h"
26 #include "monster-floor/monster-death.h"
27 #include "monster/monster-info.h"
28 #include "monster-floor/monster-move.h"
29 #include "monster-floor/monster-remover.h"
30 #include "monster/monster-status.h"
31 #include "mspell/monster-spell.h"
32 #include "pet/pet-fall-off.h"
33 #include "player/player-class.h"
34 #include "player/player-move.h"
35 #include "player/player-personalities-types.h"
36 #include "player/player-race-types.h"
37
38 // Melee-post-process-type
39 typedef struct mam_pp_type {
40     MONSTER_IDX m_idx;
41     monster_type *m_ptr;
42     bool seen;
43     GAME_TEXT m_name[160];
44     HIT_POINT dam;
45     bool known; /* Can the player be aware of this attack? */
46     concptr note;
47     bool *dead;
48     bool *fear;
49     MONSTER_IDX who;
50 } mam_pp_type;
51
52 mam_pp_type *initialize_mam_pp_type(
53     player_type *player_ptr, mam_pp_type *mam_pp_ptr, MONSTER_IDX m_idx, HIT_POINT dam, bool *dead, bool *fear, concptr note, MONSTER_IDX who)
54 {
55     mam_pp_ptr->m_idx = m_idx;
56     mam_pp_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
57     mam_pp_ptr->seen = is_seen(player_ptr, mam_pp_ptr->m_ptr);
58     mam_pp_ptr->dam = dam;
59     mam_pp_ptr->known = mam_pp_ptr->m_ptr->cdis <= MAX_SIGHT;
60     mam_pp_ptr->dead = dead;
61     mam_pp_ptr->fear = fear;
62     mam_pp_ptr->note = note;
63     mam_pp_ptr->who = who;
64     return mam_pp_ptr;
65 }
66
67 static void prepare_redraw(player_type *player_ptr, mam_pp_type *mam_pp_ptr)
68 {
69     if (!mam_pp_ptr->m_ptr->ml)
70         return;
71
72     if (player_ptr->health_who == mam_pp_ptr->m_idx)
73         player_ptr->redraw |= (PR_HEALTH);
74
75     if (player_ptr->riding == mam_pp_ptr->m_idx)
76         player_ptr->redraw |= (PR_UHEALTH);
77 }
78
79 /*!
80  * @brief モンスターが無敵だった場合の処理
81  * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
82  * @return 無敵ノーダメならTRUE、無敵でないか無敵を貫通したらFALSE
83  */
84 static bool process_invulnerability(mam_pp_type *mam_pp_ptr)
85 {
86     if (monster_invulner_remaining(mam_pp_ptr->m_ptr) && randint0(PENETRATE_INVULNERABILITY))
87         return FALSE;
88
89     if (mam_pp_ptr->seen)
90         msg_format(_("%^sはダメージを受けない。", "%^s is unharmed."), mam_pp_ptr->m_name);
91
92     return TRUE;
93 }
94
95 /*!
96  * @brief 魔法完全防御持ちの処理
97  * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
98  * @return ノーダメならTRUE、 そうでないならFALSE
99  */
100 static bool process_all_resistances(mam_pp_type *mam_pp_ptr)
101 {
102     monster_race *r_ptr = &r_info[mam_pp_ptr->m_ptr->r_idx];
103     if ((r_ptr->flagsr & RFR_RES_ALL) == 0)
104         return FALSE;
105
106     if (mam_pp_ptr->dam > 0) {
107         mam_pp_ptr->dam /= 100;
108         if ((mam_pp_ptr->dam == 0) && one_in_(3))
109             mam_pp_ptr->dam = 1;
110     }
111
112     if (mam_pp_ptr->dam != 0)
113         return FALSE;
114
115     if (mam_pp_ptr->seen)
116         msg_format(_("%^sはダメージを受けない。", "%^s is unharmed."), mam_pp_ptr->m_name);
117
118     return TRUE;
119 }
120
121 /*!
122  * @brief モンスター死亡時のメッセージ表示
123  * @param player_ptr プレーヤーへの参照ポインタ
124  * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
125  * @return なし
126  * @details
127  * 見えない位置で死んだら何も表示しない
128  * 爆発して粉々になった等ならその旨を、残りは生命か無生命かで分岐
129  */
130 static void print_monster_dead_by_monster(player_type *player_ptr, mam_pp_type *mam_pp_ptr)
131 {
132     if (!mam_pp_ptr->known)
133         return;
134
135     monster_desc(player_ptr, mam_pp_ptr->m_name, mam_pp_ptr->m_ptr, MD_TRUE_NAME);
136     if (!mam_pp_ptr->seen) {
137         player_ptr->current_floor_ptr->monster_noise = TRUE;
138         return;
139     }
140
141     if (mam_pp_ptr->note) {
142         msg_format(_("%^s%s", "%^s%s"), mam_pp_ptr->m_name, mam_pp_ptr->note);
143         return;
144     }
145
146     if (!monster_living(mam_pp_ptr->m_ptr->r_idx)) {
147         msg_format(_("%^sは破壊された。", "%^s is destroyed."), mam_pp_ptr->m_name);
148         return;
149     }
150
151     msg_format(_("%^sは殺された。", "%^s is killed."), mam_pp_ptr->m_name);
152 }
153
154 /*!
155  * @brief ダメージを受けたモンスターのHPが0未満になった際の処理
156  * @param player_ptr プレーヤーへの参照ポインタ
157  * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
158  * @return 生きていたらTRUE、それ以外 (ユニークは@以外の攻撃では死なない)はFALSE
159  */
160 static bool check_monster_hp(player_type *player_ptr, mam_pp_type *mam_pp_ptr)
161 {
162     monster_race *r_ptr = &r_info[mam_pp_ptr->m_ptr->r_idx];
163     if (mam_pp_ptr->m_ptr->hp < 0)
164         return FALSE;
165
166     if (((r_ptr->flags1 & (RF1_UNIQUE | RF1_QUESTOR)) || (r_ptr->flags7 & RF7_NAZGUL)) && !player_ptr->phase_out) {
167         mam_pp_ptr->m_ptr->hp = 1;
168         return FALSE;
169     }
170
171     sound_type kill_sound = monster_living(mam_pp_ptr->m_ptr->r_idx) ? SOUND_KILL : SOUND_N_KILL;
172     sound(kill_sound);
173     *(mam_pp_ptr->dead) = TRUE;
174     print_monster_dead_by_monster(player_ptr, mam_pp_ptr);
175     monster_gain_exp(player_ptr, mam_pp_ptr->who, mam_pp_ptr->m_ptr->r_idx);
176     monster_death(player_ptr, mam_pp_ptr->m_idx, FALSE);
177     delete_monster_idx(player_ptr, mam_pp_ptr->m_idx);
178     *(mam_pp_ptr->fear) = FALSE;
179     return TRUE;
180 }
181
182 /*!
183  * @brief 死亡等で恐慌状態をキャンセルする
184  * @param player_ptr プレーヤーへの参照ポインタ
185  * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
186  * @return なし
187  */
188 static void cancel_fear_by_pain(player_type *player_ptr, mam_pp_type *mam_pp_ptr)
189 {
190     if (!monster_fear_remaining(mam_pp_ptr->m_ptr) || (mam_pp_ptr->dam <= 0)
191         || !set_monster_monfear(player_ptr, mam_pp_ptr->m_idx, monster_fear_remaining(mam_pp_ptr->m_ptr) - randint1(mam_pp_ptr->dam / 4)))
192         return;
193
194     *(mam_pp_ptr->fear) = FALSE;
195 }
196
197 /*!
198  * @biref HP残量などに応じてモンスターを恐慌状態にする
199  * @param player_ptr プレーヤーへの参照ポインタ
200  * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
201  * @return なし
202  */
203 static void make_monster_fear(player_type *player_ptr, mam_pp_type *mam_pp_ptr)
204 {
205     monster_race *r_ptr = &r_info[mam_pp_ptr->m_ptr->r_idx];
206     if (monster_fear_remaining(mam_pp_ptr->m_ptr) || ((r_ptr->flags3 & RF3_NO_FEAR) == 0))
207         return;
208
209     int percentage = (100L * mam_pp_ptr->m_ptr->hp) / mam_pp_ptr->m_ptr->maxhp;
210     bool can_make_fear = ((percentage <= 10) && (randint0(10) < percentage)) || ((mam_pp_ptr->dam >= mam_pp_ptr->m_ptr->hp) && (randint0(100) < 80));
211     if (!can_make_fear)
212         return;
213
214     *(mam_pp_ptr->fear) = TRUE;
215     (void)set_monster_monfear(
216         player_ptr, mam_pp_ptr->m_idx, (randint1(10) + (((mam_pp_ptr->dam >= mam_pp_ptr->m_ptr->hp) && (percentage > 7)) ? 20 : ((11 - percentage) * 5))));
217 }
218
219 /*!
220  * @brief モンスター同士の乱闘による落馬処理
221  * @param player_ptr プレーヤーへの参照ポインタ
222  * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
223  * @return なし
224  */
225 static void fall_off_horse_by_melee(player_type *player_ptr, mam_pp_type *mam_pp_ptr)
226 {
227     if (!player_ptr->riding || (player_ptr->riding != mam_pp_ptr->m_idx) || (mam_pp_ptr->dam <= 0))
228         return;
229
230     monster_desc(player_ptr, mam_pp_ptr->m_name, mam_pp_ptr->m_ptr, 0);
231     if (mam_pp_ptr->m_ptr->hp > mam_pp_ptr->m_ptr->maxhp / 3)
232         mam_pp_ptr->dam = (mam_pp_ptr->dam + 1) / 2;
233
234     if (process_fall_off_horse(player_ptr, (mam_pp_ptr->dam > 200) ? 200 : mam_pp_ptr->dam, FALSE))
235         msg_format(_("%^sに振り落とされた!", "You have been thrown off from %s!"), mam_pp_ptr->m_name);
236 }
237
238 /*!
239  * todo 打撃が当たった時の後処理 (爆発持ちのモンスターを爆発させる等)なので、関数名を変更する必要あり
240  * @brief モンスターが敵モンスターに行う打撃処理 /
241  * Hack, based on mon_take_hit... perhaps all monster attacks on other monsters should use this?
242  * @param m_idx 目標となるモンスターの参照ID
243  * @param dam ダメージ量
244  * @param dead 目標となったモンスターの死亡状態を返す参照ポインタ
245  * @param fear 目標となったモンスターの恐慌状態を返す参照ポインタ
246  * @param note 目標モンスターが死亡した場合の特別メッセージ(NULLならば標準表示を行う)
247  * @param who 打撃を行ったモンスターの参照ID
248  * @return なし
249  */
250 void mon_take_hit_mon(player_type *player_ptr, MONSTER_IDX m_idx, HIT_POINT dam, bool *dead, bool *fear, concptr note, MONSTER_IDX who)
251 {
252     floor_type *floor_ptr = player_ptr->current_floor_ptr;
253     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
254     mam_pp_type tmp_mam_pp;
255     mam_pp_type *mam_pp_ptr = initialize_mam_pp_type(player_ptr, &tmp_mam_pp, m_idx, dam, dead, fear, note, who);
256     monster_desc(player_ptr, mam_pp_ptr->m_name, m_ptr, 0);
257     prepare_redraw(player_ptr, mam_pp_ptr);
258     (void)set_monster_csleep(player_ptr, m_idx, 0);
259
260     if (player_ptr->riding && (m_idx == player_ptr->riding))
261         disturb(player_ptr, TRUE, TRUE);
262
263     if (process_invulnerability(mam_pp_ptr) || process_all_resistances(mam_pp_ptr))
264         return;
265
266     m_ptr->hp -= dam;
267     if (check_monster_hp(player_ptr, mam_pp_ptr))
268         return;
269
270     *dead = FALSE;
271     cancel_fear_by_pain(player_ptr, mam_pp_ptr);
272     make_monster_fear(player_ptr, mam_pp_ptr);
273     if ((dam > 0) && !is_pet(m_ptr) && !is_friendly(m_ptr) && (mam_pp_ptr->who != m_idx)) {
274         if (is_pet(&floor_ptr->m_list[mam_pp_ptr->who]) && !player_bold(player_ptr, m_ptr->target_y, m_ptr->target_x)) {
275             set_target(m_ptr, floor_ptr->m_list[mam_pp_ptr->who].fy, floor_ptr->m_list[mam_pp_ptr->who].fx);
276         }
277     }
278
279     fall_off_horse_by_melee(player_ptr, mam_pp_ptr);
280 }