OSDN Git Service

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