OSDN Git Service

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