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"
28 static void decide_melee_spell_target(player_type *target_ptr, melee_spell_type *ms_ptr)
30 if ((target_ptr->pet_t_m_idx == 0) || !ms_ptr->pet)
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;
39 static void decide_indirection_melee_spell(player_type *target_ptr, melee_spell_type *ms_ptr)
41 if ((ms_ptr->target_idx != 0) || (ms_ptr->m_ptr->target_y == 0))
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)
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;
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))
58 ms_ptr->f4 &= RF4_INDIRECT_MASK;
59 ms_ptr->f5 &= RF5_INDIRECT_MASK;
60 ms_ptr->f6 &= RF6_INDIRECT_MASK;
63 static bool check_melee_spell_projection(player_type *target_ptr, melee_spell_type *ms_ptr)
65 if (ms_ptr->target_idx != 0)
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;
76 start = floor_ptr->m_max + 1;
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);
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))
95 static void check_darkness(player_type *target_ptr, melee_spell_type *ms_ptr)
97 if ((ms_ptr->f6 & RF6_DARKNESS) == 0)
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)
105 if (d_info[target_ptr->dungeon_idx].flags1 & DF1_DARKNESS) {
106 ms_ptr->f6 &= ~(RF6_DARKNESS);
110 if (vs_ninja && !can_use_lite_area)
111 ms_ptr->f6 &= ~(RF6_DARKNESS);
114 static void check_stupid(melee_spell_type *ms_ptr)
116 if (!ms_ptr->in_no_magic_dungeon || ((ms_ptr->r_ptr->flags2 & RF2_STUPID) != 0))
119 ms_ptr->f4 &= (RF4_NOMAGIC_MASK);
120 ms_ptr->f5 &= (RF5_NOMAGIC_MASK);
121 ms_ptr->f6 &= (RF6_NOMAGIC_MASK);
124 static void check_arena(player_type *target_ptr, melee_spell_type *ms_ptr)
126 if (!target_ptr->current_floor_ptr->inside_arena && !target_ptr->phase_out)
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);
136 static void check_melee_spell_distance(player_type *target_ptr, melee_spell_type *ms_ptr)
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))
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);
151 int dist = distance(real_y, real_x, target_ptr->y, target_ptr->x);
153 ms_ptr->f4 &= ~(RF4_BALL_MASK & ~(RF4_ROCKET));
154 ms_ptr->f5 &= ~(RF5_BALL_MASK);
155 ms_ptr->f6 &= ~(RF6_BALL_MASK);
162 ms_ptr->f4 &= ~(RF4_BIG_BALL_MASK);
163 ms_ptr->f5 &= ~(RF5_BIG_BALL_MASK);
164 ms_ptr->f6 &= ~(RF6_BIG_BALL_MASK);
167 static void check_melee_spell_rocket(player_type *target_ptr, melee_spell_type *ms_ptr)
169 if ((ms_ptr->f4 & RF4_ROCKET) == 0)
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);
179 static void check_melee_spell_beam(player_type *target_ptr, melee_spell_type *ms_ptr)
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))
185 ms_ptr->f4 &= ~(RF4_BEAM_MASK);
186 ms_ptr->f5 &= ~(RF5_BEAM_MASK);
187 ms_ptr->f6 &= ~(RF6_BEAM_MASK);
190 static void check_melee_spell_breath(player_type *target_ptr, melee_spell_type *ms_ptr)
192 if (((ms_ptr->f4 & RF4_BREATH_MASK) == 0) && ((ms_ptr->f5 & RF5_BREATH_MASK) == 0) && ((ms_ptr->f6 & RF6_BREATH_MASK) == 0))
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);
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);
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);
215 static void check_melee_spell_special(player_type *target_ptr, melee_spell_type *ms_ptr)
217 if ((ms_ptr->f6 & RF6_SPECIAL) == 0)
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);
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);
234 ms_ptr->f6 &= ~(RF6_SPECIAL);
237 static void check_riding(player_type *target_ptr, melee_spell_type *ms_ptr)
239 if (ms_ptr->m_idx != target_ptr->riding)
242 ms_ptr->f4 &= ~(RF4_RIDING_MASK);
243 ms_ptr->f5 &= ~(RF5_RIDING_MASK);
244 ms_ptr->f6 &= ~(RF6_RIDING_MASK);
247 static void check_pet(player_type *target_ptr, melee_spell_type *ms_ptr)
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);
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);
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);
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);
276 check_melee_spell_special(target_ptr, ms_ptr);
279 static void check_non_stupid(player_type *target_ptr, melee_spell_type *ms_ptr)
281 if ((ms_ptr->r_ptr->flags2 & RF2_STUPID) != 0)
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);
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);
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);
301 if ((ms_ptr->f6 & RF6_RAISE_DEAD) && !raise_possible(target_ptr, ms_ptr->m_ptr))
302 ms_ptr->f6 &= ~(RF6_RAISE_DEAD);
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);
308 static void check_smart(player_type *target_ptr, melee_spell_type *ms_ptr)
310 if ((ms_ptr->r_ptr->flags2 & RF2_SMART) == 0)
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);
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);
323 static bool set_melee_spell_set(player_type *target_ptr, melee_spell_type *ms_ptr)
325 if (!ms_ptr->f4 && !ms_ptr->f5 && !ms_ptr->f6)
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;
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;
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;
340 return (ms_ptr->num != 0) && target_ptr->playing && !target_ptr->is_dead && !target_ptr->leaving;
343 bool check_melee_spell_set(player_type *target_ptr, melee_spell_type *ms_ptr)
345 if (monster_confused_remaining(ms_ptr->m_ptr))
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))
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);
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);
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);
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);