OSDN Git Service

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