OSDN Git Service

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