2 * @brief フロアの一定範囲に効果を及ぼす (悲鳴、テレポート等)スペルの効果
7 #include "mspell/mspell-floor.h"
8 #include "blue-magic/blue-magic-checker.h"
9 #include "core/disturbance.h"
10 #include "effect/attribute-types.h"
11 #include "effect/effect-characteristics.h"
12 #include "effect/effect-processor.h"
13 #include "mind/drs-types.h"
14 #include "monster-race/race-ability-flags.h"
15 #include "monster-race/race-brightness-mask.h"
16 #include "monster-race/race-flags-resistance.h"
17 #include "monster-race/race-indice-types.h"
18 #include "monster-race/race-resistance-mask.h"
19 #include "monster/monster-info.h"
20 #include "monster/monster-status-setter.h"
21 #include "monster/monster-status.h"
22 #include "monster/monster-update.h"
23 #include "mspell/mspell-result.h"
24 #include "mspell/mspell-status.h"
25 #include "mspell/mspell-util.h"
26 #include "player-base/player-class.h"
27 #include "player/player-personality-types.h"
28 #include "player/player-status-flags.h"
29 #include "player/player-status.h"
30 #include "spell-kind/spells-lite.h"
31 #include "spell-kind/spells-neighbor.h"
32 #include "spell-kind/spells-sight.h"
33 #include "spell-kind/spells-teleport.h"
34 #include "spell-kind/spells-world.h"
35 #include "spell-realm/spells-hex.h"
36 #include "system/floor-type-definition.h"
37 #include "system/monster-entity.h"
38 #include "system/monster-race-info.h"
39 #include "system/player-type-definition.h"
40 #include "system/redrawing-flags-updater.h"
41 #include "timed-effect/timed-effects.h"
42 #include "util/bit-flags-calculator.h"
43 #include "view/display-messages.h"
46 * @brief RF4_SHRIEKの処理。叫び。 /
47 * @param m_idx 呪文を唱えるモンスターID
48 * @param player_ptr プレイヤーへの参照ポインタ
49 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
50 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
54 MonsterSpellResult spell_RF4_SHRIEK(MONSTER_IDX m_idx, PlayerType *player_ptr, MONSTER_IDX t_idx, int target_type)
56 mspell_cast_msg_simple msg(_("%s^がかん高い金切り声をあげた。", "%s^ makes a high pitched shriek."),
57 _("%s^が%sに向かって叫んだ。", "%s^ shrieks at %s."));
59 simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
61 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
62 auto result = MonsterSpellResult::make_valid();
63 if (m_ptr->r_idx == MonsterRaceId::LEE_QIEZI) {
64 msg_print(_("しかし、その声は誰の心にも響かなかった…。", "However, that voice didn't touch anyone's heart..."));
68 if (target_type == MONSTER_TO_PLAYER) {
69 aggravate_monsters(player_ptr, m_idx);
70 } else if (target_type == MONSTER_TO_MONSTER) {
71 set_monster_csleep(player_ptr, t_idx, 0);
78 * @brief RF6_WORLDの処理。時を止める。 /
79 * @param player_ptr プレイヤーへの参照ポインタ
80 * @param m_idx 呪文を唱えるモンスターID
84 MonsterSpellResult spell_RF6_WORLD(PlayerType *player_ptr, MONSTER_IDX m_idx)
86 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
87 disturb(player_ptr, true, true);
88 (void)set_monster_timewalk(player_ptr, randint1(2) + 2, m_ptr->r_idx, true);
90 return MonsterSpellResult::make_valid();
94 * @brief RF6_BLINKの処理。ショート・テレポート。 /
95 * @param player_ptr プレイヤーへの参照ポインタ
96 * @param m_idx 呪文を唱えるモンスターID
97 * @param is_quantum_effect 量子的効果によるショート・テレポートの場合時TRUE
98 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
102 MonsterSpellResult spell_RF6_BLINK(PlayerType *player_ptr, MONSTER_IDX m_idx, int target_type, bool is_quantum_effect)
104 const auto res = MonsterSpellResult::make_valid();
105 const auto m_name = monster_name(player_ptr, m_idx);
107 if (target_type == MONSTER_TO_PLAYER) {
108 disturb(player_ptr, true, true);
111 if (!is_quantum_effect && SpellHex(player_ptr).check_hex_barrier(m_idx, HEX_ANTI_TELE)) {
112 if (see_monster(player_ptr, m_idx)) {
113 msg_format(_("魔法のバリアが%s^のテレポートを邪魔した。", "Magic barrier obstructs teleporting of %s^."), m_name.data());
118 if (see_monster(player_ptr, m_idx)) {
119 msg_format(_("%s^が瞬時に消えた。", "%s^ blinks away."), m_name.data());
122 teleport_away(player_ptr, m_idx, 10, TELEPORT_SPONTANEOUS);
124 if (target_type == MONSTER_TO_PLAYER) {
125 RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_STATUSES);
132 * @brief RF6_TPORTの処理。テレポート。 /
133 * @param player_ptr プレイヤーへの参照ポインタ
134 * @param m_idx 呪文を唱えるモンスターID
135 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
139 MonsterSpellResult spell_RF6_TPORT(PlayerType *player_ptr, MONSTER_IDX m_idx, int target_type)
141 const auto res = MonsterSpellResult::make_valid();
142 const auto m_name = monster_name(player_ptr, m_idx);
144 if (target_type == MONSTER_TO_PLAYER) {
145 disturb(player_ptr, true, true);
147 if (SpellHex(player_ptr).check_hex_barrier(m_idx, HEX_ANTI_TELE)) {
148 if (see_monster(player_ptr, m_idx)) {
149 msg_format(_("魔法のバリアが%s^のテレポートを邪魔した。", "Magic barrier obstructs teleporting of %s^."), m_name.data());
154 if (see_monster(player_ptr, m_idx)) {
155 msg_format(_("%s^がテレポートした。", "%s^ teleports away."), m_name.data());
158 teleport_away_followable(player_ptr, m_idx);
164 * @brief RF6_TELE_TOの処理。テレポート・バック。 /
165 * @param player_ptr プレイヤーへの参照ポインタ
166 * @param m_idx 呪文を唱えるモンスターID
167 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
168 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
172 MonsterSpellResult spell_RF6_TELE_TO(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
174 auto res = MonsterSpellResult::make_valid();
175 res.learnable = target_type == MONSTER_TO_PLAYER;
177 auto *floor_ptr = player_ptr->current_floor_ptr;
178 auto *m_ptr = &floor_ptr->m_list[m_idx];
179 auto *t_ptr = &floor_ptr->m_list[t_idx];
180 auto *tr_ptr = &t_ptr->get_monrace();
182 mspell_cast_msg_simple msg(_("%s^があなたを引き戻した。", "%s^ commands you to return."),
183 _("%s^が%sを引き戻した。", "%s^ commands %s to return."));
185 simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
187 if (target_type == MONSTER_TO_PLAYER) {
188 teleport_player_to(player_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_PASSIVE);
192 if (target_type != MONSTER_TO_MONSTER) {
196 bool resists_tele = false;
197 const auto t_name = monster_name(player_ptr, t_idx);
199 if (tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT)) {
200 if (tr_ptr->kind_flags.has(MonsterKindType::UNIQUE) || tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
201 if (is_original_ap_and_seen(player_ptr, t_ptr)) {
202 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
204 if (see_monster(player_ptr, t_idx)) {
205 msg_format(_("%s^には効果がなかった。", "%s^ is unaffected!"), t_name.data());
208 } else if (tr_ptr->level > randint1(100)) {
209 if (is_original_ap_and_seen(player_ptr, t_ptr)) {
210 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
212 if (see_monster(player_ptr, t_idx)) {
213 msg_format(_("%s^は耐性を持っている!", "%s^ resists!"), t_name.data());
220 set_monster_csleep(player_ptr, t_idx, 0);
224 if (t_idx == player_ptr->riding) {
225 teleport_player_to(player_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_PASSIVE);
227 teleport_monster_to(player_ptr, t_idx, m_ptr->fy, m_ptr->fx, 100, TELEPORT_PASSIVE);
229 set_monster_csleep(player_ptr, t_idx, 0);
235 * @brief RF6_TELE_AWAYの処理。テレポート・アウェイ。 /
236 * @param player_ptr プレイヤーへの参照ポインタ
237 * @param m_idx 呪文を唱えるモンスターID
238 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
239 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
243 MonsterSpellResult spell_RF6_TELE_AWAY(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
245 auto res = MonsterSpellResult::make_valid();
246 res.learnable = target_type == MONSTER_TO_PLAYER;
248 auto *floor_ptr = player_ptr->current_floor_ptr;
249 MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
250 MonsterRaceInfo *tr_ptr = &t_ptr->get_monrace();
252 mspell_cast_msg_simple msg(_("%s^にテレポートさせられた。", "%s^ teleports you away."),
253 _("%s^は%sをテレポートさせた。", "%s^ teleports %s away."));
255 simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
257 if (target_type == MONSTER_TO_PLAYER) {
258 if (is_echizen(player_ptr)) {
259 msg_print(_("くっそ~", ""));
260 } else if (is_chargeman(player_ptr)) {
261 if (randint0(2) == 0) {
262 msg_print(_("ジュラル星人め!", ""));
264 msg_print(_("弱い者いじめは止めるんだ!", ""));
268 teleport_player_away(m_idx, player_ptr, 100, false);
272 if (target_type != MONSTER_TO_MONSTER) {
276 bool resists_tele = false;
277 const auto t_name = monster_name(player_ptr, t_idx);
279 if (tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT)) {
280 if (tr_ptr->kind_flags.has(MonsterKindType::UNIQUE) || tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
281 if (is_original_ap_and_seen(player_ptr, t_ptr)) {
282 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
284 if (see_monster(player_ptr, t_idx)) {
285 msg_format(_("%s^には効果がなかった。", "%s^ is unaffected!"), t_name.data());
288 } else if (tr_ptr->level > randint1(100)) {
289 if (is_original_ap_and_seen(player_ptr, t_ptr)) {
290 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
292 if (see_monster(player_ptr, t_idx)) {
293 msg_format(_("%s^は耐性を持っている!", "%s^ resists!"), t_name.data());
300 set_monster_csleep(player_ptr, t_idx, 0);
304 if (t_idx == player_ptr->riding) {
305 teleport_player_away(m_idx, player_ptr, MAX_PLAYER_SIGHT * 2 + 5, false);
307 teleport_away(player_ptr, t_idx, MAX_PLAYER_SIGHT * 2 + 5, TELEPORT_PASSIVE);
309 set_monster_csleep(player_ptr, t_idx, 0);
315 * @brief RF6_TELE_LEVELの処理。テレポート・レベル。 /
316 * @param player_ptr プレイヤーへの参照ポインタ
317 * @param m_idx 呪文を唱えるモンスターID
318 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
319 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
323 MonsterSpellResult spell_RF6_TELE_LEVEL(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
325 const auto res = MonsterSpellResult::make_valid();
327 auto *floor_ptr = player_ptr->current_floor_ptr;
328 MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
329 MonsterRaceInfo *tr_ptr = &t_ptr->get_monrace();
330 DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
331 bool resist, saving_throw;
333 if (target_type == MONSTER_TO_PLAYER) {
334 resist = (has_resist_nexus(player_ptr) != 0);
335 saving_throw = (randint0(100 + rlev / 2) < player_ptr->skill_sav);
337 mspell_cast_msg_bad_status_to_player msg(_("%s^が何か奇妙な言葉をつぶやいた。", "%s^ mumbles strangely."),
338 _("%s^があなたの足を指さした。", "%s^ gestures at your feet."), _("しかし効果がなかった!", "You are unaffected!"),
339 _("しかし効力を跳ね返した!", "You resist the effects!"));
341 spell_badstatus_message_to_player(player_ptr, m_idx, msg, resist, saving_throw);
343 if (!resist && !saving_throw) {
344 teleport_level(player_ptr, 0);
347 update_smart_learn(player_ptr, m_idx, DRS_NEXUS);
351 if (target_type != MONSTER_TO_MONSTER) {
355 resist = tr_ptr->resistance_flags.has_any_of(RFR_EFF_RESIST_NEXUS_MASK) || tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT);
356 saving_throw = (tr_ptr->misc_flags.has(MonsterMiscType::QUESTOR)) || (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
358 mspell_cast_msg_bad_status_to_monster msg(_("%s^が%sの足を指さした。", "%s^ gestures at %s's feet."),
359 _("%s^には効果がなかった。", "%s^ is unaffected!"), _("%s^は効力を跳ね返した!", "%s^ resist the effects!"), "");
361 spell_badstatus_message_to_mons(player_ptr, m_idx, t_idx, msg, resist, saving_throw);
363 if (!resist && !saving_throw) {
364 teleport_level(player_ptr, (t_idx == player_ptr->riding) ? 0 : t_idx);
371 * @brief RF6_DARKNESSの処理。暗闇or閃光。 /
372 * @param target_type プレイヤーへの参照ポインタ
375 * @param m_idx 呪文を唱えるモンスターID
376 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
377 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
379 * プレイヤーが対象かつ暗闇ならラーニング可。
381 MonsterSpellResult spell_RF6_DARKNESS(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
383 mspell_cast_msg_blind msg;
385 auto *floor_ptr = player_ptr->current_floor_ptr;
386 auto *m_ptr = &floor_ptr->m_list[m_idx];
387 auto *r_ptr = &m_ptr->get_monrace();
388 bool can_use_lite_area = false;
389 bool monster_to_monster = target_type == MONSTER_TO_MONSTER;
390 bool monster_to_player = target_type == MONSTER_TO_PLAYER;
391 const auto t_name = monster_name(player_ptr, t_idx);
393 const auto is_ninja = PlayerClass(player_ptr).equals(PlayerClassType::NINJA);
394 const auto is_living_monster = r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD);
395 const auto is_not_weak_lite = r_ptr->resistance_flags.has_not(MonsterResistanceType::HURT_LITE);
396 if (is_ninja && is_living_monster && is_not_weak_lite && r_ptr->brightness_flags.has_none_of(dark_mask)) {
397 can_use_lite_area = true;
400 const auto &t_ref = floor_ptr->m_list[t_idx];
401 if (monster_to_monster && !t_ref.is_hostile()) {
402 can_use_lite_area = false;
405 auto res = MonsterSpellResult::make_valid();
406 res.learnable = monster_to_player && !can_use_lite_area;
408 if (can_use_lite_area) {
409 msg.blind = _("%s^が何かをつぶやいた。", "%s^ mumbles.");
410 msg.to_player = _("%s^が辺りを明るく照らした。", "%s^ cast a spell to light up.");
411 msg.to_mons = _("%s^が辺りを明るく照らした。", "%s^ cast a spell to light up.");
413 msg_done = _("%s^は白い光に包まれた。", "%s^ is surrounded by a white light.");
415 msg.blind = _("%s^が何かをつぶやいた。", "%s^ mumbles.");
416 msg.to_player = _("%s^が暗闇の中で手を振った。", "%s^ gestures in shadow.");
417 msg.to_mons = _("%s^が暗闇の中で手を振った。", "%s^ gestures in shadow.");
419 msg_done = _("%s^は暗闇に包まれた。", "%s^ is surrounded by darkness.");
422 monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
424 if (see_monster(player_ptr, t_idx) && monster_to_monster) {
425 msg_format(msg_done, t_name.data());
428 if (monster_to_player) {
429 if (can_use_lite_area) {
430 (void)lite_area(player_ptr, 0, 3);
432 (void)unlite_area(player_ptr, 0, 3);
434 } else if (monster_to_monster) {
435 if (can_use_lite_area) {
436 (void)project(player_ptr, m_idx, 3, y, x, 0, AttributeType::LITE_WEAK, PROJECT_GRID | PROJECT_KILL);
437 lite_room(player_ptr, y, x);
439 (void)project(player_ptr, m_idx, 3, y, x, 0, AttributeType::DARK_WEAK, PROJECT_GRID | PROJECT_KILL);
440 unlite_room(player_ptr, y, x);
448 * @brief RF6_TRAPSの処理。トラップ。 /
449 * @param player_ptr プレイヤーへの参照ポインタ
452 * @param m_idx 呪文を唱えるモンスターID
456 MonsterSpellResult spell_RF6_TRAPS(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx)
458 const auto m_name = monster_name(player_ptr, m_idx);
459 disturb(player_ptr, true, true);
461 if (player_ptr->effects()->blindness().is_blind()) {
462 msg_format(_("%s^が何かをつぶやいて邪悪に微笑んだ。", "%s^ mumbles, and then cackles evilly."), m_name.data());
464 msg_format(_("%s^が呪文を唱えて邪悪に微笑んだ。", "%s^ casts a spell and cackles evilly."), m_name.data());
467 (void)trap_creation(player_ptr, y, x);
469 auto res = MonsterSpellResult::make_valid();
470 res.learnable = true;
476 * @brief RF6_RAISE_DEADの処理。死者復活。 /
477 * @param player_ptr プレイヤーへの参照ポインタ
478 * @param m_idx 呪文を唱えるモンスターID
479 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
480 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
484 MonsterSpellResult spell_RF6_RAISE_DEAD(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
486 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
487 mspell_cast_msg_blind msg(_("%s^が何かをつぶやいた。", "%s^ mumbles."),
488 _("%s^が死者復活の呪文を唱えた。", "%s^ casts a spell to revive corpses."), _("%s^が死者復活の呪文を唱えた。", "%s^ casts a spell to revive corpses."));
490 monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
492 animate_dead(player_ptr, m_idx, m_ptr->fy, m_ptr->fx);
494 return MonsterSpellResult::make_valid();