OSDN Git Service

[Refactor] #2807 Renamed struct monster_race to class MonsterRaceInfo
[hengbandforosx/hengbandosx.git] / src / mspell / mspell-status.cpp
1 /*!
2  * @brief プレイヤーのステータスを下げるか、モンスター自身のステータスを上げるスペル類の処理
3  * @date 2020/05/16
4  * @author Hourier
5  * @todo やや過密気味。モンスター自身のステータスとプレイヤーのステータスで分けてもいいかもしれない.
6  */
7
8 #include "mspell/mspell-status.h"
9 #include "blue-magic/blue-magic-checker.h"
10 #include "core/disturbance.h"
11 #include "core/player-redraw-types.h"
12 #include "effect/attribute-types.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-flags1.h"
18 #include "monster-race/race-flags3.h"
19 #include "monster-race/race-indice-types.h"
20 #include "monster/monster-describer.h"
21 #include "monster/monster-description-types.h"
22 #include "monster/monster-info.h"
23 #include "monster/monster-status-setter.h"
24 #include "monster/monster-status.h"
25 #include "monster/monster-update.h"
26 #include "mspell/mspell-checker.h"
27 #include "mspell/mspell-damage-calculator.h"
28 #include "mspell/mspell-result.h"
29 #include "mspell/mspell-util.h"
30 #include "player/player-personality-types.h"
31 #include "player/player-status-flags.h"
32 #include "status/bad-status-setter.h"
33 #include "status/base-status.h"
34 #include "system/floor-type-definition.h"
35 #include "system/monster-race-definition.h"
36 #include "system/monster-type-definition.h"
37 #include "system/player-type-definition.h"
38 #include "timed-effect/player-blindness.h"
39 #include "timed-effect/timed-effects.h"
40 #include "view/display-messages.h"
41
42 mspell_cast_msg_bad_status_to_player::mspell_cast_msg_bad_status_to_player(concptr blind, concptr not_blind, concptr resist, concptr saved_throw)
43     : blind(blind)
44     , not_blind(not_blind)
45     , resist(resist)
46     , saved_throw(saved_throw)
47 {
48 }
49
50 mspell_cast_msg_bad_status_to_monster::mspell_cast_msg_bad_status_to_monster(concptr default_msg, concptr resist, concptr saved_throw, concptr success)
51     : default_msg(default_msg)
52     , resist(resist)
53     , saved_throw(saved_throw)
54     , success(success)
55 {
56 }
57
58 /*!
59  * @brief 状態異常呪文のメッセージ処理関数。 /
60  * @param player_ptr プレイヤーへの参照ポインタ
61  * @param m_idx 呪文を唱えるモンスターID
62  * @param msgs メッセージの構造体
63  * @param resist 耐性の有無を判別するフラグ
64  * @param saved_throw 抵抗に成功したか判別するフラグ
65  */
66 void spell_badstatus_message_to_player(PlayerType *player_ptr, MONSTER_IDX m_idx, const mspell_cast_msg_bad_status_to_player &msgs, bool resist,
67     bool saved_throw)
68 {
69     GAME_TEXT m_name[MAX_NLEN];
70     monster_name(player_ptr, m_idx, m_name);
71
72     disturb(player_ptr, true, true);
73     if (player_ptr->effects()->blindness()->is_blind()) {
74         msg_format(msgs.blind, m_name);
75     } else {
76         msg_format(msgs.not_blind, m_name);
77     }
78
79     if (resist) {
80         msg_print(msgs.resist);
81     } else if (saved_throw) {
82         msg_print(msgs.saved_throw);
83     }
84
85     return;
86 }
87
88 /*!
89  * @brief 状態異常呪文のメッセージ処理関数(対モンスター)。 /
90  * @param player_ptr プレーヤーへの参照ポインタ
91  * @param m_idx 呪文を唱えるモンスターID
92  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
93  * @param msgs メッセージの構造体
94  * @param resist 耐性の有無を判別するフラグ
95  * @param saved_throw 抵抗に成功したか判別するフラグ
96  */
97 void spell_badstatus_message_to_mons(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, const mspell_cast_msg_bad_status_to_monster &msgs, bool resist,
98     bool saved_throw)
99 {
100     auto *floor_ptr = player_ptr->current_floor_ptr;
101     bool see_either = see_monster(player_ptr, m_idx) || see_monster(player_ptr, t_idx);
102     bool see_t = see_monster(player_ptr, t_idx);
103     bool known = monster_near_player(floor_ptr, m_idx, t_idx);
104     GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN];
105     monster_name(player_ptr, m_idx, m_name);
106     monster_name(player_ptr, t_idx, t_name);
107
108     if (known) {
109         if (see_either) {
110             msg_format(msgs.default_msg, m_name, t_name);
111         } else {
112             floor_ptr->monster_noise = true;
113         }
114     }
115
116     if (resist) {
117         if (see_t) {
118             msg_format(msgs.resist, t_name);
119         }
120     } else if (saved_throw) {
121         if (see_t) {
122             msg_format(msgs.saved_throw, t_name);
123         }
124     } else {
125         if (see_t) {
126             msg_format(msgs.success, t_name);
127         }
128     }
129
130     set_monster_csleep(player_ptr, t_idx, 0);
131 }
132
133 /*!
134  * @brief RF5_DRAIN_MANAの処理。魔力吸収。 /
135  * @param player_ptr プレイヤーへの参照ポインタ
136  * @param y 対象の地点のy座標
137  * @param x 対象の地点のx座標
138  * @param m_idx 呪文を唱えるモンスターID
139  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
140  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
141  *
142  * プレイヤーに当たったらラーニング可。
143  */
144 MonsterSpellResult spell_RF5_DRAIN_MANA(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
145 {
146     GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN];
147     monster_name(player_ptr, m_idx, m_name);
148     monster_name(player_ptr, t_idx, t_name);
149
150     if (target_type == MONSTER_TO_PLAYER) {
151         disturb(player_ptr, true, true);
152     } else if (target_type == MONSTER_TO_MONSTER && see_monster(player_ptr, m_idx)) {
153         /* Basic message */
154         msg_format(_("%^sは精神エネルギーを%sから吸いとった。", "%^s draws psychic energy from %s."), m_name, t_name);
155     }
156
157     const auto dam = monspell_damage(player_ptr, MonsterAbilityType::DRAIN_MANA, m_idx, DAM_ROLL);
158     const auto proj_res = pointed(player_ptr, y, x, m_idx, AttributeType::DRAIN_MANA, dam, target_type);
159     if (target_type == MONSTER_TO_PLAYER) {
160         update_smart_learn(player_ptr, m_idx, DRS_MANA);
161     }
162
163     auto res = MonsterSpellResult::make_valid();
164     res.learnable = proj_res.affected_player;
165
166     return res;
167 }
168
169 /*!
170  * @brief RF5_MIND_BLASTの処理。精神攻撃。 /
171  * @param player_ptr プレイヤーへの参照ポインタ
172  * @param y 対象の地点のy座標
173  * @param x 対象の地点のx座標
174  * @param m_idx 呪文を唱えるモンスターID
175  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
176  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
177  *
178  * プレイヤーに当たったらラーニング可。
179  */
180 MonsterSpellResult spell_RF5_MIND_BLAST(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
181 {
182     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
183     bool seen = (!player_ptr->effects()->blindness()->is_blind() && m_ptr->ml);
184     GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN];
185     monster_name(player_ptr, m_idx, m_name);
186     monster_name(player_ptr, t_idx, t_name);
187
188     if (target_type == MONSTER_TO_PLAYER) {
189         disturb(player_ptr, true, true);
190         if (!seen) {
191             msg_print(_("何かがあなたの精神に念を放っているようだ。", "You feel something focusing on your mind."));
192         } else {
193             msg_format(_("%^sがあなたの瞳をじっとにらんでいる。", "%^s gazes deep into your eyes."), m_name);
194         }
195     } else if (target_type == MONSTER_TO_MONSTER && see_monster(player_ptr, m_idx)) {
196         msg_format(_("%^sは%sをじっと睨んだ。", "%^s gazes intently at %s."), m_name, t_name);
197     }
198
199     const auto dam = monspell_damage(player_ptr, MonsterAbilityType::MIND_BLAST, m_idx, DAM_ROLL);
200     const auto proj_res = pointed(player_ptr, y, x, m_idx, AttributeType::MIND_BLAST, dam, target_type);
201
202     auto res = MonsterSpellResult::make_valid(dam);
203     res.learnable = proj_res.affected_player;
204
205     return res;
206 }
207
208 /*!
209  * @brief RF5_BRAIN_SMASHの処理。脳攻撃。 /
210  * @param player_ptr プレイヤーへの参照ポインタ
211  * @param y 対象の地点のy座標
212  * @param x 対象の地点のx座標
213  * @param m_idx 呪文を唱えるモンスターID
214  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
215  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
216  *
217  * プレイヤーに当たったらラーニング可。
218  */
219 MonsterSpellResult spell_RF5_BRAIN_SMASH(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
220 {
221     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
222     bool seen = (!player_ptr->effects()->blindness()->is_blind() && m_ptr->ml);
223     GAME_TEXT m_name[MAX_NLEN], t_name[MAX_NLEN];
224     monster_name(player_ptr, m_idx, m_name);
225     monster_name(player_ptr, t_idx, t_name);
226
227     if (target_type == MONSTER_TO_PLAYER) {
228         disturb(player_ptr, true, true);
229         if (!seen) {
230             msg_print(_("何かがあなたの精神に念を放っているようだ。", "You feel something focusing on your mind."));
231         } else {
232             msg_format(_("%^sがあなたの瞳をじっとにらんでいる。", "%^s gazes deep into your eyes."), m_name);
233         }
234     } else if (target_type == MONSTER_TO_MONSTER && see_monster(player_ptr, m_idx)) {
235         msg_format(_("%^sは%sをじっと睨んだ。", "%^s gazes intently at %s."), m_name, t_name);
236     }
237
238     const auto dam = monspell_damage(player_ptr, MonsterAbilityType::BRAIN_SMASH, m_idx, DAM_ROLL);
239     const auto proj_res = pointed(player_ptr, y, x, m_idx, AttributeType::BRAIN_SMASH, dam, target_type);
240
241     auto res = MonsterSpellResult::make_valid(dam);
242     res.learnable = proj_res.affected_player;
243
244     return res;
245 }
246
247 /*!
248  * @brief RF5_SCAREの処理。恐怖。 /
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_RF5_SCARE(MONSTER_IDX m_idx, PlayerType *player_ptr, 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     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
264     bool resist, saving_throw;
265
266     if (target_type == MONSTER_TO_PLAYER) {
267         resist = (has_resist_fear(player_ptr) != 0);
268         saving_throw = (randint0(100 + rlev / 2) < player_ptr->skill_sav);
269
270         mspell_cast_msg_bad_status_to_player msg(_("%^sが何かをつぶやくと、恐ろしげな音が聞こえた。", "%^s mumbles, and you hear scary noises."),
271             _("%^sが恐ろしげな幻覚を作り出した。", "%^s casts a fearful illusion."), _("しかし恐怖に侵されなかった。", "You refuse to be frightened."),
272             _("しかし恐怖に侵されなかった。", "You refuse to be frightened."));
273
274         spell_badstatus_message_to_player(player_ptr, m_idx, msg, resist, saving_throw);
275
276         if (!resist && !saving_throw) {
277             (void)BadStatusSetter(player_ptr).mod_fear(randint0(4) + 4);
278         }
279
280         update_smart_learn(player_ptr, m_idx, DRS_FEAR);
281         return res;
282     }
283
284     if (target_type != MONSTER_TO_MONSTER) {
285         return res;
286     }
287
288     resist = ((tr_ptr->flags3 & RF3_NO_FEAR) != 0);
289     saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
290
291     mspell_cast_msg_bad_status_to_monster msg(_("%^sが恐ろしげな幻覚を作り出した。", "%^s casts a fearful illusion in front of %s."),
292         _("%^sは恐怖を感じない。", "%^s refuses to be frightened."), _("%^sは恐怖を感じない。", "%^s refuses to be frightened."),
293         _("%^sは恐怖して逃げ出した!", "%^s flees in terror!"));
294
295     spell_badstatus_message_to_mons(player_ptr, m_idx, t_idx, msg, resist, saving_throw);
296
297     if (!resist && !saving_throw) {
298         set_monster_monfear(player_ptr, t_idx, t_ptr->get_remaining_fear() + randint0(4) + 4);
299     }
300
301     return res;
302 }
303
304 /*!
305  * @brief RF5_BLINDの処理。盲目。 /
306  * @param m_idx 呪文を唱えるモンスターID
307  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
308  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
309  *
310  * プレイヤーが対象ならラーニング可。
311  */
312 MonsterSpellResult spell_RF5_BLIND(MONSTER_IDX m_idx, PlayerType *player_ptr, MONSTER_IDX t_idx, int target_type)
313 {
314     auto res = MonsterSpellResult::make_valid();
315     res.learnable = target_type == MONSTER_TO_PLAYER;
316
317     auto *floor_ptr = player_ptr->current_floor_ptr;
318     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
319     MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
320     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
321     bool resist, saving_throw;
322
323     if (target_type == MONSTER_TO_PLAYER) {
324         resist = (has_resist_blind(player_ptr) != 0);
325         saving_throw = (randint0(100 + rlev / 2) < player_ptr->skill_sav);
326
327         mspell_cast_msg_bad_status_to_player msg(_("%^sが何かをつぶやいた。", "%^s mumbles."),
328             _("%^sが呪文を唱えてあなたの目をくらました!", "%^s casts a spell, burning your eyes!"), _("しかし効果がなかった!", "You are unaffected!"),
329             _("しかし効力を跳ね返した!", "You resist the effects!"));
330
331         spell_badstatus_message_to_player(player_ptr, m_idx, msg, resist, saving_throw);
332
333         if (!resist && !saving_throw) {
334             (void)BadStatusSetter(player_ptr).set_blindness(12 + randint0(4));
335         }
336
337         update_smart_learn(player_ptr, m_idx, DRS_BLIND);
338         return res;
339     }
340
341     if (target_type != MONSTER_TO_MONSTER) {
342         return res;
343     }
344
345     concptr msg_default;
346     GAME_TEXT t_name[MAX_NLEN];
347     monster_name(player_ptr, t_idx, t_name);
348
349     if (streq(t_name, "it")) {
350         msg_default = _("%sは呪文を唱えて%sの目を焼き付かせた。", "%^s casts a spell, burning %ss eyes.");
351     } else {
352         msg_default = _("%sは呪文を唱えて%sの目を焼き付かせた。", "%^s casts a spell, burning %s's eyes.");
353     }
354
355     resist = ((tr_ptr->flags3 & RF3_NO_CONF) != 0);
356     saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
357
358     mspell_cast_msg_bad_status_to_monster msg(msg_default, _("%^sには効果がなかった。", "%^s is unaffected."),
359         _("%^sには効果がなかった。", "%^s is unaffected."), _("%^sは目が見えなくなった! ", "%^s is blinded!"));
360
361     spell_badstatus_message_to_mons(player_ptr, m_idx, t_idx, msg, resist, saving_throw);
362
363     if (!resist && !saving_throw) {
364         (void)set_monster_confused(player_ptr, t_idx, t_ptr->get_remaining_confusion() + 12 + randint0(4));
365     }
366
367     return res;
368 }
369
370 /*!
371  * @brief RF5_CONFの処理。混乱。/
372  * @param m_idx 呪文を唱えるモンスターID
373  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
374  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
375  *
376  * プレイヤーが対象ならラーニング可。
377  */
378 MonsterSpellResult spell_RF5_CONF(MONSTER_IDX m_idx, PlayerType *player_ptr, MONSTER_IDX t_idx, int target_type)
379 {
380     auto res = MonsterSpellResult::make_valid();
381     res.learnable = target_type == MONSTER_TO_PLAYER;
382
383     auto *floor_ptr = player_ptr->current_floor_ptr;
384     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
385     MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
386     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
387     bool resist, saving_throw;
388
389     if (target_type == MONSTER_TO_PLAYER) {
390         resist = (has_resist_conf(player_ptr) != 0);
391         saving_throw = (randint0(100 + rlev / 2) < player_ptr->skill_sav);
392
393         mspell_cast_msg_bad_status_to_player msg(_("%^sが何かをつぶやくと、頭を悩ます音がした。", "%^s mumbles, and you hear puzzling noises."),
394             _("%^sが誘惑的な幻覚を作り出した。", "%^s creates a mesmerising illusion."),
395             _("しかし幻覚にはだまされなかった。", "You disbelieve the feeble spell."),
396             _("しかし幻覚にはだまされなかった。", "You disbelieve the feeble spell."));
397
398         spell_badstatus_message_to_player(player_ptr, m_idx, msg, resist, saving_throw);
399
400         if (!resist && !saving_throw) {
401             (void)BadStatusSetter(player_ptr).mod_confusion(randint0(4) + 4);
402         }
403
404         update_smart_learn(player_ptr, m_idx, DRS_CONF);
405         return res;
406     }
407
408     if (target_type != MONSTER_TO_MONSTER) {
409         return res;
410     }
411
412     resist = ((tr_ptr->flags3 & RF3_NO_CONF) != 0);
413     saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
414
415     mspell_cast_msg_bad_status_to_monster msg(_("%^sが%sの前に幻惑的な幻をつくり出した。", "%^s casts a mesmerizing illusion in front of %s."),
416         _("%^sは惑わされなかった。", "%^s disbelieves the feeble spell."), _("%^sは惑わされなかった。", "%^s disbelieves the feeble spell."),
417         _("%^sは混乱したようだ。", "%^s seems confused."));
418
419     spell_badstatus_message_to_mons(player_ptr, m_idx, t_idx, msg, resist, saving_throw);
420
421     if (!resist && !saving_throw) {
422         (void)set_monster_confused(player_ptr, t_idx, t_ptr->get_remaining_confusion() + 12 + randint0(4));
423     }
424
425     return res;
426 }
427
428 /*!
429  * @brief RF5_HOLDの処理。麻痺。 /
430  * @param m_idx 呪文を唱えるモンスターID
431  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
432  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
433  *
434  * プレイヤーが対象ならラーニング可。
435  */
436 MonsterSpellResult spell_RF5_HOLD(MONSTER_IDX m_idx, PlayerType *player_ptr, MONSTER_IDX t_idx, int target_type)
437 {
438     auto res = MonsterSpellResult::make_valid();
439     res.learnable = target_type == MONSTER_TO_PLAYER;
440
441     auto *floor_ptr = player_ptr->current_floor_ptr;
442     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
443     MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
444     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
445     bool resist, saving_throw;
446
447     if (target_type == MONSTER_TO_PLAYER) {
448         resist = (player_ptr->free_act != 0);
449         saving_throw = (randint0(100 + rlev / 2) < player_ptr->skill_sav);
450
451         mspell_cast_msg_bad_status_to_player msg(_("%^sが何かをつぶやいた。", "%^s mumbles."),
452             _("%^sがあなたの目をじっと見つめた!", "%^s stares deep into your eyes!"), _("しかし効果がなかった!", "You are unaffected!"),
453             _("しかし効力を跳ね返した!", "You resist the effects!"));
454
455         spell_badstatus_message_to_player(player_ptr, m_idx, msg, (bool)resist, saving_throw);
456
457         if (!resist && !saving_throw) {
458             (void)BadStatusSetter(player_ptr).mod_paralysis(randint0(4) + 4);
459         }
460
461         update_smart_learn(player_ptr, m_idx, DRS_FREE);
462         return res;
463     }
464
465     if (target_type != MONSTER_TO_MONSTER) {
466         return res;
467     }
468
469     resist = (tr_ptr->kind_flags.has(MonsterKindType::UNIQUE) || (tr_ptr->flags3 & RF3_NO_STUN) != 0);
470     saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
471
472     mspell_cast_msg_bad_status_to_monster msg(_("%^sは%sをじっと見つめた。", "%^s stares intently at %s."),
473         _("%^sには効果がなかった。", "%^s is unaffected."), _("%^sには効果がなかった。", "%^s is unaffected."), _("%^sは麻痺した!", "%^s is paralyzed!"));
474
475     spell_badstatus_message_to_mons(player_ptr, m_idx, t_idx, msg, (bool)resist, saving_throw);
476
477     if (!resist && !saving_throw) {
478         (void)set_monster_stunned(player_ptr, t_idx, t_ptr->get_remaining_stun() + randint1(4) + 4);
479     }
480
481     return res;
482 }
483
484 /*!
485  * @brief RF6_HASTEの処理。加速。 /
486  * @param player_ptr プレイヤーへの参照ポインタ
487  * @param m_idx 呪文を唱えるモンスターID
488  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
489  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
490  *
491  * ラーニング不可。
492  */
493 MonsterSpellResult spell_RF6_HASTE(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
494 {
495     bool see_m = see_monster(player_ptr, m_idx);
496     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
497     GAME_TEXT m_name[MAX_NLEN];
498     monster_name(player_ptr, m_idx, m_name);
499     char m_poss[10];
500     monster_desc(player_ptr, m_poss, m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE);
501
502     mspell_cast_msg msg(_("%^sが何かをつぶやいた。", "%^s mumbles."),
503         _("%^sが自分の体に念を送った。", format("%%^s concentrates on %s body.", m_poss)),
504         _("%^sが自分の体に念を送った。", format("%%^s concentrates on %s body.", m_poss)),
505         _("%^sが自分の体に念を送った。", format("%%^s concentrates on %s body.", m_poss)));
506
507     monspell_message_base(player_ptr, m_idx, t_idx, msg, player_ptr->effects()->blindness()->is_blind(), target_type);
508
509     if (set_monster_fast(player_ptr, m_idx, m_ptr->get_remaining_acceleration() + 100)) {
510         if (target_type == MONSTER_TO_PLAYER || (target_type == MONSTER_TO_MONSTER && see_m)) {
511             msg_format(_("%^sの動きが速くなった。", "%^s starts moving faster."), m_name);
512         }
513     }
514
515     return MonsterSpellResult::make_valid();
516 }
517
518 /*!
519  * @brief RF5_SLOWの処理。減速。 /
520  * @param m_idx 呪文を唱えるモンスターID
521  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
522  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
523  *
524  * プレイヤーが対象ならラーニング可。
525  */
526 MonsterSpellResult spell_RF5_SLOW(MONSTER_IDX m_idx, PlayerType *player_ptr, MONSTER_IDX t_idx, int target_type)
527 {
528     auto res = MonsterSpellResult::make_valid();
529     res.learnable = target_type == MONSTER_TO_PLAYER;
530
531     auto *floor_ptr = player_ptr->current_floor_ptr;
532     MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
533     MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
534     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
535     bool resist, saving_throw;
536
537     if (target_type == MONSTER_TO_PLAYER) {
538         resist = (has_resist_conf(player_ptr) != 0);
539         saving_throw = (randint0(100 + rlev / 2) < player_ptr->skill_sav);
540
541         mspell_cast_msg_bad_status_to_player msg(_("%^sがあなたの筋力を吸い取ろうとした!", "%^s drains power from your muscles!"),
542             _("%^sがあなたの筋力を吸い取ろうとした!", "%^s drains power from your muscles!"), _("しかし効果がなかった!", "You are unaffected!"),
543             _("しかし効力を跳ね返した!", "You resist the effects!"));
544
545         spell_badstatus_message_to_player(player_ptr, m_idx, msg, resist, saving_throw);
546
547         if (!resist && !saving_throw) {
548             (void)BadStatusSetter(player_ptr).mod_deceleration(randint0(4) + 4, false);
549         }
550
551         update_smart_learn(player_ptr, m_idx, DRS_FREE);
552         return res;
553     }
554
555     if (target_type != MONSTER_TO_MONSTER) {
556         return res;
557     }
558
559     concptr msg_default;
560     GAME_TEXT t_name[MAX_NLEN];
561     monster_name(player_ptr, t_idx, t_name);
562
563     if (streq(t_name, "it")) {
564         msg_default = _("%sが%sの筋肉から力を吸いとった。", "%^s drains power from %ss muscles.");
565     } else {
566         msg_default = _("%sが%sの筋肉から力を吸いとった。", "%^s drains power from %s's muscles.");
567     }
568
569     resist = (tr_ptr->kind_flags.has(MonsterKindType::UNIQUE));
570     saving_throw = (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
571
572     mspell_cast_msg_bad_status_to_monster msg(msg_default, _("%^sには効果がなかった。", "%^s is unaffected."),
573         _("%^sには効果がなかった。", "%^s is unaffected."), _("%sの動きが遅くなった。", "%^s starts moving slower."));
574
575     spell_badstatus_message_to_mons(player_ptr, m_idx, t_idx, msg, resist, saving_throw);
576
577     if (!resist && !saving_throw) {
578         set_monster_slow(player_ptr, t_idx, t_ptr->get_remaining_deceleration() + 50);
579     }
580
581     return res;
582 }
583
584 /*!
585  * @brief RF6_HEALの処理。治癒。 /
586  * @param player_ptr プレイヤーへの参照ポインタ
587  * @param m_idx 呪文を唱えるモンスターID
588  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
589  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
590  *
591  * ラーニング不可。
592  */
593 MonsterSpellResult spell_RF6_HEAL(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
594 {
595     const auto res = MonsterSpellResult::make_valid();
596
597     mspell_cast_msg msg;
598     auto *floor_ptr = player_ptr->current_floor_ptr;
599     auto *m_ptr = &floor_ptr->m_list[m_idx];
600     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
601     const auto is_blind = player_ptr->effects()->blindness()->is_blind();
602     const auto seen = (!is_blind && m_ptr->ml);
603     GAME_TEXT m_name[MAX_NLEN];
604     monster_name(player_ptr, m_idx, m_name);
605     char m_poss[10];
606     monster_desc(player_ptr, m_poss, m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE);
607
608     msg.to_player_true = _("%^sが何かをつぶやいた。", "%^s mumbles.");
609     msg.to_mons_true = _("%^sは自分の傷に念を集中した。", format("%%^s concentrates on %s wounds.", m_poss));
610     msg.to_player_false = _("%^sが自分の傷に集中した。", format("%%^s concentrates on %s wounds.", m_poss));
611     msg.to_mons_false = _("%^sは自分の傷に念を集中した。", format("%%^s concentrates on %s wounds.", m_poss));
612
613     monspell_message_base(player_ptr, m_idx, t_idx, msg, is_blind, target_type);
614
615     m_ptr->hp += (rlev * 6);
616     if (m_ptr->hp >= m_ptr->maxhp) {
617         /* Fully healed */
618         m_ptr->hp = m_ptr->maxhp;
619
620         msg.to_player_true = _("%^sは完全に治ったようだ!", "%^s sounds completely healed!");
621         msg.to_mons_true = _("%^sは完全に治ったようだ!", "%^s sounds completely healed!");
622         msg.to_player_false = _("%^sは完全に治った!", "%^s looks completely healed!");
623         msg.to_mons_false = _("%^sは完全に治った!", "%^s looks completely healed!");
624     } else {
625         msg.to_player_true = _("%^sは体力を回復したようだ。", "%^s sounds healthier.");
626         msg.to_mons_true = _("%^sは体力を回復したようだ。", "%^s sounds healthier.");
627         msg.to_player_false = _("%^sは体力を回復したようだ。", "%^s looks healthier.");
628         msg.to_mons_false = _("%^sは体力を回復したようだ。", "%^s looks healthier.");
629     }
630
631     monspell_message_base(player_ptr, m_idx, t_idx, msg, !seen, target_type);
632
633     if (player_ptr->health_who == m_idx) {
634         player_ptr->redraw |= (PR_HEALTH);
635     }
636     if (player_ptr->riding == m_idx) {
637         player_ptr->redraw |= (PR_UHEALTH);
638     }
639
640     if (!m_ptr->is_fearful()) {
641         return res;
642     }
643
644     (void)set_monster_monfear(player_ptr, m_idx, 0);
645
646     if (see_monster(player_ptr, m_idx)) {
647         msg_format(_("%^sは勇気を取り戻した。", format("%%^s recovers %s courage.", m_poss)), m_name);
648     }
649
650     return res;
651 }
652
653 /*!
654  * @brief RF6_INVULNERの処理。無敵。 /
655  * @param player_ptr プレイヤーへの参照ポインタ
656  * @param m_idx 呪文を唱えるモンスターID
657  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
658  * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
659  *
660  * ラーニング不可。
661  */
662 MonsterSpellResult spell_RF6_INVULNER(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
663 {
664     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
665     bool seen = (!player_ptr->effects()->blindness()->is_blind() && m_ptr->ml);
666     mspell_cast_msg msg(_("%^sが何かを力強くつぶやいた。", "%^s mumbles powerfully."),
667         _("%^sが何かを力強くつぶやいた。", "%^s mumbles powerfully."), _("%sは無傷の球の呪文を唱えた。", "%^s casts a Globe of Invulnerability."),
668         _("%sは無傷の球の呪文を唱えた。", "%^s casts a Globe of Invulnerability."));
669
670     monspell_message_base(player_ptr, m_idx, t_idx, msg, !seen, target_type);
671
672     if (m_ptr->ml) {
673         MonsterRaceId r_idx = m_ptr->r_idx;
674         GAME_TEXT m_name[MAX_NLEN];
675         monster_desc(player_ptr, m_name, m_ptr, MD_NONE);
676         switch (r_idx) {
677         case MonsterRaceId::MARIO:
678         case MonsterRaceId::LUIGI:
679             msg_format(_("%sはスターを取った!", "%^s got a star!"), m_name);
680             break;
681         case MonsterRaceId::DIAVOLO:
682             msg_print(_("『読める』………動きの『軌跡』が読める……", "'Read'......... I can read the 'trajectory' of movement..."));
683             break;
684         default:
685             msg_format(_("%sの身体がまばゆく輝き始めた!", "The body of %^s began to shine dazzlingly!"), m_name);
686             break;
687         }
688     }
689
690     if (!m_ptr->is_invulnerable()) {
691         (void)set_monster_invulner(player_ptr, m_idx, randint1(4) + 4, false);
692     }
693
694     return MonsterSpellResult::make_valid();
695 }
696
697 /*!
698  * @brief RF6_FORGETの処理。記憶消去。 /
699  * @param player_ptr プレイヤーへの参照ポインタ
700  * @param m_idx 呪文を唱えるモンスターID
701  *
702  * ラーニング可。
703  */
704 MonsterSpellResult spell_RF6_FORGET(PlayerType *player_ptr, MONSTER_IDX m_idx)
705 {
706     DEPTH rlev = monster_level_idx(player_ptr->current_floor_ptr, m_idx);
707     GAME_TEXT m_name[MAX_NLEN];
708     monster_name(player_ptr, m_idx, m_name);
709
710     disturb(player_ptr, true, true);
711
712     msg_format(_("%^sがあなたの記憶を消去しようとしている。", "%^s tries to blank your mind."), m_name);
713
714     if (randint0(100 + rlev / 2) < player_ptr->skill_sav) {
715         msg_print(_("しかし効力を跳ね返した!", "You resist the effects!"));
716     } else if (lose_all_info(player_ptr)) {
717         msg_print(_("記憶が薄れてしまった。", "Your memories fade away."));
718     }
719
720     auto res = MonsterSpellResult::make_valid();
721     res.learnable = true;
722
723     return res;
724 }