OSDN Git Service

Merge pull request #2922 from Slimebreath6078/feature/refactor_mflag_brightness
[hengbandforosx/hengbandosx.git] / src / mspell / mspell-floor.cpp
1 /*!
2  * @brief フロアの一定範囲に効果を及ぼす (悲鳴、テレポート等)スペルの効果
3  * @date 2020/05/16
4  * @author Hourier
5  */
6
7 #include "mspell/mspell-floor.h"
8 #include "blue-magic/blue-magic-checker.h"
9 #include "core/disturbance.h"
10 #include "core/player-update-types.h"
11 #include "effect/attribute-types.h"
12 #include "effect/effect-characteristics.h"
13 #include "effect/effect-processor.h"
14 #include "mind/drs-types.h"
15 #include "monster-race/monster-race.h"
16 #include "monster-race/race-ability-flags.h"
17 #include "monster-race/race-brightness-mask.h"
18 #include "monster-race/race-flags-resistance.h"
19 #include "monster-race/race-flags1.h"
20 #include "monster-race/race-flags3.h"
21 #include "monster-race/race-flags7.h"
22 #include "monster-race/race-indice-types.h"
23 #include "monster-race/race-resistance-mask.h"
24 #include "monster/monster-info.h"
25 #include "monster/monster-status-setter.h"
26 #include "monster/monster-status.h"
27 #include "monster/monster-update.h"
28 #include "mspell/mspell-result.h"
29 #include "mspell/mspell-status.h"
30 #include "mspell/mspell-util.h"
31 #include "player-base/player-class.h"
32 #include "player/player-personality-types.h"
33 #include "player/player-status-flags.h"
34 #include "player/player-status.h"
35 #include "spell-kind/spells-lite.h"
36 #include "spell-kind/spells-neighbor.h"
37 #include "spell-kind/spells-sight.h"
38 #include "spell-kind/spells-teleport.h"
39 #include "spell-kind/spells-world.h"
40 #include "spell-realm/spells-hex.h"
41 #include "system/floor-type-definition.h"
42 #include "system/monster-entity.h"
43 #include "system/monster-race-info.h"
44 #include "system/player-type-definition.h"
45 #include "timed-effect/player-blindness.h"
46 #include "timed-effect/timed-effects.h"
47 #include "util/bit-flags-calculator.h"
48 #include "view/display-messages.h"
49
50 /*!
51  * @brief RF4_SHRIEKの処理。叫び。 /
52  * @param m_idx 呪文を唱えるモンスターID
53  * @param player_ptr プレイヤーへの参照ポインタ
54  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
55  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
56  *
57  * ラーニング不可。
58  */
59 MonsterSpellResult spell_RF4_SHRIEK(MONSTER_IDX m_idx, PlayerType *player_ptr, MONSTER_IDX t_idx, int target_type)
60 {
61     mspell_cast_msg_simple msg(_("%^sがかん高い金切り声をあげた。", "%^s makes a high pitched shriek."),
62         _("%^sが%sに向かって叫んだ。", "%^s shrieks at %s."));
63
64     simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
65
66     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
67     auto result = MonsterSpellResult::make_valid();
68     if (m_ptr->r_idx == MonsterRaceId::LEE_QIEZI) {
69         msg_print(_("しかし、その声は誰の心にも響かなかった…。", "However, that voice didn't touch anyone's heart..."));
70         return result;
71     }
72
73     if (target_type == MONSTER_TO_PLAYER) {
74         aggravate_monsters(player_ptr, m_idx);
75     } else if (target_type == MONSTER_TO_MONSTER) {
76         set_monster_csleep(player_ptr, t_idx, 0);
77     }
78
79     return result;
80 }
81
82 /*!
83  * @brief RF6_WORLDの処理。時を止める。 /
84  * @param player_ptr プレイヤーへの参照ポインタ
85  * @param m_idx 呪文を唱えるモンスターID
86  *
87  * ラーニング不可。
88  */
89 MonsterSpellResult spell_RF6_WORLD(PlayerType *player_ptr, MONSTER_IDX m_idx)
90 {
91     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
92     GAME_TEXT m_name[MAX_NLEN];
93     monster_name(player_ptr, m_idx, m_name);
94     disturb(player_ptr, true, true);
95     (void)set_monster_timewalk(player_ptr, randint1(2) + 2, m_ptr->r_idx, true);
96
97     return MonsterSpellResult::make_valid();
98 }
99
100 /*!
101  * @brief RF6_BLINKの処理。ショート・テレポート。 /
102  * @param player_ptr プレイヤーへの参照ポインタ
103  * @param m_idx 呪文を唱えるモンスターID
104  * @param is_quantum_effect 量子的効果によるショート・テレポートの場合時TRUE
105  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
106  *
107  * ラーニング不可。
108  */
109 MonsterSpellResult spell_RF6_BLINK(PlayerType *player_ptr, MONSTER_IDX m_idx, int target_type, bool is_quantum_effect)
110 {
111     const auto res = MonsterSpellResult::make_valid();
112
113     GAME_TEXT m_name[MAX_NLEN];
114     monster_name(player_ptr, m_idx, m_name);
115
116     if (target_type == MONSTER_TO_PLAYER) {
117         disturb(player_ptr, true, true);
118     }
119
120     if (!is_quantum_effect && SpellHex(player_ptr).check_hex_barrier(m_idx, HEX_ANTI_TELE)) {
121         if (see_monster(player_ptr, m_idx)) {
122             msg_format(_("魔法のバリアが%^sのテレポートを邪魔した。", "Magic barrier obstructs teleporting of %^s."), m_name);
123         }
124         return res;
125     }
126
127     if (see_monster(player_ptr, m_idx)) {
128         msg_format(_("%^sが瞬時に消えた。", "%^s blinks away."), m_name);
129     }
130
131     teleport_away(player_ptr, m_idx, 10, TELEPORT_SPONTANEOUS);
132
133     if (target_type == MONSTER_TO_PLAYER) {
134         player_ptr->update |= (PU_MONSTERS);
135     }
136
137     return res;
138 }
139
140 /*!
141  * @brief RF6_TPORTの処理。テレポート。 /
142  * @param player_ptr プレイヤーへの参照ポインタ
143  * @param m_idx 呪文を唱えるモンスターID
144  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
145  *
146  * ラーニング不可。
147  */
148 MonsterSpellResult spell_RF6_TPORT(PlayerType *player_ptr, MONSTER_IDX m_idx, int target_type)
149 {
150     const auto res = MonsterSpellResult::make_valid();
151
152     GAME_TEXT m_name[MAX_NLEN];
153     monster_name(player_ptr, m_idx, m_name);
154
155     if (target_type == MONSTER_TO_PLAYER) {
156         disturb(player_ptr, true, true);
157     }
158     if (SpellHex(player_ptr).check_hex_barrier(m_idx, HEX_ANTI_TELE)) {
159         if (see_monster(player_ptr, m_idx)) {
160             msg_format(_("魔法のバリアが%^sのテレポートを邪魔した。", "Magic barrier obstructs teleporting of %^s."), m_name);
161         }
162         return res;
163     }
164
165     if (see_monster(player_ptr, m_idx)) {
166         msg_format(_("%^sがテレポートした。", "%^s teleports away."), m_name);
167     }
168
169     teleport_away_followable(player_ptr, m_idx);
170
171     return res;
172 }
173
174 /*!
175  * @brief RF6_TELE_TOの処理。テレポート・バック。 /
176  * @param player_ptr プレイヤーへの参照ポインタ
177  * @param m_idx 呪文を唱えるモンスターID
178  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
179  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
180  *
181  * プレイヤーが対象ならラーニング可。
182  */
183 MonsterSpellResult spell_RF6_TELE_TO(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
184 {
185     auto res = MonsterSpellResult::make_valid();
186     res.learnable = target_type == MONSTER_TO_PLAYER;
187
188     auto *floor_ptr = player_ptr->current_floor_ptr;
189     auto *m_ptr = &floor_ptr->m_list[m_idx];
190     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
191     MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
192
193     mspell_cast_msg_simple msg(_("%^sがあなたを引き戻した。", "%^s commands you to return."),
194         _("%^sが%sを引き戻した。", "%^s commands %s to return."));
195
196     simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
197
198     if (target_type == MONSTER_TO_PLAYER) {
199         teleport_player_to(player_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_PASSIVE);
200         return res;
201     }
202
203     if (target_type != MONSTER_TO_MONSTER) {
204         return res;
205     }
206
207     bool resists_tele = false;
208     GAME_TEXT t_name[MAX_NLEN];
209     monster_name(player_ptr, t_idx, t_name);
210
211     if (tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT)) {
212         if (tr_ptr->kind_flags.has(MonsterKindType::UNIQUE) || tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
213             if (is_original_ap_and_seen(player_ptr, t_ptr)) {
214                 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
215             }
216             if (see_monster(player_ptr, t_idx)) {
217                 msg_format(_("%^sには効果がなかった。", "%^s is unaffected!"), t_name);
218             }
219             resists_tele = true;
220         } else if (tr_ptr->level > randint1(100)) {
221             if (is_original_ap_and_seen(player_ptr, t_ptr)) {
222                 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
223             }
224             if (see_monster(player_ptr, t_idx)) {
225                 msg_format(_("%^sは耐性を持っている!", "%^s resists!"), t_name);
226             }
227             resists_tele = true;
228         }
229     }
230
231     if (resists_tele) {
232         set_monster_csleep(player_ptr, t_idx, 0);
233         return res;
234     }
235
236     if (t_idx == player_ptr->riding) {
237         teleport_player_to(player_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_PASSIVE);
238     } else {
239         teleport_monster_to(player_ptr, t_idx, m_ptr->fy, m_ptr->fx, 100, TELEPORT_PASSIVE);
240     }
241     set_monster_csleep(player_ptr, t_idx, 0);
242
243     return res;
244 }
245
246 /*!
247  * @brief RF6_TELE_AWAYの処理。テレポート・アウェイ。 /
248  * @param player_ptr プレイヤーへの参照ポインタ
249  * @param m_idx 呪文を唱えるモンスターID
250  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
251  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
252  *
253  * プレイヤーが対象ならラーニング可。
254  */
255 MonsterSpellResult spell_RF6_TELE_AWAY(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
256 {
257     auto res = MonsterSpellResult::make_valid();
258     res.learnable = target_type == MONSTER_TO_PLAYER;
259
260     auto *floor_ptr = player_ptr->current_floor_ptr;
261     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
262     MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
263
264     mspell_cast_msg_simple msg(_("%^sにテレポートさせられた。", "%^s teleports you away."),
265         _("%^sは%sをテレポートさせた。", "%^s teleports %s away."));
266
267     simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
268
269     if (target_type == MONSTER_TO_PLAYER) {
270         if (is_echizen(player_ptr)) {
271             msg_print(_("くっそ~", ""));
272         } else if (is_chargeman(player_ptr)) {
273             if (randint0(2) == 0) {
274                 msg_print(_("ジュラル星人め!", ""));
275             } else {
276                 msg_print(_("弱い者いじめは止めるんだ!", ""));
277             }
278         }
279
280         teleport_player_away(m_idx, player_ptr, 100, false);
281         return res;
282     }
283
284     if (target_type != MONSTER_TO_MONSTER) {
285         return res;
286     }
287
288     bool resists_tele = false;
289     GAME_TEXT t_name[MAX_NLEN];
290     monster_name(player_ptr, t_idx, t_name);
291
292     if (tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT)) {
293         if (tr_ptr->kind_flags.has(MonsterKindType::UNIQUE) || tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
294             if (is_original_ap_and_seen(player_ptr, t_ptr)) {
295                 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
296             }
297             if (see_monster(player_ptr, t_idx)) {
298                 msg_format(_("%^sには効果がなかった。", "%^s is unaffected!"), t_name);
299             }
300             resists_tele = true;
301         } else if (tr_ptr->level > randint1(100)) {
302             if (is_original_ap_and_seen(player_ptr, t_ptr)) {
303                 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
304             }
305             if (see_monster(player_ptr, t_idx)) {
306                 msg_format(_("%^sは耐性を持っている!", "%^s resists!"), t_name);
307             }
308             resists_tele = true;
309         }
310     }
311
312     if (resists_tele) {
313         set_monster_csleep(player_ptr, t_idx, 0);
314         return res;
315     }
316
317     if (t_idx == player_ptr->riding) {
318         teleport_player_away(m_idx, player_ptr, MAX_PLAYER_SIGHT * 2 + 5, false);
319     } else {
320         teleport_away(player_ptr, t_idx, MAX_PLAYER_SIGHT * 2 + 5, TELEPORT_PASSIVE);
321     }
322     set_monster_csleep(player_ptr, t_idx, 0);
323
324     return res;
325 }
326
327 /*!
328  * @brief RF6_TELE_LEVELの処理。テレポート・レベル。 /
329  * @param player_ptr プレイヤーへの参照ポインタ
330  * @param m_idx 呪文を唱えるモンスターID
331  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
332  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
333  *
334  * ラーニング不可。
335  */
336 MonsterSpellResult spell_RF6_TELE_LEVEL(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
337 {
338     const auto res = MonsterSpellResult::make_valid();
339
340     auto *floor_ptr = player_ptr->current_floor_ptr;
341     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
342     MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
343     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
344     bool resist, saving_throw;
345
346     if (target_type == MONSTER_TO_PLAYER) {
347         resist = (has_resist_nexus(player_ptr) != 0);
348         saving_throw = (randint0(100 + rlev / 2) < player_ptr->skill_sav);
349
350         mspell_cast_msg_bad_status_to_player msg(_("%^sが何か奇妙な言葉をつぶやいた。", "%^s mumbles strangely."),
351             _("%^sがあなたの足を指さした。", "%^s gestures at your feet."), _("しかし効果がなかった!", "You are unaffected!"),
352             _("しかし効力を跳ね返した!", "You resist the effects!"));
353
354         spell_badstatus_message_to_player(player_ptr, m_idx, msg, resist, saving_throw);
355
356         if (!resist && !saving_throw) {
357             teleport_level(player_ptr, 0);
358         }
359
360         update_smart_learn(player_ptr, m_idx, DRS_NEXUS);
361         return res;
362     }
363
364     if (target_type != MONSTER_TO_MONSTER) {
365         return res;
366     }
367
368     resist = tr_ptr->resistance_flags.has_any_of(RFR_EFF_RESIST_NEXUS_MASK) || tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT);
369     saving_throw = (tr_ptr->flags1 & RF1_QUESTOR) || (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
370
371     mspell_cast_msg_bad_status_to_monster msg(_("%^sが%sの足を指さした。", "%^s gestures at %s's feet."),
372         _("%^sには効果がなかった。", "%^s is unaffected!"), _("%^sは効力を跳ね返した!", "%^s resist the effects!"), "");
373
374     spell_badstatus_message_to_mons(player_ptr, m_idx, t_idx, msg, resist, saving_throw);
375
376     if (!resist && !saving_throw) {
377         teleport_level(player_ptr, (t_idx == player_ptr->riding) ? 0 : t_idx);
378     }
379
380     return res;
381 }
382
383 /*!
384  * @brief RF6_DARKNESSの処理。暗闇or閃光。 /
385  * @param target_type プレイヤーへの参照ポインタ
386  * @param y 対象の地点のy座標
387  * @param x 対象の地点のx座標
388  * @param m_idx 呪文を唱えるモンスターID
389  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
390  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
391  *
392  * プレイヤーが対象かつ暗闇ならラーニング可。
393  */
394 MonsterSpellResult spell_RF6_DARKNESS(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
395 {
396     mspell_cast_msg_blind msg;
397     concptr msg_done;
398     auto *floor_ptr = player_ptr->current_floor_ptr;
399     auto *m_ptr = &floor_ptr->m_list[m_idx];
400     auto *r_ptr = &monraces_info[m_ptr->r_idx];
401     bool can_use_lite_area = false;
402     bool monster_to_monster = target_type == MONSTER_TO_MONSTER;
403     bool monster_to_player = target_type == MONSTER_TO_PLAYER;
404     GAME_TEXT t_name[MAX_NLEN];
405     monster_name(player_ptr, t_idx, t_name);
406
407     const auto is_ninja = PlayerClass(player_ptr).equals(PlayerClassType::NINJA);
408     const auto is_living_monster = r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD);
409     const auto is_not_weak_lite = r_ptr->resistance_flags.has_not(MonsterResistanceType::HURT_LITE);
410     if (is_ninja && is_living_monster && is_not_weak_lite && r_ptr->brightness_flags.has_none_of(dark_mask)) {
411         can_use_lite_area = true;
412     }
413
414     const auto &t_ref = floor_ptr->m_list[t_idx];
415     if (monster_to_monster && !t_ref.is_hostile()) {
416         can_use_lite_area = false;
417     }
418
419     auto res = MonsterSpellResult::make_valid();
420     res.learnable = monster_to_player && !can_use_lite_area;
421
422     if (can_use_lite_area) {
423         msg.blind = _("%^sが何かをつぶやいた。", "%^s mumbles.");
424         msg.to_player = _("%^sが辺りを明るく照らした。", "%^s cast a spell to light up.");
425         msg.to_mons = _("%^sが辺りを明るく照らした。", "%^s cast a spell to light up.");
426
427         msg_done = _("%^sは白い光に包まれた。", "%^s is surrounded by a white light.");
428     } else {
429         msg.blind = _("%^sが何かをつぶやいた。", "%^s mumbles.");
430         msg.to_player = _("%^sが暗闇の中で手を振った。", "%^s gestures in shadow.");
431         msg.to_mons = _("%^sが暗闇の中で手を振った。", "%^s gestures in shadow.");
432
433         msg_done = _("%^sは暗闇に包まれた。", "%^s is surrounded by darkness.");
434     }
435
436     monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
437
438     if (see_monster(player_ptr, t_idx) && monster_to_monster) {
439         msg_format(msg_done, t_name);
440     }
441
442     if (monster_to_player) {
443         if (can_use_lite_area) {
444             (void)lite_area(player_ptr, 0, 3);
445         } else {
446             (void)unlite_area(player_ptr, 0, 3);
447         }
448     } else if (monster_to_monster) {
449         if (can_use_lite_area) {
450             (void)project(player_ptr, m_idx, 3, y, x, 0, AttributeType::LITE_WEAK, PROJECT_GRID | PROJECT_KILL);
451             lite_room(player_ptr, y, x);
452         } else {
453             (void)project(player_ptr, m_idx, 3, y, x, 0, AttributeType::DARK_WEAK, PROJECT_GRID | PROJECT_KILL);
454             unlite_room(player_ptr, y, x);
455         }
456     }
457
458     return res;
459 }
460
461 /*!
462  * @brief RF6_TRAPSの処理。トラップ。 /
463  * @param player_ptr プレイヤーへの参照ポインタ
464  * @param y 対象の地点のy座標
465  * @param x 対象の地点のx座標
466  * @param m_idx 呪文を唱えるモンスターID
467  *
468  * ラーニング可。
469  */
470 MonsterSpellResult spell_RF6_TRAPS(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx)
471 {
472     GAME_TEXT m_name[MAX_NLEN];
473     monster_name(player_ptr, m_idx, m_name);
474     disturb(player_ptr, true, true);
475
476     if (player_ptr->effects()->blindness()->is_blind()) {
477         msg_format(_("%^sが何かをつぶやいて邪悪に微笑んだ。", "%^s mumbles, and then cackles evilly."), m_name);
478     } else {
479         msg_format(_("%^sが呪文を唱えて邪悪に微笑んだ。", "%^s casts a spell and cackles evilly."), m_name);
480     }
481
482     (void)trap_creation(player_ptr, y, x);
483
484     auto res = MonsterSpellResult::make_valid();
485     res.learnable = true;
486
487     return res;
488 }
489
490 /*!
491  * @brief RF6_RAISE_DEADの処理。死者復活。 /
492  * @param player_ptr プレイヤーへの参照ポインタ
493  * @param m_idx 呪文を唱えるモンスターID
494  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
495  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
496  *
497  * ラーニング不可。
498  */
499 MonsterSpellResult spell_RF6_RAISE_DEAD(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
500 {
501     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
502     mspell_cast_msg_blind msg(_("%^sが何かをつぶやいた。", "%^s mumbles."),
503         _("%^sが死者復活の呪文を唱えた。", "%^s casts a spell to revive corpses."), _("%^sが死者復活の呪文を唱えた。", "%^s casts a spell to revive corpses."));
504
505     monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
506
507     animate_dead(player_ptr, m_idx, m_ptr->fy, m_ptr->fx);
508
509     return MonsterSpellResult::make_valid();
510 }