OSDN Git Service

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