OSDN Git Service

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