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-status.h"
23 #include "player-base/player-class.h"
24 #include "player-base/player-race.h"
25 #include "player-info/race-info.h"
26 #include "player/attack-defense-types.h"
27 #include "player/player-status-flags.h"
28 #include "player/player-status.h"
29 #include "player/special-defense-types.h"
30 #include "realm/realm-song-numbers.h"
31 #include "spell-realm/spells-song.h"
32 #include "spell/range-calc.h"
33 #include "system/angband-system.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-entity.h"
38 #include "system/monster-race-info.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 = *player_ptr->current_floor_ptr;
56 projection_path grid_g(player_ptr, AngbandSystem::get_instance().get_max_range(), y1, x1, y2, x2, PROJECT_THRU);
57 if (grid_g.path_num()) {
62 auto is_friend = m_ptr->is_pet();
63 for (const auto &[y, x] : grid_g) {
64 const Pos2D pos(y, x);
65 const auto &grid = floor.get_grid(pos);
66 if (y == y2 && x == x2) {
68 } else if (is_friend && grid.has_monster() && !m_ptr->is_hostile_to_melee(floor.m_list[grid.m_idx])) {
72 if (is_friend && player_ptr->is_located_at(pos)) {
81 * @brief モンスターが敵対モンスターに直接ブレスを当てることが可能かを判定する /
82 * Determine if a breath will hit the target.
89 * @param is_friend TRUEならば、プレイヤーを巻き込む時にブレスの判定をFALSEにする。
90 * @return ブレスを直接当てられるならばTRUEを返す
92 bool breath_direct(PlayerType *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2, POSITION rad, AttributeType typ, bool is_friend)
96 case AttributeType::LITE:
97 case AttributeType::LITE_WEAK:
100 case AttributeType::DISINTEGRATE:
108 projection_path grid_g(player_ptr, AngbandSystem::get_instance().get_max_range(), y1, x1, y2, x2, flg);
112 for (const auto &[ny, nx] : grid_g) {
113 if (flg & PROJECT_DISI) {
114 if (cave_stop_disintegration(player_ptr->current_floor_ptr, ny, nx)) {
117 } else if (flg & PROJECT_LOS) {
118 if (!cave_los_bold(player_ptr->current_floor_ptr, ny, nx)) {
122 if (!cave_has_flag_bold(player_ptr->current_floor_ptr, ny, nx, TerrainCharacteristics::PROJECT)) {
135 if (flg & PROJECT_DISI) {
136 if (in_disintegration_range(player_ptr->current_floor_ptr, y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad)) {
139 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)) {
142 } else if (flg & PROJECT_LOS) {
143 if (los(player_ptr, y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad)) {
146 if (los(player_ptr, y1, x1, player_ptr->y, player_ptr->x) && (distance(y1, x1, player_ptr->y, player_ptr->x) <= rad)) {
150 if (projectable(player_ptr, y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad)) {
153 if (projectable(player_ptr, y1, x1, player_ptr->y, player_ptr->x) && (distance(y1, x1, player_ptr->y, player_ptr->x) <= rad)) {
159 POSITION gx[1024], gy[1024];
161 POSITION gm_rad = rad;
162 breath_shape(player_ptr, grid_g, path_n, &grids, gx, gy, gm, &gm_rad, rad, y1, x1, y, x, typ);
163 for (auto i = 0; i < grids; i++) {
164 const Pos2D pos(gy[i], gx[i]);
165 if ((pos.y == y2) && (pos.x == x2)) {
168 if (player_ptr->is_located_at(pos)) {
177 if (is_friend && hityou) {
185 * @brief モンスターが特殊能力の目標地点を決める処理 /
186 * Get the actual center point of ball spells (rad > 1) (originally from TOband)
187 * @param player_ptr プレイヤーへの参照ポインタ
190 * @param ty 目標Y座標を返す参照ポインタ
191 * @param tx 目標X座標を返す参照ポインタ
192 * @param flg 判定のフラグ配列
194 void get_project_point(PlayerType *player_ptr, POSITION sy, POSITION sx, POSITION *ty, POSITION *tx, BIT_FLAGS flg)
196 projection_path path_g(player_ptr, AngbandSystem::get_instance().get_max_range(), sy, sx, *ty, *tx, flg);
199 for (const auto &[y, x] : path_g) {
200 if (!cave_has_flag_bold(player_ptr->current_floor_ptr, y, x, TerrainCharacteristics::PROJECT)) {
210 * @brief モンスターが敵モンスターに魔力消去を使うかどうかを返す /
211 * Check should monster cast dispel spell at other monster.
212 * @param player_ptr プレイヤーへの参照ポインタ
213 * @param m_idx 術者のモンスターID
214 * @param t_idx 目標のモンスターID
215 * @return 魔力消去を使うべきならばTRUEを変えす。
217 bool dispel_check_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, MONSTER_IDX t_idx)
219 const auto &t_ref = player_ptr->current_floor_ptr->m_list[t_idx];
220 if (t_ref.is_invulnerable()) {
224 constexpr auto threshold = 25;
225 if ((t_ref.mspeed < (STANDARD_SPEED + threshold)) && t_ref.is_accelerated()) {
229 if ((t_idx == player_ptr->riding) && dispel_check(player_ptr, m_idx)) {
237 * @brief モンスターがプレイヤーに魔力消去を与えるべきかを判定するルーチン
238 * Check should monster cast dispel spell.
239 * @param m_idx モンスターの構造体配列ID
240 * @return 魔力消去をかけるべきならTRUEを返す。
242 bool dispel_check(PlayerType *player_ptr, MONSTER_IDX m_idx)
244 if (is_invuln(player_ptr)) {
248 if (player_ptr->wraith_form) {
252 if (player_ptr->shield) {
256 if (player_ptr->magicdef) {
260 if (player_ptr->multishadow) {
264 if (player_ptr->dustrobe) {
268 PlayerClass pc(player_ptr);
269 if (player_ptr->shero && !pc.equals(PlayerClassType::BERSERKER)) {
273 if (player_ptr->mimic_form == MimicKindType::DEMON_LORD) {
277 const auto &floor_ref = *player_ptr->current_floor_ptr;
278 auto *m_ptr = &floor_ref.m_list[m_idx];
279 auto *r_ptr = &m_ptr->get_monrace();
280 if (r_ptr->ability_flags.has(MonsterAbilityType::BR_ACID)) {
281 if (!has_immune_acid(player_ptr) && (player_ptr->oppose_acid || music_singing(player_ptr, MUSIC_RESIST))) {
285 if (player_ptr->special_defense & DEFENSE_ACID) {
290 if (r_ptr->ability_flags.has(MonsterAbilityType::BR_FIRE)) {
291 if (!(PlayerRace(player_ptr).equals(PlayerRaceType::BALROG) && player_ptr->lev > 44)) {
292 if (!has_immune_fire(player_ptr) && (player_ptr->oppose_fire || music_singing(player_ptr, MUSIC_RESIST))) {
296 if (player_ptr->special_defense & DEFENSE_FIRE) {
302 if (r_ptr->ability_flags.has(MonsterAbilityType::BR_ELEC)) {
303 if (!has_immune_elec(player_ptr) && (player_ptr->oppose_elec || music_singing(player_ptr, MUSIC_RESIST))) {
307 if (player_ptr->special_defense & DEFENSE_ELEC) {
312 if (r_ptr->ability_flags.has(MonsterAbilityType::BR_COLD)) {
313 if (!has_immune_cold(player_ptr) && (player_ptr->oppose_cold || music_singing(player_ptr, MUSIC_RESIST))) {
317 if (player_ptr->special_defense & DEFENSE_COLD) {
322 if (r_ptr->ability_flags.has_any_of({ MonsterAbilityType::BR_POIS, MonsterAbilityType::BR_NUKE }) && !(pc.equals(PlayerClassType::NINJA) && (player_ptr->lev > 44))) {
323 if (player_ptr->oppose_pois || music_singing(player_ptr, MUSIC_RESIST)) {
327 if (player_ptr->special_defense & DEFENSE_POIS) {
332 if (player_ptr->ult_res) {
336 if (player_ptr->tsuyoshi) {
340 if ((player_ptr->special_attack & ATTACK_ACID) && r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_ACID_MASK)) {
344 if ((player_ptr->special_attack & ATTACK_FIRE) && r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_FIRE_MASK)) {
348 if ((player_ptr->special_attack & ATTACK_ELEC) && r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_ELEC_MASK)) {
352 if ((player_ptr->special_attack & ATTACK_COLD) && r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_COLD_MASK)) {
356 if ((player_ptr->special_attack & ATTACK_POIS) && r_ptr->resistance_flags.has_none_of(RFR_EFF_IM_POISON_MASK)) {
360 if ((player_ptr->pspeed < 145) && is_fast(player_ptr)) {
364 constexpr auto threshold = 25;
365 const auto threshold_speed = STANDARD_SPEED + threshold;
366 if (player_ptr->lightspeed && (m_ptr->mspeed <= threshold_speed)) {
370 const auto &m_ref = floor_ref.m_list[player_ptr->riding];
371 if (player_ptr->riding == 0) {
375 return (floor_ref.m_list[player_ptr->riding].mspeed < threshold_speed) && m_ref.is_accelerated();