OSDN Git Service

[Refactor] モンスター(ペット)に名付けているか判定するメソッドを追加
[hengbandforosx/hengbandosx.git] / src / effect / effect-monster.cpp
1 /*!
2  * @brief 魔法によるモンスターへの効果まとめ
3  * @date 2020/04/29
4  * @author Hourier
5  */
6
7 #include "effect/effect-monster.h"
8 #include "avatar/avatar.h"
9 #include "core/disturbance.h"
10 #include "core/player-redraw-types.h"
11 #include "core/stuff-handler.h"
12 #include "core/window-redrawer.h"
13 #include "effect/attribute-types.h"
14 #include "effect/effect-characteristics.h"
15 #include "effect/effect-monster-switcher.h"
16 #include "effect/effect-monster-util.h"
17 #include "effect/spells-effect-util.h"
18 #include "floor/cave.h"
19 #include "floor/floor-object.h"
20 #include "game-option/play-record-options.h"
21 #include "grid/grid.h"
22 #include "io/write-diary.h"
23 #include "main/sound-definitions-table.h"
24 #include "main/sound-of-music.h"
25 #include "monster-floor/monster-death.h"
26 #include "monster-floor/monster-move.h"
27 #include "monster-floor/monster-remover.h"
28 #include "monster-race/monster-race.h"
29 #include "monster-race/race-flags-resistance.h"
30 #include "monster-race/race-flags1.h"
31 #include "monster-race/race-flags3.h"
32 #include "monster-race/race-flags7.h"
33 #include "monster-race/race-indice-types.h"
34 #include "monster-race/race-resistance-mask.h"
35 #include "monster/monster-damage.h"
36 #include "monster/monster-describer.h"
37 #include "monster/monster-description-types.h"
38 #include "monster/monster-info.h"
39 #include "monster/monster-status-setter.h"
40 #include "monster/monster-status.h"
41 #include "monster/monster-update.h"
42 #include "object-enchant/special-object-flags.h"
43 #include "object/object-kind-hook.h"
44 #include "spell-kind/blood-curse.h"
45 #include "spell-kind/spells-polymorph.h"
46 #include "spell-kind/spells-teleport.h"
47 #include "sv-definition/sv-other-types.h"
48 #include "system/baseitem-info.h"
49 #include "system/floor-type-definition.h"
50 #include "system/grid-type-definition.h"
51 #include "system/item-entity.h"
52 #include "system/monster-entity.h"
53 #include "system/monster-race-info.h"
54 #include "system/player-type-definition.h"
55 #include "util/bit-flags-calculator.h"
56 #include "util/string-processor.h"
57 #include "view/display-messages.h"
58 #include <algorithm>
59
60 /*!
61  * @brief ビーム/ボルト/ボール系魔法によるモンスターへの効果があるかないかを判定する
62  * @param player_ptr プレイヤーへの参照ポインタ
63  * @param em_ptr モンスター効果構造体への参照ポインタ
64  * @return 効果が何もないならFALSE、何かあるならTRUE
65  */
66 static ProcessResult is_affective(PlayerType *player_ptr, effect_monster_type *em_ptr)
67 {
68     if (!em_ptr->g_ptr->m_idx) {
69         return ProcessResult::PROCESS_FALSE;
70     }
71     if (em_ptr->who && (em_ptr->g_ptr->m_idx == em_ptr->who)) {
72         return ProcessResult::PROCESS_FALSE;
73     }
74     if (sukekaku && ((em_ptr->m_ptr->r_idx == MonsterRaceId::SUKE) || (em_ptr->m_ptr->r_idx == MonsterRaceId::KAKU))) {
75         return ProcessResult::PROCESS_FALSE;
76     }
77     if (em_ptr->m_ptr->hp < 0) {
78         return ProcessResult::PROCESS_FALSE;
79     }
80     if (em_ptr->who || em_ptr->g_ptr->m_idx != player_ptr->riding) {
81         return ProcessResult::PROCESS_TRUE;
82     }
83
84     switch (em_ptr->attribute) {
85     case AttributeType::OLD_HEAL:
86     case AttributeType::OLD_SPEED:
87     case AttributeType::STAR_HEAL:
88         return ProcessResult::PROCESS_TRUE;
89     case AttributeType::OLD_SLOW:
90     case AttributeType::OLD_SLEEP:
91     case AttributeType::OLD_CLONE:
92     case AttributeType::OLD_CONF:
93     case AttributeType::OLD_POLY:
94     case AttributeType::GENOCIDE:
95     case AttributeType::E_GENOCIDE:
96         return ProcessResult::PROCESS_CONTINUE;
97     default:
98         break;
99     }
100
101     return ProcessResult::PROCESS_FALSE;
102 }
103
104 /*!
105  * @brief 魔法の効果やモンスター種別(MAKE/FEMALE/なし)に応じて表示するメッセージを変更する
106  * @param player_ptr プレイヤーへの参照ポインタ
107  * @param em_ptr モンスター効果構造体への参照ポインタ
108  */
109 static void make_description_of_affecred_monster(PlayerType *player_ptr, effect_monster_type *em_ptr)
110 {
111     em_ptr->dam = (em_ptr->dam + em_ptr->r) / (em_ptr->r + 1);
112     angband_strcpy(em_ptr->m_name, monster_desc(player_ptr, em_ptr->m_ptr, 0).data(), sizeof(em_ptr->m_name));
113     angband_strcpy(em_ptr->m_poss, monster_desc(player_ptr, em_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE).data(), sizeof(em_ptr->m_poss));
114 }
115
116 /*!
117  * @brief モンスターへの効果属性による耐性及び効果を処理する( / Proccess affecting to monster by effect.
118  * @param player_ptr プレイヤーへの参照ポインタ
119  * @param em_ptr モンスター効果構造体への参照ポインタ
120  * @return 完全な耐性が発動したらCONTINUE、そうでないなら効果処理の結果
121  * @details
122  * 完全な耐性を持っていたら、一部属性を除いて影響は及ぼさない
123  * デバッグ属性、モンスター打撃、モンスター射撃であれば貫通する
124  */
125 static ProcessResult exe_affect_monster_by_effect(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
126 {
127     const std::vector<AttributeType> effect_arrtibute = {
128         AttributeType::OLD_CLONE,
129         AttributeType::STAR_HEAL,
130         AttributeType::OLD_HEAL,
131         AttributeType::OLD_SPEED,
132         AttributeType::CAPTURE,
133         AttributeType::PHOTO,
134     };
135     const auto check = [em_ptr](const AttributeType attribute) {
136         return em_ptr->attribute == attribute;
137     };
138
139     ProcessResult result = is_affective(player_ptr, em_ptr);
140     if (result != ProcessResult::PROCESS_TRUE) {
141         if (result == ProcessResult::PROCESS_CONTINUE) {
142             em_ptr->note = _("には効果がなかった。", " is unaffected.");
143             em_ptr->dam = 0;
144         }
145         return result;
146     }
147
148     bool do_effect = em_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::RESIST_ALL);
149     do_effect |= std::any_of(effect_arrtibute.cbegin(), effect_arrtibute.cend(), check);
150
151     if (do_effect) {
152         return switch_effects_monster(player_ptr, em_ptr, cap_mon_ptr);
153     }
154
155     bool ignore_res_all = (em_ptr->attribute == AttributeType::DEBUG);
156     ignore_res_all |= (em_ptr->attribute == AttributeType::MONSTER_MELEE);
157     ignore_res_all |= (em_ptr->attribute == AttributeType::MONSTER_SHOOT);
158
159     if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL) && ignore_res_all) {
160         return switch_effects_monster(player_ptr, em_ptr);
161     }
162
163     em_ptr->note = _("には完全な耐性がある!", " is immune.");
164     em_ptr->dam = 0;
165     if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
166         em_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_ALL);
167     }
168
169     if (em_ptr->attribute == AttributeType::LITE_WEAK || em_ptr->attribute == AttributeType::KILL_WALL) {
170         em_ptr->skipped = true;
171     }
172
173     return ProcessResult::PROCESS_CONTINUE;
174 }
175
176 /*!
177  * @brief ペットの死亡を処理する
178  * @param player_ptr プレイヤーへの参照ポインタ
179  * @param em_ptr モンスター効果構造体への参照ポインタ
180  */
181 static void effect_damage_killed_pet(PlayerType *player_ptr, effect_monster_type *em_ptr)
182 {
183     bool sad = em_ptr->m_ptr->is_pet() && !(em_ptr->m_ptr->ml);
184     if (em_ptr->known && em_ptr->note) {
185         angband_strcpy(em_ptr->m_name, monster_desc(player_ptr, em_ptr->m_ptr, MD_TRUE_NAME).data(), sizeof(em_ptr->m_name));
186         if (em_ptr->see_s_msg) {
187             msg_format("%^s%s", em_ptr->m_name, em_ptr->note);
188         } else {
189             player_ptr->current_floor_ptr->monster_noise = true;
190         }
191     }
192
193     if (em_ptr->who > 0) {
194         monster_gain_exp(player_ptr, em_ptr->who, em_ptr->m_ptr->r_idx);
195     }
196
197     monster_death(player_ptr, em_ptr->g_ptr->m_idx, false, em_ptr->attribute);
198     delete_monster_idx(player_ptr, em_ptr->g_ptr->m_idx);
199     if (sad) {
200         msg_print(_("少し悲しい気分がした。", "You feel sad for a moment."));
201     }
202 }
203
204 /*!
205  * @brief モンスターの睡眠を処理する
206  * @param player_ptr プレイヤーへの参照ポインタ
207  * @param em_ptr モンスター効果構造体への参照ポインタ
208  */
209 static void effect_damage_makes_sleep(PlayerType *player_ptr, effect_monster_type *em_ptr)
210 {
211     if (em_ptr->note && em_ptr->seen_msg) {
212         msg_format("%^s%s", em_ptr->m_name, em_ptr->note);
213     } else if (em_ptr->see_s_msg) {
214         message_pain(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->dam);
215     } else {
216         player_ptr->current_floor_ptr->monster_noise = true;
217     }
218
219     if (em_ptr->do_sleep) {
220         (void)set_monster_csleep(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->do_sleep);
221     }
222 }
223
224 /*!
225  * @brief モンスターからモンスターへのダメージを処理する / Hurt the monster by damages another monster did.
226  * @param player_ptr プレイヤーへの参照ポインタ
227  * @param em_ptr モンスター効果構造体への参照ポインタ
228  * @return ダメージを処理しなかった(モンスターIDがプレイヤー自身)場合はFALSE、処理した(モンスターだった)場合TRUE
229  * @details
230  * モンスターIDがプレイヤー(0)の場合は処理しない。
231  */
232 static bool deal_effect_damage_from_monster(PlayerType *player_ptr, effect_monster_type *em_ptr)
233 {
234     if (em_ptr->who <= 0) {
235         return false;
236     }
237
238     if (player_ptr->health_who == em_ptr->g_ptr->m_idx) {
239         player_ptr->redraw |= (PR_HEALTH);
240     }
241     if (player_ptr->riding == em_ptr->g_ptr->m_idx) {
242         player_ptr->redraw |= (PR_UHEALTH);
243     }
244
245     (void)set_monster_csleep(player_ptr, em_ptr->g_ptr->m_idx, 0);
246     em_ptr->m_ptr->hp -= em_ptr->dam;
247     if (em_ptr->m_ptr->hp < 0) {
248         effect_damage_killed_pet(player_ptr, em_ptr);
249     } else {
250         effect_damage_makes_sleep(player_ptr, em_ptr);
251     }
252
253     return true;
254 }
255
256 /*!
257  * @brief 不潔な病人の治療処理
258  * @param player_ptr プレイヤーへの参照ポインタ
259  * @param em_ptr モンスター効果構造体への参照ポインタ
260  * @return 大賞モンスターが不潔な病人だった場合はTRUE、それ以外はFALSE
261  */
262 static bool heal_leaper(PlayerType *player_ptr, effect_monster_type *em_ptr)
263 {
264     if (!em_ptr->heal_leper) {
265         return false;
266     }
267
268     if (em_ptr->seen_msg) {
269         msg_print(_("不潔な病人は病気が治った!", "The Mangy looking leper is healed!"));
270     }
271
272     if (record_named_pet && em_ptr->m_ptr->is_named_pet()) {
273         const auto m2_name = monster_desc(player_ptr, em_ptr->m_ptr, MD_INDEF_VISIBLE);
274         exe_write_diary(player_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_HEAL_LEPER, m2_name.data());
275     }
276
277     delete_monster_idx(player_ptr, em_ptr->g_ptr->m_idx);
278     return true;
279 }
280
281 /*!
282  * @brief プレイヤー起因の効果によるダメージを処理 / Deal damages from player and fear by them.
283  * @param player_ptr プレイヤーへの参照ポインタ
284  * @param em_ptr モンスター効果構造体への参照ポインタ
285  * @return モンスターが死んだらTRUE、生きていたらFALSE
286  * @details
287  * em_ptr->do_fearによる恐怖メッセージもここで表示。
288  */
289 static bool deal_effect_damage_from_player(PlayerType *player_ptr, effect_monster_type *em_ptr)
290 {
291     bool fear = false;
292     MonsterDamageProcessor mdp(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->dam, &fear, em_ptr->attribute);
293     if (mdp.mon_take_hit(em_ptr->note_dies)) {
294         return true;
295     }
296
297     if (em_ptr->do_sleep) {
298         anger_monster(player_ptr, em_ptr->m_ptr);
299     }
300
301     if (em_ptr->note && em_ptr->seen) {
302         msg_format(_("%s%s", "%^s%s"), em_ptr->m_name, em_ptr->note);
303     } else if (em_ptr->known && (em_ptr->dam || !em_ptr->do_fear)) {
304         message_pain(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->dam);
305     }
306
307     if (((em_ptr->dam > 0) || em_ptr->get_angry) && !em_ptr->do_sleep) {
308         anger_monster(player_ptr, em_ptr->m_ptr);
309     }
310
311     if ((fear || em_ptr->do_fear) && em_ptr->seen) {
312         sound(SOUND_FLEE);
313         msg_format(_("%^sは恐怖して逃げ出した!", "%^s flees in terror!"), em_ptr->m_name);
314     }
315
316     return false;
317 }
318
319 /*!
320  * @brief モンスターに効果のダメージを与える / Deal effect damage to monster.
321  * @param player_ptr プレイヤーへの参照ポインタ
322  * @param em_ptr モンスター効果構造体への参照ポインタ
323  * @details
324  * 以下のいずれかの処理を行う。
325  * 1.モンスターによる効果ダメージの処理
326  * 2.不潔な病人を癒す処理
327  * 3.プレイヤーによる効果ダメージの処理
328  * 4.睡眠する処理
329  */
330 static void deal_effect_damage_to_monster(PlayerType *player_ptr, effect_monster_type *em_ptr)
331 {
332     if (em_ptr->attribute == AttributeType::DRAIN_MANA) {
333         return;
334     }
335
336     // モンスターによる効果
337     if (deal_effect_damage_from_monster(player_ptr, em_ptr)) {
338         return;
339     }
340
341     // プレイヤーによる効果
342     if (heal_leaper(player_ptr, em_ptr)) {
343         return;
344     }
345     if (deal_effect_damage_from_player(player_ptr, em_ptr)) {
346         return;
347     }
348
349     if (em_ptr->do_sleep) {
350         (void)set_monster_csleep(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->do_sleep);
351     }
352 }
353
354 /*!
355  * @brief プレイヤーが眠っている敵に効果を及ぼした場合の徳の変化
356  * @param player_ptr プレイヤーへの参照ポインタ
357  * @param em_ptr モンスター効果構造体への参照ポインタ
358  */
359 static void effect_makes_change_virtues(PlayerType *player_ptr, effect_monster_type *em_ptr)
360 {
361     if ((em_ptr->who > 0) || !em_ptr->slept) {
362         return;
363     }
364
365     if (em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::EVIL) || one_in_(5)) {
366         chg_virtue(player_ptr, V_COMPASSION, -1);
367     }
368     if (em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::EVIL) || one_in_(5)) {
369         chg_virtue(player_ptr, V_HONOUR, -1);
370     }
371 }
372
373 /*!
374  * @brief 魔法効果に対する強制処理(変身の強制解除、死なない処理)
375  * @param player_ptr プレイヤーへの参照ポインタ
376  * @param em_ptr モンスター効果構造体への参照ポインタ
377  */
378 static void affected_monster_prevents_bad_status(PlayerType *player_ptr, effect_monster_type *em_ptr)
379 {
380     if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR) || (player_ptr->riding && (em_ptr->g_ptr->m_idx == player_ptr->riding))) {
381         em_ptr->do_polymorph = false;
382     }
383
384     if ((em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR) || (em_ptr->r_ptr->population_flags.has(MonsterPopulationType::NAZGUL))) && !player_ptr->phase_out && (em_ptr->who > 0) && (em_ptr->dam > em_ptr->m_ptr->hp)) {
385         em_ptr->dam = em_ptr->m_ptr->hp;
386     }
387 }
388
389 /*!
390  * @brief モンスターの朦朧値を蓄積させる
391  * @param player_ptr プレイヤーへの参照ポインタ
392  * @param em_ptr モンスター効果構造体への参照ポインタ
393  * @param stun_damage 朦朧値
394  */
395 static void effect_damage_piles_stun(PlayerType *player_ptr, effect_monster_type *em_ptr)
396 {
397     if ((em_ptr->do_stun == 0) || em_ptr->r_ptr->resistance_flags.has_any_of({ MonsterResistanceType::RESIST_SOUND, MonsterResistanceType::RESIST_FORCE }) || (em_ptr->r_ptr->flags3 & RF3_NO_STUN)) {
398         return;
399     }
400
401     if (em_ptr->seen) {
402         em_ptr->obvious = true;
403     }
404
405     int turns = 0;
406     if (em_ptr->m_ptr->get_remaining_stun()) {
407         em_ptr->note = _("はひどくもうろうとした。", " is more dazed.");
408         turns = em_ptr->m_ptr->get_remaining_stun() + (em_ptr->do_stun / 2);
409     } else {
410         em_ptr->note = _("はもうろうとした。", " is dazed.");
411         turns = em_ptr->do_stun;
412     }
413
414     (void)set_monster_stunned(player_ptr, em_ptr->g_ptr->m_idx, turns);
415     em_ptr->get_angry = true;
416 }
417
418 /*!
419  * @brief モンスターの混乱値を蓄積させる
420  * @param player_ptr プレイヤーへの参照ポインタ
421  * @param em_ptr モンスター効果構造体への参照ポインタ
422  * @param stun_damage 混乱値
423  */
424 static void effect_damage_piles_confusion(PlayerType *player_ptr, effect_monster_type *em_ptr)
425 {
426     if ((em_ptr->do_conf == 0) || (em_ptr->r_ptr->flags3 & RF3_NO_CONF) || em_ptr->r_ptr->resistance_flags.has_any_of(RFR_EFF_RESIST_CHAOS_MASK)) {
427         return;
428     }
429
430     if (em_ptr->seen) {
431         em_ptr->obvious = true;
432     }
433
434     int turns = 0;
435     if (em_ptr->m_ptr->is_confused()) {
436         em_ptr->note = _("はさらに混乱したようだ。", " looks more confused.");
437         turns = em_ptr->m_ptr->get_remaining_confusion() + (em_ptr->do_conf / 2);
438     } else {
439         em_ptr->note = _("は混乱したようだ。", " looks confused.");
440         turns = em_ptr->do_conf;
441     }
442
443     (void)set_monster_confused(player_ptr, em_ptr->g_ptr->m_idx, turns);
444     em_ptr->get_angry = true;
445 }
446
447 /*!
448  * @brief モンスターの恐怖値を蓄積させる
449  * @param player_ptr プレイヤーへの参照ポインタ
450  * @param em_ptr モンスター効果構造体への参照ポインタ
451  * @param stun_damage 恐怖値
452  * @details
453  * 打撃ダメージによる恐怖もあるため、メッセージは後で表示。
454  */
455 static void effect_damage_piles_fear(PlayerType *player_ptr, effect_monster_type *em_ptr)
456 {
457     if (em_ptr->do_fear == 0 || any_bits(em_ptr->r_ptr->flags3, RF3_NO_FEAR)) {
458         return;
459     }
460
461     (void)set_monster_monfear(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->m_ptr->get_remaining_fear() + em_ptr->do_fear);
462     em_ptr->get_angry = true;
463 }
464
465 /*!
466  * @brief モンスターを衰弱させる
467  * @param em_ptr モンスター効果構造体への参照ポインタ
468  */
469 static void effect_damage_makes_weak(effect_monster_type *em_ptr)
470 {
471     if (em_ptr->do_time == 0) {
472         return;
473     }
474
475     if (em_ptr->seen) {
476         em_ptr->obvious = true;
477     }
478
479     if (em_ptr->do_time >= em_ptr->m_ptr->maxhp) {
480         em_ptr->do_time = em_ptr->m_ptr->maxhp - 1;
481     }
482
483     if (em_ptr->do_time) {
484         em_ptr->note = _("は弱くなったようだ。", " seems weakened.");
485         em_ptr->m_ptr->maxhp -= em_ptr->do_time;
486         if ((em_ptr->m_ptr->hp - em_ptr->dam) > em_ptr->m_ptr->maxhp) {
487             em_ptr->dam = em_ptr->m_ptr->hp - em_ptr->m_ptr->maxhp;
488         }
489     }
490
491     em_ptr->get_angry = true;
492 }
493
494 /*!
495  * @brief モンスターを変身させる
496  * @param player_ptr プレイヤーへの参照ポインタ
497  * @param em_ptr モンスター効果構造体への参照ポインタ
498  */
499 static void effect_damage_makes_polymorph(PlayerType *player_ptr, effect_monster_type *em_ptr)
500 {
501     if (!em_ptr->do_polymorph || (randint1(90) <= em_ptr->r_ptr->level)) {
502         return;
503     }
504
505     if (polymorph_monster(player_ptr, em_ptr->y, em_ptr->x)) {
506         if (em_ptr->seen) {
507             em_ptr->obvious = true;
508         }
509
510         em_ptr->note = _("が変身した!", " changes!");
511         em_ptr->dam = 0;
512     }
513
514     em_ptr->m_ptr = &player_ptr->current_floor_ptr->m_list[em_ptr->g_ptr->m_idx];
515     em_ptr->r_ptr = &monraces_info[em_ptr->m_ptr->r_idx];
516 }
517
518 /*!
519  * @brief モンスターをテレポートさせる
520  * @param player_ptr プレイヤーへの参照ポインタ
521  * @param em_ptr モンスター効果構造体への参照ポインタ
522  */
523 static void effect_damage_makes_teleport(PlayerType *player_ptr, effect_monster_type *em_ptr)
524 {
525     if (em_ptr->do_dist == 0) {
526         return;
527     }
528
529     if (em_ptr->seen) {
530         em_ptr->obvious = true;
531     }
532
533     em_ptr->note = _("が消え去った!", " disappears!");
534
535     if (!em_ptr->who) {
536         chg_virtue(player_ptr, V_VALOUR, -1);
537     }
538
539     teleport_flags tflag = i2enum<teleport_flags>((!em_ptr->who ? TELEPORT_DEC_VALOUR : TELEPORT_SPONTANEOUS) | TELEPORT_PASSIVE);
540     teleport_away(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->do_dist, tflag);
541
542     em_ptr->y = em_ptr->m_ptr->fy;
543     em_ptr->x = em_ptr->m_ptr->fx;
544     em_ptr->g_ptr = &player_ptr->current_floor_ptr->grid_array[em_ptr->y][em_ptr->x];
545 }
546
547 /*!
548  * @brief モンスターへのダメージに応じたメッセージを表示させ、異常状態を与える
549  * @param player_ptr プレイヤーへの参照ポインタ
550  * @param em_ptr モンスター効果構造体への参照ポインタ
551  * @details
552  * 以下の判定と処理を行う。
553  * 1.全耐性または無敵でダメージが通らなかった場合
554  * 2.ダメージ量が現HPを上回る場合
555  * 3.通常時(デバフをかける)
556  */
557 static void effect_damage_gives_bad_status(PlayerType *player_ptr, effect_monster_type *em_ptr)
558 {
559     int tmp_damage = em_ptr->dam;
560     em_ptr->dam = mon_damage_mod(player_ptr, em_ptr->m_ptr, em_ptr->dam, (bool)(em_ptr->attribute == AttributeType::PSY_SPEAR));
561     if ((tmp_damage > 0) && (em_ptr->dam == 0) && em_ptr->seen) {
562         em_ptr->note = _("はダメージを受けていない。", " is unharmed.");
563     }
564
565     if (em_ptr->dam > em_ptr->m_ptr->hp) {
566         em_ptr->note = em_ptr->note_dies;
567     } else {
568         effect_damage_piles_stun(player_ptr, em_ptr);
569         effect_damage_piles_confusion(player_ptr, em_ptr);
570         effect_damage_piles_fear(player_ptr, em_ptr);
571         effect_damage_makes_weak(em_ptr);
572         effect_damage_makes_polymorph(player_ptr, em_ptr);
573         effect_damage_makes_teleport(player_ptr, em_ptr);
574     }
575 }
576
577 /*!
578  * @brief 効果によるモンスターへのダメージと付随効果を処理する
579  * @param player_ptr プレイヤーへの参照ポインタ
580  * @param em_ptr モンスター効果構造体への参照ポインタ
581  * @details
582  * 以下の処理を行う。
583  * 1.奇襲による徳の変化
584  * 2.完全な耐性及び無敵によるダメージのカット
585  * 3.ダメージによる付随効果の処理(混乱/朦朧/恐怖/衰弱/変身/テレポート)
586  * 4.ダメージ処理及び恐怖メッセージ
587  * 5.悪魔領域血の呪いによる事後処理
588  */
589 static void exe_affect_monster_by_damage(PlayerType *player_ptr, effect_monster_type *em_ptr)
590 {
591     effect_makes_change_virtues(player_ptr, em_ptr);
592     affected_monster_prevents_bad_status(player_ptr, em_ptr);
593     effect_damage_gives_bad_status(player_ptr, em_ptr);
594     deal_effect_damage_to_monster(player_ptr, em_ptr);
595     if ((em_ptr->attribute == AttributeType::BLOOD_CURSE) && one_in_(4)) {
596         blood_curse_to_enemy(player_ptr, em_ptr->who);
597     }
598 }
599
600 /*!
601  * @brief モンスター闘技場にいる場合の画面更新処理
602  * @param player_ptr プレイヤーへの参照ポインタ
603  * @param em_ptr モンスター効果構造体への参照ポインタ
604  */
605 static void update_phase_out_stat(PlayerType *player_ptr, effect_monster_type *em_ptr)
606 {
607     if (!player_ptr->phase_out) {
608         return;
609     }
610
611     player_ptr->health_who = em_ptr->g_ptr->m_idx;
612     player_ptr->redraw |= (PR_HEALTH);
613     handle_stuff(player_ptr);
614 }
615
616 /*!
617  * @brief 魔法効果がペットに及んだ時の処理
618  * @param player_ptr プレイヤーへの参照ポインタ
619  * @param em_ptr モンスター効果構造体への参照ポインタ
620  */
621 static void postprocess_by_effected_pet(PlayerType *player_ptr, effect_monster_type *em_ptr)
622 {
623     auto *m_ptr = em_ptr->m_ptr;
624     if ((em_ptr->dam <= 0) || m_ptr->is_pet() || m_ptr->is_friendly()) {
625         return;
626     }
627
628     if (em_ptr->who == 0) {
629         if (!(em_ptr->flag & PROJECT_NO_HANGEKI)) {
630             set_target(m_ptr, monster_target_y, monster_target_x);
631         }
632
633         return;
634     }
635
636     const auto &m_caster_ref = *em_ptr->m_caster_ptr;
637     if ((em_ptr->who > 0) && m_caster_ref.is_pet() && !player_bold(player_ptr, m_ptr->target_y, m_ptr->target_x)) {
638         set_target(m_ptr, m_caster_ref.fy, m_caster_ref.fx);
639     }
640 }
641
642 /*!
643  * @brief 魔法効果が騎乗モンスターに及んだ時の処理
644  * @param player_ptr プレイヤーへの参照ポインタ
645  * @param em_ptr モンスター効果構造体への参照ポインタ
646  */
647 static void postprocess_by_riding_pet_effected(PlayerType *player_ptr, effect_monster_type *em_ptr)
648 {
649     if (!player_ptr->riding || (player_ptr->riding != em_ptr->g_ptr->m_idx) || (em_ptr->dam <= 0)) {
650         return;
651     }
652
653     if (em_ptr->m_ptr->hp > (em_ptr->m_ptr->maxhp / 3)) {
654         em_ptr->dam = (em_ptr->dam + 1) / 2;
655     }
656
657     rakubadam_m = (em_ptr->dam > 200) ? 200 : em_ptr->dam;
658 }
659
660 /*!
661  * @brief 写真を撮った時の処理
662  * @param player_ptr プレイヤーへの参照ポインタ
663  * @param em_ptr モンスター効果構造体への参照ポインタ
664  * @details 写真のフラッシュは弱閃光属性
665  */
666 static void postprocess_by_taking_photo(PlayerType *player_ptr, effect_monster_type *em_ptr)
667 {
668     if (em_ptr->photo == 0) {
669         return;
670     }
671
672     ItemEntity *q_ptr;
673     ItemEntity forge;
674     q_ptr = &forge;
675     q_ptr->prep(lookup_baseitem_id({ ItemKindType::STATUE, SV_PHOTO }));
676     q_ptr->pval = em_ptr->photo;
677     q_ptr->ident |= (IDENT_FULL_KNOWN);
678     (void)drop_near(player_ptr, q_ptr, -1, player_ptr->y, player_ptr->x);
679 }
680
681 /*!
682  * @brief モンスター効果の後処理 (ペット関係、記念撮影、グローバル変数更新)
683  * @param player_ptr プレイヤーへの参照ポインタ
684  * @param em_ptr モンスター効果構造体への参照ポインタ
685  */
686 static void exe_affect_monster_postprocess(PlayerType *player_ptr, effect_monster_type *em_ptr)
687 {
688     postprocess_by_effected_pet(player_ptr, em_ptr);
689     postprocess_by_riding_pet_effected(player_ptr, em_ptr);
690     postprocess_by_taking_photo(player_ptr, em_ptr);
691     project_m_n++;
692     project_m_x = em_ptr->x;
693     project_m_y = em_ptr->y;
694 }
695
696 /*!
697  * @brief 汎用的なビーム/ボルト/ボール系によるモンスターへの効果処理 / Handle a beam/bolt/ball causing damage to a monster.
698  * @param player_ptr プレイヤーへの参照ポインタ
699  * @param who 魔法を発動したモンスター(0ならばプレイヤー) / Index of "source" monster (zero for "player")
700  * @param r 効果半径(ビーム/ボルト = 0 / ボール = 1以上) / Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
701  * @param y 目標y座標 / Target y location (or location to travel "towards")
702  * @param x 目標x座標 / Target x location (or location to travel "towards")
703  * @param dam 基本威力 / Base damage roll to apply to affected monsters (or player)
704  * @param attribute 効果属性 / Type of damage to apply to monsters (and objects)
705  * @param flag 効果フラグ
706  * @param see_s_msg TRUEならばメッセージを表示する
707  * @return 何か一つでも効力があればTRUEを返す / TRUE if any "effects" of the projection were observed, else FALSE
708  * @details
709  * 以下の処理を行う。
710  * 1.魔法効果による効果に対する耐性による軽減計算及び効果の発動
711  * 2.魔法効果によるダメージの処理とダメージによる効果の発動
712  * 3.ペット及び撮影による事後効果
713  */
714 bool affect_monster(
715     PlayerType *player_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, int dam, AttributeType attribute, BIT_FLAGS flag, bool see_s_msg, std::optional<CapturedMonsterType *> cap_mon_ptr)
716 {
717     effect_monster_type tmp_effect;
718     effect_monster_type *em_ptr = initialize_effect_monster(player_ptr, &tmp_effect, who, r, y, x, dam, attribute, flag, see_s_msg);
719
720     make_description_of_affecred_monster(player_ptr, em_ptr);
721
722     if (player_ptr->riding && (em_ptr->g_ptr->m_idx == player_ptr->riding)) {
723         disturb(player_ptr, true, true);
724     }
725
726     ProcessResult result = exe_affect_monster_by_effect(player_ptr, em_ptr, cap_mon_ptr);
727     if (result != ProcessResult::PROCESS_CONTINUE) {
728         return result == ProcessResult::PROCESS_TRUE;
729     }
730
731     if (em_ptr->skipped) {
732         return false;
733     }
734
735     exe_affect_monster_by_damage(player_ptr, em_ptr);
736
737     update_phase_out_stat(player_ptr, em_ptr);
738     const auto monster_is_valid = MonsterRace(em_ptr->m_ptr->r_idx).is_valid();
739     if (monster_is_valid) {
740         update_monster(player_ptr, em_ptr->g_ptr->m_idx, false);
741     }
742
743     lite_spot(player_ptr, em_ptr->y, em_ptr->x);
744     if ((player_ptr->monster_race_idx == em_ptr->m_ptr->r_idx) && (em_ptr->seen || !monster_is_valid)) {
745         player_ptr->window_flags |= (PW_MONSTER);
746     }
747
748     exe_affect_monster_postprocess(player_ptr, em_ptr);
749     return em_ptr->obvious;
750 }