Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2023-07-24 14:43:27 +08:00
19 changed files with 1049 additions and 1179 deletions

View File

@@ -0,0 +1,4 @@
-- DB update 2023_07_18_00 -> 2023_07_18_01
SET @HELP_TEXT := 'Syntax: .wp show $option\nOptions:\non $pathid (or selected creature with loaded path) - Show path\noff - Hide path\ninfo $selected_waypoint - Show info for selected waypoint.';
UPDATE `command` SET `help` = @HELP_TEXT WHERE `name` = 'wp show';

View File

@@ -0,0 +1,4 @@
-- DB update 2023_07_18_01 -> 2023_07_18_02
-- Darting Hatchling (pet)
UPDATE `creature_template_addon` SET `auras` = 62586 WHERE `entry` = 35396;
UPDATE `creature_template` SET `ScriptName` = 'npc_pet_darting_hatchling' WHERE `entry` = 35396;

View File

@@ -0,0 +1,4 @@
-- DB update 2023_07_18_02 -> 2023_07_19_00
--
UPDATE `spell_proc_event` SET `ppmRate` = 10 WHERE `entry` = 26480;
UPDATE `spell_proc_event` SET `procFlags` = 68 WHERE `entry` = 26480;

View File

@@ -0,0 +1,3 @@
-- DB update 2023_07_19_00 -> 2023_07_19_01
--
UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 38334;

View File

@@ -0,0 +1,3 @@
-- DB update 2023_07_19_01 -> 2023_07_19_02
--
UPDATE `spell_proc_event` SET `procPhase` = 1 WHERE `entry` = 23688;

View File

@@ -0,0 +1,2 @@
-- DB update 2023_07_19_02 -> 2023_07_19_03
UPDATE `spell_proc_event` SET `procEx` = 262144 WHERE `entry` = 28200;

View File

@@ -0,0 +1,9 @@
-- DB update 2023_07_19_03 -> 2023_07_19_04
--
UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 37655;
UPDATE `spell_proc_event` SET `Cooldown` = 40000 WHERE `entry` = 37247;
UPDATE `spell_proc_event` SET `Cooldown` = 50000 WHERE `entry` = 60066;
UPDATE `spell_proc_event` SET `Cooldown` = 2000 WHERE `entry` = 15600;
UPDATE `spell_proc_event` SET `procEx` = 262144 WHERE `entry` = 37655;
UPDATE `item_template` SET `spellcooldown_2` = -1 WHERE (`entry` = 28823);

View File

