2 * @brief フロアの一定範囲に効果を及ぼす (悲鳴、テレポート等)スペルの効果
7 #include "mspell/mspell-floor.h"
8 #include "blue-magic/blue-magic-checker.h"
9 #include "core/disturbance.h"
10 #include "core/player-update-types.h"
11 #include "effect/attribute-types.h"
12 #include "effect/effect-characteristics.h"
13 #include "effect/effect-processor.h"
14 #include "mind/drs-types.h"
15 #include "monster-race/monster-race.h"
16 #include "monster-race/race-ability-flags.h"
17 #include "monster-race/race-flags-resistance.h"
18 #include "monster-race/race-flags1.h"
19 #include "monster-race/race-flags3.h"
20 #include "monster-race/race-flags7.h"
21 #include "monster-race/race-indice-types.h"
22 #include "monster-race/race-resistance-mask.h"
23 #include "monster/monster-info.h"
24 #include "monster/monster-status-setter.h"
25 #include "monster/monster-status.h"
26 #include "monster/monster-update.h"
27 #include "mspell/mspell-result.h"
28 #include "mspell/mspell-status.h"
29 #include "mspell/mspell-util.h"
30 #include "player-base/player-class.h"
31 #include "player/player-personality-types.h"
32 #include "player/player-status-flags.h"
33 #include "player/player-status.h"
34 #include "spell-kind/spells-lite.h"
35 #include "spell-kind/spells-neighbor.h"
36 #include "spell-kind/spells-sight.h"
37 #include "spell-kind/spells-teleport.h"
38 #include "spell-kind/spells-world.h"
39 #include "spell-realm/spells-hex.h"
40 #include "system/floor-type-definition.h"
41 #include "system/monster-race-info.h"
42 #include "system/monster-type-definition.h"
43 #include "system/player-type-definition.h"
44 #include "timed-effect/player-blindness.h"
45 #include "timed-effect/timed-effects.h"
46 #include "util/bit-flags-calculator.h"
47 #include "view/display-messages.h"
50 * @brief RF4_SHRIEKの処理。叫び。 /
51 * @param m_idx 呪文を唱えるモンスターID
52 * @param player_ptr プレイヤーへの参照ポインタ
53 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
54 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
58 MonsterSpellResult spell_RF4_SHRIEK(MONSTER_IDX m_idx, PlayerType *player_ptr, MONSTER_IDX t_idx, int target_type)
60 mspell_cast_msg_simple msg(_("%^sがかん高い金切り声をあげた。", "%^s makes a high pitched shriek."),
61 _("%^sが%sに向かって叫んだ。", "%^s shrieks at %s."));
63 simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
65 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
66 auto result = MonsterSpellResult::make_valid();
67 if (m_ptr->r_idx == MonsterRaceId::LEE_QIEZI) {
68 msg_print(_("しかし、その声は誰の心にも響かなかった…。", "However, that voice didn't touch anyone's heart..."));
72 if (target_type == MONSTER_TO_PLAYER) {
73 aggravate_monsters(player_ptr, m_idx);
74 } else if (target_type == MONSTER_TO_MONSTER) {
75 set_monster_csleep(player_ptr, t_idx, 0);
82 * @brief RF6_WORLDの処理。時を止める。 /
83 * @param player_ptr プレイヤーへの参照ポインタ
84 * @param m_idx 呪文を唱えるモンスターID
88 MonsterSpellResult spell_RF6_WORLD(PlayerType *player_ptr, MONSTER_IDX m_idx)
90 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
91 GAME_TEXT m_name[MAX_NLEN];
92 monster_name(player_ptr, m_idx, m_name);
93 disturb(player_ptr, true, true);
94 (void)set_monster_timewalk(player_ptr, randint1(2) + 2, m_ptr->r_idx, true);
96 return MonsterSpellResult::make_valid();
100 * @brief RF6_BLINKの処理。ショート・テレポート。 /
101 * @param player_ptr プレイヤーへの参照ポインタ
102 * @param m_idx 呪文を唱えるモンスターID
103 * @param is_quantum_effect 量子的効果によるショート・テレポートの場合時TRUE
104 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
108 MonsterSpellResult spell_RF6_BLINK(PlayerType *player_ptr, MONSTER_IDX m_idx, int target_type, bool is_quantum_effect)
110 const auto res = MonsterSpellResult::make_valid();
112 GAME_TEXT m_name[MAX_NLEN];
113 monster_name(player_ptr, m_idx, m_name);
115 if (target_type == MONSTER_TO_PLAYER) {
116 disturb(player_ptr, true, true);
119 if (!is_quantum_effect && SpellHex(player_ptr).check_hex_barrier(m_idx, HEX_ANTI_TELE)) {
120 if (see_monster(player_ptr, m_idx)) {
121 msg_format(_("魔法のバリアが%^sのテレポートを邪魔した。", "Magic barrier obstructs teleporting of %^s."), m_name);
126 if (see_monster(player_ptr, m_idx)) {
127 msg_format(_("%^sが瞬時に消えた。", "%^s blinks away."), m_name);
130 teleport_away(player_ptr, m_idx, 10, TELEPORT_SPONTANEOUS);
132 if (target_type == MONSTER_TO_PLAYER) {
133 player_ptr->update |= (PU_MONSTERS);
140 * @brief RF6_TPORTの処理。テレポート。 /
141 * @param player_ptr プレイヤーへの参照ポインタ
142 * @param m_idx 呪文を唱えるモンスターID
143 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
147 MonsterSpellResult spell_RF6_TPORT(PlayerType *player_ptr, MONSTER_IDX m_idx, int target_type)
149 const auto res = MonsterSpellResult::make_valid();
151 GAME_TEXT m_name[MAX_NLEN];
152 monster_name(player_ptr, m_idx, m_name);
154 if (target_type == MONSTER_TO_PLAYER) {
155 disturb(player_ptr, true, true);
157 if (SpellHex(player_ptr).check_hex_barrier(m_idx, HEX_ANTI_TELE)) {
158 if (see_monster(player_ptr, m_idx)) {
159 msg_format(_("魔法のバリアが%^sのテレポートを邪魔した。", "Magic barrier obstructs teleporting of %^s."), m_name);
164 if (see_monster(player_ptr, m_idx)) {
165 msg_format(_("%^sがテレポートした。", "%^s teleports away."), m_name);
168 teleport_away_followable(player_ptr, m_idx);
174 * @brief RF6_TELE_TOの処理。テレポート・バック。 /
175 * @param player_ptr プレイヤーへの参照ポインタ
176 * @param m_idx 呪文を唱えるモンスターID
177 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
178 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
182 MonsterSpellResult spell_RF6_TELE_TO(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
184 auto res = MonsterSpellResult::make_valid();
185 res.learnable = target_type == MONSTER_TO_PLAYER;
187 auto *floor_ptr = player_ptr->current_floor_ptr;
188 auto *m_ptr = &floor_ptr->m_list[m_idx];
189 MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
190 MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
192 mspell_cast_msg_simple msg(_("%^sがあなたを引き戻した。", "%^s commands you to return."),
193 _("%^sが%sを引き戻した。", "%^s commands %s to return."));
195 simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
197 if (target_type == MONSTER_TO_PLAYER) {
198 teleport_player_to(player_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_PASSIVE);
202 if (target_type != MONSTER_TO_MONSTER) {
206 bool resists_tele = false;
207 GAME_TEXT t_name[MAX_NLEN];
208 monster_name(player_ptr, t_idx, t_name);
210 if (tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT)) {
211 if (tr_ptr->kind_flags.has(MonsterKindType::UNIQUE) || tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
212 if (is_original_ap_and_seen(player_ptr, t_ptr)) {
213 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
215 if (see_monster(player_ptr, t_idx)) {
216 msg_format(_("%^sには効果がなかった。", "%^s is unaffected!"), t_name);
219 } else if (tr_ptr->level > randint1(100)) {
220 if (is_original_ap_and_seen(player_ptr, t_ptr)) {
221 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
223 if (see_monster(player_ptr, t_idx)) {
224 msg_format(_("%^sは耐性を持っている!", "%^s resists!"), t_name);
231 set_monster_csleep(player_ptr, t_idx, 0);
235 if (t_idx == player_ptr->riding) {
236 teleport_player_to(player_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_PASSIVE);
238 teleport_monster_to(player_ptr, t_idx, m_ptr->fy, m_ptr->fx, 100, TELEPORT_PASSIVE);
240 set_monster_csleep(player_ptr, t_idx, 0);
246 * @brief RF6_TELE_AWAYの処理。テレポート・アウェイ。 /
247 * @param player_ptr プレイヤーへの参照ポインタ
248 * @param m_idx 呪文を唱えるモンスターID
249 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
250 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
254 MonsterSpellResult spell_RF6_TELE_AWAY(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
256 auto res = MonsterSpellResult::make_valid();
257 res.learnable = target_type == MONSTER_TO_PLAYER;
259 auto *floor_ptr = player_ptr->current_floor_ptr;
260 MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
261 MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
263 mspell_cast_msg_simple msg(_("%^sにテレポートさせられた。", "%^s teleports you away."),
264 _("%^sは%sをテレポートさせた。", "%^s teleports %s away."));
266 simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
268 if (target_type == MONSTER_TO_PLAYER) {
269 if (is_echizen(player_ptr)) {
270 msg_print(_("くっそ~", ""));
271 } else if (is_chargeman(player_ptr)) {
272 if (randint0(2) == 0) {
273 msg_print(_("ジュラル星人め!", ""));
275 msg_print(_("弱い者いじめは止めるんだ!", ""));
279 teleport_player_away(m_idx, player_ptr, 100, false);
283 if (target_type != MONSTER_TO_MONSTER) {
287 bool resists_tele = false;
288 GAME_TEXT t_name[MAX_NLEN];
289 monster_name(player_ptr, t_idx, t_name);
291 if (tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT)) {
292 if (tr_ptr->kind_flags.has(MonsterKindType::UNIQUE) || tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
293 if (is_original_ap_and_seen(player_ptr, t_ptr)) {
294 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
296 if (see_monster(player_ptr, t_idx)) {
297 msg_format(_("%^sには効果がなかった。", "%^s is unaffected!"), t_name);
300 } else if (tr_ptr->level > randint1(100)) {
301 if (is_original_ap_and_seen(player_ptr, t_ptr)) {
302 tr_ptr->r_resistance_flags.set(MonsterResistanceType::RESIST_TELEPORT);
304 if (see_monster(player_ptr, t_idx)) {
305 msg_format(_("%^sは耐性を持っている!", "%^s resists!"), t_name);
312 set_monster_csleep(player_ptr, t_idx, 0);
316 if (t_idx == player_ptr->riding) {
317 teleport_player_away(m_idx, player_ptr, MAX_PLAYER_SIGHT * 2 + 5, false);
319 teleport_away(player_ptr, t_idx, MAX_PLAYER_SIGHT * 2 + 5, TELEPORT_PASSIVE);
321 set_monster_csleep(player_ptr, t_idx, 0);
327 * @brief RF6_TELE_LEVELの処理。テレポート・レベル。 /
328 * @param player_ptr プレイヤーへの参照ポインタ
329 * @param m_idx 呪文を唱えるモンスターID
330 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
331 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
335 MonsterSpellResult spell_RF6_TELE_LEVEL(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
337 const auto res = MonsterSpellResult::make_valid();
339 auto *floor_ptr = player_ptr->current_floor_ptr;
340 MonsterEntity *t_ptr = &floor_ptr->m_list[t_idx];
341 MonsterRaceInfo *tr_ptr = &monraces_info[t_ptr->r_idx];
342 DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
343 bool resist, saving_throw;
345 if (target_type == MONSTER_TO_PLAYER) {
346 resist = (has_resist_nexus(player_ptr) != 0);
347 saving_throw = (randint0(100 + rlev / 2) < player_ptr->skill_sav);
349 mspell_cast_msg_bad_status_to_player msg(_("%^sが何か奇妙な言葉をつぶやいた。", "%^s mumbles strangely."),
350 _("%^sがあなたの足を指さした。", "%^s gestures at your feet."), _("しかし効果がなかった!", "You are unaffected!"),
351 _("しかし効力を跳ね返した!", "You resist the effects!"));
353 spell_badstatus_message_to_player(player_ptr, m_idx, msg, resist, saving_throw);
355 if (!resist && !saving_throw) {
356 teleport_level(player_ptr, 0);
359 update_smart_learn(player_ptr, m_idx, DRS_NEXUS);
363 if (target_type != MONSTER_TO_MONSTER) {
367 resist = tr_ptr->resistance_flags.has_any_of(RFR_EFF_RESIST_NEXUS_MASK) || tr_ptr->resistance_flags.has(MonsterResistanceType::RESIST_TELEPORT);
368 saving_throw = (tr_ptr->flags1 & RF1_QUESTOR) || (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
370 mspell_cast_msg_bad_status_to_monster msg(_("%^sが%sの足を指さした。", "%^s gestures at %s's feet."),
371 _("%^sには効果がなかった。", "%^s is unaffected!"), _("%^sは効力を跳ね返した!", "%^s resist the effects!"), "");
373 spell_badstatus_message_to_mons(player_ptr, m_idx, t_idx, msg, resist, saving_throw);
375 if (!resist && !saving_throw) {
376 teleport_level(player_ptr, (t_idx == player_ptr->riding) ? 0 : t_idx);
383 * @brief RF6_DARKNESSの処理。暗闇or閃光。 /
384 * @param target_type プレイヤーへの参照ポインタ
387 * @param m_idx 呪文を唱えるモンスターID
388 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
389 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
391 * プレイヤーが対象かつ暗闇ならラーニング可。
393 MonsterSpellResult spell_RF6_DARKNESS(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
395 mspell_cast_msg_blind msg;
397 auto *floor_ptr = player_ptr->current_floor_ptr;
398 auto *m_ptr = &floor_ptr->m_list[m_idx];
399 auto *r_ptr = &monraces_info[m_ptr->r_idx];
400 bool can_use_lite_area = false;
401 bool monster_to_monster = target_type == MONSTER_TO_MONSTER;
402 bool monster_to_player = target_type == MONSTER_TO_PLAYER;
403 GAME_TEXT t_name[MAX_NLEN];
404 monster_name(player_ptr, t_idx, t_name);
406 const auto is_ninja = PlayerClass(player_ptr).equals(PlayerClassType::NINJA);
407 const auto is_living_monster = r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD);
408 const auto is_not_weak_lite = r_ptr->resistance_flags.has_not(MonsterResistanceType::HURT_LITE);
409 if (is_ninja && is_living_monster && is_not_weak_lite && none_bits(r_ptr->flags7, RF7_DARK_MASK)) {
410 can_use_lite_area = true;
413 const auto &t_ref = floor_ptr->m_list[t_idx];
414 if (monster_to_monster && !t_ref.is_hostile()) {
415 can_use_lite_area = false;
418 auto res = MonsterSpellResult::make_valid();
419 res.learnable = monster_to_player && !can_use_lite_area;
421 if (can_use_lite_area) {
422 msg.blind = _("%^sが何かをつぶやいた。", "%^s mumbles.");
423 msg.to_player = _("%^sが辺りを明るく照らした。", "%^s cast a spell to light up.");
424 msg.to_mons = _("%^sが辺りを明るく照らした。", "%^s cast a spell to light up.");
426 msg_done = _("%^sは白い光に包まれた。", "%^s is surrounded by a white light.");
428 msg.blind = _("%^sが何かをつぶやいた。", "%^s mumbles.");
429 msg.to_player = _("%^sが暗闇の中で手を振った。", "%^s gestures in shadow.");
430 msg.to_mons = _("%^sが暗闇の中で手を振った。", "%^s gestures in shadow.");
432 msg_done = _("%^sは暗闇に包まれた。", "%^s is surrounded by darkness.");
435 monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
437 if (see_monster(player_ptr, t_idx) && monster_to_monster) {
438 msg_format(msg_done, t_name);
441 if (monster_to_player) {
442 if (can_use_lite_area) {
443 (void)lite_area(player_ptr, 0, 3);
445 (void)unlite_area(player_ptr, 0, 3);
447 } else if (monster_to_monster) {
448 if (can_use_lite_area) {
449 (void)project(player_ptr, m_idx, 3, y, x, 0, AttributeType::LITE_WEAK, PROJECT_GRID | PROJECT_KILL);
450 lite_room(player_ptr, y, x);
452 (void)project(player_ptr, m_idx, 3, y, x, 0, AttributeType::DARK_WEAK, PROJECT_GRID | PROJECT_KILL);
453 unlite_room(player_ptr, y, x);
461 * @brief RF6_TRAPSの処理。トラップ。 /
462 * @param player_ptr プレイヤーへの参照ポインタ
465 * @param m_idx 呪文を唱えるモンスターID
469 MonsterSpellResult spell_RF6_TRAPS(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx)
471 GAME_TEXT m_name[MAX_NLEN];
472 monster_name(player_ptr, m_idx, m_name);
473 disturb(player_ptr, true, true);
475 if (player_ptr->effects()->blindness()->is_blind()) {
476 msg_format(_("%^sが何かをつぶやいて邪悪に微笑んだ。", "%^s mumbles, and then cackles evilly."), m_name);
478 msg_format(_("%^sが呪文を唱えて邪悪に微笑んだ。", "%^s casts a spell and cackles evilly."), m_name);
481 (void)trap_creation(player_ptr, y, x);
483 auto res = MonsterSpellResult::make_valid();
484 res.learnable = true;
490 * @brief RF6_RAISE_DEADの処理。死者復活。 /
491 * @param player_ptr プレイヤーへの参照ポインタ
492 * @param m_idx 呪文を唱えるモンスターID
493 * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
494 * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
498 MonsterSpellResult spell_RF6_RAISE_DEAD(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
500 auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
501 mspell_cast_msg_blind msg(_("%^sが何かをつぶやいた。", "%^s mumbles."),
502 _("%^sが死者復活の呪文を唱えた。", "%^s casts a spell to revive corpses."), _("%^sが死者復活の呪文を唱えた。", "%^s casts a spell to revive corpses."));
504 monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
506 animate_dead(player_ptr, m_idx, m_ptr->fy, m_ptr->fx);
508 return MonsterSpellResult::make_valid();