OSDN Git Service

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