OSDN Git Service

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