OSDN Git Service

1d87985fcb6e45f6062f8addbc5d82225b0602ba
[hengbandforosx/hengbandosx.git] / src / mspell / mspell-judgement.cpp
1 /*!
2  * @brief モンスター魔法の実装(対モンスター処理) / Monster spells (attack monster)
3  * @date 2014/01/17
4  * @author
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.  Other copyrights may also apply.
9  * 2014 Deskull rearranged comment for Doxygen.
10  */
11
12 #include "mspell/mspell-judgement.h"
13 #include "dungeon/dungeon.h"
14 #include "effect/effect-characteristics.h"
15 #include "floor/cave.h"
16 #include "floor/geometry.h"
17 #include "floor/line-of-sight.h"
18 #include "grid/feature-flag-types.h"
19 #include "main/sound-definitions-table.h"
20 #include "monster-race/monster-race.h"
21 #include "monster-race/race-flags-resistance.h"
22 #include "monster/monster-info.h"
23 #include "monster/monster-status.h"
24 #include "player-info/race-info.h"
25 #include "player/attack-defense-types.h"
26 #include "player/player-status-flags.h"
27 #include "player/player-status.h"
28 #include "player/special-defense-types.h"
29 #include "realm/realm-song-numbers.h"
30 #include "spell-realm/spells-song.h"
31 #include "spell/range-calc.h"
32 #include "spell/spell-types.h"
33 #include "system/floor-type-definition.h"
34 #include "system/grid-type-definition.h"
35 #include "system/monster-race-definition.h"
36 #include "system/monster-type-definition.h"
37 #include "system/player-type-definition.h"
38 #include "target/projection-path-calculator.h"
39
40 /*!
41  * @brief モンスターが敵対モンスターにビームを当てること可能かを判定する /
42  * Determine if a beam spell will hit the target.
43  * @param player_ptr プレイヤーへの参照ポインタ
44  * @param y1 始点のY座標
45  * @param x1 始点のX座標
46  * @param y2 目標のY座標
47  * @param x2 目標のX座標
48  * @param m_ptr 使用するモンスターの構造体参照ポインタ
49  * @return ビームが到達可能ならばTRUEを返す
50  */
51 bool direct_beam(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, monster_type *m_ptr)
52 {
53     floor_type *floor_ptr = player_ptr->current_floor_ptr;
54     uint16_t grid_g[512];
55     int grid_n = projection_path(player_ptr, grid_g, get_max_range(player_ptr), y1, x1, y2, x2, PROJECT_THRU);
56     if (!grid_n)
57         return false;
58
59     bool hit2 = false;
60     POSITION y, x;
61     bool is_friend = is_pet(m_ptr);
62     for (int i = 0; i < grid_n; i++) {
63         y = get_grid_y(grid_g[i]);
64         x = get_grid_x(grid_g[i]);
65
66         if (y == y2 && x == x2)
67             hit2 = true;
68         else if (is_friend && floor_ptr->grid_array[y][x].m_idx > 0 && !are_enemies(player_ptr, m_ptr, &floor_ptr->m_list[floor_ptr->grid_array[y][x].m_idx])) {
69             return false;
70         }
71
72         if (is_friend && player_bold(player_ptr, y, x))
73             return false;
74     }
75
76     if (!hit2)
77         return false;
78     return true;
79 }
80
81 /*!
82  * @brief モンスターが敵対モンスターに直接ブレスを当てることが可能かを判定する /
83  * Determine if a breath will hit the target.
84  * @param y1 始点のY座標
85  * @param x1 始点のX座標
86  * @param y2 目標のY座標
87  * @param x2 目標のX座標
88  * @param rad 半径
89  * @param typ 効果属性ID
90  * @param is_friend TRUEならば、プレイヤーを巻き込む時にブレスの判定をFALSEにする。
91  * @return ブレスを直接当てられるならばTRUEを返す
92  */
93 bool breath_direct(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, POSITION rad, EFFECT_ID typ, bool is_friend)
94 {
95     BIT_FLAGS flg;
96     switch (typ) {
97     case GF_LITE:
98     case GF_LITE_WEAK:
99         flg = PROJECT_LOS;
100         break;
101     case GF_DISINTEGRATE:
102         flg = PROJECT_DISI;
103         break;
104     default:
105         flg = 0;
106         break;
107     }
108
109     uint16_t grid_g[512];
110     int grid_n = projection_path(player_ptr, grid_g, get_max_range(player_ptr), y1, x1, y2, x2, flg);
111     int i;
112     POSITION y = y1;
113     POSITION x = x1;
114     for (i = 0; i < grid_n; ++i) {
115         int ny = get_grid_y(grid_g[i]);
116         int nx = get_grid_x(grid_g[i]);
117
118         if (flg & PROJECT_DISI) {
119             if (cave_stop_disintegration(player_ptr->current_floor_ptr, ny, nx))
120                 break;
121         } else if (flg & PROJECT_LOS) {
122             if (!cave_los_bold(player_ptr->current_floor_ptr, ny, nx))
123                 break;
124         } else {
125             if (!cave_has_flag_bold(player_ptr->current_floor_ptr, ny, nx, FF::PROJECT))
126                 break;
127         }
128
129         y = ny;
130         x = nx;
131     }
132
133     grid_n = i;
134     bool hit2 = false;
135     bool hityou = false;
136     if (!grid_n) {
137         if (flg & PROJECT_DISI) {
138             if (in_disintegration_range(player_ptr->current_floor_ptr, y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad))
139                 hit2 = true;
140             if (in_disintegration_range(player_ptr->current_floor_ptr, y1, x1, player_ptr->y, player_ptr->x)
141                 && (distance(y1, x1, player_ptr->y, player_ptr->x) <= rad))
142                 hityou = true;
143         } else if (flg & PROJECT_LOS) {
144             if (los(player_ptr, y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad))
145                 hit2 = true;
146             if (los(player_ptr, y1, x1, player_ptr->y, player_ptr->x) && (distance(y1, x1, player_ptr->y, player_ptr->x) <= rad))
147                 hityou = true;
148         } else {
149             if (projectable(player_ptr, y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad))
150                 hit2 = true;
151             if (projectable(player_ptr, y1, x1, player_ptr->y, player_ptr->x) && (distance(y1, x1, player_ptr->y, player_ptr->x) <= rad))
152                 hityou = true;
153         }
154     } else {
155         int grids = 0;
156         POSITION gx[1024], gy[1024];
157         POSITION gm[32];
158         POSITION gm_rad = rad;
159         breath_shape(player_ptr, grid_g, grid_n, &grids, gx, gy, gm, &gm_rad, rad, y1, x1, y, x, typ);
160         for (i = 0; i < grids; i++) {
161             y = gy[i];
162             x = gx[i];
163             if ((y == y2) && (x == x2))
164                 hit2 = true;
165             if (player_bold(player_ptr, y, x))
166                 hityou = true;
167         }
168     }
169
170     if (!hit2)
171         return false;
172     if (is_friend && hityou)
173         return false;
174
175     return true;
176 }
177
178 /*!
179  * @brief モンスターが特殊能力の目標地点を決める処理 /
180  * Get the actual center point of ball spells (rad > 1) (originally from TOband)
181  * @param player_ptr プレイヤーへの参照ポインタ
182  * @param sy 始点のY座標
183  * @param sx 始点のX座標
184  * @param ty 目標Y座標を返す参照ポインタ
185  * @param tx 目標X座標を返す参照ポインタ
186  * @param flg 判定のフラグ配列
187  */
188 void get_project_point(player_type *player_ptr, POSITION sy, POSITION sx, POSITION *ty, POSITION *tx, BIT_FLAGS flg)
189 {
190     uint16_t path_g[128];
191     int path_n = projection_path(player_ptr, path_g, get_max_range(player_ptr), sy, sx, *ty, *tx, flg);
192     *ty = sy;
193     *tx = sx;
194     for (int i = 0; i < path_n; i++) {
195         sy = get_grid_y(path_g[i]);
196         sx = get_grid_x(path_g[i]);
197         if (!cave_has_flag_bold(player_ptr->current_floor_ptr, sy, sx, FF::PROJECT))
198             break;
199
200         *ty = sy;
201         *tx = sx;
202     }
203 }
204
205 /*!
206  * @brief モンスターが敵モンスターに魔力消去を使うかどうかを返す /
207  * Check should monster cast dispel spell at other monster.
208  * @param player_ptr プレイヤーへの参照ポインタ
209  * @param m_idx 術者のモンスターID
210  * @param t_idx 目標のモンスターID
211  * @return 魔力消去を使うべきならばTRUEを変えす。
212  */
213 bool dispel_check_monster(player_type *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx)
214 {
215     monster_type *t_ptr = &player_ptr->current_floor_ptr->m_list[t_idx];
216     if (monster_invulner_remaining(t_ptr))
217         return true;
218
219     if ((t_ptr->mspeed < 135) && monster_fast_remaining(t_ptr))
220         return true;
221
222     if ((t_idx == player_ptr->riding) && dispel_check(player_ptr, m_idx))
223         return true;
224
225     return false;
226 }
227
228 /*!
229  * @brief モンスターがプレイヤーに魔力消去を与えるべきかを判定するルーチン
230  * Check should monster cast dispel spell.
231  * @param m_idx モンスターの構造体配列ID
232  * @return 魔力消去をかけるべきならTRUEを返す。
233  */
234 bool dispel_check(player_type *player_ptr, MONSTER_IDX m_idx)
235 {
236     if (is_invuln(player_ptr))
237         return true;
238
239     if (player_ptr->wraith_form)
240         return true;
241
242     if (player_ptr->shield)
243         return true;
244
245     if (player_ptr->magicdef)
246         return true;
247
248     if (player_ptr->multishadow)
249         return true;
250
251     if (player_ptr->dustrobe)
252         return true;
253
254     if (player_ptr->shero && (player_ptr->pclass != PlayerClassType::BERSERKER))
255         return true;
256
257     if (player_ptr->mimic_form == MIMIC_DEMON_LORD)
258         return true;
259
260     monster_type *m_ptr = &player_ptr->current_floor_ptr->m_list[m_idx];
261     monster_race *r_ptr = &r_info[m_ptr->r_idx];
262     if (r_ptr->ability_flags.has(RF_ABILITY::BR_ACID)) {
263         if (!has_immune_acid(player_ptr) && (player_ptr->oppose_acid || music_singing(player_ptr, MUSIC_RESIST)))
264             return true;
265
266         if (player_ptr->special_defense & DEFENSE_ACID)
267             return true;
268     }
269
270     if (r_ptr->ability_flags.has(RF_ABILITY::BR_FIRE)) {
271         if (!((player_ptr->prace == PlayerRaceType::BALROG) && player_ptr->lev > 44)) {
272             if (!has_immune_fire(player_ptr) && (player_ptr->oppose_fire || music_singing(player_ptr, MUSIC_RESIST)))
273                 return true;
274
275             if (player_ptr->special_defense & DEFENSE_FIRE)
276                 return true;
277         }
278     }
279
280     if (r_ptr->ability_flags.has(RF_ABILITY::BR_ELEC)) {
281         if (!has_immune_elec(player_ptr) && (player_ptr->oppose_elec || music_singing(player_ptr, MUSIC_RESIST)))
282             return true;
283
284         if (player_ptr->special_defense & DEFENSE_ELEC)
285             return true;
286     }
287
288     if (r_ptr->ability_flags.has(RF_ABILITY::BR_COLD)) {
289         if (!has_immune_cold(player_ptr) && (player_ptr->oppose_cold || music_singing(player_ptr, MUSIC_RESIST)))
290             return true;
291
292         if (player_ptr->special_defense & DEFENSE_COLD)
293             return true;
294     }
295
296     if (r_ptr->ability_flags.has_any_of({ RF_ABILITY::BR_POIS, RF_ABILITY::BR_NUKE }) && !((player_ptr->pclass == PlayerClassType::NINJA) && (player_ptr->lev > 44))) {
297         if (player_ptr->oppose_pois || music_singing(player_ptr, MUSIC_RESIST))
298             return true;
299
300         if (player_ptr->special_defense & DEFENSE_POIS)
301             return true;
302     }
303
304     if (player_ptr->ult_res)
305         return true;
306
307     if (player_ptr->tsuyoshi)
308         return true;
309
310     if ((player_ptr->special_attack & ATTACK_ACID) && !(r_ptr->flagsr & RFR_EFF_IM_ACID_MASK))
311         return true;
312
313     if ((player_ptr->special_attack & ATTACK_FIRE) && !(r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK))
314         return true;
315
316     if ((player_ptr->special_attack & ATTACK_ELEC) && !(r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK))
317         return true;
318
319     if ((player_ptr->special_attack & ATTACK_COLD) && !(r_ptr->flagsr & RFR_EFF_IM_COLD_MASK))
320         return true;
321
322     if ((player_ptr->special_attack & ATTACK_POIS) && !(r_ptr->flagsr & RFR_EFF_IM_POIS_MASK))
323         return true;
324
325     if ((player_ptr->pspeed < 145) && is_fast(player_ptr))
326         return true;
327
328     if (player_ptr->lightspeed && (m_ptr->mspeed < 136))
329         return true;
330
331     if (player_ptr->riding && (player_ptr->current_floor_ptr->m_list[player_ptr->riding].mspeed < 135)
332         && monster_fast_remaining(&player_ptr->current_floor_ptr->m_list[player_ptr->riding]))
333         return true;
334
335     return false;
336 }