1 #include "mspell/mspell-attack.h"
2 #include "blue-magic/blue-magic-checker.h"
3 #include "core/disturbance.h"
4 #include "core/player-redraw-types.h"
5 #include "dungeon/dungeon-flag-types.h"
6 #include "dungeon/dungeon.h"
7 #include "dungeon/quest.h"
8 #include "floor/cave.h"
9 #include "monster-floor/monster-move.h"
10 #include "monster-race/monster-race.h"
11 #include "monster-race/race-ability-mask.h"
12 #include "monster-race/race-flags2.h"
13 #include "monster-race/race-indice-types.h"
14 #include "monster/monster-describer.h"
15 #include "monster/monster-flag-types.h"
16 #include "monster/monster-info.h"
17 #include "monster/monster-status.h"
18 #include "mspell/assign-monster-spell.h"
19 #include "mspell/improper-mspell-remover.h"
20 #include "mspell/mspell-attack-util.h"
21 #include "mspell/mspell-checker.h"
22 #include "mspell/mspell-learn-checker.h"
23 #include "mspell/mspell-lite.h"
24 #include "mspell/mspell-result.h"
25 #include "mspell/mspell-selector.h"
26 #include "mspell/mspell-util.h"
27 #include "player-base/player-class.h"
28 #include "player-info/mane-data-type.h"
29 #include "player/attack-defense-types.h"
30 #include "spell-kind/spells-world.h"
31 #include "spell-realm/spells-hex.h"
32 #include "system/floor-type-definition.h"
33 #include "system/monster-race-definition.h"
34 #include "system/monster-type-definition.h"
35 #include "system/player-type-definition.h"
36 #include "target/projection-path-calculator.h"
37 #include "view/display-messages.h"
38 #include "world/world.h"
41 #include "monster/monster-description-types.h"
46 static void set_no_magic_mask(msa_type *msa_ptr)
48 if (!msa_ptr->no_inate)
51 msa_ptr->ability_flags.reset(RF_ABILITY_NOMAGIC_MASK);
54 static void check_mspell_stupid(PlayerType *player_ptr, msa_type *msa_ptr)
56 floor_type *floor_ptr = player_ptr->current_floor_ptr;
57 msa_ptr->in_no_magic_dungeon = d_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::NO_MAGIC) && floor_ptr->dun_level && (!floor_ptr->inside_quest || quest_type::is_fixed(floor_ptr->inside_quest));
58 if (!msa_ptr->in_no_magic_dungeon || ((msa_ptr->r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID))))
61 msa_ptr->ability_flags &= RF_ABILITY_NOMAGIC_MASK;
64 static void check_mspell_smart(PlayerType *player_ptr, msa_type *msa_ptr)
66 if (msa_ptr->r_ptr->behavior_flags.has_not(MonsterBehaviorType::SMART))
69 if ((msa_ptr->m_ptr->hp < msa_ptr->m_ptr->maxhp / 10) && (randint0(100) < 50)) {
70 msa_ptr->ability_flags &= RF_ABILITY_INT_MASK;
73 if (msa_ptr->ability_flags.has(MonsterAbilityType::TELE_LEVEL) && is_teleport_level_ineffective(player_ptr, 0)) {
74 msa_ptr->ability_flags.reset(MonsterAbilityType::TELE_LEVEL);
78 static void check_mspell_arena(PlayerType *player_ptr, msa_type *msa_ptr)
80 if (!player_ptr->current_floor_ptr->inside_arena && !player_ptr->phase_out)
83 msa_ptr->ability_flags.reset(RF_ABILITY_SUMMON_MASK).reset(MonsterAbilityType::TELE_LEVEL);
85 if (msa_ptr->m_ptr->r_idx == MON_ROLENTO)
86 msa_ptr->ability_flags.reset(MonsterAbilityType::SPECIAL);
89 static bool check_mspell_non_stupid(PlayerType *player_ptr, msa_type *msa_ptr)
91 if (msa_ptr->r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID))
95 msa_ptr->ability_flags.reset(MonsterAbilityType::DRAIN_MANA);
97 if (msa_ptr->ability_flags.has_any_of(RF_ABILITY_BOLT_MASK) && !clean_shot(player_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, player_ptr->y, player_ptr->x, false)) {
98 msa_ptr->ability_flags.reset(RF_ABILITY_BOLT_MASK);
101 if (msa_ptr->ability_flags.has_any_of(RF_ABILITY_SUMMON_MASK) && !(summon_possible(player_ptr, msa_ptr->y, msa_ptr->x))) {
102 msa_ptr->ability_flags.reset(RF_ABILITY_SUMMON_MASK);
105 if (msa_ptr->ability_flags.has(MonsterAbilityType::RAISE_DEAD) && !raise_possible(player_ptr, msa_ptr->m_ptr))
106 msa_ptr->ability_flags.reset(MonsterAbilityType::RAISE_DEAD);
108 if (msa_ptr->ability_flags.has(MonsterAbilityType::SPECIAL) && (msa_ptr->m_ptr->r_idx == MON_ROLENTO) && !summon_possible(player_ptr, msa_ptr->y, msa_ptr->x))
109 msa_ptr->ability_flags.reset(MonsterAbilityType::SPECIAL);
111 return msa_ptr->ability_flags.any();
114 static void set_mspell_list(msa_type *msa_ptr)
116 EnumClassFlagGroup<MonsterAbilityType>::get_flags(msa_ptr->ability_flags, std::back_inserter(msa_ptr->mspells));
119 static void describe_mspell_monster(PlayerType *player_ptr, msa_type *msa_ptr)
121 monster_desc(player_ptr, msa_ptr->m_name, msa_ptr->m_ptr, 0x00);
125 /* Get the monster possessive ("his"/"her"/"its") */
127 monster_desc(player_ptr, m_poss, msa_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE);
131 static bool switch_do_spell(PlayerType *player_ptr, msa_type *msa_ptr)
133 switch (msa_ptr->do_spell) {
134 case DO_SPELL_NONE: {
137 msa_ptr->thrown_spell = choose_attack_spell(player_ptr, msa_ptr);
138 if (msa_ptr->thrown_spell != MonsterAbilityType::MAX)
144 case DO_SPELL_BR_LITE:
145 msa_ptr->thrown_spell = MonsterAbilityType::BR_LITE;
147 case DO_SPELL_BR_DISI:
148 msa_ptr->thrown_spell = MonsterAbilityType::BR_DISI;
150 case DO_SPELL_BA_LITE:
151 msa_ptr->thrown_spell = MonsterAbilityType::BA_LITE;
158 static bool check_mspell_continuation(PlayerType *player_ptr, msa_type *msa_ptr)
160 if (msa_ptr->ability_flags.none())
163 remove_bad_spells(msa_ptr->m_idx, player_ptr, msa_ptr->ability_flags);
164 check_mspell_arena(player_ptr, msa_ptr);
165 if (msa_ptr->ability_flags.none() || !check_mspell_non_stupid(player_ptr, msa_ptr))
168 set_mspell_list(msa_ptr);
169 if (msa_ptr->mspells.empty() || !player_ptr->playing || player_ptr->is_dead || player_ptr->leaving)
172 describe_mspell_monster(player_ptr, msa_ptr);
173 if (!switch_do_spell(player_ptr, msa_ptr) || (msa_ptr->thrown_spell == MonsterAbilityType::MAX))
179 static bool check_mspell_unexploded(PlayerType *player_ptr, msa_type *msa_ptr)
181 PERCENTAGE fail_rate = 25 - (msa_ptr->rlev + 3) / 4;
182 if (msa_ptr->r_ptr->behavior_flags.has(MonsterBehaviorType::STUPID))
185 if (!spell_is_inate(msa_ptr->thrown_spell) && (msa_ptr->in_no_magic_dungeon || (monster_stunned_remaining(msa_ptr->m_ptr) && one_in_(2)) || (randint0(100) < fail_rate))) {
186 disturb(player_ptr, true, true);
187 msg_format(_("%^sは呪文を唱えようとしたが失敗した。", "%^s tries to cast a spell, but fails."), msa_ptr->m_name);
191 if (!spell_is_inate(msa_ptr->thrown_spell) && SpellHex(player_ptr).check_hex_barrier(msa_ptr->m_idx, HEX_ANTI_MAGIC)) {
192 msg_format(_("反魔法バリアが%^sの呪文をかき消した。", "Anti magic barrier cancels the spell which %^s casts."), msa_ptr->m_name);
200 * @brief モンスターが使おうとする特技がプレイヤーに届くかどうかを返す
202 * ターゲット (msa_ptr->y, msa_ptr->x) は設定済みとする。
204 static bool check_thrown_mspell(PlayerType *player_ptr, msa_type *msa_ptr)
206 // プレイヤーがモンスターを正しく視認できていれば思い出に残る。
207 // FIXME: ここで処理するのはおかしいような?
208 msa_ptr->can_remember = is_original_ap_and_seen(player_ptr, msa_ptr->m_ptr);
210 // ターゲットがプレイヤー位置なら直接射線が通っているので常に届く。
211 bool direct = player_bold(player_ptr, msa_ptr->y, msa_ptr->x);
215 // ターゲットがプレイヤー位置からずれているとき、直接の射線を必要とする特技
216 // (ボルト系など)は届かないものとみなす。
217 switch (msa_ptr->thrown_spell) {
218 case MonsterAbilityType::DISPEL:
219 case MonsterAbilityType::SHOOT:
220 case MonsterAbilityType::DRAIN_MANA:
221 case MonsterAbilityType::MIND_BLAST:
222 case MonsterAbilityType::BRAIN_SMASH:
223 case MonsterAbilityType::CAUSE_1:
224 case MonsterAbilityType::CAUSE_2:
225 case MonsterAbilityType::CAUSE_3:
226 case MonsterAbilityType::CAUSE_4:
227 case MonsterAbilityType::BO_ACID:
228 case MonsterAbilityType::BO_ELEC:
229 case MonsterAbilityType::BO_FIRE:
230 case MonsterAbilityType::BO_COLD:
231 case MonsterAbilityType::BO_NETH:
232 case MonsterAbilityType::BO_WATE:
233 case MonsterAbilityType::BO_MANA:
234 case MonsterAbilityType::BO_PLAS:
235 case MonsterAbilityType::BO_ICEE:
236 case MonsterAbilityType::BO_VOID:
237 case MonsterAbilityType::BO_ABYSS:
238 case MonsterAbilityType::MISSILE:
239 case MonsterAbilityType::SCARE:
240 case MonsterAbilityType::BLIND:
241 case MonsterAbilityType::CONF:
242 case MonsterAbilityType::SLOW:
243 case MonsterAbilityType::HOLD:
244 case MonsterAbilityType::HAND_DOOM:
245 case MonsterAbilityType::TELE_TO:
246 case MonsterAbilityType::TELE_AWAY:
247 case MonsterAbilityType::TELE_LEVEL:
248 case MonsterAbilityType::PSY_SPEAR:
249 case MonsterAbilityType::DARKNESS:
250 case MonsterAbilityType::FORGET:
257 static void check_mspell_imitation(PlayerType *player_ptr, msa_type *msa_ptr)
259 bool seen = (!player_ptr->blind && msa_ptr->m_ptr->ml);
260 bool can_imitate = player_has_los_bold(player_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx);
261 if (!seen || !can_imitate || (w_ptr->timewalk_m_idx != 0) || (player_ptr->pclass != PlayerClassType::IMITATOR))
264 /* Not RF_ABILITY::SPECIAL */
265 if (msa_ptr->thrown_spell == MonsterAbilityType::SPECIAL)
268 auto mane_data = PlayerClass(player_ptr).get_specific_data<mane_data_type>();
270 if (mane_data->mane_list.size() == MAX_MANE) {
271 mane_data->mane_list.pop_front();
274 mane_data->mane_list.push_back({ msa_ptr->thrown_spell, msa_ptr->dam });
275 mane_data->new_mane = true;
276 player_ptr->redraw |= PR_IMITATION;
279 static void remember_mspell(msa_type *msa_ptr)
281 if (!msa_ptr->can_remember)
284 msa_ptr->r_ptr->r_ability_flags.set(msa_ptr->thrown_spell);
285 if (msa_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
286 msa_ptr->r_ptr->r_cast_spell++;
290 * @brief モンスターの特殊技能メインルーチン /
291 * Creatures can cast spells, shoot missiles, and breathe.
292 * @param player_ptr プレイヤーへの参照ポインタ
293 * @param m_idx モンスター構造体配列のID
294 * @return 実際に特殊技能を利用したらTRUEを返す
296 bool make_attack_spell(PlayerType *player_ptr, MONSTER_IDX m_idx)
299 msa_type *msa_ptr = initialize_msa_type(player_ptr, &tmp_msa, m_idx);
300 if (monster_confused_remaining(msa_ptr->m_ptr)) {
301 reset_target(msa_ptr->m_ptr);
305 if (msa_ptr->m_ptr->mflag.has(MonsterTemporaryFlagType::PREVENT_MAGIC) || !is_hostile(msa_ptr->m_ptr) || ((msa_ptr->m_ptr->cdis > get_max_range(player_ptr)) && !msa_ptr->m_ptr->target_y))
308 decide_lite_range(player_ptr, msa_ptr);
309 if (!decide_lite_projection(player_ptr, msa_ptr))
312 reset_target(msa_ptr->m_ptr);
313 msa_ptr->rlev = ((msa_ptr->r_ptr->level >= 1) ? msa_ptr->r_ptr->level : 1);
314 set_no_magic_mask(msa_ptr);
315 decide_lite_area(player_ptr, msa_ptr);
316 check_mspell_stupid(player_ptr, msa_ptr);
317 check_mspell_smart(player_ptr, msa_ptr);
318 if (!check_mspell_continuation(player_ptr, msa_ptr))
321 if (check_mspell_unexploded(player_ptr, msa_ptr))
324 // 特技がプレイヤーに届かないなら使わない。
325 if (!check_thrown_mspell(player_ptr, msa_ptr))
329 const auto monspell_res = monspell_to_player(player_ptr, msa_ptr->thrown_spell, msa_ptr->y, msa_ptr->x, m_idx);
330 if (!monspell_res.valid)
333 msa_ptr->dam = monspell_res.dam;
334 check_mspell_imitation(player_ptr, msa_ptr);
335 remember_mspell(msa_ptr);
336 if (player_ptr->is_dead && (msa_ptr->r_ptr->r_deaths < MAX_SHORT) && !player_ptr->current_floor_ptr->inside_arena)
337 msa_ptr->r_ptr->r_deaths++;