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"
28 * @brief 精神のないモンスターのPsi攻撃に対する完全な耐性を発動する
29 * @param player_ptr プレイヤーへの参照ポインタ
30 * @param em_ptr モンスター効果への参照ポインタ
31 * @return 完全な耐性を発動した場合TRUE、そうでなければFALSE
33 static bool resisted_psi_because_empty_mind(PlayerType *player_ptr, EffectMonster *em_ptr)
35 if (em_ptr->r_ptr->misc_flags.has_not(MonsterMiscType::EMPTY_MIND)) {
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);
49 * @brief 異質な精神のモンスター及び強力なモンスターのPsi攻撃に対する耐性を発動する
50 * @param em_ptr モンスター効果への参照ポインタ
51 * @return 耐性を発動した場合TRUE、そうでなければFALSE
54 * 1) STUPIDまたはWIERD_MINDである
56 * 3) レベルが d(3*ダメージ) より大きい
58 static bool resisted_psi_because_weird_mind_or_powerful(EffectMonster *em_ptr)
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) {
68 em_ptr->note = _("には耐性がある!", " resists!");
74 * @brief 堕落した精神のモンスターへのPsi攻撃のダメージ反射を発動する
75 * @param player_ptr プレイヤーへの参照ポインタ
76 * @param em_ptr モンスター効果への参照ポインタ
77 * @return ダメージ反射を発動した場合TRUE、そうでなければFALSE
79 * 以下の条件を満たす場合に 1/2 の確率でダメージ反射する
80 * 1) UNDEADまたはDEMONである
81 * 2) レベルが詠唱者の レベル/2 より大きい
83 static bool reflects_psi_with_currupted_mind(PlayerType *player_ptr, EffectMonster *em_ptr)
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);
93 msg_format(_("%s^の堕落した精神は攻撃を跳ね返した!",
94 (em_ptr->seen ? "%s^'s corrupted mind backlashes your attack!" : "%s^s corrupted mind backlashes your attack!")),
100 * @brief モンスターがPsi攻撃をダメージ反射した場合のプレイヤーへの追加効果を発動する
101 * @param player_ptr プレイヤーへの参照ポインタ
102 * @param em_ptr モンスター効果への参照ポインタ
105 * 3/4の確率または影分身時はダメージ及び追加効果はない。
107 static void effect_monster_psi_reflect_extra_effect(PlayerType *player_ptr, EffectMonster *em_ptr)
109 if (!one_in_(4) || check_multishadow(player_ptr)) {
113 BadStatusSetter bss(player_ptr);
114 switch (randint1(4)) {
116 (void)bss.mod_confusion(3 + randint1(em_ptr->dam));
119 (void)bss.mod_stun(randint1(em_ptr->dam));
122 if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR)) {
123 em_ptr->note = _("には効果がなかった。", " is unaffected.");
125 (void)bss.mod_fear(3 + randint1(em_ptr->dam));
130 if (!player_ptr->free_act) {
131 (void)bss.mod_paralysis(randint1(em_ptr->dam));
139 * @brief モンスターのPsi攻撃に対する耐性を発動する
140 * @param player_ptr プレイヤーへの参照ポインタ
141 * @param em_ptr モンスター効果への参照ポインタ
143 * 耐性を発動した精神の堕落したモンスターは効力を跳ね返すことがある。
145 static void effect_monster_psi_resist(PlayerType *player_ptr, EffectMonster *em_ptr)
147 if (resisted_psi_because_empty_mind(player_ptr, em_ptr)) {
150 if (!resisted_psi_because_weird_mind_or_powerful(em_ptr)) {
153 if (!reflects_psi_with_currupted_mind(player_ptr, em_ptr)) {
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!"));
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);
172 * @brief モンスターへのPsi攻撃の追加効果を発動する
173 * @param player_ptr プレイヤーへの参照ポインタ
174 * @param em_ptr モンスター効果への参照ポインタ
176 * 効果は、混乱、朦朧、恐怖、麻痺(各耐性無効)
177 * ダメージがないか3/4の確率で効果なし
179 static void effect_monster_psi_extra_effect(EffectMonster *em_ptr)
181 if ((em_ptr->dam <= 0) || !one_in_(4)) {
185 switch (randint1(4)) {
187 em_ptr->do_conf = 3 + randint1(em_ptr->dam);
190 em_ptr->do_stun = 3 + randint1(em_ptr->dam);
193 em_ptr->do_fear = 3 + randint1(em_ptr->dam);
196 em_ptr->note = _("は眠り込んでしまった!", " falls asleep!");
197 em_ptr->do_sleep = 3 + randint1(em_ptr->dam);
203 * @brief モンスターへのPsi攻撃(PSI)の効果を発動する
204 * @param player_ptr プレイヤーへの参照ポインタ
205 * @param em_ptr モンスター効果への参照ポインタ
206 * @return PROICESS_CONTINUE
209 * モンスターの耐性とそれに不随した効果を発動する。
211 ProcessResult effect_monster_psi(PlayerType *player_ptr, EffectMonster *em_ptr)
214 em_ptr->obvious = true;
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);
221 em_ptr->skipped = true;
222 return ProcessResult::PROCESS_CONTINUE;
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;
232 * @brief モンスターのPsi攻撃(PSI_DRAIN)に対する耐性を発動する
233 * @param player_ptr プレイヤーへの参照ポインタ
234 * @param em_ptr モンスター効果への参照ポインタ
236 * 耐性を発動した精神の堕落したモンスターは効力を跳ね返すことがある。
238 static void effect_monster_psi_drain_resist(PlayerType *player_ptr, EffectMonster *em_ptr)
240 if (resisted_psi_because_empty_mind(player_ptr, em_ptr)) {
243 if (!resisted_psi_because_weird_mind_or_powerful(em_ptr)) {
246 if (!reflects_psi_with_currupted_mind(player_ptr, em_ptr)) {
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!"));
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);
264 msg_print(_("超能力パワーを吸いとられた!", "Your psychic energy is drained!"));
265 player_ptr->csp -= damroll(5, em_ptr->dam) / 2;
266 if (player_ptr->csp < 0) {
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);
278 * @brief モンスターへのPsi攻撃(PSI_DRAIN)のダメージをMPに変換する
279 * @param player_ptr プレイヤーへの参照ポインタ
280 * @param em_ptr モンスター効果への参照ポインタ
282 static void effect_monster_psi_drain_change_power(PlayerType *player_ptr, EffectMonster *em_ptr)
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);
289 b = std::min(player_ptr->msp, player_ptr->csp + b);
291 auto &rfu = RedrawingFlagsUpdater::get_instance();
292 rfu.set_flag(MainWindowRedrawingFlag::MP);
293 rfu.set_flag(SubWindowRedrawingFlag::SPELL);
297 * @brief モンスターへのPsi攻撃(PSI_DRAIN)の効果を発動する
298 * @param player_ptr プレイヤーへの参照ポインタ
299 * @param em_ptr モンスター効果への参照ポインタ
300 * @return PROICESS_CONTINUE
302 * ダメージがないか3/4の確率で追加効果なし
304 ProcessResult effect_monster_psi_drain(PlayerType *player_ptr, EffectMonster *em_ptr)
307 em_ptr->obvious = true;
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);
315 em_ptr->note_dies = _("の精神は崩壊し、肉体は抜け殻となった。", " collapses, a mindless husk.");
316 return ProcessResult::PROCESS_CONTINUE;
320 * @brief モンスターへのテレキネシス(TELEKINESIS)の効果を発動する
321 * @param player_ptr プレイヤーへの参照ポインタ
322 * @param em_ptr モンスター効果への参照ポインタ
323 * @return PROICESS_CONTINUE
327 ProcessResult effect_monster_telekinesis(PlayerType *player_ptr, EffectMonster *em_ptr)
330 em_ptr->obvious = true;
333 if (player_ptr->riding && (em_ptr->g_ptr->m_idx == player_ptr->riding)) {
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))) {
343 em_ptr->obvious = false;
346 return ProcessResult::PROCESS_CONTINUE;