OSDN Git Service

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