OSDN Git Service

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