2 * @brief モンスター同士の打撃後処理 / Melee post-process.
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
13 #include "melee/melee-postprocess.h"
14 #include "core/disturbance.h"
15 #include "core/player-redraw-types.h"
16 #include "effect/attribute-types.h"
17 #include "floor/cave.h"
18 #include "floor/geometry.h"
19 #include "grid/grid.h"
20 #include "main/sound-definitions-table.h"
21 #include "main/sound-of-music.h"
22 #include "monster-attack/monster-attack-table.h"
23 #include "monster-floor/monster-death.h"
24 #include "monster-floor/monster-move.h"
25 #include "monster-floor/monster-remover.h"
26 #include "monster-race/monster-race-hook.h"
27 #include "monster-race/monster-race.h"
28 #include "monster-race/race-flags-resistance.h"
29 #include "monster-race/race-flags1.h"
30 #include "monster-race/race-flags3.h"
31 #include "monster-race/race-flags7.h"
32 #include "monster/monster-describer.h"
33 #include "monster/monster-description-types.h"
34 #include "monster/monster-info.h"
35 #include "monster/monster-status-setter.h"
36 #include "monster/monster-status.h"
37 #include "pet/pet-fall-off.h"
38 #include "player-info/class-info.h"
39 #include "player-info/race-types.h"
40 #include "player/player-personality-types.h"
41 #include "system/floor-type-definition.h"
42 #include "system/monster-entity.h"
43 #include "system/monster-race-info.h"
44 #include "system/player-type-definition.h"
45 #include "util/bit-flags-calculator.h"
46 #include "util/string-processor.h"
47 #include "view/display-messages.h"
49 // Melee-post-process-type
54 GAME_TEXT m_name[160];
56 bool known; /* Can the player be aware of this attack? */
63 mam_pp_type *initialize_mam_pp_type(
64 PlayerType *player_ptr, mam_pp_type *mam_pp_ptr, MONSTER_IDX m_idx, int dam, bool *dead, bool *fear, concptr note, MONSTER_IDX who)
66 mam_pp_ptr->m_idx = m_idx;
67 mam_pp_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
68 mam_pp_ptr->seen = is_seen(player_ptr, mam_pp_ptr->m_ptr);
69 mam_pp_ptr->dam = dam;
70 mam_pp_ptr->known = mam_pp_ptr->m_ptr->cdis <= MAX_PLAYER_SIGHT;
71 mam_pp_ptr->dead = dead;
72 mam_pp_ptr->fear = fear;
73 mam_pp_ptr->note = note;
74 mam_pp_ptr->who = who;
78 static void prepare_redraw(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
80 if (!mam_pp_ptr->m_ptr->ml) {
84 if (player_ptr->health_who == mam_pp_ptr->m_idx) {
85 player_ptr->redraw |= (PR_HEALTH);
88 if (player_ptr->riding == mam_pp_ptr->m_idx) {
89 player_ptr->redraw |= (PR_UHEALTH);
94 * @brief モンスターが無敵だった場合の処理
95 * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
96 * @return 無敵ノーダメならTRUE、無敵でないか無敵を貫通したらFALSE
98 static bool process_invulnerability(mam_pp_type *mam_pp_ptr)
100 if (mam_pp_ptr->m_ptr->is_invulnerable() && randint0(PENETRATE_INVULNERABILITY)) {
104 if (mam_pp_ptr->seen) {
105 msg_format(_("%s^はダメージを受けない。", "%s^ is unharmed."), mam_pp_ptr->m_name);
113 * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
114 * @return ノーダメならTRUE、 そうでないならFALSE
116 static bool process_all_resistances(mam_pp_type *mam_pp_ptr)
118 auto *r_ptr = &monraces_info[mam_pp_ptr->m_ptr->r_idx];
119 if (r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_ALL)) {
123 if (mam_pp_ptr->dam > 0) {
124 mam_pp_ptr->dam /= 100;
125 if ((mam_pp_ptr->dam == 0) && one_in_(3)) {
130 if (mam_pp_ptr->dam != 0) {
134 if (mam_pp_ptr->seen) {
135 msg_format(_("%s^はダメージを受けない。", "%s^ is unharmed."), mam_pp_ptr->m_name);
142 * @brief モンスター死亡時のメッセージ表示
143 * @param player_ptr プレイヤーへの参照ポインタ
144 * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
147 * 爆発して粉々になった等ならその旨を、残りは生命か無生命かで分岐
149 static void print_monster_dead_by_monster(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
151 if (!mam_pp_ptr->known) {
155 angband_strcpy(mam_pp_ptr->m_name, monster_desc(player_ptr, mam_pp_ptr->m_ptr, MD_TRUE_NAME).data(), sizeof(mam_pp_ptr->m_name));
156 if (!mam_pp_ptr->seen) {
157 player_ptr->current_floor_ptr->monster_noise = true;
161 if (mam_pp_ptr->note) {
162 sound_type kill_sound = monster_living(mam_pp_ptr->m_ptr->r_idx) ? SOUND_KILL : SOUND_N_KILL;
164 msg_format(_("%s^%s", "%s^%s"), mam_pp_ptr->m_name, mam_pp_ptr->note);
168 if (!monster_living(mam_pp_ptr->m_ptr->r_idx)) {
170 msg_format(_("%s^は破壊された。", "%s^ is destroyed."), mam_pp_ptr->m_name);
175 msg_format(_("%s^は殺された。", "%s^ is killed."), mam_pp_ptr->m_name);
179 * @brief ダメージを受けたモンスターのHPが0未満になった際の処理
180 * @param player_ptr プレイヤーへの参照ポインタ
181 * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
182 * @return 生きていたらTRUE、それ以外 (ユニークは@以外の攻撃では死なない)はFALSE
184 static bool check_monster_hp(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
186 auto *r_ptr = &monraces_info[mam_pp_ptr->m_ptr->r_idx];
187 if (mam_pp_ptr->m_ptr->hp < 0) {
191 auto is_like_unique = r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
192 is_like_unique |= any_bits(r_ptr->flags1, RF1_QUESTOR);
193 is_like_unique |= r_ptr->population_flags.has(MonsterPopulationType::NAZGUL);
194 if (is_like_unique && !player_ptr->phase_out) {
195 mam_pp_ptr->m_ptr->hp = 1;
199 *(mam_pp_ptr->dead) = true;
200 print_monster_dead_by_monster(player_ptr, mam_pp_ptr);
201 monster_gain_exp(player_ptr, mam_pp_ptr->who, mam_pp_ptr->m_ptr->r_idx);
202 monster_death(player_ptr, mam_pp_ptr->m_idx, false, AttributeType::NONE);
203 delete_monster_idx(player_ptr, mam_pp_ptr->m_idx);
204 *(mam_pp_ptr->fear) = false;
209 * @brief 死亡等で恐慌状態をキャンセルする
210 * @param player_ptr プレイヤーへの参照ポインタ
211 * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
213 static void cancel_fear_by_pain(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
215 const auto &m_ref = *mam_pp_ptr->m_ptr;
216 const auto dam = mam_pp_ptr->dam;
217 if (!m_ref.is_fearful() || (dam <= 0) || !set_monster_monfear(player_ptr, mam_pp_ptr->m_idx, m_ref.get_remaining_fear() - randint1(dam / 4))) {
221 *(mam_pp_ptr->fear) = false;
225 * @biref HP残量などに応じてモンスターを恐慌状態にする
226 * @param player_ptr プレイヤーへの参照ポインタ
227 * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
229 static void make_monster_fear(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
231 auto *r_ptr = &monraces_info[mam_pp_ptr->m_ptr->r_idx];
232 if (mam_pp_ptr->m_ptr->is_fearful() || ((r_ptr->flags3 & RF3_NO_FEAR) == 0)) {
236 int percentage = (100L * mam_pp_ptr->m_ptr->hp) / mam_pp_ptr->m_ptr->maxhp;
237 bool can_make_fear = ((percentage <= 10) && (randint0(10) < percentage)) || ((mam_pp_ptr->dam >= mam_pp_ptr->m_ptr->hp) && (randint0(100) < 80));
238 if (!can_make_fear) {
242 *(mam_pp_ptr->fear) = true;
243 (void)set_monster_monfear(
244 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))));
248 * @brief モンスター同士の乱闘による落馬処理
249 * @param player_ptr プレイヤーへの参照ポインタ
250 * @param mam_pp_ptr 標的モンスター構造体への参照ポインタ
252 static void fall_off_horse_by_melee(PlayerType *player_ptr, mam_pp_type *mam_pp_ptr)
254 if (!player_ptr->riding || (player_ptr->riding != mam_pp_ptr->m_idx) || (mam_pp_ptr->dam <= 0)) {
258 angband_strcpy(mam_pp_ptr->m_name, monster_desc(player_ptr, mam_pp_ptr->m_ptr, 0).data(), sizeof(mam_pp_ptr->m_name));
259 if (mam_pp_ptr->m_ptr->hp > mam_pp_ptr->m_ptr->maxhp / 3) {
260 mam_pp_ptr->dam = (mam_pp_ptr->dam + 1) / 2;
263 if (process_fall_off_horse(player_ptr, (mam_pp_ptr->dam > 200) ? 200 : mam_pp_ptr->dam, false)) {
264 msg_format(_("%s^に振り落とされた!", "You have been thrown off from %s!"), mam_pp_ptr->m_name);
269 * @brief モンスターが敵モンスターに行う打撃処理 /
270 * Hack, based on mon_take_hit... perhaps all monster attacks on other monsters should use this?
271 * @param m_idx 目標となるモンスターの参照ID
273 * @param dead 目標となったモンスターの死亡状態を返す参照ポインタ
274 * @param fear 目標となったモンスターの恐慌状態を返す参照ポインタ
275 * @param note 目標モンスターが死亡した場合の特別メッセージ(nullptrならば標準表示を行う)
276 * @param who 打撃を行ったモンスターの参照ID
277 * @todo 打撃が当たった時の後処理 (爆発持ちのモンスターを爆発させる等)なので、関数名を変更する必要あり
279 void mon_take_hit_mon(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *dead, bool *fear, concptr note, MONSTER_IDX who)
281 auto *floor_ptr = player_ptr->current_floor_ptr;
282 auto *m_ptr = &floor_ptr->m_list[m_idx];
283 mam_pp_type tmp_mam_pp;
284 mam_pp_type *mam_pp_ptr = initialize_mam_pp_type(player_ptr, &tmp_mam_pp, m_idx, dam, dead, fear, note, who);
285 angband_strcpy(mam_pp_ptr->m_name, monster_desc(player_ptr, m_ptr, 0).data(), sizeof(mam_pp_ptr->m_name));
286 prepare_redraw(player_ptr, mam_pp_ptr);
287 (void)set_monster_csleep(player_ptr, m_idx, 0);
289 if (player_ptr->riding && (m_idx == player_ptr->riding)) {
290 disturb(player_ptr, true, true);
293 if (process_invulnerability(mam_pp_ptr) || process_all_resistances(mam_pp_ptr)) {
298 if (check_monster_hp(player_ptr, mam_pp_ptr)) {
303 cancel_fear_by_pain(player_ptr, mam_pp_ptr);
304 make_monster_fear(player_ptr, mam_pp_ptr);
305 if ((dam > 0) && !m_ptr->is_pet() && !m_ptr->is_friendly() && (mam_pp_ptr->who != m_idx)) {
306 const auto &m_ref = floor_ptr->m_list[who];
307 if (m_ref.is_pet() && !player_bold(player_ptr, m_ptr->target_y, m_ptr->target_x)) {
308 set_target(m_ptr, m_ref.fy, m_ref.fx);
312 fall_off_horse_by_melee(player_ptr, mam_pp_ptr);