OSDN Git Service

d347482b6c10a5522de65b3609b3be0d3bada250
[hengband/hengband.git] / src / effect / effect-monster.c
1 /*!
2  * @brief 魔法によるモンスターへの効果まとめ
3  * @date 2020/04/29
4  * @author Hourier
5  */
6
7 #include "effect/effect-monster.h"
8 #include "core/disturbance.h"
9 #include "core/player-redraw-types.h"
10 #include "core/stuff-handler.h"
11 #include "core/window-redrawer.h"
12 #include "effect/effect-characteristics.h"
13 #include "effect/effect-monster-switcher.h"
14 #include "floor/cave.h"
15 #include "floor/floor-object.h"
16 #include "game-option/play-record-options.h"
17 #include "io/write-diary.h"
18 #include "main/sound-definitions-table.h"
19 #include "main/sound-of-music.h"
20 #include "monster-floor/monster-death.h"
21 #include "monster-floor/monster-move.h"
22 #include "monster-floor/monster-remover.h"
23 #include "monster-race/monster-race.h"
24 #include "monster-race/race-flags-resistance.h"
25 #include "monster-race/race-flags1.h"
26 #include "monster-race/race-flags3.h"
27 #include "monster-race/race-flags7.h"
28 #include "monster-race/race-indice-types.h"
29 #include "monster/monster-describer.h"
30 #include "monster/monster-description-types.h"
31 #include "monster/monster-info.h"
32 #include "monster/monster-status-setter.h"
33 #include "monster/monster-status.h"
34 #include "monster/monster-update.h"
35 #include "object-enchant/special-object-flags.h"
36 #include "object/object-generator.h"
37 #include "object/object-kind-hook.h"
38 #include "player-info/avatar.h"
39 #include "spell-kind/blood-curse.h"
40 #include "spell-kind/spells-polymorph.h"
41 #include "spell-kind/spells-teleport.h"
42 #include "spell/spell-types.h"
43 #include "spells-effect-util.h"
44 #include "sv-definition/sv-other-types.h"
45 #include "system/floor-type-definition.h"
46 #include "system/object-type-definition.h"
47 #include "view/display-messages.h"
48
49 /*!
50  * @brief ビーム/ボルト/ボール系魔法によるモンスターへの効果があるかないかを判定する
51  * @param caster_ptr プレーヤーへの参照ポインタ
52  * @param em_ptr モンスター効果構造体への参照ポインタ
53  * @return 効果が何もないならFALSE、何かあるならTRUE
54  */
55 static bool is_never_effect(player_type *caster_ptr, effect_monster_type *em_ptr)
56 {
57     if (!em_ptr->g_ptr->m_idx)
58         return FALSE;
59     if (em_ptr->who && (em_ptr->g_ptr->m_idx == em_ptr->who))
60         return FALSE;
61     if ((em_ptr->g_ptr->m_idx == caster_ptr->riding) && !em_ptr->who && !(em_ptr->effect_type == GF_OLD_HEAL) && !(em_ptr->effect_type == GF_OLD_SPEED)
62         && !(em_ptr->effect_type == GF_STAR_HEAL))
63         return FALSE;
64     if (sukekaku && ((em_ptr->m_ptr->r_idx == MON_SUKE) || (em_ptr->m_ptr->r_idx == MON_KAKU)))
65         return FALSE;
66     if (em_ptr->m_ptr->hp < 0)
67         return FALSE;
68
69     return TRUE;
70 }
71
72 /*!
73  * @brief 魔法の効果やモンスター種別(MAKE/FEMALE/なし)に応じて表示するメッセージを変更する
74  * @param caster_ptr プレーヤーへの参照ポインタ
75  * @param em_ptr モンスター効果構造体への参照ポインタ
76  * @return なし
77  */
78 static void decide_spell_result_description(player_type *caster_ptr, effect_monster_type *em_ptr)
79 {
80     em_ptr->dam = (em_ptr->dam + em_ptr->r) / (em_ptr->r + 1);
81     monster_desc(caster_ptr, em_ptr->m_name, em_ptr->m_ptr, 0);
82     monster_desc(caster_ptr, em_ptr->m_poss, em_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE);
83     if (caster_ptr->riding && (em_ptr->g_ptr->m_idx == caster_ptr->riding))
84         disturb(caster_ptr, TRUE, TRUE);
85 }
86
87 /*!
88  * @brief 完全な耐性を持っていたら、モンスターへの効果処理をスキップする
89  * @param caster_ptr プレーヤーへの参照ポインタ
90  * @param em_ptr モンスター効果構造体への参照ポインタ
91  * @return 完全耐性ならCONTINUE、そうでないなら効果処理の結果
92  */
93 static process_result process_monster_perfect_resistance(player_type *caster_ptr, effect_monster_type *em_ptr)
94 {
95     if (((em_ptr->r_ptr->flagsr & RFR_RES_ALL) == 0) || em_ptr->effect_type == GF_OLD_CLONE || em_ptr->effect_type == GF_STAR_HEAL
96         || em_ptr->effect_type == GF_OLD_HEAL || em_ptr->effect_type == GF_OLD_SPEED || em_ptr->effect_type == GF_CAPTURE || em_ptr->effect_type == GF_PHOTO)
97         return switch_effects_monster(caster_ptr, em_ptr);
98
99     em_ptr->note = _("には完全な耐性がある!", " is immune.");
100     em_ptr->dam = 0;
101     if (is_original_ap_and_seen(caster_ptr, em_ptr->m_ptr))
102         em_ptr->r_ptr->r_flagsr |= (RFR_RES_ALL);
103
104     if (em_ptr->effect_type == GF_LITE_WEAK || em_ptr->effect_type == GF_KILL_WALL)
105         em_ptr->skipped = TRUE;
106
107     return PROCESS_CONTINUE;
108 }
109
110 /*!
111  * @brief ペットの死亡を処理する
112  * @param caster_ptr プレーヤーへの参照ポインタ
113  * @param em_ptr モンスター効果構造体への参照ポインタ
114  * @return なし
115  */
116 static void process_pet_death(player_type *caster_ptr, effect_monster_type *em_ptr)
117 {
118     bool sad = is_pet(em_ptr->m_ptr) && !(em_ptr->m_ptr->ml);
119     if (em_ptr->known && em_ptr->note) {
120         monster_desc(caster_ptr, em_ptr->m_name, em_ptr->m_ptr, MD_TRUE_NAME);
121         if (em_ptr->see_s_msg)
122             msg_format("%^s%s", em_ptr->m_name, em_ptr->note);
123         else
124             caster_ptr->current_floor_ptr->monster_noise = TRUE;
125     }
126
127     if (em_ptr->who > 0)
128         monster_gain_exp(caster_ptr, em_ptr->who, em_ptr->m_ptr->r_idx);
129
130     monster_death(caster_ptr, em_ptr->g_ptr->m_idx, FALSE);
131     delete_monster_idx(caster_ptr, em_ptr->g_ptr->m_idx);
132     if (sad)
133         msg_print(_("少し悲しい気分がした。", "You feel sad for a moment."));
134 }
135
136 /*!
137  * @brief モンスターの睡眠を処理する
138  * @param caster_ptr プレーヤーへの参照ポインタ
139  * @param em_ptr モンスター効果構造体への参照ポインタ
140  * @return なし
141  */
142 static void process_monster_sleep(player_type *caster_ptr, effect_monster_type *em_ptr)
143 {
144     if (em_ptr->note && em_ptr->seen_msg)
145         msg_format("%^s%s", em_ptr->m_name, em_ptr->note);
146     else if (em_ptr->see_s_msg)
147         message_pain(caster_ptr, em_ptr->g_ptr->m_idx, em_ptr->dam);
148     else
149         caster_ptr->current_floor_ptr->monster_noise = TRUE;
150
151     if (em_ptr->do_sleep)
152         (void)set_monster_csleep(caster_ptr, em_ptr->g_ptr->m_idx, em_ptr->do_sleep);
153 }
154
155 /*!
156  * @brief モンスターの被ダメージを処理する / If another monster did the damage, hurt the monster by hand
157  * @param caster_ptr プレーヤーへの参照ポインタ
158  * @param em_ptr モンスター効果構造体への参照ポインタ
159  * @return モンスターIDがプレーヤー自身だった場合FALSE、モンスターだった場合TRUE
160  */
161 static bool process_monster_damage(player_type *caster_ptr, effect_monster_type *em_ptr)
162 {
163     if (em_ptr->who <= 0)
164         return FALSE;
165
166     if (caster_ptr->health_who == em_ptr->g_ptr->m_idx)
167         caster_ptr->redraw |= (PR_HEALTH);
168     if (caster_ptr->riding == em_ptr->g_ptr->m_idx)
169         caster_ptr->redraw |= (PR_UHEALTH);
170
171     (void)set_monster_csleep(caster_ptr, em_ptr->g_ptr->m_idx, 0);
172     em_ptr->m_ptr->hp -= em_ptr->dam;
173     if (em_ptr->m_ptr->hp < 0)
174         process_pet_death(caster_ptr, em_ptr);
175     else
176         process_monster_sleep(caster_ptr, em_ptr);
177
178     return TRUE;
179 }
180
181 /*!
182  * @brief 不潔な病人の治療処理
183  * @param caster_ptr プレーヤーへの参照ポインタ
184  * @param em_ptr モンスター効果構造体への参照ポインタ
185  * @return 大賞モンスターが不潔な病人だった場合はTRUE、それ以外はFALSE
186  */
187 static bool heal_leaper(player_type *caster_ptr, effect_monster_type *em_ptr)
188 {
189     if (!em_ptr->heal_leper)
190         return FALSE;
191
192     if (em_ptr->seen_msg)
193         msg_print(_("不潔な病人は病気が治った!", "The Mangy looking leper is healed!"));
194
195     if (record_named_pet && is_pet(em_ptr->m_ptr) && em_ptr->m_ptr->nickname) {
196         char m2_name[MAX_NLEN];
197         monster_desc(caster_ptr, m2_name, em_ptr->m_ptr, MD_INDEF_VISIBLE);
198         exe_write_diary(caster_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_HEAL_LEPER, m2_name);
199     }
200
201     delete_monster_idx(caster_ptr, em_ptr->g_ptr->m_idx);
202     return TRUE;
203 }
204
205 /*!
206  * @brief モンスターの恐慌処理 / If the player did it, give him experience, check fear
207  * @param caster_ptr プレーヤーへの参照ポインタ
208  * @param em_ptr モンスター効果構造体への参照ポインタ
209  * @return モンスターが死んだらTRUE、生きていたらFALSE
210  */
211 static bool process_monster_fear(player_type *caster_ptr, effect_monster_type *em_ptr)
212 {
213     bool fear = FALSE;
214     if (mon_take_hit(caster_ptr, em_ptr->g_ptr->m_idx, em_ptr->dam, &fear, em_ptr->note_dies))
215         return TRUE;
216
217     if (em_ptr->do_sleep)
218         anger_monster(caster_ptr, em_ptr->m_ptr);
219
220     if (em_ptr->note && em_ptr->seen)
221         msg_format(_("%s%s", "%^s%s"), em_ptr->m_name, em_ptr->note);
222     else if (em_ptr->known && (em_ptr->dam || !em_ptr->do_fear))
223         message_pain(caster_ptr, em_ptr->g_ptr->m_idx, em_ptr->dam);
224
225     if (((em_ptr->dam > 0) || em_ptr->get_angry) && !em_ptr->do_sleep)
226         anger_monster(caster_ptr, em_ptr->m_ptr);
227
228     if ((fear || em_ptr->do_fear) && em_ptr->seen) {
229         sound(SOUND_FLEE);
230         msg_format(_("%^sは恐怖して逃げ出した!", "%^s flees in terror!"), em_ptr->m_name);
231     }
232
233     return FALSE;
234 }
235
236 /*!
237  * todo 睡眠処理があるので、死に際とは言えない。適切な関数名に要修正
238  * @brief モンスターの死に際処理 (魔力吸収を除く)
239  * @param caster_ptr プレーヤーへの参照ポインタ
240  * @param em_ptr モンスター効果構造体への参照ポインタ
241  * @return なし
242  */
243 static void process_monster_last_moment(player_type *caster_ptr, effect_monster_type *em_ptr)
244 {
245     if (em_ptr->effect_type == GF_DRAIN_MANA)
246         return;
247
248     if (process_monster_damage(caster_ptr, em_ptr))
249         return;
250     if (heal_leaper(caster_ptr, em_ptr))
251         return;
252     if (process_monster_fear(caster_ptr, em_ptr))
253         return;
254
255     if (em_ptr->do_sleep)
256         (void)set_monster_csleep(caster_ptr, em_ptr->g_ptr->m_idx, em_ptr->do_sleep);
257 }
258
259 /*!
260  * @brief 魔法の効果による汎用処理 (変身の有無、現在HPの減算、徳の変化)
261  * @param caster_ptr プレーヤーへの参照ポインタ
262  * @param em_ptr モンスター効果構造体への参照ポインタ
263  * @return なし
264  */
265 static void process_spell_result(player_type *caster_ptr, effect_monster_type *em_ptr)
266 {
267     if ((em_ptr->r_ptr->flags1 & RF1_UNIQUE) || (em_ptr->r_ptr->flags1 & RF1_QUESTOR) || (caster_ptr->riding && (em_ptr->g_ptr->m_idx == caster_ptr->riding)))
268         em_ptr->do_polymorph = FALSE;
269
270     if (((em_ptr->r_ptr->flags1 & (RF1_UNIQUE | RF1_QUESTOR)) || (em_ptr->r_ptr->flags7 & RF7_NAZGUL)) && !caster_ptr->phase_out && (em_ptr->who > 0)
271         && (em_ptr->dam > em_ptr->m_ptr->hp))
272         em_ptr->dam = em_ptr->m_ptr->hp;
273
274     if ((em_ptr->who > 0) || !em_ptr->slept)
275         return;
276
277     if (!(em_ptr->r_ptr->flags3 & RF3_EVIL) || one_in_(5))
278         chg_virtue(caster_ptr, V_COMPASSION, -1);
279     if (!(em_ptr->r_ptr->flags3 & RF3_EVIL) || one_in_(5))
280         chg_virtue(caster_ptr, V_HONOUR, -1);
281 }
282
283 /*!
284  * @brief モンスターの朦朧値を蓄積させる
285  * @param caster_ptr プレーヤーへの参照ポインタ
286  * @param em_ptr モンスター効果構造体への参照ポインタ
287  * @param stun_damage 朦朧値
288  * @return なし
289  */
290 static void pile_monster_stun(player_type *caster_ptr, effect_monster_type *em_ptr, int *stun_damage)
291 {
292     if ((em_ptr->do_stun == 0) || (em_ptr->r_ptr->flagsr & (RFR_RES_SOUN | RFR_RES_WALL)) || (em_ptr->r_ptr->flags3 & RF3_NO_STUN))
293         return;
294
295     if (em_ptr->seen)
296         em_ptr->obvious = TRUE;
297
298     if (monster_stunned_remaining(em_ptr->m_ptr)) {
299         em_ptr->note = _("はひどくもうろうとした。", " is more dazed.");
300         *stun_damage = monster_stunned_remaining(em_ptr->m_ptr) + (em_ptr->do_stun / 2);
301     } else {
302         em_ptr->note = _("はもうろうとした。", " is dazed.");
303         *stun_damage = em_ptr->do_stun;
304     }
305
306     (void)set_monster_stunned(caster_ptr, em_ptr->g_ptr->m_idx, *stun_damage);
307     em_ptr->get_angry = TRUE;
308 }
309
310 /*!
311  * @brief モンスターの混乱値を蓄積させる
312  * @param caster_ptr プレーヤーへの参照ポインタ
313  * @param em_ptr モンスター効果構造体への参照ポインタ
314  * @param stun_damage 混乱値
315  * @return なし
316  */
317 static void pile_monster_conf(player_type *caster_ptr, effect_monster_type *em_ptr, int *conf_damage)
318 {
319     if ((em_ptr->do_conf == 0) || (em_ptr->r_ptr->flags3 & RF3_NO_CONF) || (em_ptr->r_ptr->flagsr & RFR_EFF_RES_CHAO_MASK))
320         return;
321
322     if (em_ptr->seen)
323         em_ptr->obvious = TRUE;
324
325     if (monster_confused_remaining(em_ptr->m_ptr)) {
326         em_ptr->note = _("はさらに混乱したようだ。", " looks more confused.");
327         *conf_damage = monster_confused_remaining(em_ptr->m_ptr) + (em_ptr->do_conf / 2);
328     } else {
329         em_ptr->note = _("は混乱したようだ。", " looks confused.");
330         *conf_damage = em_ptr->do_conf;
331     }
332
333     (void)set_monster_confused(caster_ptr, em_ptr->g_ptr->m_idx, *conf_damage);
334     em_ptr->get_angry = TRUE;
335 }
336
337 /*!
338  * @brief モンスターを衰弱させる
339  * @param em_ptr モンスター効果構造体への参照ポインタ
340  * @return なし
341  */
342 static void process_monster_weakening(effect_monster_type *em_ptr)
343 {
344     if (em_ptr->do_time == 0)
345         return;
346
347     if (em_ptr->seen)
348         em_ptr->obvious = TRUE;
349
350     if (em_ptr->do_time >= em_ptr->m_ptr->maxhp)
351         em_ptr->do_time = em_ptr->m_ptr->maxhp - 1;
352
353     if (em_ptr->do_time) {
354         em_ptr->note = _("は弱くなったようだ。", " seems weakened.");
355         em_ptr->m_ptr->maxhp -= em_ptr->do_time;
356         if ((em_ptr->m_ptr->hp - em_ptr->dam) > em_ptr->m_ptr->maxhp)
357             em_ptr->dam = em_ptr->m_ptr->hp - em_ptr->m_ptr->maxhp;
358     }
359
360     em_ptr->get_angry = TRUE;
361 }
362
363 /*!
364  * @brief モンスターを変身させる
365  * @param caster_ptr プレーヤーへの参照ポインタ
366  * @param em_ptr モンスター効果構造体への参照ポインタ
367  * @return なし
368  */
369 static void process_monster_polymorph(player_type *caster_ptr, effect_monster_type *em_ptr)
370 {
371     if (!em_ptr->do_polymorph || (randint1(90) <= em_ptr->r_ptr->level))
372         return;
373
374     if (polymorph_monster(caster_ptr, em_ptr->y, em_ptr->x)) {
375         if (em_ptr->seen)
376             em_ptr->obvious = TRUE;
377
378         em_ptr->note = _("が変身した!", " changes!");
379         em_ptr->dam = 0;
380     }
381
382     em_ptr->m_ptr = &caster_ptr->current_floor_ptr->m_list[em_ptr->g_ptr->m_idx];
383     em_ptr->r_ptr = &r_info[em_ptr->m_ptr->r_idx];
384 }
385
386 /*!
387  * @brief モンスターをテレポートさせる
388  * @param caster_ptr プレーヤーへの参照ポインタ
389  * @param em_ptr モンスター効果構造体への参照ポインタ
390  * @return なし
391  */
392 static void process_monster_teleport(player_type *caster_ptr, effect_monster_type *em_ptr)
393 {
394     if (em_ptr->do_dist == 0)
395         return;
396
397     if (em_ptr->seen)
398         em_ptr->obvious = TRUE;
399
400     em_ptr->note = _("が消え去った!", " disappears!");
401
402     if (!em_ptr->who)
403         chg_virtue(caster_ptr, V_VALOUR, -1);
404
405     teleport_away(caster_ptr, em_ptr->g_ptr->m_idx, em_ptr->do_dist, (!em_ptr->who ? TELEPORT_DEC_VALOUR : 0L) | TELEPORT_PASSIVE);
406
407     em_ptr->y = em_ptr->m_ptr->fy;
408     em_ptr->x = em_ptr->m_ptr->fx;
409     em_ptr->g_ptr = &caster_ptr->current_floor_ptr->grid_array[em_ptr->y][em_ptr->x];
410 }
411
412 /*!
413  * @brief モンスターの異常状態を処理する
414  * @param caster_ptr プレーヤーへの参照ポインタ
415  * @param em_ptr モンスター効果構造体への参照ポインタ
416  * @parama tmp_damage 朦朧/混乱値
417  * @return なし
418  */
419 static void process_monster_bad_status(player_type *caster_ptr, effect_monster_type *em_ptr, int *tmp_damage)
420 {
421     pile_monster_stun(caster_ptr, em_ptr, tmp_damage);
422     pile_monster_conf(caster_ptr, em_ptr, tmp_damage);
423     process_monster_weakening(em_ptr);
424     process_monster_polymorph(caster_ptr, em_ptr);
425     process_monster_teleport(caster_ptr, em_ptr);
426     if (em_ptr->do_fear == 0)
427         return;
428
429     (void)set_monster_monfear(caster_ptr, em_ptr->g_ptr->m_idx, monster_fear_remaining(em_ptr->m_ptr) + em_ptr->do_fear);
430     em_ptr->get_angry = TRUE;
431 }
432
433 /*!
434  * @brief モンスターへのダメージに応じたメッセージを表示させ、異常状態を与える
435  * @param caster_ptr プレーヤーへの参照ポインタ
436  * @param em_ptr モンスター効果構造体への参照ポインタ
437  * @return なし
438  */
439 static void process_monster_bad_stat_damage(player_type *caster_ptr, effect_monster_type *em_ptr)
440 {
441     int tmp_damage = em_ptr->dam;
442     em_ptr->dam = mon_damage_mod(caster_ptr, em_ptr->m_ptr, em_ptr->dam, (bool)(em_ptr->effect_type == GF_PSY_SPEAR));
443     if ((tmp_damage > 0) && (em_ptr->dam == 0))
444         em_ptr->note = _("はダメージを受けていない。", " is unharmed.");
445
446     if (em_ptr->dam > em_ptr->m_ptr->hp)
447         em_ptr->note = em_ptr->note_dies;
448     else
449         process_monster_bad_status(caster_ptr, em_ptr, &tmp_damage);
450 }
451
452 /*!
453  * todo 関数名が微妙、もっと適切な関数名が欲しい
454  * @brief モンスターへの影響全般を処理する
455  * @param caster_ptr プレーヤーへの参照ポインタ
456  * @param em_ptr モンスター効果構造体への参照ポインタ
457  * @return なし
458  */
459 static void process_spell(player_type *caster_ptr, effect_monster_type *em_ptr)
460 {
461     process_spell_result(caster_ptr, em_ptr);
462     process_monster_bad_stat_damage(caster_ptr, em_ptr);
463     process_monster_last_moment(caster_ptr, em_ptr);
464     if ((em_ptr->effect_type == GF_BLOOD_CURSE) && one_in_(4))
465         blood_curse_to_enemy(caster_ptr, em_ptr->who);
466 }
467
468 /*!
469  * @brief モンスター闘技場にいる場合の画面更新処理
470  * @param caster_ptr プレーヤーへの参照ポインタ
471  * @param em_ptr モンスター効果構造体への参照ポインタ
472  * @return なし
473  */
474 static void update_phase_out_stat(player_type *caster_ptr, effect_monster_type *em_ptr)
475 {
476     if (!caster_ptr->phase_out)
477         return;
478
479     caster_ptr->health_who = em_ptr->g_ptr->m_idx;
480     caster_ptr->redraw |= (PR_HEALTH);
481     handle_stuff(caster_ptr);
482 }
483
484 /*!
485  * @brief 魔法効果がペットに及んだ時の処理
486  * @param caster_ptr プレーヤーへの参照ポインタ
487  * @param em_ptr モンスター効果構造体への参照ポインタ
488  * @return なし
489  */
490 static void postprocess_spell_pet(player_type *caster_ptr, effect_monster_type *em_ptr)
491 {
492     if ((em_ptr->dam <= 0) || is_pet(em_ptr->m_ptr) || is_friendly(em_ptr->m_ptr))
493         return;
494
495     if (em_ptr->who == 0) {
496         if (!(em_ptr->flag & PROJECT_NO_HANGEKI))
497             set_target(em_ptr->m_ptr, monster_target_y, monster_target_x);
498
499         return;
500     }
501
502     if ((em_ptr->who > 0) && is_pet(em_ptr->m_caster_ptr) && !player_bold(caster_ptr, em_ptr->m_ptr->target_y, em_ptr->m_ptr->target_x))
503         set_target(em_ptr->m_ptr, em_ptr->m_caster_ptr->fy, em_ptr->m_caster_ptr->fx);
504 }
505
506 /*!
507  * @brief 魔法効果が騎乗モンスターに及んだ時の処理
508  * @param caster_ptr プレーヤーへの参照ポインタ
509  * @param em_ptr モンスター効果構造体への参照ポインタ
510  * @return なし
511  */
512 static void postprocess_spell_riding(player_type *caster_ptr, effect_monster_type *em_ptr)
513 {
514     if (!caster_ptr->riding || (caster_ptr->riding != em_ptr->g_ptr->m_idx) || (em_ptr->dam <= 0))
515         return;
516
517     if (em_ptr->m_ptr->hp > (em_ptr->m_ptr->maxhp / 3))
518         em_ptr->dam = (em_ptr->dam + 1) / 2;
519
520     rakubadam_m = (em_ptr->dam > 200) ? 200 : em_ptr->dam;
521 }
522
523 /*!
524  * @brief 写真を撮った時の処理
525  * @param caster_ptr プレーヤーへの参照ポインタ
526  * @param em_ptr モンスター効果構造体への参照ポインタ
527  * @return なし
528  * @details 写真のフラッシュは弱閃光属性
529  */
530 static void postprocess_spell_photo(player_type *caster_ptr, effect_monster_type *em_ptr)
531 {
532     if (em_ptr->photo == 0)
533         return;
534
535     object_type *q_ptr;
536     object_type forge;
537     q_ptr = &forge;
538     object_prep(caster_ptr, q_ptr, lookup_kind(TV_STATUE, SV_PHOTO));
539     q_ptr->pval = em_ptr->photo;
540     q_ptr->ident |= (IDENT_FULL_KNOWN);
541     (void)drop_near(caster_ptr, q_ptr, -1, caster_ptr->y, caster_ptr->x);
542 }
543
544 /*!
545  * @brief モンスター効果の後処理 (ペット関係、記念撮影、グローバル変数更新)
546  * @param caster_ptr プレーヤーへの参照ポインタ
547  * @param em_ptr モンスター効果構造体への参照ポインタ
548  * @return なし
549  */
550 static void postprocess_spell(player_type *caster_ptr, effect_monster_type *em_ptr)
551 {
552     postprocess_spell_pet(caster_ptr, em_ptr);
553     postprocess_spell_riding(caster_ptr, em_ptr);
554     postprocess_spell_photo(caster_ptr, em_ptr);
555     project_m_n++;
556     project_m_x = em_ptr->x;
557     project_m_y = em_ptr->y;
558 }
559
560 /*!
561  * @brief 汎用的なビーム/ボルト/ボール系によるモンスターへの効果処理 / Handle a beam/bolt/ball causing damage to a monster.
562  * @param caster_ptr プレーヤーへの参照ポインタ
563  * @param who 魔法を発動したモンスター(0ならばプレイヤー) / Index of "source" monster (zero for "player")
564  * @param r 効果半径(ビーム/ボルト = 0 / ボール = 1以上) / Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
565  * @param y 目標y座標 / Target y location (or location to travel "towards")
566  * @param x 目標x座標 / Target x location (or location to travel "towards")
567  * @param dam 基本威力 / Base damage roll to apply to affected monsters (or player)
568  * @param effect_type 効果属性 / Type of damage to apply to monsters (and objects)
569  * @param flag 効果フラグ
570  * @param see_s_msg TRUEならばメッセージを表示する
571  * @return 何か一つでも効力があればTRUEを返す / TRUE if any "effects" of the projection were observed, else FALSE
572  */
573 bool affect_monster(
574     player_type *caster_ptr, MONSTER_IDX who, POSITION r, POSITION y, POSITION x, HIT_POINT dam, EFFECT_ID effect_type, BIT_FLAGS flag, bool see_s_msg)
575 {
576     effect_monster_type tmp_effect;
577     effect_monster_type *em_ptr = initialize_effect_monster(caster_ptr, &tmp_effect, who, r, y, x, dam, effect_type, flag, see_s_msg);
578     if (!is_never_effect(caster_ptr, em_ptr))
579         return FALSE;
580
581     decide_spell_result_description(caster_ptr, em_ptr);
582     process_result result = process_monster_perfect_resistance(caster_ptr, em_ptr);
583     if (result != PROCESS_CONTINUE)
584         return (bool)result;
585
586     if (em_ptr->skipped)
587         return FALSE;
588
589     process_spell(caster_ptr, em_ptr);
590     update_phase_out_stat(caster_ptr, em_ptr);
591     if (em_ptr->m_ptr->r_idx)
592         update_monster(caster_ptr, em_ptr->g_ptr->m_idx, FALSE);
593
594     lite_spot(caster_ptr, em_ptr->y, em_ptr->x);
595     if ((caster_ptr->monster_race_idx == em_ptr->m_ptr->r_idx) && (em_ptr->seen || !em_ptr->m_ptr->r_idx))
596         caster_ptr->window |= (PW_MONSTER);
597
598     postprocess_spell(caster_ptr, em_ptr);
599     return em_ptr->obvious;
600 }