OSDN Git Service

Merge pull request #2157 from Hourier/Replace-Auto
[hengbandforosx/hengbandosx.git] / src / mspell / mspell-floor.cpp
1 /*!
2  * @brief フロアの一定範囲に効果を及ぼす (悲鳴、テレポート等)スペルの効果
3  * @date 2020/05/16
4  * @author Hourier
5  */
6
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/effect-characteristics.h"
12 #include "effect/effect-processor.h"
13 #include "mind/drs-types.h"
14 #include "monster-race/monster-race.h"
15 #include "monster-race/race-ability-flags.h"
16 #include "monster-race/race-flags-resistance.h"
17 #include "monster-race/race-flags1.h"
18 #include "monster-race/race-flags3.h"
19 #include "monster-race/race-flags7.h"
20 #include "monster-race/race-indice-types.h"
21 #include "monster/monster-info.h"
22 #include "monster/monster-status-setter.h"
23 #include "monster/monster-status.h"
24 #include "monster/monster-update.h"
25 #include "mspell/mspell-result.h"
26 #include "mspell/mspell-status.h"
27 #include "mspell/mspell-util.h"
28 #include "player-base/player-class.h"
29 #include "player/player-personality-types.h"
30 #include "player/player-status-flags.h"
31 #include "player/player-status.h"
32 #include "spell-kind/spells-lite.h"
33 #include "spell-kind/spells-neighbor.h"
34 #include "spell-kind/spells-sight.h"
35 #include "spell-kind/spells-teleport.h"
36 #include "spell-kind/spells-world.h"
37 #include "spell-realm/spells-hex.h"
38 #include "effect/attribute-types.h"
39 #include "system/floor-type-definition.h"
40 #include "system/monster-race-definition.h"
41 #include "system/monster-type-definition.h"
42 #include "system/player-type-definition.h"
43 #include "view/display-messages.h"
44
45 /*!
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
51  *
52  * ラーニング不可。
53  */
54 MonsterSpellResult spell_RF4_SHRIEK(MONSTER_IDX m_idx, PlayerType *player_ptr, MONSTER_IDX t_idx, int target_type)
55 {
56     mspell_cast_msg_simple msg(_("%^sがかん高い金切り声をあげた。", "%^s makes a high pitched shriek."),
57         _("%^sが%sに向かって叫んだ。", "%^s shrieks at %s."));
58
59     simple_monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
60
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 == MON_LEE_QIEZI) {
64         msg_print(_("しかし、その声は誰の心にも響かなかった…。", "However, that voice didn't touch anyone's heart..."));
65         return result;
66     }
67
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);
72     }
73
74     return result;
75 }
76
77 /*!
78  * @brief RF6_WORLDの処理。時を止める。 /
79  * @param player_ptr プレイヤーへの参照ポインタ
80  * @param m_idx 呪文を唱えるモンスターID
81  *
82  * ラーニング不可。
83  */
84 MonsterSpellResult spell_RF6_WORLD(PlayerType *player_ptr, MONSTER_IDX m_idx)
85 {
86     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
87     GAME_TEXT m_name[MAX_NLEN];
88     monster_name(player_ptr, m_idx, m_name);
89     disturb(player_ptr, true, true);
90     (void)set_monster_timewalk(player_ptr, randint1(2) + 2, m_ptr->r_idx, true);
91
92     return MonsterSpellResult::make_valid();
93 }
94
95 /*!
96  * @brief RF6_BLINKの処理。ショート・テレポート。 /
97  * @param player_ptr プレイヤーへの参照ポインタ
98  * @param m_idx 呪文を唱えるモンスターID
99  * @param is_quantum_effect 量子的効果によるショート・テレポートの場合時TRUE
100  * @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
101  *
102  * ラーニング不可。
103  */
104 MonsterSpellResult spell_RF6_BLINK(PlayerType *player_ptr, MONSTER_IDX m_idx, int TARGET_TYPE, bool is_quantum_effect)
105 {
106     const auto res = MonsterSpellResult::make_valid();
107
108     GAME_TEXT m_name[MAX_NLEN];
109     monster_name(player_ptr, m_idx, m_name);
110
111     if (TARGET_TYPE == MONSTER_TO_PLAYER)
112         disturb(player_ptr, true, true);
113
114     if (!is_quantum_effect && SpellHex(player_ptr).check_hex_barrier(m_idx, HEX_ANTI_TELE)) {
115         if (see_monster(player_ptr, m_idx))
116             msg_format(_("魔法のバリアが%^sのテレポートを邪魔した。", "Magic barrier obstructs teleporting of %^s."), m_name);
117         return res;
118     }
119
120     if (see_monster(player_ptr, m_idx))
121         msg_format(_("%^sが瞬時に消えた。", "%^s blinks away."), m_name);
122
123     teleport_away(player_ptr, m_idx, 10, TELEPORT_SPONTANEOUS);
124
125     if (TARGET_TYPE == MONSTER_TO_PLAYER)
126         player_ptr->update |= (PU_MONSTERS);
127
128     return res;
129 }
130
131 /*!
132  * @brief RF6_TPORTの処理。テレポート。 /
133  * @param player_ptr プレイヤーへの参照ポインタ
134  * @param m_idx 呪文を唱えるモンスターID
135  * @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
136  *
137  * ラーニング不可。
138  */
139 MonsterSpellResult spell_RF6_TPORT(PlayerType *player_ptr, MONSTER_IDX m_idx, int TARGET_TYPE)
140 {
141     const auto res = MonsterSpellResult::make_valid();
142
143     GAME_TEXT m_name[MAX_NLEN];
144     monster_name(player_ptr, m_idx, m_name);
145
146     if (TARGET_TYPE == MONSTER_TO_PLAYER)
147         disturb(player_ptr, true, true);
148     if (SpellHex(player_ptr).check_hex_barrier(m_idx, HEX_ANTI_TELE)) {
149         if (see_monster(player_ptr, m_idx))
150             msg_format(_("魔法のバリアが%^sのテレポートを邪魔した。", "Magic barrier obstructs teleporting of %^s."), m_name);
151         return res;
152     }
153
154     if (see_monster(player_ptr, m_idx))
155         msg_format(_("%^sがテレポートした。", "%^s teleports away."), m_name);
156
157     teleport_away_followable(player_ptr, m_idx);
158
159     return res;
160 }
161
162 /*!
163  * @brief RF6_TELE_TOの処理。テレポート・バック。 /
164  * @param player_ptr プレイヤーへの参照ポインタ
165  * @param m_idx 呪文を唱えるモンスターID
166  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
167  * @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
168  *
169  * プレイヤーが対象ならラーニング可。
170  */
171 MonsterSpellResult spell_RF6_TELE_TO(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
172 {
173     auto res = MonsterSpellResult::make_valid();
174     res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
175
176     auto *floor_ptr = player_ptr->current_floor_ptr;
177     auto *m_ptr = &floor_ptr->m_list[m_idx];
178     monster_type *t_ptr = &floor_ptr->m_list[t_idx];
179     monster_race *tr_ptr = &r_info[t_ptr->r_idx];
180
181     mspell_cast_msg_simple msg(_("%^sがあなたを引き戻した。", "%^s commands you to return."),
182         _("%^sが%sを引き戻した。", "%^s commands %s to return."));
183
184     simple_monspell_message(player_ptr, m_idx, t_idx, msg, TARGET_TYPE);
185
186     if (TARGET_TYPE == MONSTER_TO_PLAYER) {
187         teleport_player_to(player_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_PASSIVE);
188         return res;
189     }
190
191     if (TARGET_TYPE != MONSTER_TO_MONSTER)
192         return res;
193
194     bool resists_tele = false;
195     GAME_TEXT t_name[MAX_NLEN];
196     monster_name(player_ptr, t_idx, t_name);
197
198     if (tr_ptr->flagsr & RFR_RES_TELE) {
199         if ((tr_ptr->flags1 & RF1_UNIQUE) || (tr_ptr->flagsr & RFR_RES_ALL)) {
200             if (is_original_ap_and_seen(player_ptr, t_ptr))
201                 tr_ptr->r_flagsr |= RFR_RES_TELE;
202             if (see_monster(player_ptr, t_idx)) {
203                 msg_format(_("%^sには効果がなかった。", "%^s is unaffected!"), t_name);
204             }
205             resists_tele = true;
206         } else if (tr_ptr->level > randint1(100)) {
207             if (is_original_ap_and_seen(player_ptr, t_ptr))
208                 tr_ptr->r_flagsr |= RFR_RES_TELE;
209             if (see_monster(player_ptr, t_idx)) {
210                 msg_format(_("%^sは耐性を持っている!", "%^s resists!"), t_name);
211             }
212             resists_tele = true;
213         }
214     }
215
216     if (resists_tele) {
217         set_monster_csleep(player_ptr, t_idx, 0);
218         return res;
219     }
220
221     if (t_idx == player_ptr->riding)
222         teleport_player_to(player_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_PASSIVE);
223     else
224         teleport_monster_to(player_ptr, t_idx, m_ptr->fy, m_ptr->fx, 100, TELEPORT_PASSIVE);
225     set_monster_csleep(player_ptr, t_idx, 0);
226
227     return res;
228 }
229
230 /*!
231  * @brief RF6_TELE_AWAYの処理。テレポート・アウェイ。 /
232  * @param player_ptr プレイヤーへの参照ポインタ
233  * @param m_idx 呪文を唱えるモンスターID
234  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
235  * @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
236  *
237  * プレイヤーが対象ならラーニング可。
238  */
239 MonsterSpellResult spell_RF6_TELE_AWAY(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
240 {
241     auto res = MonsterSpellResult::make_valid();
242     res.learnable = TARGET_TYPE == MONSTER_TO_PLAYER;
243
244     auto *floor_ptr = player_ptr->current_floor_ptr;
245     monster_type *t_ptr = &floor_ptr->m_list[t_idx];
246     monster_race *tr_ptr = &r_info[t_ptr->r_idx];
247
248     mspell_cast_msg_simple msg(_("%^sにテレポートさせられた。", "%^s teleports you away."),
249         _("%^sは%sをテレポートさせた。", "%^s teleports %s away."));
250
251     simple_monspell_message(player_ptr, m_idx, t_idx, msg, TARGET_TYPE);
252
253     if (TARGET_TYPE == MONSTER_TO_PLAYER) {
254         if (is_echizen(player_ptr))
255             msg_print(_("くっそ~", ""));
256         else if (is_chargeman(player_ptr)) {
257             if (randint0(2) == 0)
258                 msg_print(_("ジュラル星人め!", ""));
259             else
260                 msg_print(_("弱い者いじめは止めるんだ!", ""));
261         }
262
263         teleport_player_away(m_idx, player_ptr, 100, false);
264         return res;
265     }
266
267     if (TARGET_TYPE != MONSTER_TO_MONSTER)
268         return res;
269
270     bool resists_tele = false;
271     GAME_TEXT t_name[MAX_NLEN];
272     monster_name(player_ptr, t_idx, t_name);
273
274     if (tr_ptr->flagsr & RFR_RES_TELE) {
275         if ((tr_ptr->flags1 & RF1_UNIQUE) || (tr_ptr->flagsr & RFR_RES_ALL)) {
276             if (is_original_ap_and_seen(player_ptr, t_ptr))
277                 tr_ptr->r_flagsr |= RFR_RES_TELE;
278             if (see_monster(player_ptr, t_idx)) {
279                 msg_format(_("%^sには効果がなかった。", "%^s is unaffected!"), t_name);
280             }
281             resists_tele = true;
282         } else if (tr_ptr->level > randint1(100)) {
283             if (is_original_ap_and_seen(player_ptr, t_ptr))
284                 tr_ptr->r_flagsr |= RFR_RES_TELE;
285             if (see_monster(player_ptr, t_idx)) {
286                 msg_format(_("%^sは耐性を持っている!", "%^s resists!"), t_name);
287             }
288             resists_tele = true;
289         }
290     }
291
292     if (resists_tele) {
293         set_monster_csleep(player_ptr, t_idx, 0);
294         return res;
295     }
296
297     if (t_idx == player_ptr->riding)
298         teleport_player_away(m_idx, player_ptr, MAX_SIGHT * 2 + 5, false);
299     else
300         teleport_away(player_ptr, t_idx, MAX_SIGHT * 2 + 5, TELEPORT_PASSIVE);
301     set_monster_csleep(player_ptr, t_idx, 0);
302
303     return res;
304 }
305
306 /*!
307  * @brief RF6_TELE_LEVELの処理。テレポート・レベル。 /
308  * @param player_ptr プレイヤーへの参照ポインタ
309  * @param m_idx 呪文を唱えるモンスターID
310  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
311  * @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
312  *
313  * ラーニング不可。
314  */
315 MonsterSpellResult spell_RF6_TELE_LEVEL(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
316 {
317     const auto res = MonsterSpellResult::make_valid();
318
319     auto *floor_ptr = player_ptr->current_floor_ptr;
320     monster_type *t_ptr = &floor_ptr->m_list[t_idx];
321     monster_race *tr_ptr = &r_info[t_ptr->r_idx];
322     DEPTH rlev = monster_level_idx(floor_ptr, m_idx);
323     bool resist, saving_throw;
324
325     if (TARGET_TYPE == MONSTER_TO_PLAYER) {
326         resist = (has_resist_nexus(player_ptr) != 0);
327         saving_throw = (randint0(100 + rlev / 2) < player_ptr->skill_sav);
328
329         mspell_cast_msg_bad_status_to_player msg(_("%^sが何か奇妙な言葉をつぶやいた。", "%^s mumbles strangely."),
330             _("%^sがあなたの足を指さした。", "%^s gestures at your feet."), _("しかし効果がなかった!", "You are unaffected!"),
331             _("しかし効力を跳ね返した!", "You resist the effects!"));
332
333         spell_badstatus_message_to_player(player_ptr, m_idx, msg, resist, saving_throw);
334
335         if (!resist && !saving_throw) {
336             teleport_level(player_ptr, 0);
337         }
338
339         update_smart_learn(player_ptr, m_idx, DRS_NEXUS);
340         return res;
341     }
342
343     if (TARGET_TYPE != MONSTER_TO_MONSTER)
344         return res;
345
346     resist = tr_ptr->flagsr & (RFR_EFF_RES_NEXU_MASK | RFR_RES_TELE);
347     saving_throw = (tr_ptr->flags1 & RF1_QUESTOR) || (tr_ptr->level > randint1((rlev - 10) < 1 ? 1 : (rlev - 10)) + 10);
348
349     mspell_cast_msg_bad_status_to_monster msg(_("%^sが%sの足を指さした。", "%^s gestures at %s's feet."),
350         _("%^sには効果がなかった。", "%^s is unaffected!"), _("%^sは効力を跳ね返した!", "%^s resist the effects!"), "");
351
352     spell_badstatus_message_to_mons(player_ptr, m_idx, t_idx, msg, resist, saving_throw);
353
354     if (!resist && !saving_throw) {
355         teleport_level(player_ptr, (t_idx == player_ptr->riding) ? 0 : t_idx);
356     }
357
358     return res;
359 }
360
361 /*!
362  * @brief RF6_DARKNESSの処理。暗闇or閃光。 /
363  * @param target_type プレイヤーへの参照ポインタ
364  * @param y 対象の地点のy座標
365  * @param x 対象の地点のx座標
366  * @param m_idx 呪文を唱えるモンスターID
367  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
368  * @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
369  *
370  * プレイヤーが対象かつ暗闇ならラーニング可。
371  */
372 MonsterSpellResult spell_RF6_DARKNESS(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
373 {
374     mspell_cast_msg_blind msg;
375     concptr msg_done;
376     auto *floor_ptr = player_ptr->current_floor_ptr;
377     auto *m_ptr = &floor_ptr->m_list[m_idx];
378     monster_type *t_ptr = &floor_ptr->m_list[t_idx];
379     auto *r_ptr = &r_info[m_ptr->r_idx];
380     bool can_use_lite_area = false;
381     bool monster_to_monster = TARGET_TYPE == MONSTER_TO_MONSTER;
382     bool monster_to_player = TARGET_TYPE == MONSTER_TO_PLAYER;
383     GAME_TEXT t_name[MAX_NLEN];
384     monster_name(player_ptr, t_idx, t_name);
385
386     if (PlayerClass(player_ptr).equals(PlayerClassType::NINJA) && !(r_ptr->flags3 & (RF3_UNDEAD | RF3_HURT_LITE)) && !(r_ptr->flags7 & RF7_DARK_MASK))
387         can_use_lite_area = true;
388
389     if (monster_to_monster && !is_hostile(t_ptr))
390         can_use_lite_area = false;
391
392     auto res = MonsterSpellResult::make_valid();
393     res.learnable = monster_to_player && !can_use_lite_area;
394
395     if (can_use_lite_area) {
396         msg.blind = _("%^sが何かをつぶやいた。", "%^s mumbles.");
397         msg.to_player = _("%^sが辺りを明るく照らした。", "%^s cast a spell to light up.");
398         msg.to_mons = _("%^sが辺りを明るく照らした。", "%^s cast a spell to light up.");
399
400         msg_done = _("%^sは白い光に包まれた。", "%^s is surrounded by a white light.");
401     } else {
402         msg.blind = _("%^sが何かをつぶやいた。", "%^s mumbles.");
403         msg.to_player = _("%^sが暗闇の中で手を振った。", "%^s gestures in shadow.");
404         msg.to_mons = _("%^sが暗闇の中で手を振った。", "%^s gestures in shadow.");
405
406         msg_done = _("%^sは暗闇に包まれた。", "%^s is surrounded by darkness.");
407     }
408
409     monspell_message(player_ptr, m_idx, t_idx, msg, TARGET_TYPE);
410
411     if (see_monster(player_ptr, t_idx) && monster_to_monster) {
412         msg_format(msg_done, t_name);
413     }
414
415     if (monster_to_player) {
416         if (can_use_lite_area) {
417             (void)lite_area(player_ptr, 0, 3);
418         } else {
419             (void)unlite_area(player_ptr, 0, 3);
420         }
421     } else if (monster_to_monster) {
422         if (can_use_lite_area) {
423             (void)project(player_ptr, m_idx, 3, y, x, 0, AttributeType::LITE_WEAK, PROJECT_GRID | PROJECT_KILL);
424             lite_room(player_ptr, y, x);
425         } else {
426             (void)project(player_ptr, m_idx, 3, y, x, 0, AttributeType::DARK_WEAK, PROJECT_GRID | PROJECT_KILL);
427             unlite_room(player_ptr, y, x);
428         }
429     }
430
431     return res;
432 }
433
434 /*!
435  * @brief RF6_TRAPSの処理。トラップ。 /
436  * @param player_ptr プレイヤーへの参照ポインタ
437  * @param y 対象の地点のy座標
438  * @param x 対象の地点のx座標
439  * @param m_idx 呪文を唱えるモンスターID
440  *
441  * ラーニング可。
442  */
443 MonsterSpellResult spell_RF6_TRAPS(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx)
444 {
445     GAME_TEXT m_name[MAX_NLEN];
446     monster_name(player_ptr, m_idx, m_name);
447     disturb(player_ptr, true, true);
448
449     if (player_ptr->blind)
450         msg_format(_("%^sが何かをつぶやいて邪悪に微笑んだ。", "%^s mumbles, and then cackles evilly."), m_name);
451     else
452         msg_format(_("%^sが呪文を唱えて邪悪に微笑んだ。", "%^s casts a spell and cackles evilly."), m_name);
453
454     (void)trap_creation(player_ptr, y, x);
455
456     auto res = MonsterSpellResult::make_valid();
457     res.learnable = true;
458
459     return res;
460 }
461
462 /*!
463  * @brief RF6_RAISE_DEADの処理。死者復活。 /
464  * @param player_ptr プレイヤーへの参照ポインタ
465  * @param m_idx 呪文を唱えるモンスターID
466  * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
467  * @param TARGET_TYPE プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
468  *
469  * ラーニング不可。
470  */
471 MonsterSpellResult spell_RF6_RAISE_DEAD(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
472 {
473     auto *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
474     mspell_cast_msg_blind msg(_("%^sが何かをつぶやいた。", "%^s mumbles."),
475         _("%^sが死者復活の呪文を唱えた。", "%^s casts a spell to revive corpses."), _("%^sが死者復活の呪文を唱えた。", "%^s casts a spell to revive corpses."));
476
477     monspell_message(player_ptr, m_idx, t_idx, msg, TARGET_TYPE);
478
479     animate_dead(player_ptr, m_idx, m_ptr->fy, m_ptr->fx);
480
481     return MonsterSpellResult::make_valid();
482 }