OSDN Git Service

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