OSDN Git Service

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