2 * @brief モンスター魔法の実装(対モンスター処理) / Monster spells (attack monster)
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.
12 #include "mspell/mspell-judgement.h"
13 #include "effect/attribute-types.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-base/player-class.h"
25 #include "player-base/player-race.h"
26 #include "player-info/race-info.h"
27 #include "player/attack-defense-types.h"
28 #include "player/player-status-flags.h"
29 #include "player/player-status.h"
30 #include "player/special-defense-types.h"
31 #include "realm/realm-song-numbers.h"
32 #include "spell-realm/spells-song.h"
33 #include "spell/range-calc.h"
34 #include "system/dungeon-info.h"
35 #include "system/floor-type-definition.h"
36 #include "system/grid-type-definition.h"
37 #include "system/monster-race-info.h"
38 #include "system/monster-type-definition.h"
39 #include "system/player-type-definition.h"
40 #include "target/projection-path-calculator.h"
43 * @brief モンスターが敵対モンスターにビームを当てること可能かを判定する /
44 * Determine if a beam spell will hit the target.
45 * @param player_ptr プレイヤーへの参照ポインタ
50 * @param m_ptr 使用するモンスターの構造体参照ポインタ
51 * @return ビームが到達可能ならばTRUEを返す
53 bool direct_beam(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, MonsterEntity *m_ptr)
55 auto *floor_ptr = player_ptr->current_floor_ptr;
56 projection_path grid_g(player_ptr, get_max_range(player_ptr), y1, x1, y2, x2, PROJECT_THRU);
57 if (grid_g.path_num()) {
62 bool is_friend = m_ptr->is_pet();
63 for (const auto &[y, x] : grid_g) {
64 const auto &g_ref = floor_ptr->grid_array[y][x];
65 if (y == y2 && x == x2) {
67 } else if (is_friend && g_ref.m_idx > 0 && !are_enemies(player_ptr, *m_ptr, floor_ptr->m_list[g_ref.m_idx])) {
71 if (is_friend && player_bold(player_ptr, y, x)) {
83 * @brief モンスターが敵対モンスターに直接ブレスを当てることが可能かを判定する /
84 * Determine if a breath will hit the target.
91 * @param is_friend TRUEならば、プレイヤーを巻き込む時にブレスの判定をFALSEにする。
92 * @return ブレスを直接当てられるならばTRUEを返す
94 bool breath_direct(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, POSITION rad, AttributeType typ, bool is_friend)
98 case AttributeType::LITE:
99 case AttributeType::LITE_WEAK:
102 case AttributeType::DISINTEGRATE:
110 projection_path grid_g(player_ptr, get_max_range(player_ptr), y1, x1, y2, x2, flg);
114 for (const auto &[ny, nx] : grid_g) {
115 if (flg & PROJECT_DISI) {
116 if (cave_stop_disintegration(player_ptr->current_floor_ptr, ny, nx)) {
119 } else if (flg & PROJECT_LOS) {
120 if (!cave_los_bold(player_ptr->current_floor_ptr, ny, nx)) {
124 if (!cave_has_flag_bold(player_ptr->current_floor_ptr, ny, nx, TerrainCharacteristics::PROJECT)) {
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)) {
141 if (in_disintegration_range(player_ptr->current_floor_ptr, y1, x1, player_ptr->y, player_ptr->x) && (distance(y1, x1, player_ptr->y, player_ptr->x) <= rad)) {
144 } else if (flg & PROJECT_LOS) {
145 if (los(player_ptr, y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad)) {
148 if (los(player_ptr, y1, x1, player_ptr->y, player_ptr->x) && (distance(y1, x1, player_ptr->y, player_ptr->x) <= rad)) {
152 if (projectable(player_ptr, y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad)) {
155 if (projectable(player_ptr, y1, x1, player_ptr->y, player_ptr->x) && (distance(y1, x1, player_ptr->y, player_ptr->x) <= rad)) {
161 POSITION gx[1024], gy[1024];
163 POSITION gm_rad = rad;
164 breath_shape(player_ptr, grid_g, grid_g.path_num(), &grids, gx, gy, gm, &gm_rad, rad, y1, x1, y, x, typ);
165 for (i = 0; i < grids; i++) {
168 if ((y == y2) && (x == x2)) {
171 if (player_bold(player_ptr, y, x)) {
180 if (is_friend && hityou) {
188 * @brief モンスターが特殊能力の目標地点を決める処理 /
189 * Get the actual center point of ball spells (rad > 1) (originally from TOband)
190 * @param player_ptr プレイヤーへの参照ポインタ
193 * @param ty 目標Y座標を返す参照ポインタ
194 * @param tx 目標X座標を返す参照ポインタ
195 * @param flg 判定のフラグ配列
197 void get_project_point(PlayerType *player_ptr, POSITION sy, POSITION sx, POSITION *ty, POSITION *tx, BIT_FLAGS flg)
199 projection_path path_g(player_ptr, get_max_range(player_ptr), sy, sx, *ty, *tx, flg);
202 for (const auto &[y, x] : path_g) {
203 if (!cave_has_flag_bold(player_ptr->current_floor_ptr, y, x, TerrainCharacteristics::PROJECT)) {
213 * @brief モンスターが敵モンスターに魔力消去を使うかどうかを返す /
214 * Check should monster cast dispel spell at other monster.
215 * @param player_ptr プレイヤーへの参照ポインタ
216 * @param m_idx 術者のモンスターID
217 * @param t_idx 目標のモンスターID
218 * @return 魔力消去を使うべきならばTRUEを変えす。
220 bool dispel_check_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx)
222 const auto &t_ref = player_ptr->current_floor_ptr->m_list[t_idx];
223 if (t_ref.is_invulnerable()) {
227 constexpr auto threshold = 25;
228 if ((t_ref.mspeed < (STANDARD_SPEED + threshold)) && t_ref.is_accelerated()) {
232 if ((t_idx == player_ptr->riding) && dispel_check(player_ptr, m_idx)) {
240 * @brief モンスターがプレイヤーに魔力消去を与えるべきかを判定するルーチン
241 * Check should monster cast dispel spell.
242 * @param m_idx モンスターの構造体配列ID
243 * @return 魔力消去をかけるべきならTRUEを返す。
245 bool dispel_check(PlayerType *player_ptr, MONSTER_IDX m_idx)
247 if (is_invuln(player_ptr)) {
251 if (player_ptr->wraith_form) {
255 if (player_ptr->shield) {
259 if (player_ptr->magicdef) {
263 if (player_ptr->multishadow) {
267 if (player_ptr->dustrobe) {
271 PlayerClass pc(player_ptr);
272 if (player_ptr->shero && !pc.equals(PlayerClassType::BERSERKER)) {
276 if (player_ptr->mimic_form == MimicKindType::DEMON_LORD) {
280 const auto &floor_ref = *player_ptr->current_floor_ptr;
281 auto *m_ptr = &floor_ref.m_list[m_idx];
282 auto *r_ptr = &monraces_info[m_ptr->r_idx];
283 if (r_ptr->ability_flags.has(MonsterAbilityType::BR_ACID)) {
284 if (!has_immune_acid(player_ptr) && (player_ptr->oppose_acid || music_singing(player_ptr, MUSIC_RESIST))) {
288 if (player_ptr->special_defense & DEFENSE_ACID) {
293 if (r_ptr->ability_flags.has(MonsterAbilityType::BR_FIRE)) {
294 if (!(PlayerRace(player_ptr).equals(PlayerRaceType::BALROG) && player_ptr->lev > 44)) {
295 if (!has_immune_fire(player_ptr) && (player_ptr->oppose_fire || music_singing(player_ptr, MUSIC_RESIST))) {
299 if (player_ptr->special_defense & DEFENSE_FIRE) {
305 if (r_ptr->ability_flags.has(MonsterAbilityType::BR_ELEC)) {
306 if (!has_immune_elec(player_ptr) && (player_ptr->oppose_elec || music_singing(player_ptr, MUSIC_RESIST))) {
310 if (player_ptr->special_defense & DEFENSE_ELEC) {
315 if (r_ptr->ability_flags.has(MonsterAbilityType::BR_COLD)) {
316 if (!has_immune_cold(player_ptr) && (player_ptr->oppose_cold || music_singing(player_ptr, MUSIC_RESIST))) {
320 if (player_ptr->special_defense & DEFENSE_COLD) {
325 if (r_ptr->ability_flags.has_any_of({ MonsterAbilityType::BR_POIS, MonsterAbilityType::BR_NUKE }) && !(pc.equals(PlayerClassType::NINJA) && (player_ptr->lev > 44))) {
326 if (player_ptr->oppose_pois || music_singing(player_ptr, MUSIC_RESIST)) {
330 if (player_ptr->special_defense & DEFENSE_POIS) {
335 if (player_ptr->ult_res) {
339 if (player_ptr->tsuyoshi) {
343 if ((player_ptr->special_attack & ATTACK_ACID) && r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_ACID_MASK)) {
347 if ((player_ptr->special_attack & ATTACK_FIRE) && r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_FIRE_MASK)) {
351 if ((player_ptr->special_attack & ATTACK_ELEC) && r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_ELEC_MASK)) {
355 if ((player_ptr->special_attack & ATTACK_COLD) && r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_COLD_MASK)) {
359 if ((player_ptr->special_attack & ATTACK_POIS) && r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_POISON_MASK)) {
363 if ((player_ptr->pspeed < 145) && is_fast(player_ptr)) {
367 constexpr auto threshold = 25;
368 const auto threshold_speed = STANDARD_SPEED + threshold;
369 if (player_ptr->lightspeed && (m_ptr->mspeed <= threshold_speed)) {
373 const auto &m_ref = floor_ref.m_list[player_ptr->riding];
374 if (player_ptr->riding == 0) {
378 return (floor_ref.m_list[player_ptr->riding].mspeed < threshold_speed) && m_ref.is_accelerated();