OSDN Git Service

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