OSDN Git Service

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