OSDN Git Service

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