OSDN Git Service

Merge branch 'master' of git.osdn.net:/gitroot/hengband/hengband
[hengband/hengband.git] / src / mspell / mspell-checker.c
1 /*!
2  * @brief モンスター魔法の実装 / Monster spells (attack player)
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-checker.h"
13 #include "blue-magic/blue-magic-checker.h"
14 #include "core/disturbance.h"
15 #include "core/player-redraw-types.h"
16 #include "dungeon/dungeon-flag-types.h"
17 #include "dungeon/dungeon.h"
18 #include "dungeon/quest.h"
19 #include "effect/effect-characteristics.h"
20 #include "effect/effect-processor.h"
21 #include "floor/cave.h"
22 #include "floor/line-of-sight.h"
23 #include "grid/grid.h"
24 #include "monster-floor/monster-move.h"
25 #include "monster-race/monster-race.h"
26 #include "monster-race/race-flags-ability1.h"
27 #include "monster-race/race-flags-ability2.h"
28 #include "monster-race/race-flags2.h"
29 #include "monster-race/race-flags3.h"
30 #include "monster-race/race-flags4.h"
31 #include "monster-race/race-flags7.h"
32 #include "monster-race/race-indice-types.h"
33 #include "monster/monster-describer.h"
34 #include "monster/monster-description-types.h"
35 #include "monster/monster-flag-types.h"
36 #include "monster/monster-info.h"
37 #include "monster/monster-status.h"
38 #include "mspell/assign-monster-spell.h"
39 #include "mspell/improper-mspell-remover.h"
40 #include "mspell/mspell-judgement.h"
41 #include "mspell/mspell-learn-checker.h"
42 #include "mspell/mspell-mask-definitions.h"
43 #include "mspell/mspell-selector.h"
44 #include "mspell/mspell-util.h"
45 #include "object-enchant/object-curse.h"
46 #include "player/attack-defense-types.h"
47 #include "player/player-class.h"
48 #include "player/player-race-types.h"
49 #include "spell-kind/spells-world.h"
50 #include "spell-realm/spells-hex.h"
51 #include "spell/range-calc.h"
52 #include "spell/spell-types.h"
53 #include "system/floor-type-definition.h"
54 #include "target/projection-path-calculator.h"
55 #include "util/bit-flags-calculator.h"
56 #include "view/display-messages.h"
57 #include "world/world.h"
58
59 /*!
60  * @brief モンスターにとって所定の地点が召還に相応しい地点かどうかを返す。 /
61  * Determine if there is a space near the player in which a summoned creature can appear
62  * @param target_ptr プレーヤーへの参照ポインタ
63  * @param y1 判定を行いたいマスのY座標
64  * @param x1 判定を行いたいマスのX座標
65  * @return 召還に相応しいならばTRUEを返す
66  */
67 bool summon_possible(player_type *target_ptr, POSITION y1, POSITION x1)
68 {
69     floor_type *floor_ptr = target_ptr->current_floor_ptr;
70     for (POSITION y = y1 - 2; y <= y1 + 2; y++) {
71         for (POSITION x = x1 - 2; x <= x1 + 2; x++) {
72             if (!in_bounds(floor_ptr, y, x))
73                 continue;
74
75             if (distance(y1, x1, y, x) > 2)
76                 continue;
77
78             if (pattern_tile(floor_ptr, y, x))
79                 continue;
80
81             if (is_cave_empty_bold(target_ptr, y, x) && projectable(target_ptr, y1, x1, y, x) && projectable(target_ptr, y, x, y1, x1))
82                 return TRUE;
83         }
84     }
85
86     return FALSE;
87 }
88
89 /*!
90  * @brief モンスターにとって死者復活を行うべき状態かどうかを返す /
91  * Determine if there is a space near the player in which a summoned creature can appear
92  * @param target_ptr プレーヤーへの参照ポインタ
93  * @param m_ptr 判定を行いたいモンスターの構造体参照ポインタ
94  * @return 死者復活が有効な状態ならばTRUEを返す。
95  */
96 bool raise_possible(player_type *target_ptr, monster_type *m_ptr)
97 {
98     POSITION y = m_ptr->fy;
99     POSITION x = m_ptr->fx;
100     floor_type *floor_ptr = target_ptr->current_floor_ptr;
101     for (POSITION xx = x - 5; xx <= x + 5; xx++) {
102         grid_type *g_ptr;
103         for (POSITION yy = y - 5; yy <= y + 5; yy++) {
104             if (distance(y, x, yy, xx) > 5)
105                 continue;
106             if (!los(target_ptr, y, x, yy, xx))
107                 continue;
108             if (!projectable(target_ptr, y, x, yy, xx))
109                 continue;
110
111             g_ptr = &floor_ptr->grid_array[yy][xx];
112             OBJECT_IDX this_o_idx, next_o_idx = 0;
113             for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
114                 object_type *o_ptr = &floor_ptr->o_list[this_o_idx];
115                 next_o_idx = o_ptr->next_o_idx;
116                 if (o_ptr->tval == TV_CORPSE) {
117                     if (!monster_has_hostile_align(target_ptr, m_ptr, 0, 0, &r_info[o_ptr->pval]))
118                         return TRUE;
119                 }
120             }
121         }
122     }
123
124     return FALSE;
125 }
126
127 /*!
128  * @brief モンスターにとってボルト型魔法が有効な状態かを返す /
129  * Determine if a bolt spell will hit the player.
130  * @param target_ptr プレーヤーへの参照ポインタ
131  * @param y1 ボルト魔法発射地点のY座標
132  * @param x1 ボルト魔法発射地点のX座標
133  * @param y2 ボルト魔法目標地点のY座標
134  * @param x2 ボルト魔法目標地点のX座標
135  * @param is_friend モンスターがプレイヤーに害意を持たない(ペットか友好的)ならばTRUEをつける
136  * @return ボルト型魔法が有効ならばTRUEを返す。
137  * @details
138  * Originally, it was possible for a friendly to shoot another friendly.\n
139  * Change it so a "clean shot" means no equally friendly monster is\n
140  * between the attacker and target.\n
141  *\n
142  * This is exactly like "projectable", but it will\n
143  * return FALSE if a monster is in the way.\n
144  * no equally friendly monster is\n
145  * between the attacker and target.\n
146  */
147 bool clean_shot(player_type *target_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, bool is_friend)
148 {
149     floor_type *floor_ptr = target_ptr->current_floor_ptr;
150     u16b grid_g[512];
151     int grid_n = projection_path(target_ptr, grid_g, get_max_range(target_ptr), y1, x1, y2, x2, 0);
152     if (!grid_n)
153         return FALSE;
154
155     POSITION y = get_grid_y(grid_g[grid_n - 1]);
156     POSITION x = get_grid_x(grid_g[grid_n - 1]);
157     if ((y != y2) || (x != x2))
158         return FALSE;
159
160     for (int i = 0; i < grid_n; i++) {
161         y = get_grid_y(grid_g[i]);
162         x = get_grid_x(grid_g[i]);
163
164         if ((floor_ptr->grid_array[y][x].m_idx > 0) && !((y == y2) && (x == x2))) {
165             monster_type *m_ptr = &floor_ptr->m_list[floor_ptr->grid_array[y][x].m_idx];
166             if (is_friend == is_pet(m_ptr)) {
167                 return FALSE;
168             }
169         }
170
171         if (player_bold(target_ptr, y, x) && is_friend)
172             return FALSE;
173     }
174
175     return TRUE;
176 }
177
178 /*!
179  * @brief モンスターのボルト型魔法処理 /
180  * Cast a bolt at the player Stop if we hit a monster Affect monsters and the player
181  * @param target_ptr プレーヤーへの参照ポインタ
182  * @param m_idx モンスターのID
183  * @param y 目標のY座標
184  * @param x 目標のX座標
185  * @param typ 効果属性ID
186  * @param dam_hp 威力
187  * @param monspell モンスター魔法のID
188  * @param target_type モンスターからモンスターへ撃つならMONSTER_TO_MONSTER、モンスターからプレイヤーならMONSTER_TO_PLAYER
189  * @return なし
190  */
191 void bolt(player_type *target_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, EFFECT_ID typ, int dam_hp, int monspell, int target_type)
192 {
193     BIT_FLAGS flg = 0;
194     switch (target_type) {
195     case MONSTER_TO_MONSTER:
196         flg = PROJECT_STOP | PROJECT_KILL;
197         break;
198     case MONSTER_TO_PLAYER:
199         flg = PROJECT_STOP | PROJECT_KILL | PROJECT_PLAYER;
200         break;
201     }
202
203     if (typ != GF_ARROW)
204         flg |= PROJECT_REFLECTABLE;
205
206     bool learnable = spell_learnable(target_ptr, m_idx);
207     (void)project(target_ptr, m_idx, 0, y, x, dam_hp, typ, flg, (learnable ? monspell : -1));
208 }
209
210 /*!
211  * @brief モンスターのビーム型魔法処理 /
212  * @param target_ptr プレーヤーへの参照ポインタ
213  * @param m_idx モンスターのID
214  * @param y 目標のY座標
215  * @param x 目標のX座標
216  * @param typ 効果属性ID
217  * @param dam_hp 威力
218  * @param monspell モンスター魔法のID
219  * @param target_type モンスターからモンスターへ撃つならMONSTER_TO_MONSTER、モンスターからプレイヤーならMONSTER_TO_PLAYER
220  * @return なし
221  */
222 void beam(player_type *target_ptr, MONSTER_IDX m_idx, POSITION y, POSITION x, EFFECT_ID typ, int dam_hp, int monspell, int target_type)
223 {
224     BIT_FLAGS flg = 0;
225     switch (target_type) {
226     case MONSTER_TO_MONSTER:
227         flg = PROJECT_BEAM | PROJECT_KILL | PROJECT_THRU;
228         break;
229     case MONSTER_TO_PLAYER:
230         flg = PROJECT_BEAM | PROJECT_KILL | PROJECT_THRU | PROJECT_PLAYER;
231         break;
232     }
233
234     bool learnable = spell_learnable(target_ptr, m_idx);
235     (void)project(target_ptr, m_idx, 0, y, x, dam_hp, typ, flg, (learnable ? monspell : -1));
236 }
237
238 /*!
239  * @brief モンスターのボール型&ブレス型魔法処理 /
240  * Cast a breath (or ball) attack at the player Pass over any monsters that may be in the way Affect grids, objects, monsters, and the player
241  * @param target_ptr プレーヤーへの参照ポインタ
242  * @param y 目標地点のY座標
243  * @param x 目標地点のX座標
244  * @param m_idx モンスターのID
245  * @param typ 効果属性ID
246  * @param dam_hp 威力
247  * @param rad 半径
248  * @param breath
249  * @param monspell モンスター魔法のID
250  * @param target_type モンスターからモンスターへ撃つならMONSTER_TO_MONSTER、モンスターからプレイヤーならMONSTER_TO_PLAYER
251  * @return なし
252  */
253 void breath(
254     player_type *target_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, EFFECT_ID typ, int dam_hp, POSITION rad, bool breath, int monspell, int target_type)
255 {
256     monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
257     monster_race *r_ptr = &r_info[m_ptr->r_idx];
258     BIT_FLAGS flg = 0x00;
259     switch (target_type) {
260     case MONSTER_TO_MONSTER:
261         flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
262         break;
263     case MONSTER_TO_PLAYER:
264         flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_PLAYER;
265         break;
266     }
267
268     if ((rad < 1) && breath)
269         rad = (r_ptr->flags2 & (RF2_POWERFUL)) ? 3 : 2;
270
271     if (breath)
272         rad = 0 - rad;
273
274     switch (typ) {
275     case GF_ROCKET:
276         flg |= PROJECT_STOP;
277         break;
278     case GF_DRAIN_MANA:
279     case GF_MIND_BLAST:
280     case GF_BRAIN_SMASH:
281     case GF_CAUSE_1:
282     case GF_CAUSE_2:
283     case GF_CAUSE_3:
284     case GF_CAUSE_4:
285     case GF_HAND_DOOM:
286         flg |= (PROJECT_HIDE | PROJECT_AIMED);
287         break;
288     }
289
290     bool learnable = spell_learnable(target_ptr, m_idx);
291     (void)project(target_ptr, m_idx, rad, y, x, dam_hp, typ, flg, (learnable ? monspell : -1));
292 }
293
294 /*!
295  * @brief ID値が非魔術的な特殊技能かどうかを返す /
296  * Return TRUE if a spell is inate spell.
297  * @param spell 判定対象のID
298  * @return 非魔術的な特殊技能ならばTRUEを返す。
299  */
300 bool spell_is_inate(SPELL_IDX spell)
301 {
302     if (spell < 32 * 4) /* Set RF4 */
303     {
304         if ((1L << (spell - 32 * 3)) & RF4_NOMAGIC_MASK)
305             return TRUE;
306     }
307
308     if (spell < 32 * 5) /* Set RF5 */
309     {
310         if ((1L << (spell - 32 * 4)) & RF5_NOMAGIC_MASK)
311             return TRUE;
312     }
313
314     if (spell < 32 * 6) /* Set RF6 */
315     {
316         if ((1L << (spell - 32 * 5)) & RF6_NOMAGIC_MASK)
317             return TRUE;
318     }
319
320     /* This spell is not "inate" */
321     return FALSE;
322 }