#include "dungeon/dungeon.h"
#include "dungeon/quest.h"
#include "floor/cave.h"
-#include "floor/floor.h"
-#include "grid/feature.h"
-#include "grid/grid.h"
-#include "io/targeting.h"
#include "monster-floor/monster-move.h"
#include "monster-race/monster-race.h"
#include "monster-race/race-flags-ability1.h"
#include "monster-race/race-flags-ability2.h"
#include "monster-race/race-flags2.h"
-#include "monster-race/race-flags3.h"
#include "monster-race/race-flags4.h"
-#include "monster-race/race-flags7.h"
#include "monster-race/race-indice-types.h"
#include "monster/monster-describer.h"
#include "monster/monster-flag-types.h"
#include "monster/monster-status.h"
#include "mspell/assign-monster-spell.h"
#include "mspell/improper-mspell-remover.h"
+#include "mspell/mspell-attack-util.h"
#include "mspell/mspell-checker.h"
-#include "mspell/mspell-judgement.h"
+#include "mspell/mspell-lite.h"
#include "mspell/mspell-mask-definitions.h"
#include "mspell/mspell-selector.h"
#include "mspell/mspell-util.h"
#include "player/attack-defense-types.h"
#include "spell-kind/spells-world.h"
#include "spell-realm/spells-hex.h"
-#include "spell/range-calc.h"
#include "system/floor-type-definition.h"
-#include "system/monster-type-definition.h"
-#include "util/bit-flags-calculator.h"
+#include "target/projection-path-calculator.h"
#include "view/display-messages.h"
#include "world/world.h"
#ifdef JP
#include "monster/monster-description-types.h"
#endif
-#define DO_SPELL_NONE 0
-#define DO_SPELL_BR_LITE 1
-#define DO_SPELL_BR_DISI 2
-#define DO_SPELL_BA_LITE 3
-
-// Monster Spell Attack.
-typedef struct msa_type {
- MONSTER_IDX m_idx;
- monster_type *m_ptr;
- monster_race *r_ptr;
- bool no_inate;
- BIT_FLAGS f4;
- BIT_FLAGS f5;
- BIT_FLAGS f6;
- POSITION x;
- POSITION y;
- POSITION x_br_lite;
- POSITION y_br_lite;
- bool do_spell;
- bool in_no_magic_dungeon;
- bool success;
-} msa_type;
-
-msa_type *initialize_msa_type(player_type *target_ptr, msa_type *msa_ptr, MONSTER_IDX m_idx)
+static void set_no_magic_mask(msa_type *msa_ptr)
{
- msa_ptr->m_idx = m_idx;
- msa_ptr->m_ptr = &target_ptr->current_floor_ptr->m_list[m_idx];
- msa_ptr->r_ptr = &r_info[msa_ptr->m_ptr->r_idx];
- msa_ptr->no_inate = randint0(100) >= (msa_ptr->r_ptr->freq_spell * 2);
- msa_ptr->f4 = msa_ptr->r_ptr->flags4;
- msa_ptr->f5 = msa_ptr->r_ptr->a_ability_flags1;
- msa_ptr->f6 = msa_ptr->r_ptr->a_ability_flags2;
- msa_ptr->x = target_ptr->x;
- msa_ptr->y = target_ptr->y;
- msa_ptr->x_br_lite = 0;
- msa_ptr->y_br_lite = 0;
- msa_ptr->do_spell = DO_SPELL_NONE;
- return msa_ptr;
-}
-
-/*!
- * @brief モンスターがプレイヤーにダメージを与えるための最適な座標を算出する /
- * @param target_ptr プレーヤーへの参照ポインタ
- * @param m_ptr 技能を使用するモンスター構造体の参照ポインタ
- * @param yp 最適な目標地点のY座標を返す参照ポインタ
- * @param xp 最適な目標地点のX座標を返す参照ポインタ
- * @param f_flag 射線に入れるのを避ける地形の所持フラグ
- * @param path_check 射線を判定するための関数ポインタ
- * @return 有効な座標があった場合TRUEを返す
- */
-static bool adjacent_grid_check(player_type *target_ptr, monster_type *m_ptr, POSITION *yp, POSITION *xp, int f_flag,
- bool (*path_check)(player_type *, POSITION, POSITION, POSITION, POSITION))
-{
- static int tonari_y[4][8] = { { -1, -1, -1, 0, 0, 1, 1, 1 }, { -1, -1, -1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 0, -1, -1, -1 }, { 1, 1, 1, 0, 0, -1, -1, -1 } };
- static int tonari_x[4][8] = { { -1, 0, 1, -1, 1, -1, 0, 1 }, { 1, 0, -1, 1, -1, 1, 0, -1 }, { -1, 0, 1, -1, 1, -1, 0, 1 }, { 1, 0, -1, 1, -1, 1, 0, -1 } };
-
- int next;
- if (m_ptr->fy < target_ptr->y && m_ptr->fx < target_ptr->x)
- next = 0;
- else if (m_ptr->fy < target_ptr->y)
- next = 1;
- else if (m_ptr->fx < target_ptr->x)
- next = 2;
- else
- next = 3;
-
- floor_type *floor_ptr = target_ptr->current_floor_ptr;
- for (int i = 0; i < 8; i++) {
- int next_x = *xp + tonari_x[next][i];
- int next_y = *yp + tonari_y[next][i];
- grid_type *g_ptr;
- g_ptr = &floor_ptr->grid_array[next_y][next_x];
- if (!cave_have_flag_grid(g_ptr, f_flag))
- continue;
-
- if (path_check(target_ptr, m_ptr->fy, m_ptr->fx, next_y, next_x)) {
- *yp = next_y;
- *xp = next_x;
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static void decide_lite_range(player_type *target_ptr, msa_type *msa_ptr)
-{
- if ((msa_ptr->f4 & RF4_BR_LITE) == 0)
- return;
-
- msa_ptr->y_br_lite = msa_ptr->y;
- msa_ptr->x_br_lite = msa_ptr->x;
- if (los(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y_br_lite, msa_ptr->x_br_lite)) {
- feature_type *f_ptr = &f_info[target_ptr->current_floor_ptr->grid_array[msa_ptr->y_br_lite][msa_ptr->x_br_lite].feat];
- if (!have_flag(f_ptr->flags, FF_LOS) && have_flag(f_ptr->flags, FF_PROJECT) && one_in_(2))
- msa_ptr->f4 &= ~(RF4_BR_LITE);
- } else if (!adjacent_grid_check(target_ptr, msa_ptr->m_ptr, &msa_ptr->y_br_lite, &msa_ptr->x_br_lite, FF_LOS, los))
- msa_ptr->f4 &= ~(RF4_BR_LITE);
-
- if ((msa_ptr->f4 & RF4_BR_LITE) != 0)
- return;
-
- msa_ptr->y_br_lite = 0;
- msa_ptr->x_br_lite = 0;
-}
-
-static void feature_projection(floor_type *floor_ptr, msa_type *msa_ptr)
-{
- feature_type *f_ptr = &f_info[floor_ptr->grid_array[msa_ptr->y][msa_ptr->x].feat];
- if (have_flag(f_ptr->flags, FF_PROJECT))
- return;
-
- if ((msa_ptr->f4 & RF4_BR_DISI) && have_flag(f_ptr->flags, FF_HURT_DISI) && one_in_(2)) {
- msa_ptr->do_spell = DO_SPELL_BR_DISI;
- return;
- }
-
- if ((msa_ptr->f4 & RF4_BR_LITE) && have_flag(f_ptr->flags, FF_LOS) && one_in_(2))
- msa_ptr->do_spell = DO_SPELL_BR_LITE;
-}
-
-static void check_lite_area_by_mspell(player_type *target_ptr, msa_type *msa_ptr)
-{
- if ((msa_ptr->f4 & RF4_BR_DISI) && (msa_ptr->m_ptr->cdis < get_max_range(target_ptr) / 2)
- && in_disintegration_range(target_ptr->current_floor_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x)
- && (one_in_(10) || (projectable(target_ptr, msa_ptr->y, msa_ptr->x, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx) && one_in_(2)))) {
- msa_ptr->do_spell = DO_SPELL_BR_DISI;
- msa_ptr->success = TRUE;
- return;
- }
-
- if ((msa_ptr->f4 & RF4_BR_LITE) && (msa_ptr->m_ptr->cdis < get_max_range(target_ptr) / 2)
- && los(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x) && one_in_(5)) {
- msa_ptr->do_spell = DO_SPELL_BR_LITE;
- msa_ptr->success = TRUE;
- return;
- }
-
- if (((msa_ptr->f5 & RF5_BA_LITE) == 0) || (msa_ptr->m_ptr->cdis > get_max_range(target_ptr)))
- return;
-
- POSITION by = msa_ptr->y, bx = msa_ptr->x;
- get_project_point(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, &by, &bx, 0L);
- if ((distance(by, bx, msa_ptr->y, msa_ptr->x) <= 3) && los(target_ptr, by, bx, msa_ptr->y, msa_ptr->x) && one_in_(5)) {
- msa_ptr->do_spell = DO_SPELL_BA_LITE;
- msa_ptr->success = TRUE;
- }
-}
-
-static void decide_lite_breath(player_type *target_ptr, msa_type *msa_ptr)
-{
- if (msa_ptr->success)
+ if (!msa_ptr->no_inate)
return;
- if (msa_ptr->m_ptr->target_y && msa_ptr->m_ptr->target_x) {
- msa_ptr->y = msa_ptr->m_ptr->target_y;
- msa_ptr->x = msa_ptr->m_ptr->target_x;
- msa_ptr->f4 &= RF4_INDIRECT_MASK;
- msa_ptr->f5 &= RF5_INDIRECT_MASK;
- msa_ptr->f6 &= RF6_INDIRECT_MASK;
- msa_ptr->success = TRUE;
- }
-
- if ((msa_ptr->y_br_lite == 0) || (msa_ptr->x_br_lite == 0) || (msa_ptr->m_ptr->cdis > get_max_range(target_ptr) / 2) || !one_in_(5))
- return;
-
- if (msa_ptr->success) {
- msa_ptr->f4 |= RF4_BR_LITE;
- return;
- }
-
- msa_ptr->y = msa_ptr->y_br_lite;
- msa_ptr->x = msa_ptr->x_br_lite;
- msa_ptr->do_spell = DO_SPELL_BR_LITE;
- msa_ptr->success = TRUE;
-}
-
-static bool decide_lite_projection(player_type *target_ptr, msa_type *msa_ptr)
-{
- if (projectable(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x)) {
- feature_projection(target_ptr->current_floor_ptr, msa_ptr);
- return TRUE;
- }
-
- msa_ptr->success = FALSE;
- check_lite_area_by_mspell(target_ptr, msa_ptr);
- if (!msa_ptr->success)
- msa_ptr->success = adjacent_grid_check(target_ptr, msa_ptr->m_ptr, &msa_ptr->y, &msa_ptr->x, FF_PROJECT, projectable);
-
- decide_lite_breath(target_ptr, msa_ptr);
- return msa_ptr->success;
-}
-
-static void decide_lite_area(player_type *target_ptr, msa_type *msa_ptr)
-{
- if ((msa_ptr->f6 & RF6_DARKNESS) == 0)
- return;
-
- bool can_use_lite_area = (target_ptr->pclass == CLASS_NINJA) && ((msa_ptr->r_ptr->flags3 & (RF3_UNDEAD | RF3_HURT_LITE)) == 0)
- && ((msa_ptr->r_ptr->flags7 & RF7_DARK_MASK) == 0);
-
- if ((msa_ptr->r_ptr->flags2 & RF2_STUPID) != 0)
- return;
-
- if (d_info[target_ptr->dungeon_idx].flags1 & DF1_DARKNESS) {
- msa_ptr->f6 &= ~(RF6_DARKNESS);
- return;
- }
-
- if ((target_ptr->pclass == CLASS_NINJA) && !can_use_lite_area)
- msa_ptr->f6 &= ~(RF6_DARKNESS);
+ msa_ptr->f4 &= ~(RF4_NOMAGIC_MASK);
+ msa_ptr->f5 &= ~(RF5_NOMAGIC_MASK);
+ msa_ptr->f6 &= ~(RF6_NOMAGIC_MASK);
}
static void check_mspell_stupid(player_type *target_ptr, msa_type *msa_ptr)
msa_ptr->f6 &= ~(RF6_SPECIAL);
}
-/*!
- * @brief モンスターの特殊技能メインルーチン /
- * Creatures can cast spells, shoot missiles, and breathe.
- * @param target_ptr プレーヤーへの参照ポインタ
- * @param m_idx モンスター構造体配列のID
- * @return 実際に特殊技能を利用したらTRUEを返す
- */
-bool make_attack_spell(player_type *target_ptr, MONSTER_IDX m_idx)
+static bool check_mspell_non_stupid(player_type *target_ptr, msa_type *msa_ptr)
{
-#ifdef JP
-#else
- char m_poss[80];
-#endif
- msa_type tmp_msa;
- msa_type *msa_ptr = initialize_msa_type(target_ptr, &tmp_msa, m_idx);
- if (monster_confused_remaining(msa_ptr->m_ptr)) {
- reset_target(msa_ptr->m_ptr);
- return FALSE;
- }
-
- if (((msa_ptr->m_ptr->mflag & MFLAG_NICE) != 0) || !is_hostile(msa_ptr->m_ptr)
- || ((msa_ptr->m_ptr->cdis > get_max_range(target_ptr)) && !msa_ptr->m_ptr->target_y))
- return FALSE;
+ if ((msa_ptr->r_ptr->flags2 & RF2_STUPID) != 0)
+ return TRUE;
- decide_lite_range(target_ptr, msa_ptr);
- if (!decide_lite_projection(target_ptr, msa_ptr))
- return FALSE;
+ if (!target_ptr->csp)
+ msa_ptr->f5 &= ~(RF5_DRAIN_MANA);
- reset_target(msa_ptr->m_ptr);
- DEPTH rlev = ((msa_ptr->r_ptr->level >= 1) ? msa_ptr->r_ptr->level : 1);
- if (msa_ptr->no_inate) {
- msa_ptr->f4 &= ~(RF4_NOMAGIC_MASK);
- msa_ptr->f5 &= ~(RF5_NOMAGIC_MASK);
- msa_ptr->f6 &= ~(RF6_NOMAGIC_MASK);
+ if (((msa_ptr->f4 & RF4_BOLT_MASK) || (msa_ptr->f5 & RF5_BOLT_MASK) || (msa_ptr->f6 & RF6_BOLT_MASK))
+ && !clean_shot(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, target_ptr->y, target_ptr->x, FALSE)) {
+ msa_ptr->f4 &= ~(RF4_BOLT_MASK);
+ msa_ptr->f5 &= ~(RF5_BOLT_MASK);
+ msa_ptr->f6 &= ~(RF6_BOLT_MASK);
}
- decide_lite_area(target_ptr, msa_ptr);
- check_mspell_stupid(target_ptr, msa_ptr);
- check_mspell_smart(target_ptr, msa_ptr);
- if (!msa_ptr->f4 && !msa_ptr->f5 && !msa_ptr->f6)
- return FALSE;
-
- remove_bad_spells(m_idx, target_ptr, &msa_ptr->f4, &msa_ptr->f5, &msa_ptr->f6);
- check_mspell_arena(target_ptr,, msa_ptr);
- if (!msa_ptr->f4 && !msa_ptr->f5 && !msa_ptr->f6)
- return FALSE;
-
- if (!(msa_ptr->r_ptr->flags2 & RF2_STUPID)) {
- if (!target_ptr->csp)
- msa_ptr->f5 &= ~(RF5_DRAIN_MANA);
-
- if (((msa_ptr->f4 & RF4_BOLT_MASK) || (msa_ptr->f5 & RF5_BOLT_MASK) || (msa_ptr->f6 & RF6_BOLT_MASK))
- && !clean_shot(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, target_ptr->y, target_ptr->x, FALSE)) {
- msa_ptr->f4 &= ~(RF4_BOLT_MASK);
- msa_ptr->f5 &= ~(RF5_BOLT_MASK);
- msa_ptr->f6 &= ~(RF6_BOLT_MASK);
- }
-
- if (((msa_ptr->f4 & RF4_SUMMON_MASK) || (msa_ptr->f5 & RF5_SUMMON_MASK) || (msa_ptr->f6 & RF6_SUMMON_MASK))
- && !(summon_possible(target_ptr, msa_ptr->y, msa_ptr->x))) {
- msa_ptr->f4 &= ~(RF4_SUMMON_MASK);
- msa_ptr->f5 &= ~(RF5_SUMMON_MASK);
- msa_ptr->f6 &= ~(RF6_SUMMON_MASK);
- }
+ if (((msa_ptr->f4 & RF4_SUMMON_MASK) || (msa_ptr->f5 & RF5_SUMMON_MASK) || (msa_ptr->f6 & RF6_SUMMON_MASK))
+ && !(summon_possible(target_ptr, msa_ptr->y, msa_ptr->x))) {
+ msa_ptr->f4 &= ~(RF4_SUMMON_MASK);
+ msa_ptr->f5 &= ~(RF5_SUMMON_MASK);
+ msa_ptr->f6 &= ~(RF6_SUMMON_MASK);
+ }
- if ((msa_ptr->f6 & RF6_RAISE_DEAD) && !raise_possible(target_ptr, msa_ptr->m_ptr)) {
- msa_ptr->f6 &= ~(RF6_RAISE_DEAD);
- }
+ if ((msa_ptr->f6 & RF6_RAISE_DEAD) && !raise_possible(target_ptr, msa_ptr->m_ptr))
+ msa_ptr->f6 &= ~(RF6_RAISE_DEAD);
- if (msa_ptr->f6 & RF6_SPECIAL) {
- if ((msa_ptr->m_ptr->r_idx == MON_ROLENTO) && !summon_possible(target_ptr, msa_ptr->y, msa_ptr->x)) {
- msa_ptr->f6 &= ~(RF6_SPECIAL);
- }
- }
+ if (((msa_ptr->f6 & RF6_SPECIAL) != 0) && (msa_ptr->m_ptr->r_idx == MON_ROLENTO) && !summon_possible(target_ptr, msa_ptr->y, msa_ptr->x))
+ msa_ptr->f6 &= ~(RF6_SPECIAL);
- if (!msa_ptr->f4 && !msa_ptr->f5 && !msa_ptr->f6)
- return FALSE;
- }
+ return (msa_ptr->f4 != 0) || (msa_ptr->f5 != 0) || (msa_ptr->f6 != 0);
+}
- byte spell[96], num = 0;
+static void set_mspell_list(msa_type *msa_ptr)
+{
for (int k = 0; k < 32; k++)
if (msa_ptr->f4 & (1L << k))
- spell[num++] = k + RF4_SPELL_START;
+ msa_ptr->mspells[msa_ptr->num++] = k + RF4_SPELL_START;
for (int k = 0; k < 32; k++)
if (msa_ptr->f5 & (1L << k))
- spell[num++] = k + RF5_SPELL_START;
+ msa_ptr->mspells[msa_ptr->num++] = k + RF5_SPELL_START;
for (int k = 0; k < 32; k++)
if (msa_ptr->f6 & (1L << k))
- spell[num++] = k + RF6_SPELL_START;
-
- if (!num || !target_ptr->playing || target_ptr->is_dead || target_ptr->leaving)
- return FALSE;
+ msa_ptr->mspells[msa_ptr->num++] = k + RF6_SPELL_START;
+}
- GAME_TEXT m_name[MAX_NLEN];
- monster_desc(target_ptr, m_name, msa_ptr->m_ptr, 0x00);
+static void describe_mspell_monster(player_type *target_ptr, msa_type *msa_ptr)
+{
+ monster_desc(target_ptr, msa_ptr->m_name, msa_ptr->m_ptr, 0x00);
#ifdef JP
#else
/* Get the monster possessive ("his"/"her"/"its") */
+ char m_poss[80];
monster_desc(target_ptr, m_poss, msa_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE);
#endif
+}
- SPELL_IDX thrown_spell = 0;
+static bool switch_do_spell(player_type *target_ptr, msa_type *msa_ptr)
+{
switch (msa_ptr->do_spell) {
case DO_SPELL_NONE: {
int attempt = 10;
while (attempt--) {
- thrown_spell = choose_attack_spell(target_ptr, m_idx, spell, num);
- if (thrown_spell)
+ msa_ptr->thrown_spell = choose_attack_spell(target_ptr, msa_ptr);
+ if (msa_ptr->thrown_spell)
break;
}
- break;
+
+ return TRUE;
}
case DO_SPELL_BR_LITE:
- thrown_spell = 96 + 14; /* RF4_BR_LITE */
- break;
+ msa_ptr->thrown_spell = 96 + 14; /* RF4_BR_LITE */
+ return TRUE;
case DO_SPELL_BR_DISI:
- thrown_spell = 96 + 31; /* RF4_BR_DISI */
- break;
+ msa_ptr->thrown_spell = 96 + 31; /* RF4_BR_DISI */
+ return TRUE;
case DO_SPELL_BA_LITE:
- thrown_spell = 128 + 20; /* RF5_BA_LITE */
- break;
+ msa_ptr->thrown_spell = 128 + 20; /* RF5_BA_LITE */
+ return TRUE;
default:
return FALSE;
}
+}
+
+static bool check_mspell_continuation(player_type *target_ptr, msa_type *msa_ptr)
+{
+ if ((msa_ptr->f4 == 0) && (msa_ptr->f5 == 0) && (msa_ptr->f6 == 0))
+ return FALSE;
- if (!thrown_spell)
+ remove_bad_spells(msa_ptr->m_idx, target_ptr, &msa_ptr->f4, &msa_ptr->f5, &msa_ptr->f6);
+ check_mspell_arena(target_ptr, msa_ptr);
+ if (((msa_ptr->f4 == 0) && (msa_ptr->f5 == 0) && (msa_ptr->f6 == 0)) || !check_mspell_non_stupid(target_ptr, msa_ptr))
return FALSE;
- PERCENTAGE failrate = 25 - (rlev + 3) / 4;
+ set_mspell_list(msa_ptr);
+ if ((msa_ptr->num == 0) || !target_ptr->playing || target_ptr->is_dead || target_ptr->leaving)
+ return FALSE;
+ describe_mspell_monster(target_ptr, msa_ptr);
+ if (!switch_do_spell(target_ptr, msa_ptr) || (msa_ptr->thrown_spell == 0))
+ return FALSE;
+
+ return TRUE;
+}
+
+static bool check_mspell_unexploded(player_type *target_ptr, msa_type *msa_ptr)
+{
+ PERCENTAGE fail_rate = 25 - (msa_ptr->rlev + 3) / 4;
if (msa_ptr->r_ptr->flags2 & RF2_STUPID)
- failrate = 0;
+ fail_rate = 0;
- if (!spell_is_inate(thrown_spell) && (msa_ptr->in_no_magic_dungeon || (monster_stunned_remaining(msa_ptr->m_ptr) && one_in_(2)) || (randint0(100) < failrate))) {
+ 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))) {
disturb(target_ptr, TRUE, TRUE);
- msg_format(_("%^sは呪文を唱えようとしたが失敗した。", "%^s tries to cast a spell, but fails."), m_name);
-
+ msg_format(_("%^sは呪文を唱えようとしたが失敗した。", "%^s tries to cast a spell, but fails."), msa_ptr->m_name);
return TRUE;
}
- if (!spell_is_inate(thrown_spell) && magic_barrier(target_ptr, m_idx)) {
- msg_format(_("反魔法バリアが%^sの呪文をかき消した。", "Anti magic barrier cancels the spell which %^s casts."), m_name);
+ if (!spell_is_inate(msa_ptr->thrown_spell) && magic_barrier(target_ptr, msa_ptr->m_idx)) {
+ msg_format(_("反魔法バリアが%^sの呪文をかき消した。", "Anti magic barrier cancels the spell which %^s casts."), msa_ptr->m_name);
return TRUE;
}
+ return FALSE;
+}
+
+static bool check_thrown_mspell(player_type *target_ptr, msa_type *msa_ptr)
+{
bool direct = player_bold(target_ptr, msa_ptr->y, msa_ptr->x);
- bool can_remember = is_original_ap_and_seen(target_ptr, msa_ptr->m_ptr);
- if (!direct) {
- switch (thrown_spell) {
- case 96 + 2: /* RF4_DISPEL */
- case 96 + 4: /* RF4_SHOOT */
- case 128 + 9: /* RF5_DRAIN_MANA */
- case 128 + 10: /* RF5_MIND_BLAST */
- case 128 + 11: /* RF5_BRAIN_SMASH */
- case 128 + 12: /* RF5_CAUSE_1 */
- case 128 + 13: /* RF5_CAUSE_2 */
- case 128 + 14: /* RF5_CAUSE_3 */
- case 128 + 15: /* RF5_CAUSE_4 */
- case 128 + 16: /* RF5_BO_ACID */
- case 128 + 17: /* RF5_BO_ELEC */
- case 128 + 18: /* RF5_BO_FIRE */
- case 128 + 19: /* RF5_BO_COLD */
- case 128 + 21: /* RF5_BO_NETH */
- case 128 + 22: /* RF5_BO_WATE */
- case 128 + 23: /* RF5_BO_MANA */
- case 128 + 24: /* RF5_BO_PLAS */
- case 128 + 25: /* RF5_BO_ICEE */
- case 128 + 26: /* RF5_MISSILE */
- case 128 + 27: /* RF5_SCARE */
- case 128 + 28: /* RF5_BLIND */
- case 128 + 29: /* RF5_CONF */
- case 128 + 30: /* RF5_SLOW */
- case 128 + 31: /* RF5_HOLD */
- case 160 + 1: /* RF6_HAND_DOOM */
- case 160 + 8: /* RF6_TELE_TO */
- case 160 + 9: /* RF6_TELE_AWAY */
- case 160 + 10: /* RF6_TELE_LEVEL */
- case 160 + 11: /* RF6_PSY_SPEAR */
- case 160 + 12: /* RF6_DARKNESS */
- case 160 + 14: /* RF6_FORGET */
- return FALSE;
- }
- }
+ msa_ptr->can_remember = is_original_ap_and_seen(target_ptr, msa_ptr->m_ptr);
+ if (direct)
+ return TRUE;
- int dam = monspell_to_player(target_ptr, thrown_spell, msa_ptr->y, msa_ptr->x, m_idx);
- if (dam < 0)
+ switch (msa_ptr->thrown_spell) {
+ case 96 + 2: /* RF4_DISPEL */
+ case 96 + 4: /* RF4_SHOOT */
+ case 128 + 9: /* RF5_DRAIN_MANA */
+ case 128 + 10: /* RF5_MIND_BLAST */
+ case 128 + 11: /* RF5_BRAIN_SMASH */
+ case 128 + 12: /* RF5_CAUSE_1 */
+ case 128 + 13: /* RF5_CAUSE_2 */
+ case 128 + 14: /* RF5_CAUSE_3 */
+ case 128 + 15: /* RF5_CAUSE_4 */
+ case 128 + 16: /* RF5_BO_ACID */
+ case 128 + 17: /* RF5_BO_ELEC */
+ case 128 + 18: /* RF5_BO_FIRE */
+ case 128 + 19: /* RF5_BO_COLD */
+ case 128 + 21: /* RF5_BO_NETH */
+ case 128 + 22: /* RF5_BO_WATE */
+ case 128 + 23: /* RF5_BO_MANA */
+ case 128 + 24: /* RF5_BO_PLAS */
+ case 128 + 25: /* RF5_BO_ICEE */
+ case 128 + 26: /* RF5_MISSILE */
+ case 128 + 27: /* RF5_SCARE */
+ case 128 + 28: /* RF5_BLIND */
+ case 128 + 29: /* RF5_CONF */
+ case 128 + 30: /* RF5_SLOW */
+ case 128 + 31: /* RF5_HOLD */
+ case 160 + 1: /* RF6_HAND_DOOM */
+ case 160 + 8: /* RF6_TELE_TO */
+ case 160 + 9: /* RF6_TELE_AWAY */
+ case 160 + 10: /* RF6_TELE_LEVEL */
+ case 160 + 11: /* RF6_PSY_SPEAR */
+ case 160 + 12: /* RF6_DARKNESS */
+ case 160 + 14: /* RF6_FORGET */
return FALSE;
-
- if ((target_ptr->action == ACTION_LEARN) && thrown_spell > 175) {
- learn_spell(target_ptr, thrown_spell - 96);
+ default:
+ return TRUE;
}
+}
+static void check_mspell_imitation(player_type *target_ptr, msa_type *msa_ptr)
+{
bool seen = (!target_ptr->blind && msa_ptr->m_ptr->ml);
- bool maneable = player_has_los_bold(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx);
- if (seen && maneable && !current_world_ptr->timewalk_m_idx && (target_ptr->pclass == CLASS_IMITATOR)) {
- if (thrown_spell != 167) /* Not RF6_SPECIAL */
- {
- if (target_ptr->mane_num == MAX_MANE) {
- int i;
- target_ptr->mane_num--;
- for (i = 0; i < target_ptr->mane_num; i++) {
- target_ptr->mane_spell[i] = target_ptr->mane_spell[i + 1];
- target_ptr->mane_dam[i] = target_ptr->mane_dam[i + 1];
- }
- }
-
- target_ptr->mane_spell[target_ptr->mane_num] = thrown_spell - 96;
- target_ptr->mane_dam[target_ptr->mane_num] = dam;
- target_ptr->mane_num++;
- target_ptr->new_mane = TRUE;
- target_ptr->redraw |= PR_IMITATION;
+ bool can_imitate = player_has_los_bold(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx);
+ if (!seen || !can_imitate || (current_world_ptr->timewalk_m_idx != 0) || (target_ptr->pclass != CLASS_IMITATOR))
+ return;
+
+ /* Not RF6_SPECIAL */
+ if (msa_ptr->thrown_spell == 167)
+ return;
+
+ if (target_ptr->mane_num == MAX_MANE) {
+ target_ptr->mane_num--;
+ for (int i = 0; i < target_ptr->mane_num; i++) {
+ target_ptr->mane_spell[i] = target_ptr->mane_spell[i + 1];
+ target_ptr->mane_dam[i] = target_ptr->mane_dam[i + 1];
}
}
- if (can_remember) {
- if (thrown_spell < 32 * 4) {
- msa_ptr->r_ptr->r_flags4 |= (1L << (thrown_spell - 32 * 3));
- if (msa_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
- msa_ptr->r_ptr->r_cast_spell++;
- } else if (thrown_spell < 32 * 5) {
- msa_ptr->r_ptr->r_flags5 |= (1L << (thrown_spell - 32 * 4));
- if (msa_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
- msa_ptr->r_ptr->r_cast_spell++;
- } else if (thrown_spell < 32 * 6) {
- msa_ptr->r_ptr->r_flags6 |= (1L << (thrown_spell - 32 * 5));
- if (msa_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
- msa_ptr->r_ptr->r_cast_spell++;
- }
+ target_ptr->mane_spell[target_ptr->mane_num] = msa_ptr->thrown_spell - 96;
+ target_ptr->mane_dam[target_ptr->mane_num] = msa_ptr->dam;
+ target_ptr->mane_num++;
+ target_ptr->new_mane = TRUE;
+ target_ptr->redraw |= PR_IMITATION;
+}
+
+static void remember_mspell(msa_type *msa_ptr)
+{
+ if (!msa_ptr->can_remember)
+ return;
+
+ if (msa_ptr->thrown_spell < 32 * 4) {
+ msa_ptr->r_ptr->r_flags4 |= (1L << (msa_ptr->thrown_spell - 32 * 3));
+ if (msa_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
+ msa_ptr->r_ptr->r_cast_spell++;
+
+ return;
}
+
+ if (msa_ptr->thrown_spell < 32 * 5) {
+ msa_ptr->r_ptr->r_flags5 |= (1L << (msa_ptr->thrown_spell - 32 * 4));
+ if (msa_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
+ msa_ptr->r_ptr->r_cast_spell++;
- if (target_ptr->is_dead && (msa_ptr->r_ptr->r_deaths < MAX_SHORT) && !target_ptr->current_floor_ptr->inside_arena) {
- msa_ptr->r_ptr->r_deaths++;
+ return;
}
+
+ if (msa_ptr->thrown_spell < 32 * 6) {
+ msa_ptr->r_ptr->r_flags6 |= (1L << (msa_ptr->thrown_spell - 32 * 5));
+ if (msa_ptr->r_ptr->r_cast_spell < MAX_UCHAR)
+ msa_ptr->r_ptr->r_cast_spell++;
+ }
+}
+
+/*!
+ * @brief モンスターの特殊技能メインルーチン /
+ * Creatures can cast spells, shoot missiles, and breathe.
+ * @param target_ptr プレーヤーへの参照ポインタ
+ * @param m_idx モンスター構造体配列のID
+ * @return 実際に特殊技能を利用したらTRUEを返す
+ */
+bool make_attack_spell(player_type *target_ptr, MONSTER_IDX m_idx)
+{
+ msa_type tmp_msa;
+ msa_type *msa_ptr = initialize_msa_type(target_ptr, &tmp_msa, m_idx);
+ if (monster_confused_remaining(msa_ptr->m_ptr)) {
+ reset_target(msa_ptr->m_ptr);
+ return FALSE;
+ }
+
+ if (((msa_ptr->m_ptr->mflag & MFLAG_NICE) != 0) || !is_hostile(msa_ptr->m_ptr)
+ || ((msa_ptr->m_ptr->cdis > get_max_range(target_ptr)) && !msa_ptr->m_ptr->target_y))
+ return FALSE;
+
+ decide_lite_range(target_ptr, msa_ptr);
+ if (!decide_lite_projection(target_ptr, msa_ptr))
+ return FALSE;
+
+ reset_target(msa_ptr->m_ptr);
+ msa_ptr->rlev = ((msa_ptr->r_ptr->level >= 1) ? msa_ptr->r_ptr->level : 1);
+ set_no_magic_mask(msa_ptr);
+ decide_lite_area(target_ptr, msa_ptr);
+ check_mspell_stupid(target_ptr, msa_ptr);
+ check_mspell_smart(target_ptr, msa_ptr);
+ if (!check_mspell_continuation(target_ptr, msa_ptr))
+ return FALSE;
+
+ if (check_mspell_unexploded(target_ptr, msa_ptr))
+ return TRUE;
+
+ if (!check_thrown_mspell(target_ptr, msa_ptr))
+ return FALSE;
+
+ msa_ptr->dam = monspell_to_player(target_ptr, msa_ptr->thrown_spell, msa_ptr->y, msa_ptr->x, m_idx);
+ if (msa_ptr->dam < 0)
+ return FALSE;
+
+ if ((target_ptr->action == ACTION_LEARN) && msa_ptr->thrown_spell > 175)
+ learn_spell(target_ptr, msa_ptr->thrown_spell - 96);
+
+ check_mspell_imitation(target_ptr, msa_ptr);
+ remember_mspell(msa_ptr);
+ if (target_ptr->is_dead && (msa_ptr->r_ptr->r_deaths < MAX_SHORT) && !target_ptr->current_floor_ptr->inside_arena)
+ msa_ptr->r_ptr->r_deaths++;
return TRUE;
}