OSDN Git Service

Merge pull request #716 from sikabane-works/release/3.0.0Alpha16
[hengbandforosx/hengbandosx.git] / src / mspell / mspell-attack.cpp
1 #include "mspell/mspell-attack.h"
2 #include "blue-magic/blue-magic-checker.h"
3 #include "core/disturbance.h"
4 #include "core/player-redraw-types.h"
5 #include "dungeon/dungeon-flag-types.h"
6 #include "dungeon/dungeon.h"
7 #include "dungeon/quest.h"
8 #include "floor/cave.h"
9 #include "monster-floor/monster-move.h"
10 #include "monster-race/monster-race.h"
11 #include "monster-race/race-flags-ability1.h"
12 #include "monster-race/race-flags-ability2.h"
13 #include "monster-race/race-flags2.h"
14 #include "monster-race/race-flags4.h"
15 #include "monster-race/race-indice-types.h"
16 #include "monster/monster-describer.h"
17 #include "monster/monster-flag-types.h"
18 #include "monster/monster-info.h"
19 #include "monster/monster-status.h"
20 #include "mspell/assign-monster-spell.h"
21 #include "mspell/improper-mspell-remover.h"
22 #include "mspell/mspell-attack-util.h"
23 #include "mspell/mspell-checker.h"
24 #include "mspell/mspell-learn-checker.h"
25 #include "mspell/mspell-lite.h"
26 #include "mspell/mspell-mask-definitions.h"
27 #include "mspell/mspell-selector.h"
28 #include "mspell/mspell-type.h"
29 #include "mspell/mspell-util.h"
30 #include "mspell/mspell.h"
31 #include "player/attack-defense-types.h"
32 #include "spell-kind/spells-world.h"
33 #include "spell-realm/spells-hex.h"
34 #include "system/floor-type-definition.h"
35 #include "target/projection-path-calculator.h"
36 #include "view/display-messages.h"
37 #include "world/world.h"
38 #ifdef JP
39 #else
40 #include "monster/monster-description-types.h"
41 #endif
42
43 static void set_no_magic_mask(msa_type *msa_ptr)
44 {
45     if (!msa_ptr->no_inate)
46         return;
47
48     msa_ptr->f4 &= ~(RF4_NOMAGIC_MASK);
49     msa_ptr->f5 &= ~(RF5_NOMAGIC_MASK);
50     msa_ptr->f6 &= ~(RF6_NOMAGIC_MASK);
51 }
52
53 static void check_mspell_stupid(player_type *target_ptr, msa_type *msa_ptr)
54 {
55     floor_type *floor_ptr = target_ptr->current_floor_ptr;
56     msa_ptr->in_no_magic_dungeon = (d_info[target_ptr->dungeon_idx].flags1 & DF1_NO_MAGIC) && floor_ptr->dun_level
57         && (!floor_ptr->inside_quest || is_fixed_quest_idx(floor_ptr->inside_quest));
58     if (!msa_ptr->in_no_magic_dungeon || ((msa_ptr->r_ptr->flags2 & RF2_STUPID) != 0))
59         return;
60
61     msa_ptr->f4 &= RF4_NOMAGIC_MASK;
62     msa_ptr->f5 &= RF5_NOMAGIC_MASK;
63     msa_ptr->f6 &= RF6_NOMAGIC_MASK;
64 }
65
66 static void check_mspell_smart(player_type *target_ptr, msa_type *msa_ptr)
67 {
68     if ((msa_ptr->r_ptr->flags2 & RF2_SMART) == 0)
69         return;
70
71     if ((msa_ptr->m_ptr->hp < msa_ptr->m_ptr->maxhp / 10) && (randint0(100) < 50)) {
72         msa_ptr->f4 &= (RF4_INT_MASK);
73         msa_ptr->f5 &= (RF5_INT_MASK);
74         msa_ptr->f6 &= (RF6_INT_MASK);
75     }
76
77     if ((msa_ptr->f6 & RF6_TELE_LEVEL) && is_teleport_level_ineffective(target_ptr, 0)) {
78         msa_ptr->f6 &= ~(RF6_TELE_LEVEL);
79     }
80 }
81
82 static void check_mspell_arena(player_type *target_ptr, msa_type *msa_ptr)
83 {
84     if (!target_ptr->current_floor_ptr->inside_arena && !target_ptr->phase_out)
85         return;
86
87     msa_ptr->f4 &= ~(RF4_SUMMON_MASK);
88     msa_ptr->f5 &= ~(RF5_SUMMON_MASK);
89     msa_ptr->f6 &= ~(RF6_SUMMON_MASK | RF6_TELE_LEVEL);
90
91     if (msa_ptr->m_ptr->r_idx == MON_ROLENTO)
92         msa_ptr->f6 &= ~(RF6_SPECIAL);
93 }
94
95 static bool check_mspell_non_stupid(player_type *target_ptr, msa_type *msa_ptr)
96 {
97     if ((msa_ptr->r_ptr->flags2 & RF2_STUPID) != 0)
98         return TRUE;
99
100     if (!target_ptr->csp)
101         msa_ptr->f5 &= ~(RF5_DRAIN_MANA);
102
103     if (((msa_ptr->f4 & RF4_BOLT_MASK) || (msa_ptr->f5 & RF5_BOLT_MASK) || (msa_ptr->f6 & RF6_BOLT_MASK))
104         && !clean_shot(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, target_ptr->y, target_ptr->x, FALSE)) {
105         msa_ptr->f4 &= ~(RF4_BOLT_MASK);
106         msa_ptr->f5 &= ~(RF5_BOLT_MASK);
107         msa_ptr->f6 &= ~(RF6_BOLT_MASK);
108     }
109
110     if (((msa_ptr->f4 & RF4_SUMMON_MASK) || (msa_ptr->f5 & RF5_SUMMON_MASK) || (msa_ptr->f6 & RF6_SUMMON_MASK))
111         && !(summon_possible(target_ptr, msa_ptr->y, msa_ptr->x))) {
112         msa_ptr->f4 &= ~(RF4_SUMMON_MASK);
113         msa_ptr->f5 &= ~(RF5_SUMMON_MASK);
114         msa_ptr->f6 &= ~(RF6_SUMMON_MASK);
115     }
116
117     if ((msa_ptr->f6 & RF6_RAISE_DEAD) && !raise_possible(target_ptr, msa_ptr->m_ptr))
118         msa_ptr->f6 &= ~(RF6_RAISE_DEAD);
119
120     if (((msa_ptr->f6 & RF6_SPECIAL) != 0) && (msa_ptr->m_ptr->r_idx == MON_ROLENTO) && !summon_possible(target_ptr, msa_ptr->y, msa_ptr->x))
121         msa_ptr->f6 &= ~(RF6_SPECIAL);
122
123     return (msa_ptr->f4 != 0) || (msa_ptr->f5 != 0) || (msa_ptr->f6 != 0);
124 }
125
126 static void set_mspell_list(msa_type *msa_ptr)
127 {
128     for (int k = 0; k < 32; k++)
129         if (msa_ptr->f4 & (1UL << k))
130             msa_ptr->mspells[msa_ptr->num++] = k + RF4_SPELL_START;
131
132     for (int k = 0; k < 32; k++)
133         if (msa_ptr->f5 & (1UL << k))
134             msa_ptr->mspells[msa_ptr->num++] = k + RF5_SPELL_START;
135
136     for (int k = 0; k < 32; k++)
137         if (msa_ptr->f6 & (1UL << k))
138             msa_ptr->mspells[msa_ptr->num++] = k + RF6_SPELL_START;
139 }
140
141 static void describe_mspell_monster(player_type *target_ptr, msa_type *msa_ptr)
142 {
143     monster_desc(target_ptr, msa_ptr->m_name, msa_ptr->m_ptr, 0x00);
144
145 #ifdef JP
146 #else
147     /* Get the monster possessive ("his"/"her"/"its") */
148     char m_poss[80];
149     monster_desc(target_ptr, m_poss, msa_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE);
150 #endif
151 }
152
153 static bool switch_do_spell(player_type *target_ptr, msa_type *msa_ptr)
154 {
155     switch (msa_ptr->do_spell) {
156     case DO_SPELL_NONE: {
157         int attempt = 10;
158         while (attempt--) {
159             msa_ptr->thrown_spell = choose_attack_spell(target_ptr, msa_ptr);
160             if (msa_ptr->thrown_spell)
161                 break;
162         }
163
164         return TRUE;
165     }
166     case DO_SPELL_BR_LITE:
167         msa_ptr->thrown_spell = 96 + 14; /* RF4_BR_LITE */
168         return TRUE;
169     case DO_SPELL_BR_DISI:
170         msa_ptr->thrown_spell = 96 + 31; /* RF4_BR_DISI */
171         return TRUE;
172     case DO_SPELL_BA_LITE:
173         msa_ptr->thrown_spell = 128 + 20; /* RF5_BA_LITE */
174         return TRUE;
175     default:
176         return FALSE;
177     }
178 }
179
180 static bool check_mspell_continuation(player_type *target_ptr, msa_type *msa_ptr)
181 {
182     if ((msa_ptr->f4 == 0) && (msa_ptr->f5 == 0) && (msa_ptr->f6 == 0))
183         return FALSE;
184
185     remove_bad_spells(msa_ptr->m_idx, target_ptr, &msa_ptr->f4, &msa_ptr->f5, &msa_ptr->f6);
186     check_mspell_arena(target_ptr, msa_ptr);
187     if (((msa_ptr->f4 == 0) && (msa_ptr->f5 == 0) && (msa_ptr->f6 == 0)) || !check_mspell_non_stupid(target_ptr, msa_ptr))
188         return FALSE;
189
190     set_mspell_list(msa_ptr);
191     if ((msa_ptr->num == 0) || !target_ptr->playing || target_ptr->is_dead || target_ptr->leaving)
192         return FALSE;
193
194     describe_mspell_monster(target_ptr, msa_ptr);
195     if (!switch_do_spell(target_ptr, msa_ptr) || (msa_ptr->thrown_spell == 0))
196         return FALSE;
197
198     return TRUE;
199 }
200
201 static bool check_mspell_unexploded(player_type *target_ptr, msa_type *msa_ptr)
202 {
203     PERCENTAGE fail_rate = 25 - (msa_ptr->rlev + 3) / 4;
204     if (msa_ptr->r_ptr->flags2 & RF2_STUPID)
205         fail_rate = 0;
206
207     if (!spell_is_inate(msa_ptr->thrown_spell)
208         && (msa_ptr->in_no_magic_dungeon || (monster_stunned_remaining(msa_ptr->m_ptr) && one_in_(2)) || (randint0(100) < fail_rate))) {
209         disturb(target_ptr, TRUE, TRUE);
210         msg_format(_("%^sは呪文を唱えようとしたが失敗した。", "%^s tries to cast a spell, but fails."), msa_ptr->m_name);
211         return TRUE;
212     }
213
214     if (!spell_is_inate(msa_ptr->thrown_spell) && magic_barrier(target_ptr, msa_ptr->m_idx)) {
215         msg_format(_("反魔法バリアが%^sの呪文をかき消した。", "Anti magic barrier cancels the spell which %^s casts."), msa_ptr->m_name);
216         return TRUE;
217     }
218
219     return FALSE;
220 }
221
222 /*!
223  * @brief モンスターが使おうとする特技がプレイヤーに届くかどうかを返す
224  *
225  * ターゲット (msa_ptr->y, msa_ptr->x) は設定済みとする。
226  */
227 static bool check_thrown_mspell(player_type *target_ptr, msa_type *msa_ptr)
228 {
229     // プレイヤーがモンスターを正しく視認できていれば思い出に残る。
230     // FIXME: ここで処理するのはおかしいような?
231     msa_ptr->can_remember = is_original_ap_and_seen(target_ptr, msa_ptr->m_ptr);
232
233     // ターゲットがプレイヤー位置なら直接射線が通っているので常に届く。
234     bool direct = player_bold(target_ptr, msa_ptr->y, msa_ptr->x);
235     if (direct)
236         return TRUE;
237
238     // ターゲットがプレイヤー位置からずれているとき、直接の射線を必要とする特技
239     // (ボルト系など)は届かないものとみなす。
240     switch (msa_ptr->thrown_spell) {
241     case 96 + 2: /* RF4_DISPEL */
242     case 96 + 4: /* RF4_SHOOT */
243     case 128 + 9: /* RF5_DRAIN_MANA */
244     case 128 + 10: /* RF5_MIND_BLAST */
245     case 128 + 11: /* RF5_BRAIN_SMASH */
246     case 128 + 12: /* RF5_CAUSE_1 */
247     case 128 + 13: /* RF5_CAUSE_2 */
248     case 128 + 14: /* RF5_CAUSE_3 */
249     case 128 + 15: /* RF5_CAUSE_4 */
250     case 128 + 16: /* RF5_BO_ACID */
251     case 128 + 17: /* RF5_BO_ELEC */
252     case 128 + 18: /* RF5_BO_FIRE */
253     case 128 + 19: /* RF5_BO_COLD */
254     case 128 + 21: /* RF5_BO_NETH */
255     case 128 + 22: /* RF5_BO_WATE */
256     case 128 + 23: /* RF5_BO_MANA */
257     case 128 + 24: /* RF5_BO_PLAS */
258     case 128 + 25: /* RF5_BO_ICEE */
259     case 128 + 26: /* RF5_MISSILE */
260     case 128 + 27: /* RF5_SCARE */
261     case 128 + 28: /* RF5_BLIND */
262     case 128 + 29: /* RF5_CONF */
263     case 128 + 30: /* RF5_SLOW */
264     case 128 + 31: /* RF5_HOLD */
265     case 160 + 1: /* RF6_HAND_DOOM */
266     case 160 + 8: /* RF6_TELE_TO */
267     case 160 + 9: /* RF6_TELE_AWAY */
268     case 160 + 10: /* RF6_TELE_LEVEL */
269     case 160 + 11: /* RF6_PSY_SPEAR */
270     case 160 + 12: /* RF6_DARKNESS */
271     case 160 + 14: /* RF6_FORGET */
272         return FALSE;
273     default:
274         return TRUE;
275     }
276 }
277
278 static void check_mspell_imitation(player_type *target_ptr, msa_type *msa_ptr)
279 {
280     bool seen = (!target_ptr->blind && msa_ptr->m_ptr->ml);
281     bool can_imitate = player_has_los_bold(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx);
282     if (!seen || !can_imitate || (current_world_ptr->timewalk_m_idx != 0) || (target_ptr->pclass != CLASS_IMITATOR))
283         return;
284
285     /* Not RF6_SPECIAL */
286     if (msa_ptr->thrown_spell == 167)
287         return;
288
289     if (target_ptr->mane_num == MAX_MANE) {
290         target_ptr->mane_num--;
291         for (int i = 0; i < target_ptr->mane_num; i++) {
292             target_ptr->mane_spell[i] = target_ptr->mane_spell[i + 1];
293             target_ptr->mane_dam[i] = target_ptr->mane_dam[i + 1];
294         }
295     }
296
297     target_ptr->mane_spell[target_ptr->mane_num] = msa_ptr->thrown_spell - 96;
298     target_ptr->mane_dam[target_ptr->mane_num] = msa_ptr->dam;
299     target_ptr->mane_num++;
300     target_ptr->new_mane = TRUE;
301     target_ptr->redraw |= PR_IMITATION;
302 }
303
304 static void remember_mspell(msa_type *msa_ptr)
305 {
306     if (!msa_ptr->can_remember)
307         return;
308
309     if (msa_ptr->thrown_spell < 32 * 4) {
310         msa_ptr->r_ptr->r_flags4 |= (1UL << (msa_ptr->thrown_spell - 32 * 3));
311         if (msa_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
312             msa_ptr->r_ptr->r_cast_spell++;
313
314         return;
315     }
316
317     if (msa_ptr->thrown_spell < 32 * 5) {
318         msa_ptr->r_ptr->r_flags5 |= (1UL << (msa_ptr->thrown_spell - 32 * 4));
319         if (msa_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
320             msa_ptr->r_ptr->r_cast_spell++;
321
322         return;
323     }
324
325     if (msa_ptr->thrown_spell < 32 * 6) {
326         msa_ptr->r_ptr->r_flags6 |= (1UL << (msa_ptr->thrown_spell - 32 * 5));
327         if (msa_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
328             msa_ptr->r_ptr->r_cast_spell++;
329     }
330 }
331
332 /*!
333  * @brief モンスターの特殊技能メインルーチン /
334  * Creatures can cast spells, shoot missiles, and breathe.
335  * @param target_ptr プレーヤーへの参照ポインタ
336  * @param m_idx モンスター構造体配列のID
337  * @return 実際に特殊技能を利用したらTRUEを返す
338  */
339 bool make_attack_spell(player_type *target_ptr, MONSTER_IDX m_idx)
340 {
341     msa_type tmp_msa;
342     msa_type *msa_ptr = initialize_msa_type(target_ptr, &tmp_msa, m_idx);
343     if (monster_confused_remaining(msa_ptr->m_ptr)) {
344         reset_target(msa_ptr->m_ptr);
345         return FALSE;
346     }
347
348     if (msa_ptr->m_ptr->mflag.has(MFLAG::PREVENT_MAGIC) || !is_hostile(msa_ptr->m_ptr)
349         || ((msa_ptr->m_ptr->cdis > get_max_range(target_ptr)) && !msa_ptr->m_ptr->target_y))
350         return FALSE;
351
352     decide_lite_range(target_ptr, msa_ptr);
353     if (!decide_lite_projection(target_ptr, msa_ptr))
354         return FALSE;
355
356     reset_target(msa_ptr->m_ptr);
357     msa_ptr->rlev = ((msa_ptr->r_ptr->level >= 1) ? msa_ptr->r_ptr->level : 1);
358     set_no_magic_mask(msa_ptr);
359     decide_lite_area(target_ptr, msa_ptr);
360     check_mspell_stupid(target_ptr, msa_ptr);
361     check_mspell_smart(target_ptr, msa_ptr);
362     if (!check_mspell_continuation(target_ptr, msa_ptr))
363         return FALSE;
364
365     if (check_mspell_unexploded(target_ptr, msa_ptr))
366         return TRUE;
367
368     // 特技がプレイヤーに届かないなら使わない。
369     if (!check_thrown_mspell(target_ptr, msa_ptr))
370         return FALSE;
371
372     // 特技を使う。
373     const auto monspell_res = monspell_to_player(target_ptr, msa_ptr->thrown_spell, msa_ptr->y, msa_ptr->x, m_idx);
374     if (!monspell_res.valid)
375         return FALSE;
376
377     msa_ptr->dam = monspell_res.dam;
378     check_mspell_imitation(target_ptr, msa_ptr);
379     remember_mspell(msa_ptr);
380     if (target_ptr->is_dead && (msa_ptr->r_ptr->r_deaths < MAX_SHORT) && !target_ptr->current_floor_ptr->inside_arena)
381         msa_ptr->r_ptr->r_deaths++;
382
383     return TRUE;
384 }