@@ -0,0 +1,44 @@
-- DB update 2023_07_19_04 -> 2023_07_22_00
UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName`='' WHERE `entry` IN (18445,18369,20812);
UPDATE `gameobject_template` SET `Data2`=300000, `AIName`='SmartGameObjectAI', `ScriptName`='' WHERE `entry` IN (182521,182349,182350);
DELETE FROM `smart_scripts` WHERE `entryorguid` IN (182521,182349,182350) AND `source_type`=1;
DELETE FROM `smart_scripts` WHERE `entryorguid` IN (18445,18369,20812) AND `source_type`=0;
DELETE FROM `smart_scripts` WHERE `entryorguid` IN (1844500,1836900,2081200) AND `source_type`=9;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(182521, 1, 0 ,1,70, 0, 100, 0, 2, 0, 0,0,64,1,0,0,0,0,0,16,0,0,0,0, 0, 0, 0, 'Corkis Prison - On State Changed - Store Targetlist'),
(182521, 1, 1 ,2,61, 0, 100, 0, 0, 0, 0,0,100,1,0,0,0,0,0,19,18445,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Send Targetlist'),
(182521, 1, 2 ,0,61, 0, 100, 0, 0, 0, 0,0,45,1,1,0,0,0,0,19,18445,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Set Data'),
(18445, 0, 0 ,0,38, 0, 100, 0, 1, 1, 0,0,80,1844500,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - On Data Set - Action list'),
(1844500, 9, 0 ,0,0, 0, 100, 0, 0, 0, 0,0,1,0,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Say'),
(1844500, 9, 1 ,0,0, 0, 100, 0, 0, 0, 0,0,33,18444,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Kill Credit'),
(1844500, 9, 2 ,0,0, 0, 100, 0, 4000, 4000, 0,0,69,0,0,0,0,0,0,8,0,0,0,-896.082, 8687.346, 170.455, 3.81311, 'Corki - Action listt - Move Forward'),
(1844500, 9, 3 ,0,0, 0, 100, 0, 4000, 4000, 0,0,41,0,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - Action list - Despawn after 5 seconds'),
(182349, 1, 0 ,1,70, 0, 100, 0, 2, 0, 0,0,64,1,0,0,0,0,0,16,0,0,0,0, 0, 0, 0, 'Corkis Prison - On State Changed - Store Targetlist'),
(182349, 1, 1 ,2,61, 0, 100, 0, 0, 0, 0,0,100,1,0,0,0,0,0,19,18369,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Send Targetlist'),
(182349, 1, 2 ,0,61, 0, 100, 0, 0, 0, 0,0,45,1,1,0,0,0,0,19,18369,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Set Data'),
(18369, 0, 0 ,0,38, 0, 100, 0, 1, 1, 0,0,80,1836900,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - On Data Set - Action list'),
(1836900, 9, 0 , 0, 0, 0, 100, 0, 0, 0, 0,0,1,0,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Say'),
(1836900, 9, 1 , 0, 0, 0, 100, 0, 0, 0, 0,0,33,18369,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Kill Credit'),
(1836900, 9, 2 ,0,0, 0, 100, 0, 4000, 4000, 0,0,69,0,0,0,0,0,0,8,0,0,0,-2547.684, 6271.637, 14.767, 5.349, 'Corki - Action list - Move Forward'),
(1836900, 9, 3 , 0, 0, 0, 100, 0, 4000, 4000, 0,0,41,0,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - Action list - Despawn after 5 seconds'),
(182350, 1, 0 ,1,70, 0, 100, 0, 2, 0, 0,0,64,1,0,0,0,0,0,16,0,0,0,0, 0, 0, 0, 'Corkis Prison - On State Changed - Store Targetlist'),
(182350, 1, 1 ,2,61, 0, 100, 0, 0, 0, 0,0,100,1,0,0,0,0,0,19,20812,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Send Targetlist'),
(182350, 1, 2 ,0,61, 0, 100, 0, 0, 0, 0,0,45,1,1,0,0,0,0,19,20812,0,0,0, 0, 0, 0, 'Corkis Prison - Script - Set Data'),
(20812, 0, 0 ,0,38, 0, 100, 0, 1, 1, 0,0,80,2081200,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - On Data Set - Action list'),
(2081200, 9, 0 , 0, 0, 0, 100, 0, 0, 0, 0,0,1,0,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Say'),
(2081200, 9, 1 , 0, 0, 0, 100, 0, 0, 0, 0,0,33,20812,0,0,0,0,0,12,1,0,0,0, 0, 0, 0, 'Corki - Action list - Kill Credit'),
(2081200, 9, 2 , 0, 0, 0, 100, 0, 4000, 4000, 0,0,69,0,0,0,0,0,0,8,0,0,0,-1001.022, 8113.366, -95.849, 0.352908, 'Corki - Action list - Move Forward'),
(2081200, 9, 3 , 0, 0, 0, 100, 0, 4000, 4000, 0,0,41,0,0,0,0,0,0,1,0,0,0,0, 0, 0, 0, 'Corki - Action list - Despawn after 5 seconds');
UPDATE `creature` SET `position_x`=-2563.89,`position_y`=6288.29,`position_z`=15.295,`orientation`=5.23599 WHERE `guid`=65786 AND `id1`=18369;
UPDATE `creature` SET `position_x`=-918.143,`position_y`=8663.94,`position_z`=172.542,`orientation`=0.523599 WHERE `guid`=65849 AND `id1`=18445;
DELETE FROM `creature_questender` WHERE `id` IN (18369,18445);
INSERT INTO `creature_questender` (`id`, `quest`) VALUES
(18445, 9954);
DELETE FROM `creature_queststarter` WHERE `id` IN (18369,18445);
INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES
(18369, 9923),
(18445, 9955);

View File

@@ -0,0 +1,13 @@
-- DB update 2023_07_22_00 -> 2023_07_23_00
--
DELETE FROM `smart_scripts` WHERE `entryorguid` = 17256 AND `source_type` = 0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(17256, 0, 0, 0, 0, 0, 100, 0, 20900, 28200, 12100, 19400, 0, 11, 30510, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - In Combat - Cast \'Shadow Bolt Volley\''),
(17256, 0, 1, 0, 74, 0, 100, 0, 0, 50, 14500, 15000, 30, 11, 30528, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - On Friendly Between 0-50% Health - Cast \'Dark Mending\''),
(17256, 0, 2, 0, 0, 0, 100, 0, 6000, 12000, 17000, 28000, 0, 11, 30530, 0, 0, 0, 0, 0, 6, 30, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - In Combat - Cast \'Fear\''),
(17256, 0, 3, 0, 0, 0, 100, 0, 19650, 63350, 60000, 60000, 0, 11, 30511, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - In Combat - Cast \'Burning Abyssal\''),
(17256, 0, 4, 0, 1, 0, 100, 0, 3600, 3600, 3600, 3600, 0, 11, 30207, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - Out of Combat - Cast \'Shadow Grasp\''),
(17256, 0, 5, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 11, 30531, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - On Just Died - Cast \'Soul Transfer\''),
(17256, 0, 6, 0, 6, 0, 100, 512, 0, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 10, 91254, 17257, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - On Just Died - Do Action on Magtheridon'),
(17256, 0, 7, 0, 4, 0, 100, 512, 0, 0, 0, 0, 0, 34, 10, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - On Aggro - Set Instance Data 10 to 1'),
(17256, 0, 8, 0, 25, 0, 100, 512, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hellfire Channeler - On Reset - Set Reactstate Defensive');

View File

@@ -660,7 +660,7 @@ void WorldSession::LogoutPlayer(bool save)
guild->HandleMemberLogout(this);
///- Remove pet
_player->RemovePet(nullptr, PET_SAVE_AS_CURRENT, true);
_player->RemovePet(nullptr, PET_SAVE_AS_CURRENT);
// pussywizard: on logout remove auras that are removed at map change (before saving to db)
// there are some positive auras from boss encounters that can be kept by logging out and logging in after boss is dead, and may be used on next bosses

View File

@@ -4547,6 +4547,12 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->MaxAffectedTargets = 1;
});
// Mulgore Hatchling (periodic)
ApplySpellFix({ 62586 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].TriggerSpell = 62585; // Mulgore Hatchling (fear)
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];

View File

@@ -24,18 +24,18 @@
enum Texts
{
SAY_KILL = 0,
SAY_RANDOM = 1,
SAY_DISARMED = 2,
SAY_MIDNIGHT_KILL = 3,
SAY_APPEAR = 4,
SAY_MOUNT = 5,
SAY_KILL = 0,
SAY_RANDOM = 1,
SAY_DISARMED = 2,
SAY_MIDNIGHT_KILL = 3,
SAY_APPEAR = 4,
SAY_MOUNT = 5,
SAY_DEATH = 3,
SAY_DEATH = 3,
// Midnight
EMOTE_CALL_ATTUMEN = 0,
EMOTE_MOUNT_UP = 1
EMOTE_CALL_ATTUMEN = 0,
EMOTE_MOUNT_UP = 1
};
enum Spells
@@ -45,7 +45,6 @@ enum Spells
SPELL_INTANGIBLE_PRESENCE = 29833,
SPELL_SPAWN_SMOKE = 10389,
SPELL_CHARGE = 29847,
// Midnight
SPELL_KNOCKDOWN = 29711,
SPELL_SUMMON_ATTUMEN = 29714,
@@ -62,406 +61,357 @@ enum Phases
enum Actions
{
ACTION_SET_MIDNIGHT_PHASE,
ACTION_SET_MIDNIGHT_PHASE
};
class boss_attumen : public CreatureScript
struct boss_attumen : public BossAI
{
public:
boss_attumen() : CreatureScript("boss_attumen") { }
struct boss_attumenAI : public BossAI
boss_attumen(Creature* creature) : BossAI(creature, DATA_ATTUMEN)
{
boss_attumenAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN)
{
Initialize();
}
Initialize();
}
void Initialize()
void Initialize()
{
_phase = PHASE_NONE;
}
void Reset() override
{
Initialize();
}
bool CanMeleeHit()
{
return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f);
}
void EnterEvadeMode(EvadeReason why) override
{
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
midnight->AI()->EnterEvadeMode(why);
}
me->DespawnOrUnsummon();
}
void ScheduleTasks() override
{
scheduler.Schedule(15s, 25s, [this](TaskContext task)
{
DoCastVictim(SPELL_SHADOWCLEAVE);
task.Repeat(15s, 25s);
});
scheduler.Schedule(25s, 45s, [this](TaskContext task)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
DoCast(target, SPELL_INTANGIBLE_PRESENCE);
}
task.Repeat(25s, 45s);
});
scheduler.Schedule(30s, 1min, [this](TaskContext task)
{
Talk(SAY_RANDOM);
task.Repeat(30s, 1min);
});
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override
{
// Attumen does not die until he mounts Midnight, let health fall to 1 and prevent further damage.
if (damage >= me->GetHealth() && _phase != PHASE_MOUNTED)
{
damage = me->GetHealth() - 1;
}
if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage))
{
_phase = PHASE_NONE;
}
void Reset() override
{
Initialize();
}
bool CanMeleeHit()
{
return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f);
}
void EnterEvadeMode(EvadeReason why) override
{
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
midnight->AI()->EnterEvadeMode(why);
}
me->DespawnOrUnsummon();
}
void ScheduleTasks() override
{
scheduler.Schedule(Seconds(15), Seconds(25), [this](TaskContext task)
{
DoCastVictim(SPELL_SHADOWCLEAVE);
task.Repeat(Seconds(15), Seconds(25));
});
scheduler.Schedule(Seconds(25), Seconds(45), [this](TaskContext task)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
DoCast(target, SPELL_INTANGIBLE_PRESENCE);
}
task.Repeat(Seconds(25), Seconds(45));
});
scheduler.Schedule(Seconds(30), Seconds(60), [this](TaskContext task)
{
Talk(SAY_RANDOM);
task.Repeat(Seconds(30), Seconds(60));
});
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override
{
// Attumen does not die until he mounts Midnight, let health fall to 1 and prevent further damage.
if (damage >= me->GetHealth() && _phase != PHASE_MOUNTED)
{
damage = me->GetHealth() - 1;
}
if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage))
{
_phase = PHASE_NONE;
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
midnight->AI()->DoCastAOE(SPELL_MOUNT, true);
}
midnight->AI()->DoCastAOE(SPELL_MOUNT, true);
}
}
}
void KilledUnit(Unit* /*victim*/) override
void KilledUnit(Unit* victim) override
{
if (victim->GetTypeId() == TYPEID_PLAYER)
{
Talk(SAY_KILL);
}
}
void JustSummoned(Creature* summon) override
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED)
{
if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED)
{
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
if (midnight->GetHealth() > me->GetHealth())
{
summon->SetHealth(midnight->GetHealth());
}
else
{
summon->SetHealth(me->GetHealth());
}
summon->AI()->DoZoneInCombat();
}
}
BossAI::JustSummoned(summon);
}
void IsSummonedBy(WorldObject* summoner) override
{
if (summoner->GetEntry() == NPC_MIDNIGHT)
{
_phase = PHASE_ATTUMEN_ENGAGES;
}
if (summoner->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN)
{
_phase = PHASE_MOUNTED;
DoCastSelf(SPELL_SPAWN_SMOKE);
scheduler.Schedule(Seconds(10), Seconds(25), [this](TaskContext task)
{
Unit* target = nullptr;
std::vector<Unit*> target_list;
for (auto* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
target = ref->GetVictim();
if (target && !target->IsWithinDist(me, 8.00f, false) && target->IsWithinDist(me, 25.0f, false))
target_list.push_back(target);
target = nullptr;
}
if (!target_list.empty())
{
target = Acore::Containers::SelectRandomContainerElement(target_list);
}
DoCast(target, SPELL_CHARGE);
task.Repeat(Seconds(10), Seconds(25));
});
scheduler.Schedule(Seconds(25), Seconds(35), [this](TaskContext task)
{
DoCastVictim(SPELL_KNOCKDOWN);
task.Repeat(Seconds(25), Seconds(35));
});
}
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
midnight->KillSelf();
if (midnight->GetHealth() > me->GetHealth())
{
summon->SetHealth(midnight->GetHealth());
}
else
{
summon->SetHealth(me->GetHealth());
}
summon->AI()->DoZoneInCombat();
}
}
BossAI::JustSummoned(summon);
}
_JustDied();
void IsSummonedBy(WorldObject* summoner) override
{
if (summoner->GetEntry() == NPC_MIDNIGHT)
{
_phase = PHASE_ATTUMEN_ENGAGES;
}
if (summoner->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN)
{
_phase = PHASE_MOUNTED;
DoCastSelf(SPELL_SPAWN_SMOKE);
scheduler.Schedule(10s, 25s, [this](TaskContext task)
{
Unit* target = nullptr;
std::vector<Unit*> target_list;
for (auto* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
target = ref->GetVictim();
if (target && !target->IsWithinDist(me, 8.00f, false) && target->IsWithinDist(me, 25.0f, false))
{
target_list.push_back(target);
}
target = nullptr;
}
if (!target_list.empty())
{
target = Acore::Containers::SelectRandomContainerElement(target_list);
}
DoCast(target, SPELL_CHARGE);
task.Repeat(10s, 25s);
});
scheduler.Schedule(25s, 35s, [this](TaskContext task)
{
DoCastVictim(SPELL_KNOCKDOWN);
task.Repeat(25s, 35s);
});
}
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
midnight->KillSelf();
}
_JustDied();
}
void UpdateAI(uint32 diff) override
{
if (_phase != PHASE_NONE)
{
if (!UpdateVictim())
{
return;
}
}
if (!CanMeleeHit())
{
BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY);
}
scheduler.Update(diff, std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
if (spellInfo->Mechanic == MECHANIC_DISARM)
{
Talk(SAY_DISARMED);
}
void UpdateAI(uint32 diff) override
if (spellInfo->Id == SPELL_MOUNT)
{
if (_phase != PHASE_NONE)
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
if (!UpdateVictim())
_phase = PHASE_NONE;
scheduler.CancelAll();
midnight->AI()->DoAction(ACTION_SET_MIDNIGHT_PHASE);
midnight->AttackStop();
midnight->RemoveAllAttackers();
midnight->SetReactState(REACT_PASSIVE);
midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f);
midnight->AI()->Talk(EMOTE_MOUNT_UP);
me->AttackStop();
me->RemoveAllAttackers();
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f);
Talk(SAY_MOUNT);
scheduler.Schedule(1s, [this](TaskContext task)
{
return;
}
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
if (me->IsWithinDist2d(midnight, 5.0f))
{
DoCastAOE(SPELL_SUMMON_ATTUMEN_MOUNTED);
me->DespawnOrUnsummon(1s, 0s);
midnight->SetVisible(false);
}
else
{
midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f);
me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f);
task.Repeat();
}
}
});
}
}
}
private:
uint8 _phase;
};
struct boss_midnight : public BossAI
{
boss_midnight(Creature* creature) : BossAI(creature, DATA_ATTUMEN), _phase(PHASE_NONE) { }
void Reset() override
{
BossAI::Reset();
me->SetVisible(true);
me->SetReactState(REACT_DEFENSIVE);
}
bool CanMeleeHit()
{
return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override
{
// Midnight never dies, let health fall to 1 and prevent further damage.
if (damage >= me->GetHealth())
{
damage = me->GetHealth() - 1;
}
if (_phase == PHASE_NONE && me->HealthBelowPctDamaged(95, damage))
{
_phase = PHASE_ATTUMEN_ENGAGES;
Talk(EMOTE_CALL_ATTUMEN);
DoCastAOE(SPELL_SUMMON_ATTUMEN);
}
else if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage))
{
_phase = PHASE_MOUNTED;
DoCastAOE(SPELL_MOUNT, true);
}
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN)
{
summon->AI()->AttackStart(me->GetVictim());
summon->AI()->Talk(SAY_APPEAR);
}
BossAI::JustSummoned(summon);
}
void DoAction(int32 actionId) override
{
if (actionId == ACTION_SET_MIDNIGHT_PHASE)
{
_phase = PHASE_MOUNTED;
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
scheduler.Schedule(15s, 25s, [this](TaskContext task)
{
DoCastVictim(SPELL_KNOCKDOWN);
task.Repeat(15s, 25s);
});
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
me->DespawnOnEvade(10s);
_phase = PHASE_NONE;
}
void KilledUnit(Unit* /*victim*/) override
{
if (_phase == PHASE_ATTUMEN_ENGAGES)
{
if (Creature* attumen = instance->GetCreature(DATA_ATTUMEN))
{
Talk(SAY_MIDNIGHT_KILL, attumen);
}
}
}
void UpdateAI(uint32 diff) override
{
if (_phase != PHASE_MOUNTED)
{
if (!UpdateVictim())
{
return;
}
if (!CanMeleeHit())
{
BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY);
}
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
if (spellInfo->Mechanic == MECHANIC_DISARM)
{
Talk(SAY_DISARMED);
}
if (spellInfo->Id == SPELL_MOUNT)
{
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
_phase = PHASE_NONE;
scheduler.CancelAll();
midnight->AI()->DoAction(ACTION_SET_MIDNIGHT_PHASE);
midnight->AttackStop();
midnight->RemoveAllAttackers();
midnight->SetReactState(REACT_PASSIVE);
midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f);
midnight->AI()->Talk(EMOTE_MOUNT_UP);
me->AttackStop();
me->RemoveAllAttackers();
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f);
Talk(SAY_MOUNT);
scheduler.Schedule(Seconds(1), [this](TaskContext task)
{
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
{
if (me->IsWithinDist2d(midnight, 5.0f))
{
DoCastAOE(SPELL_SUMMON_ATTUMEN_MOUNTED);
me->DespawnOrUnsummon(1s, 0s);
midnight->SetVisible(false);
}
else
{
midnight->GetMotionMaster()->MoveFollow(me, 2.0f, 0.0f);
me->GetMotionMaster()->MoveFollow(midnight, 2.0f, 0.0f);
task.Repeat();
}
}
});
}
}
}
private:
uint8 _phase;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetKarazhanAI<boss_attumenAI>(creature);
scheduler.Update(diff, std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
private:
uint8 _phase;
};
class boss_midnight : public CreatureScript
class spell_midnight_fixate : public AuraScript
{
public:
boss_midnight() : CreatureScript("boss_midnight") { }
PrepareAuraScript(spell_midnight_fixate)
struct boss_midnightAI : public BossAI
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
boss_midnightAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN), _phase(PHASE_NONE) { }
void Reset() override
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
{
BossAI::Reset();
me->SetVisible(true);
me->SetReactState(REACT_DEFENSIVE);
caster->TauntApply(target);
}
bool CanMeleeHit()
{
return me->GetVictim() && (me->GetVictim()->GetPositionZ() < 53.0f || me->GetVictim()->GetDistance(me->GetHomePosition()) < 50.0f);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override
{
// Midnight never dies, let health fall to 1 and prevent further damage.
if (damage >= me->GetHealth())
{
damage = me->GetHealth() - 1;
}
if (_phase == PHASE_NONE && me->HealthBelowPctDamaged(95, damage))
{
_phase = PHASE_ATTUMEN_ENGAGES;
Talk(EMOTE_CALL_ATTUMEN);
DoCastAOE(SPELL_SUMMON_ATTUMEN);
}
else if (_phase == PHASE_ATTUMEN_ENGAGES && me->HealthBelowPctDamaged(25, damage))
{
_phase = PHASE_MOUNTED;
DoCastAOE(SPELL_MOUNT, true);
}
}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_ATTUMEN_THE_HUNTSMAN)
{
summon->AI()->AttackStart(me->GetVictim());
summon->AI()->Talk(SAY_APPEAR);
}
BossAI::JustSummoned(summon);
}
void DoAction(int32 actionId) override
{
if (actionId == ACTION_SET_MIDNIGHT_PHASE)
{
_phase = PHASE_MOUNTED;
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
scheduler.Schedule(Seconds(15), Seconds(25), [this](TaskContext task)
{
DoCastVictim(SPELL_KNOCKDOWN);
task.Repeat(Seconds(15), Seconds(25));
});
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
me->DespawnOnEvade(10s);
_phase = PHASE_NONE;
}
void KilledUnit(Unit* /*victim*/) override
{
if (_phase == PHASE_ATTUMEN_ENGAGES)
{
if (Creature* attumen = instance->GetCreature(DATA_ATTUMEN))
{
Talk(SAY_MIDNIGHT_KILL, attumen);
}
}
}
void UpdateAI(uint32 diff) override
{
if (_phase != PHASE_MOUNTED)
{
if (!UpdateVictim())
{
return;
}
if (!CanMeleeHit())
{
BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY);
}
}
scheduler.Update(diff,
std::bind(&BossAI::DoMeleeAttackIfReady, this));
}
private:
uint8 _phase;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetKarazhanAI<boss_midnightAI>(creature);
}
};
class spell_midnight_fixate : public SpellScriptLoader
{
public:
spell_midnight_fixate() : SpellScriptLoader("spell_midnight_fixate") { }
class spell_midnight_fixate_AuraScript : public AuraScript
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
PrepareAuraScript(spell_midnight_fixate_AuraScript);
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
caster->TauntApply(target);
caster->TauntFadeOut(target);
}
}
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
caster->TauntFadeOut(target);
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_midnight_fixate_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_midnight_fixate_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
void Register() override
{
return new spell_midnight_fixate_AuraScript();
OnEffectApply += AuraEffectApplyFn(spell_midnight_fixate::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_midnight_fixate::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_boss_attumen()
{
new boss_midnight();
new boss_attumen();
new spell_midnight_fixate();
RegisterKarazhanCreatureAI(boss_midnight);
RegisterKarazhanCreatureAI(boss_attumen);
RegisterSpellScript(spell_midnight_fixate);
}

View File

@@ -46,19 +46,15 @@ enum Spells
enum Misc
{
EVENT_GUEST_TALK = 1,
EVENT_GUEST_TALK2 = 2,
EVENT_SPELL_VANISH = 3,
EVENT_SPELL_GARROTE = 4,
EVENT_SPELL_BLIND = 5,
EVENT_SPELL_GOUGE = 6,
EVENT_SPELL_ENRAGE = 7,
EVENT_KILL_TALK = 8,
ACTIVE_GUEST_COUNT = 4,
MAX_GUEST_COUNT = 6
};
enum Groups
{
GROUP_PRECOMBAT_TALK = 0
};
const Position GuestsPosition[4] =
{
{-10987.38f, -1883.38f, 81.73f, 1.50f},
@@ -78,6 +74,10 @@ struct boss_moroes : public BossAI
boss_moroes(Creature* creature) : BossAI(creature, DATA_MOROES)
{
_activeGuests = 0;
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void InitializeAI() override
@@ -111,46 +111,83 @@ struct boss_moroes : public BossAI
me->SummonCreature(GuestEntries[i], GuestsPosition[summons.size()], TEMPSUMMON_MANUAL_DESPAWN);
}
}
_events2.Reset();
_events2.ScheduleEvent(EVENT_GUEST_TALK, 10s);
scheduler.Schedule(10s, GROUP_PRECOMBAT_TALK, [this](TaskContext context)
{
if(Creature* guest = GetRandomGuest())
{
guest->AI()->Talk(SAY_GUEST);
}
context.Repeat(5s);
}).Schedule(1min, 2min, GROUP_PRECOMBAT_TALK, [this](TaskContext context)
{
//this was not scheduled in the previous commit
//does this have to be removed?
Talk(SAY_OUT_OF_COMBAT);
context.Repeat(1min, 2min);
});
}
void Reset() override
{
BossAI::Reset();
DoCastSelf(SPELL_DUAL_WIELD, true);
_recentlySpoken = false;
_vanished = false;
ScheduleHealthCheckEvent(30, [&] {
DoCastSelf(SPELL_FRENZY, true);
});
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_VANISH, 30s);
events.ScheduleEvent(EVENT_SPELL_BLIND, 20s);
events.ScheduleEvent(EVENT_SPELL_GOUGE, 13s);
events.ScheduleEvent(EVENT_SPELL_ENRAGE, 10min);
_events2.Reset();
me->CallForHelp(20.0f);
DoZoneInCombat();
}
scheduler.CancelGroup(GROUP_PRECOMBAT_TALK);
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
{
if (HealthBelowPct(30))
scheduler.Schedule(30s, [this](TaskContext context)
{
DoCastSelf(SPELL_FRENZY, true);
}
scheduler.DelayAll(9s);
_vanished = true;
Talk(SAY_SPECIAL);
DoCastSelf(SPELL_VANISH);
me->SetImmuneToAll(true);
scheduler.Schedule(5s, 7s, [this](TaskContext)
{
me->SetImmuneToAll(false);
DoCastRandomTarget(SPELL_GARROTE, 0, 100.0f, true, true);
DoCastSelf(SPELL_VANISH_TELEPORT);
_vanished = false;
});
context.Repeat(30s);
}).Schedule(20s, [this](TaskContext context)
{
DoCastMaxThreat(SPELL_BLIND, 1, 10.0f, true);
context.Repeat(25s, 40s);
}).Schedule(13s, [this](TaskContext context)
{
DoCastVictim(SPELL_GOUGE);
context.Repeat(25s, 40s);
}).Schedule(10min, [this](TaskContext)
{
DoCastSelf(SPELL_BERSERK, true);
});
}
void KilledUnit(Unit* victim) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
if(!_recentlySpoken && victim->GetTypeId() == TYPEID_PLAYER)
{
if (victim->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_KILL);
_recentlySpoken = true;
scheduler.Schedule(5s, [this](TaskContext)
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 5s);
}
_recentlySpoken = false;
});
}
}
@@ -176,66 +213,22 @@ struct boss_moroes : public BossAI
void UpdateAI(uint32 diff) override
{
_events2.Update(diff);
switch (_events2.ExecuteEvent())
{
case EVENT_GUEST_TALK:
if (Creature* guest = GetRandomGuest())
{
guest->AI()->Talk(SAY_GUEST);
}
_events2.Repeat(5s);
break;
case EVENT_GUEST_TALK2:
Talk(SAY_OUT_OF_COMBAT);
_events2.Repeat(1min, 2min);
break;
}
scheduler.Update(diff);
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
if (_vanished == false)
{
case EVENT_SPELL_ENRAGE:
DoCastSelf(SPELL_BERSERK, true);
break;
case EVENT_SPELL_BLIND:
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 10.0f, true))
{
DoCast(target, SPELL_BLIND);
}
events.Repeat(25s, 40s);
break;
case EVENT_SPELL_GOUGE:
DoCastVictim(SPELL_GOUGE);
events.Repeat(25s, 40s);
return;
case EVENT_SPELL_VANISH:
events.DelayEvents(9s);
events.SetPhase(1);
DoCastSelf(SPELL_VANISH);
events.Repeat(30s);
events.ScheduleEvent(EVENT_SPELL_GARROTE, 5s, 7s);
return;
case EVENT_SPELL_GARROTE:
Talk(SAY_SPECIAL);
DoCastRandomTarget(SPELL_GARROTE, 0, 100.0f, true, true);
DoCastSelf(SPELL_VANISH_TELEPORT);
events.SetPhase(0);
break;
}
if (events.GetPhaseMask() == 0) // Xinef: not in vanish
DoMeleeAttackIfReady();
}
}
private:
EventMap _events2;
uint8 _activeGuests;
bool _recentlySpoken;
bool _vanished;
};
class spell_moroes_vanish : public SpellScript

View File

@@ -19,7 +19,7 @@
#include "ScriptedCreature.h"
#include "karazhan.h"
enum ServantQuartersSpells
enum Spells
{
SPELL_SNEAK = 22766,
SPELL_ACIDIC_FANG = 29901,
@@ -33,41 +33,37 @@ enum ServantQuartersSpells
SPELL_RAVAGE = 29906
};
enum ServantQuertersMisc
{
EVENT_SPELL_ACIDIC_FANG = 1,
EVENT_SPELL_HYAKISS_WEB = 2,
EVENT_SPELL_DIVE = 10,
EVENT_SPELL_SONIC_BURST = 11,
EVENT_SPELL_WING_BUFFET = 12,
EVENT_SPELL_FEAR = 13,
EVENT_SPELL_RAVAGE = 20,
EVENT_CHECK_VISIBILITY = 30
};
struct boss_servant_quarters : public BossAI
{
boss_servant_quarters(Creature* creature) : BossAI(creature, DATA_SERVANT_QUARTERS) { }
void Reset() override
{
events.Reset();
_scheduler.CancelAll();
me->SetVisible(false);
me->SetReactState(REACT_PASSIVE);
me->SetFaction(FACTION_FRIENDLY);
_events2.Reset();
_events2.ScheduleEvent(EVENT_CHECK_VISIBILITY, 5s);
_scheduler.Schedule(5s, [this](TaskContext context)
{
if (instance->GetBossState(DATA_SERVANT_QUARTERS) == DONE)
{
me->SetVisible(true);
me->SetReactState(REACT_AGGRESSIVE);
me->RestoreFaction();
}
else
{
context.Repeat(5s);
}
});
if (me->GetEntry() == NPC_HYAKISS_THE_LURKER)
{
DoCastSelf(SPELL_SNEAK, true);
}
if (instance->GetData(DATA_SELECTED_RARE) != me->GetEntry())
{
me->DespawnOrUnsummon(1);
}
}
void JustEngagedWith(Unit* /*who*/) override
@@ -75,18 +71,42 @@ struct boss_servant_quarters : public BossAI
me->setActive(true);
if (me->GetEntry() == NPC_HYAKISS_THE_LURKER)
{
events.ScheduleEvent(EVENT_SPELL_ACIDIC_FANG, 5s);
events.ScheduleEvent(EVENT_SPELL_HYAKISS_WEB, 9s);
_scheduler.Schedule(5s, [this](TaskContext context)
{
DoCastVictim(SPELL_ACIDIC_FANG);
context.Repeat(12s, 18s);
}).Schedule(9s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_HYAKISS_WEB, 0, 30.0f);
context.Repeat(15s);
});
}
else if (me->GetEntry() == NPC_SHADIKITH_THE_GLIDER)
{
events.ScheduleEvent(EVENT_SPELL_SONIC_BURST, 4s);
events.ScheduleEvent(EVENT_SPELL_WING_BUFFET, 7s);
events.ScheduleEvent(EVENT_SPELL_DIVE, 10s);
_scheduler.Schedule(4s, [this](TaskContext context)
{
DoCastSelf(SPELL_SONIC_BURST);
context.Repeat(12s, 18s);
}).Schedule(7s, [this](TaskContext context)
{
DoCastSelf(SPELL_WING_BUFFET);
context.Repeat(12s, 18s);
}).Schedule(10s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, 40.0f, false, true)))
{
me->CastSpell(target, SPELL_DIVE);
}
context.Repeat(20s);
});
}
else // if (me->GetEntry() == NPC_ROKAD_THE_RAVAGER)
{
events.ScheduleEvent(EVENT_SPELL_RAVAGE, 3s);
_scheduler.Schedule(3s, [this](TaskContext context)
{
DoCastVictim(SPELL_RAVAGE);
context.Repeat(10500ms);
});
}
}
@@ -97,70 +117,28 @@ struct boss_servant_quarters : public BossAI
void MovementInform(uint32 type, uint32 point) override
{
if (type == POINT_MOTION_TYPE && point == EVENT_CHARGE)
events.ScheduleEvent(EVENT_SPELL_FEAR, 0);
{
_scheduler.Schedule(1ms, [this](TaskContext /*context*/)
{
DoCastVictim(SPELL_FEAR);
});
}
}
void UpdateAI(uint32 diff) override
{
_events2.Update(diff);
switch (_events2.ExecuteEvent())
{
case EVENT_CHECK_VISIBILITY:
if (instance->GetBossState(DATA_SERVANT_QUARTERS) == DONE)
{
me->SetVisible(true);
me->SetReactState(REACT_AGGRESSIVE);
me->RestoreFaction();
}
else
_events2.ScheduleEvent(EVENT_CHECK_VISIBILITY, 5s);
break;
}
if (!UpdateVictim())
return;
events.Update(diff);
_scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_SPELL_ACIDIC_FANG:
me->CastSpell(me->GetVictim(), SPELL_ACIDIC_FANG, false);
events.Repeat(12s, 18s);
break;
case EVENT_SPELL_HYAKISS_WEB:
DoCastRandomTarget(SPELL_HYAKISS_WEB, 0, 30.0f);
events.Repeat(15s);
break;
case EVENT_SPELL_SONIC_BURST:
DoCastSelf(SPELL_SONIC_BURST);
events.Repeat(12s, 18s);
break;
case EVENT_SPELL_WING_BUFFET:
DoCastSelf(SPELL_WING_BUFFET);
events.Repeat(12s, 18s);
break;
case EVENT_SPELL_DIVE:
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, 40.0f, false, true)))
me->CastSpell(target, SPELL_DIVE, false);
events.Repeat(20s);
break;
case EVENT_SPELL_FEAR:
DoCastVictim(SPELL_FEAR);
break;
case EVENT_SPELL_RAVAGE:
me->CastSpell(me->GetVictim(), SPELL_RAVAGE, false);
events.ScheduleEvent(EVENT_SPELL_RAVAGE, 10500);
break;
}
DoMeleeAttackIfReady();
}
private:
EventMap _events2;
TaskScheduler _scheduler;
};
void AddSC_boss_servant_quarters()

View File

@@ -20,6 +20,7 @@
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "karazhan.h"
#include "TaskScheduler.h"
enum ShadeOfAran
{
@@ -58,9 +59,9 @@ enum ShadeOfAran
SPELL_SHADOW_PYRO = 29978,
//Creatures
CREATURE_WATER_ELEMENTAL = 17167,
CREATURE_SHADOW_OF_ARAN = 18254,
CREATURE_ARAN_BLIZZARD = 17161,
NPC_WATER_ELEMENTAL = 17167,
NPC_SHADOW_OF_ARAN = 18254,
NPC_ARAN_BLIZZARD = 17161,
};
enum SuperSpell
@@ -70,560 +71,458 @@ enum SuperSpell
SUPER_AE,
};
class boss_shade_of_aran : public CreatureScript
enum Groups
{
public:
boss_shade_of_aran() : CreatureScript("boss_shade_of_aran") { }
GROUP_FLAMEWREATH = 0,
GROUP_DRINKING = 1
};
struct boss_aranAI : public BossAI
Position const elementalPos[4] =
{
{-11168.1f, -1939.29f, 232.092f, 1.46f},
{-11138.2f, -1915.38f, 232.092f, 3.00f},
{-11161.7f, -1885.36f, 232.092f, 4.59f},
{-11192.4f, -1909.36f, 232.092f, 6.19f}
};
struct boss_shade_of_aran : public BossAI
{
boss_shade_of_aran(Creature* creature) : BossAI(creature, DATA_ARAN)
{
boss_aranAI(Creature* creature) : BossAI(creature, DATA_ARAN)
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
uint8 LastSuperSpell;
ObjectGuid FlameWreathTarget[3];
float FWTargPosX[3];
float FWTargPosY[3];
uint32 CurrentNormalSpell;
bool Drinking;
void Reset() override
{
BossAI::Reset();
drinkScheduler.CancelAll();
LastSuperSpell = rand() % 3;
for (uint8 i = 0; i < 3; ++i)
FlameWreathTarget[i].Clear();
CurrentNormalSpell = 0;
_arcaneCooledDown = true;
_fireCooledDown = true;
_frostCooledDown = true;
Drinking = false;
// Not in progress
instance->SetData(DATA_ARAN, NOT_STARTED);
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
{
libraryDoor->SetGoState(GO_STATE_ACTIVE);
libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
uint32 SecondarySpellTimer;
uint32 NormalCastTimer;
uint32 SuperCastTimer;
uint32 BerserkTimer;
uint32 CloseDoorTimer; // Don't close the door right on aggro in case some people are still entering.
ScheduleHealthCheckEvent(40, [&]{
Talk(SAY_ELEMENTALS);
uint8 LastSuperSpell;
uint32 FlameWreathTimer;
uint32 FlameWreathCheckTime;
ObjectGuid FlameWreathTarget[3];
float FWTargPosX[3];
float FWTargPosY[3];
uint32 CurrentNormalSpell;
uint32 ArcaneCooldown;
uint32 FireCooldown;
uint32 FrostCooldown;
uint32 DrinkInterruptTimer;
bool ElementalsSpawned;
bool Drinking;
bool DrinkInturrupted;
void Reset() override
{
SecondarySpellTimer = 5000;
NormalCastTimer = 0;
SuperCastTimer = 35000;
BerserkTimer = 720000;
CloseDoorTimer = 15000;
LastSuperSpell = rand() % 3;
FlameWreathTimer = 0;
FlameWreathCheckTime = 0;
for (uint8 i = 0; i < 3; ++i)
FlameWreathTarget[i].Clear();
CurrentNormalSpell = 0;
ArcaneCooldown = 0;
FireCooldown = 0;
FrostCooldown = 0;
DrinkInterruptTimer = 10000;
ElementalsSpawned = false;
Drinking = false;
DrinkInturrupted = false;
// Not in progress
instance->SetData(DATA_ARAN, NOT_STARTED);
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
for(Position pos : elementalPos)
{
libraryDoor->SetGoState(GO_STATE_ACTIVE);
libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
if(Creature* elemental = me->SummonCreature(NPC_WATER_ELEMENTAL, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000))
{
if(Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true))
{
DoStartNoMovement(target);
elemental->SetInCombatWithZone();
elemental->CombatStart(target);
}
}
}
}
});
}
void KilledUnit(Unit* /*victim*/) override
void KilledUnit(Unit* /*victim*/) override
{
Talk(SAY_KILL);
}
void TriggerArcaneCooldown()
{
scheduler.Schedule(5s, [this](TaskContext)
{
Talk(SAY_KILL);
}
_arcaneCooledDown = true;
});
}
void JustDied(Unit* /*killer*/) override
void TriggerFireCooldown()
{
scheduler.Schedule(5s, [this](TaskContext)
{
Talk(SAY_DEATH);
_fireCooledDown = true;
});
}
instance->SetData(DATA_ARAN, DONE);
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
{
libraryDoor->SetGoState(GO_STATE_ACTIVE);
libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
}
void JustEngagedWith(Unit* /*who*/) override
void TriggerFrostCooldown()
{
scheduler.Schedule(5s, [this](TaskContext)
{
Talk(SAY_AGGRO);
_frostCooledDown = true;
});
}
instance->SetData(DATA_ARAN, IN_PROGRESS);
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
instance->SetData(DATA_ARAN, DONE);
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
{
libraryDoor->SetGoState(GO_STATE_ACTIVE);
libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
instance->SetData(DATA_ARAN, IN_PROGRESS);
DoZoneInCombat();
//handle timed closing door
scheduler.Schedule(15s, [this](TaskContext)
{
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
{
libraryDoor->SetGoState(GO_STATE_READY);
libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
DoZoneInCombat();
}
void FlameWreathEffect()
}).Schedule(1ms, [this](TaskContext context)
{
std::vector<Unit*> targets;
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
if (t_list.empty())
return;
//store the threat list in a different container
for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
if (!me->IsNonMeleeSpellCast(false))
{
Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
//only on alive players
if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
targets.push_back(target);
}
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
if (!target)
return;
//cut down to size if we have more than 3 targets
while (targets.size() > 3)
targets.erase(targets.begin() + rand() % targets.size());
uint32 Spells[3];
uint8 AvailableSpells = 0;
uint32 i = 0;
for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
{
if (*itr)
//Check for what spells are not on cooldown
if (_arcaneCooledDown)
{
FlameWreathTarget[i] = (*itr)->GetGUID();
FWTargPosX[i] = (*itr)->GetPositionX();
FWTargPosY[i] = (*itr)->GetPositionY();
DoCast((*itr), SPELL_FLAME_WREATH, true);
++i;
Spells[AvailableSpells] = SPELL_ARCMISSLE;
++AvailableSpells;
}
if (_fireCooledDown)
{
Spells[AvailableSpells] = SPELL_FIREBALL;
++AvailableSpells;
}
if (_frostCooledDown)
{
Spells[AvailableSpells] = SPELL_FROSTBOLT;
++AvailableSpells;
}
//If no available spells wait 1 second and try again
if (AvailableSpells)
{
CurrentNormalSpell = Spells[rand() % AvailableSpells];
DoCast(target, CurrentNormalSpell);
}
}
}
void UpdateAI(uint32 diff) override
context.Repeat(10s);
}).Schedule(5s, [this](TaskContext context)
{
if (!UpdateVictim())
return;
if (CloseDoorTimer)
switch (urand(0, 1))
{
if (CloseDoorTimer <= diff)
{
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
case 0:
DoCastSelf(SPELL_AOE_CS);
break;
case 1:
DoCastRandomTarget(SPELL_CHAINSOFICE);
break;
}
context.Repeat(5s, 20s);
}).Schedule(35s, [this](TaskContext context)
{
uint8 Available[2];
switch (LastSuperSpell)
{
case SUPER_AE:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_FLAME:
Available[0] = SUPER_AE;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_BLIZZARD:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_AE;
break;
}
LastSuperSpell = Available[urand(0, 1)];
switch (LastSuperSpell)
{
case SUPER_AE:
Talk(SAY_EXPLOSION);
DoCastSelf(SPELL_BLINK_CENTER, true);
DoCastSelf(SPELL_PLAYERPULL, true);
DoCastSelf(SPELL_MASSSLOW, true);
DoCastSelf(SPELL_AEXPLOSION, false);
break;
case SUPER_FLAME:
Talk(SAY_FLAMEWREATH);
scheduler.Schedule(20s, GROUP_FLAMEWREATH, [this](TaskContext)
{
libraryDoor->SetGoState(GO_STATE_READY);
libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
CloseDoorTimer = 0;
}
else
CloseDoorTimer -= diff;
}
//Cooldowns for casts
if (ArcaneCooldown)
{
if (ArcaneCooldown >= diff)
ArcaneCooldown -= diff;
else
ArcaneCooldown = 0;
}
if (FireCooldown)
{
if (FireCooldown >= diff)
FireCooldown -= diff;
else
FireCooldown = 0;
}
if (FrostCooldown)
{
if (FrostCooldown >= diff)
FrostCooldown -= diff;
else
FrostCooldown = 0;
}
if (!Drinking && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20)
{
Drinking = true;
me->InterruptNonMeleeSpells(false);
Talk(SAY_DRINK);
if (!DrinkInturrupted)
{
DoCast(me, SPELL_MASS_POLY, true);
DoCast(me, SPELL_CONJURE, false);
DoCast(me, SPELL_DRINK, false);
me->SetStandState(UNIT_STAND_STATE_SIT);
DrinkInterruptTimer = 10000;
}
}
//Drink Interrupt
if (Drinking && DrinkInturrupted)
{
Drinking = false;
me->RemoveAurasDueToSpell(SPELL_DRINK);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCast(me, SPELL_POTION, false);
}
//Drink Interrupt Timer
if (Drinking && !DrinkInturrupted)
{
if (DrinkInterruptTimer >= diff)
DrinkInterruptTimer -= diff;
else
{
me->SetStandState(UNIT_STAND_STATE_STAND);
DoCast(me, SPELL_POTION, true);
DoCast(me, SPELL_AOE_PYROBLAST, false);
DrinkInturrupted = true;
Drinking = false;
}
}
//Don't execute any more code if we are drinking
if (Drinking)
return;
//Normal casts
if (NormalCastTimer <= diff)
{
if (!me->IsNonMeleeSpellCast(false))
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
if (!target)
return;
uint32 Spells[3];
uint8 AvailableSpells = 0;
//Check for what spells are not on cooldown
if (!ArcaneCooldown)
scheduler.CancelGroup(GROUP_FLAMEWREATH);
}).Schedule(500ms, GROUP_FLAMEWREATH, [this](TaskContext context)
{
Spells[AvailableSpells] = SPELL_ARCMISSLE;
++AvailableSpells;
}
if (!FireCooldown)
{
Spells[AvailableSpells] = SPELL_FIREBALL;
++AvailableSpells;
}
if (!FrostCooldown)
{
Spells[AvailableSpells] = SPELL_FROSTBOLT;
++AvailableSpells;
}
//If no available spells wait 1 second and try again
if (AvailableSpells)
{
CurrentNormalSpell = Spells[rand() % AvailableSpells];
DoCast(target, CurrentNormalSpell);
}
}
NormalCastTimer = 1000;
}
else
NormalCastTimer -= diff;
if (SecondarySpellTimer <= diff)
{
switch (urand(0, 1))
{
case 0:
DoCast(me, SPELL_AOE_CS);
break;
case 1:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(target, SPELL_CHAINSOFICE);
break;
}
SecondarySpellTimer = urand(5000, 20000);
}
else
SecondarySpellTimer -= diff;
if (SuperCastTimer <= diff)
{
uint8 Available[2];
switch (LastSuperSpell)
{
case SUPER_AE:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_FLAME:
Available[0] = SUPER_AE;
Available[1] = SUPER_BLIZZARD;
break;
case SUPER_BLIZZARD:
Available[0] = SUPER_FLAME;
Available[1] = SUPER_AE;
break;
}
LastSuperSpell = Available[urand(0, 1)];
switch (LastSuperSpell)
{
case SUPER_AE:
Talk(SAY_EXPLOSION);
DoCast(me, SPELL_BLINK_CENTER, true);
DoCast(me, SPELL_PLAYERPULL, true);
DoCast(me, SPELL_MASSSLOW, true);
DoCast(me, SPELL_AEXPLOSION, false);
break;
case SUPER_FLAME:
Talk(SAY_FLAMEWREATH);
FlameWreathTimer = 20000;
FlameWreathCheckTime = 500;
FlameWreathTarget[0].Clear();
FlameWreathTarget[1].Clear();
FlameWreathTarget[2].Clear();
FlameWreathEffect();
break;
case SUPER_BLIZZARD:
Talk(SAY_BLIZZARD);
if (Creature* pSpawn = me->SummonCreature(CREATURE_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000))
for (uint8 i = 0; i < 3; ++i)
{
pSpawn->SetFaction(me->GetFaction());
pSpawn->CastSpell(pSpawn, SPELL_CIRCULAR_BLIZZARD, false);
if (!FlameWreathTarget[i])
continue;
Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]);
if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
{
unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
unit->CastSpell(unit, 11027, true);
FlameWreathTarget[i].Clear();
}
}
break;
}
context.Repeat(500ms);
});
SuperCastTimer = urand(35000, 40000);
}
else
SuperCastTimer -= diff;
FlameWreathTarget[0].Clear();
FlameWreathTarget[1].Clear();
FlameWreathTarget[2].Clear();
if (!ElementalsSpawned && HealthBelowPct(40))
{
ElementalsSpawned = true;
FlameWreathEffect();
break;
Creature* ElementalOne = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11168.1f, -1939.29f, 232.092f, 1.46f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000);
Creature* ElementalTwo = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11138.2f, -1915.38f, 232.092f, 3.00f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000);
Creature* ElementalThree = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11161.7f, -1885.36f, 232.092f, 4.59f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000);
Creature* ElementalFour = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11192.4f, -1909.36f, 232.092f, 6.19f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000);
case SUPER_BLIZZARD:
Talk(SAY_BLIZZARD);
if (ElementalOne)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true);
if (!target)
return;
DoStartNoMovement(target);
ElementalOne->SetInCombatWithZone();
ElementalOne->CombatStart(target);
ElementalOne->SetFaction(me->GetFaction());
ElementalOne->SetUnitMovementFlags(MOVEMENTFLAG_ROOT);
ElementalOne->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0);
}
if (ElementalTwo)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true);
if (!target)
return;
DoStartNoMovement(target);
ElementalTwo->SetInCombatWithZone();
ElementalTwo->CombatStart(target);
ElementalTwo->SetFaction(me->GetFaction());
ElementalTwo->SetUnitMovementFlags(MOVEMENTFLAG_ROOT);
ElementalTwo->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0);
}
if (ElementalThree)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true);
if (!target)
return;
DoStartNoMovement(target);
ElementalThree->SetInCombatWithZone();
ElementalThree->CombatStart(target);
ElementalThree->SetFaction(me->GetFaction());
ElementalThree->SetUnitMovementFlags(MOVEMENTFLAG_ROOT);
ElementalThree->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0);
}
if (ElementalFour)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100, true);
if (!target)
return;
DoStartNoMovement(target);
ElementalFour->SetInCombatWithZone();
ElementalFour->CombatStart(target);
ElementalFour->SetFaction(me->GetFaction());
ElementalFour->SetUnitMovementFlags(MOVEMENTFLAG_ROOT);
ElementalFour->SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, 0);
}
Talk(SAY_ELEMENTALS);
}
if (BerserkTimer <= diff)
{
for (uint32 i = 0; i < 5; ++i)
{
if (Creature* unit = me->SummonCreature(CREATURE_SHADOW_OF_ARAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000))
if (Creature* pSpawn = me->SummonCreature(NPC_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000))
{
unit->Attack(me->GetVictim(), true);
unit->SetFaction(me->GetFaction());
pSpawn->SetFaction(me->GetFaction());
pSpawn->CastSpell(me, SPELL_CIRCULAR_BLIZZARD, false);
}
}
Talk(SAY_TIMEOVER);
BerserkTimer = 60000;
break;
}
else
BerserkTimer -= diff;
//Flame Wreath check
if (FlameWreathTimer)
context.Repeat(35s, 40s);
}).Schedule(12min, [this](TaskContext context)
{
for (uint32 i = 0; i < 5; ++i)
{
if (FlameWreathTimer >= diff)
FlameWreathTimer -= diff;
else
FlameWreathTimer = 0;
if (FlameWreathCheckTime <= diff)
if (Creature* unit = me->SummonCreature(NPC_SHADOW_OF_ARAN, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000))
{
for (uint8 i = 0; i < 3; ++i)
{
if (!FlameWreathTarget[i])
continue;
Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]);
if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
{
unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
unit->CastSpell(unit, 11027, true);
FlameWreathTarget[i].Clear();
}
}
FlameWreathCheckTime = 500;
unit->Attack(me->GetVictim(), true);
unit->SetFaction(me->GetFaction());
}
else
FlameWreathCheckTime -= diff;
}
if (ArcaneCooldown && FireCooldown && FrostCooldown)
DoMeleeAttackIfReady();
Talk(SAY_TIMEOVER);
context.Repeat(1min);
});
}
void FlameWreathEffect()
{
std::vector<Unit*> targets;
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
if (t_list.empty())
return;
//store the threat list in a different container
for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
{
Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
//only on alive players
if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
targets.push_back(target);
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
//cut down to size if we have more than 3 targets
while (targets.size() > 3)
targets.erase(targets.begin() + rand() % targets.size());
uint32 i = 0;
for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
{
if (!DrinkInturrupted && Drinking && damage)
DrinkInturrupted = true;
if (*itr)
{
FlameWreathTarget[i] = (*itr)->GetGUID();
FWTargPosX[i] = (*itr)->GetPositionX();
FWTargPosY[i] = (*itr)->GetPositionY();
DoCast((*itr), SPELL_FLAME_WREATH, true);
++i;
}
}
}
void SpellHit(Unit* /*pAttacker*/, SpellInfo const* Spell) override
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
drinkScheduler.Update(diff);
if (!UpdateVictim())
return;
if (!Drinking && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20)
{
//We only care about interrupt effects and only if they are durring a spell currently being cast
if ((Spell->Effects[0].Effect != SPELL_EFFECT_INTERRUPT_CAST &&
Spell->Effects[1].Effect != SPELL_EFFECT_INTERRUPT_CAST &&
Spell->Effects[2].Effect != SPELL_EFFECT_INTERRUPT_CAST) || !me->IsNonMeleeSpellCast(false))
return;
//Interrupt effect
Drinking = true;
me->InterruptNonMeleeSpells(false);
//Normally we would set the cooldown equal to the spell duration
//but we do not have access to the DurationStore
Talk(SAY_DRINK);
switch (CurrentNormalSpell)
scheduler.DelayAll(10s);
DoCastSelf(SPELL_MASS_POLY, true);
DoCastSelf(SPELL_CONJURE, false);
me->SetReactState(REACT_PASSIVE);
me->SetStandState(UNIT_STAND_STATE_SIT);
DoCastSelf(SPELL_DRINK, true);
_currentHealth = me->GetHealth();
drinkScheduler.Schedule(500ms, GROUP_DRINKING, [this](TaskContext context)
{
case SPELL_ARCMISSLE:
ArcaneCooldown = 5000;
break;
case SPELL_FIREBALL:
FireCooldown = 5000;
break;
case SPELL_FROSTBOLT:
FrostCooldown = 5000;
break;
//check for damage to interrupt
if(CheckDamageDuringDrinking(_currentHealth))
{
Drinking = false;
me->RemoveAurasDueToSpell(SPELL_DRINK);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_POTION, false);
DoCastSelf(SPELL_AOE_PYROBLAST, false);
drinkScheduler.CancelGroup(GROUP_DRINKING);
} else {
context.Repeat(500ms);
}
}).Schedule(10s, GROUP_DRINKING, [this](TaskContext)
{
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_POTION, true);
DoCastSelf(SPELL_AOE_PYROBLAST, false);
Drinking = false;
drinkScheduler.CancelGroup(GROUP_DRINKING);
});
}
if (_arcaneCooledDown && _fireCooledDown && _frostCooledDown && !Drinking)
DoMeleeAttackIfReady();
}
bool CheckDamageDuringDrinking(uint32 oldHealth)
{
if (Drinking)
{
if (me->GetHealth() < oldHealth)
{
return true;
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetKarazhanAI<boss_aranAI>(creature);
return false;
}
void SpellHit(Unit* /*pAttacker*/, SpellInfo const* Spell) override
{
//We only care about interrupt effects and only if they are durring a spell currently being cast
if ((Spell->Effects[0].Effect != SPELL_EFFECT_INTERRUPT_CAST &&
Spell->Effects[1].Effect != SPELL_EFFECT_INTERRUPT_CAST &&
Spell->Effects[2].Effect != SPELL_EFFECT_INTERRUPT_CAST) || !me->IsNonMeleeSpellCast(false))
return;
//Interrupt effect
me->InterruptNonMeleeSpells(false);
//Normally we would set the cooldown equal to the spell duration
//but we do not have access to the DurationStore
switch (CurrentNormalSpell)
{
case SPELL_ARCMISSLE:
TriggerArcaneCooldown();
break;
case SPELL_FIREBALL:
TriggerFireCooldown();
break;
case SPELL_FROSTBOLT:
TriggerFrostCooldown();
break;
}
}
private:
TaskScheduler drinkScheduler;
bool _arcaneCooledDown;
bool _fireCooledDown;
bool _frostCooledDown;
uint32 _currentHealth;
};
class npc_aran_elemental : public CreatureScript
struct npc_aran_elemental : public ScriptedAI
{
public:
npc_aran_elemental() : CreatureScript("npc_aran_elemental") { }
CreatureAI* GetAI(Creature* creature) const override
npc_aran_elemental(Creature* creature) : ScriptedAI(creature)
{
return new water_elementalAI(creature);
SetCombatMovement(false);
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct water_elementalAI : public ScriptedAI
void Reset() override
{
water_elementalAI(Creature* creature) : ScriptedAI(creature)
_scheduler.CancelAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.Schedule(2s, [this](TaskContext context)
{
}
DoCastVictim(SPELL_WATERBOLT);
context.Repeat(2s);
});
}
uint32 CastTimer;
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
void Reset() override
{
CastTimer = 2000 + (rand() % 3000);
}
void JustEngagedWith(Unit* /*who*/) override { }
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (CastTimer <= diff)
{
DoCastVictim(SPELL_WATERBOLT);
CastTimer = urand(2000, 5000);
}
else
CastTimer -= diff;
}
};
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
};
void AddSC_boss_shade_of_aran()
{
new boss_shade_of_aran();
new npc_aran_elemental();
RegisterKarazhanCreatureAI(boss_shade_of_aran);
RegisterKarazhanCreatureAI(npc_aran_elemental);
}

View File

@@ -242,7 +242,11 @@ struct boss_eye_of_cthun : public BossAI
{
scheduler.Schedule(5s, [this](TaskContext task)
{
DoCastRandomTarget(SPELL_GREEN_BEAM);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
{
DoCast(target, SPELL_GREEN_BEAM);
DarkGlareAngle = me->GetAngle(target); //keep as the location dark glare will be at
}
task.SetGroup(GROUP_BEAM_PHASE);
task.Repeat(3s);
@@ -284,21 +288,18 @@ struct boss_eye_of_cthun : public BossAI
scheduler.Schedule(1s, [this](TaskContext /*task*/)
{
//Select random target for dark beam to start on
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
{
//Face our target
DarkGlareAngle = me->GetAngle(target);
DarkGlareTick = 0;
ClockWise = RAND(true, false);
//Select last target that had a beam cast on it
//Face our target
//Add red coloration to C'thun
DoCast(me, SPELL_RED_COLORATION, true);
DarkGlareTick = 0;
ClockWise = RAND(true, false);
me->StopMoving();
me->SetFacingToObject(target);
me->SetOrientation(DarkGlareAngle);
}
//Add red coloration to C'thun
DoCast(me, SPELL_RED_COLORATION, true);
me->StopMoving();
me->SetOrientation(DarkGlareAngle);
me->SetFacingTo(DarkGlareAngle);
scheduler.Schedule(3s, [this](TaskContext tasker)
{

View File

@@ -59,7 +59,13 @@ enum Spells
enum Groups
{
GROUP_INTERRUPT_CHECK = 0
GROUP_INTERRUPT_CHECK = 0,
GROUP_EARLY_RELEASE_CHECK = 1
};
enum Actions
{
ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT = 1
};
class DealDebrisDamage : public BasicEvent
@@ -92,8 +98,10 @@ struct boss_magtheridon : public BossAI
void Reset() override
{
BossAI::Reset();
_channelersKilled = 0;
_currentPhase = 0;
_recentlySpoken = false;
_magReleased = false;
_interruptScheduler.CancelAll();
scheduler.Schedule(90s, [this](TaskContext context)
{
@@ -154,60 +162,86 @@ struct boss_magtheridon : public BossAI
BossAI::JustDied(killer);
}
void ScheduleCombatEvents()
{
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(false);
me->SetReactState(REACT_AGGRESSIVE);
instance->SetData(DATA_ACTIVATE_CUBES, 1);
me->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE);
scheduler.Schedule(9s, [this](TaskContext context)
{
DoCastVictim(SPELL_CLEAVE);
context.Repeat(1200ms, 16300ms);
}).Schedule(20s, [this](TaskContext context)
{
me->CastCustomSpell(SPELL_BLAZE, SPELLVALUE_MAX_TARGETS, 1);
context.Repeat(11s, 39s);
}).Schedule(40s, [this](TaskContext context)
{
DoCastSelf(SPELL_QUAKE); //needs fixes with custom spell
scheduler.Schedule(7s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_BLAST_NOVA);
_interruptScheduler.Schedule(50ms, GROUP_INTERRUPT_CHECK, [this](TaskContext context)
{
if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5)
{
Talk(SAY_BANISH);
me->InterruptNonMeleeSpells(true);
scheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
}
else
context.Repeat(50ms);
}).Schedule(12s, GROUP_INTERRUPT_CHECK, [this](TaskContext /*context*/)
{
_interruptScheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
});
});
context.Repeat(53s, 56s);
}).Schedule(22min, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_BERSERK, true);
});
}
void DoAction(int32 action) override
{
if (action == ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT)
{
_channelersKilled++;
if (_channelersKilled >= 5 && !_magReleased)
{
Talk(SAY_EMOTE_FREE);
Talk(SAY_FREE);
scheduler.CancelGroup(GROUP_EARLY_RELEASE_CHECK); //cancel regular countdown
scheduler.Schedule(3s, [this](TaskContext)
{
_magReleased = true; //redundancy
ScheduleCombatEvents();
});
}
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_EMOTE_BEGIN);
scheduler.Schedule(60s, [this](TaskContext /*context*/)
scheduler.Schedule(60s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/)
{
Talk(SAY_EMOTE_NEARLY);
}).Schedule(120s, [this](TaskContext /*context*/)
}).Schedule(120s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/)
{
Talk(SAY_EMOTE_FREE);
}).Schedule(123s, [this](TaskContext /*context*/)
Talk(SAY_FREE);
}).Schedule(123s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/)
{
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetImmuneToPC(false);
me->SetReactState(REACT_AGGRESSIVE);
instance->SetData(DATA_ACTIVATE_CUBES, 1);
me->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE);
scheduler.Schedule(9s, [this](TaskContext context)
{
DoCastVictim(SPELL_CLEAVE);
context.Repeat(1200ms, 16300ms);
}).Schedule(20s, [this](TaskContext context)
{
me->CastCustomSpell(SPELL_BLAZE, SPELLVALUE_MAX_TARGETS, 1);
context.Repeat(11s, 39s);
}).Schedule(40s, [this](TaskContext context)
{
DoCastSelf(SPELL_QUAKE); //needs fixes with custom spell
scheduler.Schedule(7s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_BLAST_NOVA);
_interruptScheduler.Schedule(50ms, GROUP_INTERRUPT_CHECK, [this](TaskContext context)
{
if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5)
{
Talk(SAY_BANISH);
me->InterruptNonMeleeSpells(true);
scheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
}
else
context.Repeat(50ms);
}).Schedule(12s, GROUP_INTERRUPT_CHECK, [this](TaskContext /*context*/)
{
_interruptScheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
});
});
context.Repeat(53s, 56s);
}).Schedule(1320s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_BERSERK, true);
});
ScheduleCombatEvents();
});
}
@@ -227,7 +261,9 @@ struct boss_magtheridon : public BossAI
private:
bool _recentlySpoken;
bool _magReleased;
uint8 _currentPhase;
uint8 _channelersKilled;
TaskScheduler _interruptScheduler;
};

View File

@@ -259,127 +259,6 @@ public:
};
};
/*######
## go_corkis_prison and npc_corki
######*/
enum CorkiData
{
// first quest
QUEST_HELP = 9923,
NPC_CORKI = 18445,
NPC_CORKI_CREDIT_1 = 18369,
GO_CORKIS_PRISON = 182349,
CORKI_SAY_THANKS = 0,
// 2nd quest
QUEST_CORKIS_GONE_MISSING_AGAIN = 9924,
NPC_CORKI_2 = 20812,
GO_CORKIS_PRISON_2 = 182350,
CORKI_SAY_PROMISE = 0,
// 3rd quest
QUEST_CHOWAR_THE_PILLAGER = 9955,
NPC_CORKI_3 = 18369,
NPC_CORKI_CREDIT_3 = 18444,
GO_CORKIS_PRISON_3 = 182521,
CORKI_SAY_LAST = 0
};
class go_corkis_prison : public GameObjectScript
{
public:
go_corkis_prison() : GameObjectScript("go_corkis_prison") { }
bool OnGossipHello(Player* player, GameObject* go) override
{
go->SetGoState(GO_STATE_READY);
if (go->GetEntry() == GO_CORKIS_PRISON)
{
if (Creature* corki = go->FindNearestCreature(NPC_CORKI, 25, true))
{
corki->GetMotionMaster()->MovePoint(1, go->GetPositionX() + 5, go->GetPositionY(), go->GetPositionZ());
if (player)
player->KilledMonsterCredit(NPC_CORKI_CREDIT_1);
}
}
if (go->GetEntry() == GO_CORKIS_PRISON_2)
{
if (Creature* corki = go->FindNearestCreature(NPC_CORKI_2, 25, true))
{
corki->GetMotionMaster()->MovePoint(1, go->GetPositionX() - 5, go->GetPositionY(), go->GetPositionZ());
if (player)
player->KilledMonsterCredit(NPC_CORKI_2);
}
}
if (go->GetEntry() == GO_CORKIS_PRISON_3)
{
if (Creature* corki = go->FindNearestCreature(NPC_CORKI_3, 25, true))
{
corki->GetMotionMaster()->MovePoint(1, go->GetPositionX() + 4, go->GetPositionY(), go->GetPositionZ());
if (player)
player->KilledMonsterCredit(NPC_CORKI_CREDIT_3);
}
}
return true;
}
};
class npc_corki : public CreatureScript
{
public:
npc_corki() : CreatureScript("npc_corki") { }
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_corkiAI(creature);
}
struct npc_corkiAI : public ScriptedAI
{
npc_corkiAI(Creature* creature) : ScriptedAI(creature) { }
uint32 Say_Timer;
bool ReleasedFromCage;
void Reset() override
{
Say_Timer = 5000;
ReleasedFromCage = false;
}
void UpdateAI(uint32 diff) override
{
if (ReleasedFromCage)
{
if (Say_Timer <= diff)
{
me->DespawnOrUnsummon();
ReleasedFromCage = false;
}
else
Say_Timer -= diff;
}
}
void MovementInform(uint32 type, uint32 id) override
{
if (type == POINT_MOTION_TYPE && id == 1)
{
Say_Timer = 5000;
ReleasedFromCage = true;
if (me->GetEntry() == NPC_CORKI)
Talk(CORKI_SAY_THANKS);
if (me->GetEntry() == NPC_CORKI_2)
Talk(CORKI_SAY_PROMISE);
if (me->GetEntry() == NPC_CORKI_3)
Talk(CORKI_SAY_LAST);
}
};
};
};
/*#####
## npc_kurenai_captive
#####*/
@@ -608,8 +487,6 @@ void AddSC_nagrand()
{
new npc_maghar_captive();
new npc_creditmarker_visit_with_ancestors();
new npc_corki();
new go_corkis_prison();
new npc_kurenai_captive();
new go_warmaul_prison();
}

View File

@@ -774,6 +774,49 @@ struct npc_pet_gen_moth : public NullCreatureAI
}
};
// Darting Hatchling
enum Darting
{
SPELL_DARTING_ON_SPAWN = 62586, // Applied on spawn via creature_template_addon
SPELL_DARTING_FEAR = 62585, // Applied every 20s from SPELL_DARTING_ON_SPAWN
};
struct npc_pet_darting_hatchling : public NullCreatureAI
{
npc_pet_darting_hatchling(Creature* c) : NullCreatureAI(c)
{
goFast = false;
checkTimer = 0;
}
bool goFast;
uint32 checkTimer;
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
if (spellInfo->Id == SPELL_DARTING_FEAR)
{
goFast = true;
}
}
void UpdateAI(uint32 diff) override
{
if (!goFast)
{
return;
}
checkTimer += diff;
if (checkTimer >= 2000)
{
me->RemoveAurasDueToSpell(SPELL_DARTING_FEAR);
checkTimer = 0;
goFast = false;
}
}
};
void AddSC_generic_pet_scripts()
{
RegisterCreatureAI(npc_pet_gen_soul_trader_beacon);
@@ -788,4 +831,5 @@ void AddSC_generic_pet_scripts()
RegisterCreatureAI(npc_pet_gen_toxic_wasteling);
RegisterCreatureAI(npc_pet_gen_fetch_ball);
RegisterCreatureAI(npc_pet_gen_moth);
RegisterCreatureAI(npc_pet_darting_hatchling);
}