OSDN Git Service

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