OSDN Git Service

[Refactor] #1558 Replaced set_afraid() to afraidness() and transferred it into the...
[hengbandforosx/hengbandosx.git] / src / effect / effect-monster-psi.cpp
1 #include "effect/effect-monster-psi.h"
2 #include "core/player-redraw-types.h"
3 #include "core/window-redrawer.h"
4 #include "effect/effect-monster-util.h"
5 #include "floor/line-of-sight.h"
6 #include "mind/mind-mirror-master.h"
7 #include "monster-race/monster-race.h"
8 #include "monster-race/race-flags1.h"
9 #include "monster-race/race-flags2.h"
10 #include "monster-race/race-flags3.h"
11 #include "monster/monster-describer.h"
12 #include "monster/monster-description-types.h"
13 #include "monster/monster-info.h"
14 #include "player/player-damage.h"
15 #include "status/bad-status-setter.h"
16 #include "system/grid-type-definition.h"
17 #include "system/monster-race-definition.h"
18 #include "system/monster-type-definition.h"
19 #include "system/player-type-definition.h"
20 #include "timed-effect/player-stun.h"
21 #include "timed-effect/timed-effects.h"
22 #include "util/bit-flags-calculator.h"
23 #include "view/display-messages.h"
24 #include "world/world.h"
25
26 /*!
27  * @brief 精神のないモンスターのPsi攻撃に対する完全な耐性を発動する
28  * @param player_ptr プレイヤーへの参照ポインタ
29  * @param em_ptr モンスター効果への参照ポインタ
30  * @return 完全な耐性を発動した場合TRUE、そうでなければFALSE
31  */
32 static bool resisted_psi_because_empty_mind(player_type *player_ptr, effect_monster_type *em_ptr)
33 {
34     if (none_bits(em_ptr->r_ptr->flags2, RF2_EMPTY_MIND))
35         return false;
36
37     em_ptr->dam = 0;
38     em_ptr->note = _("には完全な耐性がある!", " is immune.");
39     if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr))
40         set_bits(em_ptr->r_ptr->r_flags2, RF2_EMPTY_MIND);
41
42     return true;
43 }
44
45 /*!
46  * @brief 異質な精神のモンスター及び強力なモンスターのPsi攻撃に対する耐性を発動する
47  * @param em_ptr モンスター効果への参照ポインタ
48  * @return 耐性を発動した場合TRUE、そうでなければFALSE
49  * @details
50  * 以下のいずれかの場合は耐性がある
51  * 1) STUPIDまたはWIERD_MINDである
52  * 2) ANIMALである
53  * 3) レベルが d(3*ダメージ) より大きい
54  */
55 static bool resisted_psi_because_weird_mind_or_powerful(effect_monster_type *em_ptr)
56 {
57     bool has_resistance = any_bits(em_ptr->r_ptr->flags2, RF2_STUPID | RF2_WEIRD_MIND) || any_bits(em_ptr->r_ptr->flags3, RF3_ANIMAL)
58         || (em_ptr->r_ptr->level > randint1(3 * em_ptr->dam));
59     if (!has_resistance)
60         return false;
61
62     em_ptr->note = _("には耐性がある!", " resists!");
63     em_ptr->dam /= 3;
64     return true;
65 }
66
67 /*!
68  * @brief 堕落した精神のモンスターへのPsi攻撃のダメージ反射を発動する
69  * @param player_ptr プレイヤーへの参照ポインタ
70  * @param em_ptr モンスター効果への参照ポインタ
71  * @return ダメージ反射を発動した場合TRUE、そうでなければFALSE
72  * @details
73  * 以下の条件を満たす場合に 1/2 の確率でダメージ反射する
74  * 1) UNDEADまたはDEMONである
75  * 2) レベルが詠唱者の レベル/2 より大きい
76  */
77 static bool reflects_psi_with_currupted_mind(player_type *player_ptr, effect_monster_type *em_ptr)
78 {
79     bool is_corrupted = any_bits(em_ptr->r_ptr->flags3, RF3_UNDEAD | RF3_DEMON) && (em_ptr->r_ptr->level > player_ptr->lev / 2) && one_in_(2);
80     if (!is_corrupted)
81         return false;
82
83     em_ptr->note = nullptr;
84     msg_format(_("%^sの堕落した精神は攻撃を跳ね返した!",
85                    (em_ptr->seen ? "%^s's corrupted mind backlashes your attack!" : "%^ss corrupted mind backlashes your attack!")),
86         em_ptr->m_name);
87     return true;
88 }
89
90 /*!
91  * @brief モンスターがPsi攻撃をダメージ反射した場合のプレイヤーへの追加効果を発動する
92  * @param player_ptr プレイヤーへの参照ポインタ
93  * @param em_ptr モンスター効果への参照ポインタ
94  * @details
95  * 効果は、混乱、朦朧、恐怖、麻痺
96  * 3/4の確率または影分身時はダメージ及び追加効果はない。
97  */
98 static void effect_monster_psi_reflect_extra_effect(player_type *player_ptr, effect_monster_type *em_ptr)
99 {
100     if (!one_in_(4) || check_multishadow(player_ptr)) {
101         return;
102     }
103
104     BadStatusSetter bss(player_ptr);
105     switch (randint1(4)) {
106     case 1:
107         (void)bss.confusion(player_ptr->confused + 3 + randint1(em_ptr->dam));
108         return;
109     case 2:
110         set_stun(player_ptr, player_ptr->effects()->stun()->current() + randint1(em_ptr->dam));
111         return;
112     case 3:
113         if (any_bits(em_ptr->r_ptr->flags3, RF3_NO_FEAR)) {
114             em_ptr->note = _("には効果がなかった。", " is unaffected.");
115         } else {
116             (void)bss.afraidness(player_ptr->afraid + 3 + randint1(em_ptr->dam));
117         }
118
119         return;
120     default:
121         if (!player_ptr->free_act) {
122             (void)set_paralyzed(player_ptr, player_ptr->paralyzed + randint1(em_ptr->dam));
123         }
124
125         return;
126     }
127 }
128
129 /*!
130  * @brief モンスターのPsi攻撃に対する耐性を発動する
131  * @param player_ptr プレイヤーへの参照ポインタ
132  * @param em_ptr モンスター効果への参照ポインタ
133  * @details
134  * 耐性を発動した精神の堕落したモンスターは効力を跳ね返すことがある。
135  */
136 static void effect_monster_psi_resist(player_type *player_ptr, effect_monster_type *em_ptr)
137 {
138     if (resisted_psi_because_empty_mind(player_ptr, em_ptr))
139         return;
140     if (!resisted_psi_because_weird_mind_or_powerful(em_ptr))
141         return;
142     if (!reflects_psi_with_currupted_mind(player_ptr, em_ptr))
143         return;
144
145     /* プレイヤーの反射判定 */
146     if ((randint0(100 + em_ptr->r_ptr->level / 2) < player_ptr->skill_sav) && !check_multishadow(player_ptr)) {
147         msg_print(_("しかし効力を跳ね返した!", "You resist the effects!"));
148         em_ptr->dam = 0;
149         return;
150     }
151
152     /* Injure +/- confusion */
153     monster_desc(player_ptr, em_ptr->killer, em_ptr->m_ptr, MD_WRONGDOER_NAME);
154     take_hit(player_ptr, DAMAGE_ATTACK, em_ptr->dam, em_ptr->killer);
155     effect_monster_psi_reflect_extra_effect(player_ptr, em_ptr);
156     em_ptr->dam = 0;
157 }
158
159 /*!
160  * @brief モンスターへのPsi攻撃の追加効果を発動する
161  * @param player_ptr プレイヤーへの参照ポインタ
162  * @param em_ptr モンスター効果への参照ポインタ
163  * @details
164  * 効果は、混乱、朦朧、恐怖、麻痺(各耐性無効)
165  * ダメージがないか3/4の確率で効果なし
166  */
167 static void effect_monster_psi_extra_effect(effect_monster_type *em_ptr)
168 {
169     if ((em_ptr->dam <= 0) || !one_in_(4))
170         return;
171
172     switch (randint1(4)) {
173     case 1:
174         em_ptr->do_conf = 3 + randint1(em_ptr->dam);
175         break;
176     case 2:
177         em_ptr->do_stun = 3 + randint1(em_ptr->dam);
178         break;
179     case 3:
180         em_ptr->do_fear = 3 + randint1(em_ptr->dam);
181         break;
182     default:
183         em_ptr->note = _("は眠り込んでしまった!", " falls asleep!");
184         em_ptr->do_sleep = 3 + randint1(em_ptr->dam);
185         break;
186     }
187 }
188
189 /*!
190  * @brief モンスターへのPsi攻撃(GF_PSI)の効果を発動する
191  * @param player_ptr プレイヤーへの参照ポインタ
192  * @param em_ptr モンスター効果への参照ポインタ
193  * @return PROICESS_CONTINUE
194  * @details
195  * 視界による影響を発動する。
196  * モンスターの耐性とそれに不随した効果を発動する。
197  */
198 process_result effect_monster_psi(player_type *player_ptr, effect_monster_type *em_ptr)
199 {
200     if (em_ptr->seen)
201         em_ptr->obvious = true;
202     if (!(los(player_ptr, em_ptr->m_ptr->fy, em_ptr->m_ptr->fx, player_ptr->y, player_ptr->x))) {
203         if (em_ptr->seen_msg)
204             msg_format(_("%sはあなたが見えないので影響されない!", "%^s can't see you, and isn't affected!"), em_ptr->m_name);
205
206         em_ptr->skipped = true;
207         return PROCESS_CONTINUE;
208     }
209
210     effect_monster_psi_resist(player_ptr, em_ptr);
211     effect_monster_psi_extra_effect(em_ptr);
212     em_ptr->note_dies = _("の精神は崩壊し、肉体は抜け殻となった。", " collapses, a mindless husk.");
213     return PROCESS_CONTINUE;
214 }
215
216 /*!
217  * @brief モンスターのPsi攻撃(GF_PSI_DRAIN)に対する耐性を発動する
218  * @param player_ptr プレイヤーへの参照ポインタ
219  * @param em_ptr モンスター効果への参照ポインタ
220  * @details
221  * 耐性を発動した精神の堕落したモンスターは効力を跳ね返すことがある。
222  */
223 static void effect_monster_psi_drain_resist(player_type *player_ptr, effect_monster_type *em_ptr)
224 {
225     if (resisted_psi_because_empty_mind(player_ptr, em_ptr))
226         return;
227     if (!resisted_psi_because_weird_mind_or_powerful(em_ptr))
228         return;
229     if (!reflects_psi_with_currupted_mind(player_ptr, em_ptr))
230         return;
231
232     /* プレイヤーの反射判定 */
233     if ((randint0(100 + em_ptr->r_ptr->level / 2) < player_ptr->skill_sav) && !check_multishadow(player_ptr)) {
234         msg_print(_("あなたは効力を跳ね返した!", "You resist the effects!"));
235         em_ptr->dam = 0;
236         return;
237     }
238
239     monster_desc(player_ptr, em_ptr->killer, em_ptr->m_ptr, MD_WRONGDOER_NAME);
240     if (check_multishadow(player_ptr)) {
241         take_hit(player_ptr, DAMAGE_ATTACK, em_ptr->dam, em_ptr->killer);
242         em_ptr->dam = 0;
243         return;
244     }
245
246     msg_print(_("超能力パワーを吸いとられた!", "Your psychic energy is drained!"));
247     player_ptr->csp -= damroll(5, em_ptr->dam) / 2;
248     if (player_ptr->csp < 0)
249         player_ptr->csp = 0;
250
251     set_bits(player_ptr->redraw, PR_MANA);
252     set_bits(player_ptr->window_flags, PW_SPELL);
253     take_hit(player_ptr, DAMAGE_ATTACK, em_ptr->dam, em_ptr->killer);
254     em_ptr->dam = 0;
255 }
256
257 /*!
258  * @brief モンスターへのPsi攻撃(GF_PSI_DRAIN)のダメージをMPに変換する
259  * @param player_ptr プレイヤーへの参照ポインタ
260  * @param em_ptr モンスター効果への参照ポインタ
261  */
262 static void effect_monster_psi_drain_change_power(player_type *player_ptr, effect_monster_type *em_ptr)
263 {
264     int b = damroll(5, em_ptr->dam) / 4;
265     concptr str = (player_ptr->pclass == CLASS_MINDCRAFTER) ? _("超能力パワー", "psychic energy") : _("魔力", "mana");
266     concptr msg = _("あなたは%sの苦痛を%sに変換した!", (em_ptr->seen ? "You convert %s's pain into %s!" : "You convert %ss pain into %s!"));
267     msg_format(msg, em_ptr->m_name, str);
268
269     b = MIN(player_ptr->msp, player_ptr->csp + b);
270     player_ptr->csp = b;
271     set_bits(player_ptr->redraw, PR_MANA);
272     set_bits(player_ptr->window_flags, PW_SPELL);
273 }
274
275 /*!
276  * @brief モンスターへのPsi攻撃(GF_PSI_DRAIN)の効果を発動する
277  * @param player_ptr プレイヤーへの参照ポインタ
278  * @param em_ptr モンスター効果への参照ポインタ
279  * @return PROICESS_CONTINUE
280  * @details
281  * ダメージがないか3/4の確率で追加効果なし
282  */
283 process_result effect_monster_psi_drain(player_type *player_ptr, effect_monster_type *em_ptr)
284 {
285     if (em_ptr->seen)
286         em_ptr->obvious = true;
287
288     effect_monster_psi_drain_resist(player_ptr, em_ptr);
289     if (em_ptr->dam > 0)
290         effect_monster_psi_drain_change_power(player_ptr, em_ptr);
291
292     em_ptr->note_dies = _("の精神は崩壊し、肉体は抜け殻となった。", " collapses, a mindless husk.");
293     return PROCESS_CONTINUE;
294 }
295
296 /*!
297  * @brief モンスターへのテレキネシス(GF_TELEKINESIS)の効果を発動する
298  * @param player_ptr プレイヤーへの参照ポインタ
299  * @param em_ptr モンスター効果への参照ポインタ
300  * @return PROICESS_CONTINUE
301  * @details
302  * 朦朧+ショートテレポートアウェイ
303  */
304 process_result effect_monster_telekinesis(player_type *player_ptr, effect_monster_type *em_ptr)
305 {
306     if (em_ptr->seen)
307         em_ptr->obvious = true;
308     if (one_in_(4)) {
309         if (player_ptr->riding && (em_ptr->g_ptr->m_idx == player_ptr->riding))
310             em_ptr->do_dist = 0;
311         else
312             em_ptr->do_dist = 7;
313     }
314
315     em_ptr->do_stun = damroll((em_ptr->caster_lev / 20) + 3, em_ptr->dam) + 1;
316     if (any_bits(em_ptr->r_ptr->flags1, RF1_UNIQUE) || (em_ptr->r_ptr->level > 5 + randint1(em_ptr->dam))) {
317         em_ptr->do_stun = 0;
318         em_ptr->obvious = false;
319     }
320
321     return PROCESS_CONTINUE;
322 }