OSDN Git Service

Merge pull request #716 from sikabane-works/release/3.0.0Alpha16
[hengbandforosx/hengbandosx.git] / src / melee / melee-spell-flags-checker.cpp
1 #include "melee/melee-spell-flags-checker.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "dungeon/dungeon.h"
4 #include "effect/effect-characteristics.h"
5 #include "floor/line-of-sight.h"
6 #include "melee/melee-spell-util.h"
7 #include "monster-floor/monster-move.h"
8 #include "monster-race/monster-race.h"
9 #include "monster-race/race-flags-ability1.h"
10 #include "monster-race/race-flags-ability2.h"
11 #include "monster-race/race-flags2.h"
12 #include "monster-race/race-flags3.h"
13 #include "monster-race/race-flags4.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 "mspell/mspell-checker.h"
19 #include "mspell/mspell-judgement.h"
20 #include "mspell/mspell-mask-definitions.h"
21 #include "mspell/mspell-util.h"
22 #include "pet/pet-util.h"
23 #include "spell-kind/spells-world.h"
24 #include "spell/spell-types.h"
25 #include "system/floor-type-definition.h"
26 #include "target/projection-path-calculator.h"
27
28 static void decide_melee_spell_target(player_type *target_ptr, melee_spell_type *ms_ptr)
29 {
30     if ((target_ptr->pet_t_m_idx == 0) || !ms_ptr->pet)
31         return;
32
33     ms_ptr->target_idx = target_ptr->pet_t_m_idx;
34     ms_ptr->t_ptr = &target_ptr->current_floor_ptr->m_list[ms_ptr->target_idx];
35     if ((ms_ptr->m_idx == ms_ptr->target_idx) || !projectable(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx))
36         ms_ptr->target_idx = 0;
37 }
38
39 static void decide_indirection_melee_spell(player_type *target_ptr, melee_spell_type *ms_ptr)
40 {
41     if ((ms_ptr->target_idx != 0) || (ms_ptr->m_ptr->target_y == 0))
42         return;
43
44     floor_type *floor_ptr = target_ptr->current_floor_ptr;
45     ms_ptr->target_idx = floor_ptr->grid_array[ms_ptr->m_ptr->target_y][ms_ptr->m_ptr->target_x].m_idx;
46     if (ms_ptr->target_idx == 0)
47         return;
48
49     ms_ptr->t_ptr = &floor_ptr->m_list[ms_ptr->target_idx];
50     if ((ms_ptr->m_idx == ms_ptr->target_idx) || ((ms_ptr->target_idx != target_ptr->pet_t_m_idx) && !are_enemies(target_ptr, ms_ptr->m_ptr, ms_ptr->t_ptr))) {
51         ms_ptr->target_idx = 0;
52         return;
53     }
54
55     if (projectable(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx))
56         return;
57
58     ms_ptr->f4 &= RF4_INDIRECT_MASK;
59     ms_ptr->f5 &= RF5_INDIRECT_MASK;
60     ms_ptr->f6 &= RF6_INDIRECT_MASK;
61 }
62
63 static bool check_melee_spell_projection(player_type *target_ptr, melee_spell_type *ms_ptr)
64 {
65     if (ms_ptr->target_idx != 0)
66         return TRUE;
67
68     int start;
69     int plus = 1;
70     floor_type *floor_ptr = target_ptr->current_floor_ptr;
71     if (target_ptr->phase_out) {
72         start = randint1(floor_ptr->m_max - 1) + floor_ptr->m_max;
73         if (randint0(2))
74             plus = -1;
75     } else
76         start = floor_ptr->m_max + 1;
77
78     for (int i = start; ((i < start + floor_ptr->m_max) && (i > start - floor_ptr->m_max)); i += plus) {
79         MONSTER_IDX dummy = (i % floor_ptr->m_max);
80         if (!dummy)
81             continue;
82
83         ms_ptr->target_idx = dummy;
84         ms_ptr->t_ptr = &floor_ptr->m_list[ms_ptr->target_idx];
85         if (!monster_is_valid(ms_ptr->t_ptr) || (ms_ptr->m_idx == ms_ptr->target_idx) || !are_enemies(target_ptr, ms_ptr->m_ptr, ms_ptr->t_ptr)
86             || !projectable(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx))
87             continue;
88
89         return TRUE;
90     }
91
92     return FALSE;
93 }
94
95 static void check_darkness(player_type *target_ptr, melee_spell_type *ms_ptr)
96 {
97     if ((ms_ptr->f6 & RF6_DARKNESS) == 0)
98         return;
99
100     bool vs_ninja = (target_ptr->pclass == CLASS_NINJA) && !is_hostile(ms_ptr->t_ptr);
101     bool can_use_lite_area = vs_ninja && !(ms_ptr->r_ptr->flags3 & (RF3_UNDEAD | RF3_HURT_LITE)) && !(ms_ptr->r_ptr->flags7 & RF7_DARK_MASK);
102     if ((ms_ptr->r_ptr->flags2 & RF2_STUPID) != 0)
103         return;
104
105     if (d_info[target_ptr->dungeon_idx].flags1 & DF1_DARKNESS) {
106         ms_ptr->f6 &= ~(RF6_DARKNESS);
107         return;
108     }
109
110     if (vs_ninja && !can_use_lite_area)
111         ms_ptr->f6 &= ~(RF6_DARKNESS);
112 }
113
114 static void check_stupid(melee_spell_type *ms_ptr)
115 {
116     if (!ms_ptr->in_no_magic_dungeon || ((ms_ptr->r_ptr->flags2 & RF2_STUPID) != 0))
117         return;
118
119     ms_ptr->f4 &= (RF4_NOMAGIC_MASK);
120     ms_ptr->f5 &= (RF5_NOMAGIC_MASK);
121     ms_ptr->f6 &= (RF6_NOMAGIC_MASK);
122 }
123
124 static void check_arena(player_type *target_ptr, melee_spell_type *ms_ptr)
125 {
126     if (!target_ptr->current_floor_ptr->inside_arena && !target_ptr->phase_out)
127         return;
128
129     ms_ptr->f4 &= ~(RF4_SUMMON_MASK);
130     ms_ptr->f5 &= ~(RF5_SUMMON_MASK);
131     ms_ptr->f6 &= ~(RF6_SUMMON_MASK | RF6_TELE_LEVEL);
132     if (ms_ptr->m_ptr->r_idx == MON_ROLENTO)
133         ms_ptr->f6 &= ~(RF6_SPECIAL);
134 }
135
136 static void check_melee_spell_distance(player_type *target_ptr, melee_spell_type *ms_ptr)
137 {
138     if (((ms_ptr->f4 & (RF4_BALL_MASK & ~(RF4_ROCKET))) == 0) && ((ms_ptr->f5 & RF5_BALL_MASK) == 0) && ((ms_ptr->f6 & RF6_BALL_MASK) == 0))
139         return;
140
141     POSITION real_y = ms_ptr->y;
142     POSITION real_x = ms_ptr->x;
143     get_project_point(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, &real_y, &real_x, 0L);
144     if (!projectable(target_ptr, real_y, real_x, target_ptr->y, target_ptr->x) && ((ms_ptr->f5 & RF5_BA_LITE) != 0)
145         && (distance(real_y, real_x, target_ptr->y, target_ptr->x) <= 4) && los(target_ptr, real_y, real_x, target_ptr->y, target_ptr->x)) {
146         ms_ptr->f5 &= ~(RF5_BA_LITE);
147
148         return;
149     }
150
151     int dist = distance(real_y, real_x, target_ptr->y, target_ptr->x);
152     if (dist <= 2) {
153         ms_ptr->f4 &= ~(RF4_BALL_MASK & ~(RF4_ROCKET));
154         ms_ptr->f5 &= ~(RF5_BALL_MASK);
155         ms_ptr->f6 &= ~(RF6_BALL_MASK);
156         return;
157     }
158
159     if (dist > 4)
160         return;
161
162     ms_ptr->f4 &= ~(RF4_BIG_BALL_MASK);
163     ms_ptr->f5 &= ~(RF5_BIG_BALL_MASK);
164     ms_ptr->f6 &= ~(RF6_BIG_BALL_MASK);
165 }
166
167 static void check_melee_spell_rocket(player_type *target_ptr, melee_spell_type *ms_ptr)
168 {
169     if ((ms_ptr->f4 & RF4_ROCKET) == 0)
170         return;
171
172     POSITION real_y = ms_ptr->y;
173     POSITION real_x = ms_ptr->x;
174     get_project_point(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, &real_y, &real_x, PROJECT_STOP);
175     if (projectable(target_ptr, real_y, real_x, target_ptr->y, target_ptr->x) && (distance(real_y, real_x, target_ptr->y, target_ptr->x) <= 2))
176         ms_ptr->f4 &= ~(RF4_ROCKET);
177 }
178
179 static void check_melee_spell_beam(player_type *target_ptr, melee_spell_type *ms_ptr)
180 {
181     if ((((ms_ptr->f4 & RF4_BEAM_MASK) == 0) && ((ms_ptr->f5 & RF5_BEAM_MASK) == 0) && ((ms_ptr->f6 & RF6_BEAM_MASK) == 0))
182         || direct_beam(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx, ms_ptr->m_ptr))
183         return;
184
185     ms_ptr->f4 &= ~(RF4_BEAM_MASK);
186     ms_ptr->f5 &= ~(RF5_BEAM_MASK);
187     ms_ptr->f6 &= ~(RF6_BEAM_MASK);
188 }
189
190 static void check_melee_spell_breath(player_type *target_ptr, melee_spell_type *ms_ptr)
191 {
192     if (((ms_ptr->f4 & RF4_BREATH_MASK) == 0) && ((ms_ptr->f5 & RF5_BREATH_MASK) == 0) && ((ms_ptr->f6 & RF6_BREATH_MASK) == 0))
193         return;
194
195     POSITION rad = (ms_ptr->r_ptr->flags2 & RF2_POWERFUL) ? 3 : 2;
196     if (!breath_direct(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx, rad, 0, TRUE)) {
197         ms_ptr->f4 &= ~(RF4_BREATH_MASK);
198         ms_ptr->f5 &= ~(RF5_BREATH_MASK);
199         ms_ptr->f6 &= ~(RF6_BREATH_MASK);
200         return;
201     }
202
203     if ((ms_ptr->f4 & RF4_BR_LITE)
204         && !breath_direct(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx, rad, GF_LITE, TRUE)) {
205         ms_ptr->f4 &= ~(RF4_BR_LITE);
206         return;
207     }
208
209     if ((ms_ptr->f4 & RF4_BR_DISI)
210         && !breath_direct(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx, rad, GF_DISINTEGRATE, TRUE)) {
211         ms_ptr->f4 &= ~(RF4_BR_DISI);
212     }
213 }
214
215 static void check_melee_spell_special(player_type *target_ptr, melee_spell_type *ms_ptr)
216 {
217     if ((ms_ptr->f6 & RF6_SPECIAL) == 0)
218         return;
219
220     if (ms_ptr->m_ptr->r_idx == MON_ROLENTO) {
221         if ((target_ptr->pet_extra_flags & (PF_ATTACK_SPELL | PF_SUMMON_SPELL)) != (PF_ATTACK_SPELL | PF_SUMMON_SPELL))
222             ms_ptr->f6 &= ~(RF6_SPECIAL);
223
224         return;
225     }
226
227     if (ms_ptr->r_ptr->d_char == 'B') {
228         if ((target_ptr->pet_extra_flags & (PF_ATTACK_SPELL | PF_TELEPORT)) != (PF_ATTACK_SPELL | PF_TELEPORT))
229             ms_ptr->f6 &= ~(RF6_SPECIAL);
230
231         return;
232     }
233
234     ms_ptr->f6 &= ~(RF6_SPECIAL);
235 }
236
237 static void check_riding(player_type *target_ptr, melee_spell_type *ms_ptr)
238 {
239     if (ms_ptr->m_idx != target_ptr->riding)
240         return;
241
242     ms_ptr->f4 &= ~(RF4_RIDING_MASK);
243     ms_ptr->f5 &= ~(RF5_RIDING_MASK);
244     ms_ptr->f6 &= ~(RF6_RIDING_MASK);
245 }
246
247 static void check_pet(player_type *target_ptr, melee_spell_type *ms_ptr)
248 {
249     if (!ms_ptr->pet)
250         return;
251
252     ms_ptr->f4 &= ~(RF4_SHRIEK);
253     ms_ptr->f6 &= ~(RF6_DARKNESS | RF6_TRAPS);
254     if (!(target_ptr->pet_extra_flags & PF_TELEPORT))
255         ms_ptr->f6 &= ~(RF6_BLINK | RF6_TPORT | RF6_TELE_TO | RF6_TELE_AWAY | RF6_TELE_LEVEL);
256
257     if (!(target_ptr->pet_extra_flags & PF_ATTACK_SPELL)) {
258         ms_ptr->f4 &= ~(RF4_ATTACK_MASK);
259         ms_ptr->f5 &= ~(RF5_ATTACK_MASK);
260         ms_ptr->f6 &= ~(RF6_ATTACK_MASK);
261     }
262
263     if (!(target_ptr->pet_extra_flags & PF_SUMMON_SPELL)) {
264         ms_ptr->f4 &= ~(RF4_SUMMON_MASK);
265         ms_ptr->f5 &= ~(RF5_SUMMON_MASK);
266         ms_ptr->f6 &= ~(RF6_SUMMON_MASK);
267     }
268
269     if (!(target_ptr->pet_extra_flags & PF_BALL_SPELL) && (ms_ptr->m_idx != target_ptr->riding)) {
270         check_melee_spell_distance(target_ptr, ms_ptr);
271         check_melee_spell_rocket(target_ptr, ms_ptr);
272         check_melee_spell_beam(target_ptr, ms_ptr);
273         check_melee_spell_breath(target_ptr, ms_ptr);
274     }
275
276     check_melee_spell_special(target_ptr, ms_ptr);
277 }
278
279 static void check_non_stupid(player_type *target_ptr, melee_spell_type *ms_ptr)
280 {
281     if ((ms_ptr->r_ptr->flags2 & RF2_STUPID) != 0)
282         return;
283
284     if (((ms_ptr->f4 & RF4_BOLT_MASK) || (ms_ptr->f5 & RF5_BOLT_MASK) || (ms_ptr->f6 & RF6_BOLT_MASK))
285         && !clean_shot(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx, ms_ptr->pet)) {
286         ms_ptr->f4 &= ~(RF4_BOLT_MASK);
287         ms_ptr->f5 &= ~(RF5_BOLT_MASK);
288         ms_ptr->f6 &= ~(RF6_BOLT_MASK);
289     }
290
291     if (((ms_ptr->f4 & RF4_SUMMON_MASK) || (ms_ptr->f5 & RF5_SUMMON_MASK) || (ms_ptr->f6 & RF6_SUMMON_MASK))
292         && !(summon_possible(target_ptr, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx))) {
293         ms_ptr->f4 &= ~(RF4_SUMMON_MASK);
294         ms_ptr->f5 &= ~(RF5_SUMMON_MASK);
295         ms_ptr->f6 &= ~(RF6_SUMMON_MASK);
296     }
297
298     if ((ms_ptr->f4 & RF4_DISPEL) && !dispel_check_monster(target_ptr, ms_ptr->m_idx, ms_ptr->target_idx))
299         ms_ptr->f4 &= ~(RF4_DISPEL);
300
301     if ((ms_ptr->f6 & RF6_RAISE_DEAD) && !raise_possible(target_ptr, ms_ptr->m_ptr))
302         ms_ptr->f6 &= ~(RF6_RAISE_DEAD);
303
304     if (((ms_ptr->f6 & RF6_SPECIAL) != 0) && (ms_ptr->m_ptr->r_idx == MON_ROLENTO) && !summon_possible(target_ptr, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx))
305         ms_ptr->f6 &= ~(RF6_SPECIAL);
306 }
307
308 static void check_smart(player_type *target_ptr, melee_spell_type *ms_ptr)
309 {
310     if ((ms_ptr->r_ptr->flags2 & RF2_SMART) == 0)
311         return;
312
313     if ((ms_ptr->m_ptr->hp < ms_ptr->m_ptr->maxhp / 10) && (randint0(100) < 50)) {
314         ms_ptr->f4 &= (RF4_INT_MASK);
315         ms_ptr->f5 &= (RF5_INT_MASK);
316         ms_ptr->f6 &= (RF6_INT_MASK);
317     }
318
319     if ((ms_ptr->f6 & RF6_TELE_LEVEL) && is_teleport_level_ineffective(target_ptr, (ms_ptr->target_idx == target_ptr->riding) ? 0 : ms_ptr->target_idx))
320         ms_ptr->f6 &= ~(RF6_TELE_LEVEL);
321 }
322
323 static bool set_melee_spell_set(player_type *target_ptr, melee_spell_type *ms_ptr)
324 {
325     if (!ms_ptr->f4 && !ms_ptr->f5 && !ms_ptr->f6)
326         return FALSE;
327
328     for (int k = 0; k < 32; k++)
329         if (ms_ptr->f4 & (1UL << k))
330             ms_ptr->spell[ms_ptr->num++] = k + RF4_SPELL_START;
331
332     for (int k = 0; k < 32; k++)
333         if (ms_ptr->f5 & (1UL << k))
334             ms_ptr->spell[ms_ptr->num++] = k + RF5_SPELL_START;
335
336     for (int k = 0; k < 32; k++)
337         if (ms_ptr->f6 & (1UL << k))
338             ms_ptr->spell[ms_ptr->num++] = k + RF6_SPELL_START;
339
340     return (ms_ptr->num != 0) && target_ptr->playing && !target_ptr->is_dead && !target_ptr->leaving;
341 }
342
343 bool check_melee_spell_set(player_type *target_ptr, melee_spell_type *ms_ptr)
344 {
345     if (monster_confused_remaining(ms_ptr->m_ptr))
346         return FALSE;
347
348     ms_ptr->f4 = ms_ptr->r_ptr->flags4;
349     ms_ptr->f5 = ms_ptr->r_ptr->a_ability_flags1;
350     ms_ptr->f6 = ms_ptr->r_ptr->a_ability_flags2;
351     decide_melee_spell_target(target_ptr, ms_ptr);
352     decide_indirection_melee_spell(target_ptr, ms_ptr);
353     if (!check_melee_spell_projection(target_ptr, ms_ptr))
354         return FALSE;
355
356     ms_ptr->y = ms_ptr->t_ptr->fy;
357     ms_ptr->x = ms_ptr->t_ptr->fx;
358     reset_target(ms_ptr->m_ptr);
359     ms_ptr->f6 &= ~(RF6_WORLD | RF6_TRAPS | RF6_FORGET);
360     if (((ms_ptr->f4 & RF4_BR_LITE) != 0) && !los(target_ptr, ms_ptr->m_ptr->fy, ms_ptr->m_ptr->fx, ms_ptr->t_ptr->fy, ms_ptr->t_ptr->fx))
361         ms_ptr->f4 &= ~(RF4_BR_LITE);
362
363     if (((ms_ptr->f6 & RF6_SPECIAL) != 0) && (ms_ptr->m_ptr->r_idx != MON_ROLENTO) && (ms_ptr->r_ptr->d_char != 'B'))
364         ms_ptr->f6 &= ~(RF6_SPECIAL);
365
366     check_darkness(target_ptr, ms_ptr);
367     check_stupid(ms_ptr);
368     check_arena(target_ptr, ms_ptr);
369     if (target_ptr->phase_out && !one_in_(3))
370         ms_ptr->f6 &= ~(RF6_HEAL);
371
372     check_riding(target_ptr, ms_ptr);
373     check_pet(target_ptr, ms_ptr);
374     check_non_stupid(target_ptr, ms_ptr);
375     check_smart(target_ptr, ms_ptr);
376     return set_melee_spell_set(target_ptr, ms_ptr);
377 }