mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-03-15 05:25:08 +00:00
Merge branch 'master' into Playerbot
This commit is contained in:
4
data/sql/updates/db_world/2023_07_18_01.sql
Normal file
4
data/sql/updates/db_world/2023_07_18_01.sql
Normal 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';
|
||||||
4
data/sql/updates/db_world/2023_07_18_02.sql
Normal file
4
data/sql/updates/db_world/2023_07_18_02.sql
Normal 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;
|
||||||
4
data/sql/updates/db_world/2023_07_19_00.sql
Normal file
4
data/sql/updates/db_world/2023_07_19_00.sql
Normal 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;
|
||||||
3
data/sql/updates/db_world/2023_07_19_01.sql
Normal file
3
data/sql/updates/db_world/2023_07_19_01.sql
Normal 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;
|
||||||
3
data/sql/updates/db_world/2023_07_19_02.sql
Normal file
3
data/sql/updates/db_world/2023_07_19_02.sql
Normal 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;
|
||||||
2
data/sql/updates/db_world/2023_07_19_03.sql
Normal file
2
data/sql/updates/db_world/2023_07_19_03.sql
Normal 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;
|
||||||
9
data/sql/updates/db_world/2023_07_19_04.sql
Normal file
9
data/sql/updates/db_world/2023_07_19_04.sql
Normal 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);
|
||||||
44
data/sql/updates/db_world/2023_07_22_00.sql
Normal file
44
data/sql/updates/db_world/2023_07_22_00.sql
Normal 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);
|
||||||
|
|
||||||
13
data/sql/updates/db_world/2023_07_23_00.sql
Normal file
13
data/sql/updates/db_world/2023_07_23_00.sql
Normal 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');
|
||||||
@@ -660,7 +660,7 @@ void WorldSession::LogoutPlayer(bool save)
|
|||||||
guild->HandleMemberLogout(this);
|
guild->HandleMemberLogout(this);
|
||||||
|
|
||||||
///- Remove pet
|
///- 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)
|
// 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
|
// 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
|
||||||
|
|||||||
@@ -4547,6 +4547,12 @@ void SpellMgr::LoadSpellInfoCorrections()
|
|||||||
spellInfo->MaxAffectedTargets = 1;
|
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)
|
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||||
{
|
{
|
||||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||||
|
|||||||
@@ -24,18 +24,18 @@
|
|||||||
|
|
||||||
enum Texts
|
enum Texts
|
||||||
{
|
{
|
||||||
SAY_KILL = 0,
|
SAY_KILL = 0,
|
||||||
SAY_RANDOM = 1,
|
SAY_RANDOM = 1,
|
||||||
SAY_DISARMED = 2,
|
SAY_DISARMED = 2,
|
||||||
SAY_MIDNIGHT_KILL = 3,
|
SAY_MIDNIGHT_KILL = 3,
|
||||||
SAY_APPEAR = 4,
|
SAY_APPEAR = 4,
|
||||||
SAY_MOUNT = 5,
|
SAY_MOUNT = 5,
|
||||||
|
|
||||||
SAY_DEATH = 3,
|
SAY_DEATH = 3,
|
||||||
|
|
||||||
// Midnight
|
// Midnight
|
||||||
EMOTE_CALL_ATTUMEN = 0,
|
EMOTE_CALL_ATTUMEN = 0,
|
||||||
EMOTE_MOUNT_UP = 1
|
EMOTE_MOUNT_UP = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Spells
|
enum Spells
|
||||||
@@ -45,7 +45,6 @@ enum Spells
|
|||||||
SPELL_INTANGIBLE_PRESENCE = 29833,
|
SPELL_INTANGIBLE_PRESENCE = 29833,
|
||||||
SPELL_SPAWN_SMOKE = 10389,
|
SPELL_SPAWN_SMOKE = 10389,
|
||||||
SPELL_CHARGE = 29847,
|
SPELL_CHARGE = 29847,
|
||||||
|
|
||||||
// Midnight
|
// Midnight
|
||||||
SPELL_KNOCKDOWN = 29711,
|
SPELL_KNOCKDOWN = 29711,
|
||||||
SPELL_SUMMON_ATTUMEN = 29714,
|
SPELL_SUMMON_ATTUMEN = 29714,
|
||||||
@@ -62,406 +61,357 @@ enum Phases
|
|||||||
|
|
||||||
enum Actions
|
enum Actions
|
||||||
{
|
{
|
||||||
ACTION_SET_MIDNIGHT_PHASE,
|
ACTION_SET_MIDNIGHT_PHASE
|
||||||
};
|
};
|
||||||
|
|
||||||
class boss_attumen : public CreatureScript
|
struct boss_attumen : public BossAI
|
||||||
{
|
{
|
||||||
public:
|
boss_attumen(Creature* creature) : BossAI(creature, DATA_ATTUMEN)
|
||||||
boss_attumen() : CreatureScript("boss_attumen") { }
|
|
||||||
|
|
||||||
struct boss_attumenAI : public BossAI
|
|
||||||
{
|
{
|
||||||
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;
|
_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))
|
if (Creature* midnight = instance->GetCreature(DATA_MIDNIGHT))
|
||||||
{
|
{
|
||||||
midnight->AI()->EnterEvadeMode(why);
|
midnight->AI()->DoCastAOE(SPELL_MOUNT, true);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void KilledUnit(Unit* /*victim*/) override
|
void KilledUnit(Unit* victim) override
|
||||||
|
{
|
||||||
|
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||||
{
|
{
|
||||||
Talk(SAY_KILL);
|
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))
|
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())
|
if (!CanMeleeHit())
|
||||||
{
|
{
|
||||||
BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY);
|
BossAI::EnterEvadeMode(EvadeReason::EVADE_REASON_BOUNDARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler.Update(diff,
|
|
||||||
std::bind(&BossAI::DoMeleeAttackIfReady, this));
|
|
||||||
}
|
}
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 _phase;
|
||||||
};
|
};
|
||||||
|
|
||||||
class boss_midnight : public CreatureScript
|
class spell_midnight_fixate : public AuraScript
|
||||||
{
|
{
|
||||||
public:
|
PrepareAuraScript(spell_midnight_fixate)
|
||||||
boss_midnight() : CreatureScript("boss_midnight") { }
|
|
||||||
|
|
||||||
struct boss_midnightAI : public BossAI
|
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||||
{
|
{
|
||||||
boss_midnightAI(Creature* creature) : BossAI(creature, DATA_ATTUMEN), _phase(PHASE_NONE) { }
|
Unit* target = GetTarget();
|
||||||
|
if (Unit* caster = GetCaster())
|
||||||
void Reset() override
|
|
||||||
{
|
{
|
||||||
BossAI::Reset();
|
caster->TauntApply(target);
|
||||||
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(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
|
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||||
{
|
|
||||||
public:
|
|
||||||
spell_midnight_fixate() : SpellScriptLoader("spell_midnight_fixate") { }
|
|
||||||
|
|
||||||
class spell_midnight_fixate_AuraScript : public AuraScript
|
|
||||||
{
|
{
|
||||||
PrepareAuraScript(spell_midnight_fixate_AuraScript);
|
Unit* target = GetTarget();
|
||||||
|
if (Unit* caster = GetCaster())
|
||||||
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
caster->TauntFadeOut(target);
|
||||||
if (Unit* caster = GetCaster())
|
|
||||||
caster->TauntApply(target);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
void Register() override
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
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()
|
void AddSC_boss_attumen()
|
||||||
{
|
{
|
||||||
new boss_midnight();
|
RegisterKarazhanCreatureAI(boss_midnight);
|
||||||
new boss_attumen();
|
RegisterKarazhanCreatureAI(boss_attumen);
|
||||||
new spell_midnight_fixate();
|
RegisterSpellScript(spell_midnight_fixate);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,19 +46,15 @@ enum Spells
|
|||||||
|
|
||||||
enum Misc
|
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,
|
ACTIVE_GUEST_COUNT = 4,
|
||||||
MAX_GUEST_COUNT = 6
|
MAX_GUEST_COUNT = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Groups
|
||||||
|
{
|
||||||
|
GROUP_PRECOMBAT_TALK = 0
|
||||||
|
};
|
||||||
|
|
||||||
const Position GuestsPosition[4] =
|
const Position GuestsPosition[4] =
|
||||||
{
|
{
|
||||||
{-10987.38f, -1883.38f, 81.73f, 1.50f},
|
{-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)
|
boss_moroes(Creature* creature) : BossAI(creature, DATA_MOROES)
|
||||||
{
|
{
|
||||||
_activeGuests = 0;
|
_activeGuests = 0;
|
||||||
|
scheduler.SetValidator([this]
|
||||||
|
{
|
||||||
|
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeAI() override
|
void InitializeAI() override
|
||||||
@@ -111,46 +111,83 @@ struct boss_moroes : public BossAI
|
|||||||
me->SummonCreature(GuestEntries[i], GuestsPosition[summons.size()], TEMPSUMMON_MANUAL_DESPAWN);
|
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
|
void Reset() override
|
||||||
{
|
{
|
||||||
BossAI::Reset();
|
BossAI::Reset();
|
||||||
DoCastSelf(SPELL_DUAL_WIELD, true);
|
DoCastSelf(SPELL_DUAL_WIELD, true);
|
||||||
|
_recentlySpoken = false;
|
||||||
|
_vanished = false;
|
||||||
|
|
||||||
|
ScheduleHealthCheckEvent(30, [&] {
|
||||||
|
DoCastSelf(SPELL_FRENZY, true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void JustEngagedWith(Unit* who) override
|
void JustEngagedWith(Unit* who) override
|
||||||
{
|
{
|
||||||
BossAI::JustEngagedWith(who);
|
BossAI::JustEngagedWith(who);
|
||||||
Talk(SAY_AGGRO);
|
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);
|
me->CallForHelp(20.0f);
|
||||||
DoZoneInCombat();
|
DoZoneInCombat();
|
||||||
}
|
scheduler.CancelGroup(GROUP_PRECOMBAT_TALK);
|
||||||
|
|
||||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
scheduler.Schedule(30s, [this](TaskContext context)
|
||||||
{
|
|
||||||
if (HealthBelowPct(30))
|
|
||||||
{
|
{
|
||||||
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
|
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);
|
_recentlySpoken = false;
|
||||||
events.ScheduleEvent(EVENT_KILL_TALK, 5s);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,66 +213,22 @@ struct boss_moroes : public BossAI
|
|||||||
|
|
||||||
void UpdateAI(uint32 diff) override
|
void UpdateAI(uint32 diff) override
|
||||||
{
|
{
|
||||||
_events2.Update(diff);
|
scheduler.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UpdateVictim())
|
if (!UpdateVictim())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
events.Update(diff);
|
if (_vanished == false)
|
||||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (events.ExecuteEvent())
|
|
||||||
{
|
{
|
||||||
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();
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EventMap _events2;
|
EventMap _events2;
|
||||||
uint8 _activeGuests;
|
uint8 _activeGuests;
|
||||||
|
bool _recentlySpoken;
|
||||||
|
bool _vanished;
|
||||||
};
|
};
|
||||||
|
|
||||||
class spell_moroes_vanish : public SpellScript
|
class spell_moroes_vanish : public SpellScript
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include "ScriptedCreature.h"
|
#include "ScriptedCreature.h"
|
||||||
#include "karazhan.h"
|
#include "karazhan.h"
|
||||||
|
|
||||||
enum ServantQuartersSpells
|
enum Spells
|
||||||
{
|
{
|
||||||
SPELL_SNEAK = 22766,
|
SPELL_SNEAK = 22766,
|
||||||
SPELL_ACIDIC_FANG = 29901,
|
SPELL_ACIDIC_FANG = 29901,
|
||||||
@@ -33,41 +33,37 @@ enum ServantQuartersSpells
|
|||||||
SPELL_RAVAGE = 29906
|
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
|
struct boss_servant_quarters : public BossAI
|
||||||
{
|
{
|
||||||
boss_servant_quarters(Creature* creature) : BossAI(creature, DATA_SERVANT_QUARTERS) { }
|
boss_servant_quarters(Creature* creature) : BossAI(creature, DATA_SERVANT_QUARTERS) { }
|
||||||
|
|
||||||
void Reset() override
|
void Reset() override
|
||||||
{
|
{
|
||||||
events.Reset();
|
_scheduler.CancelAll();
|
||||||
me->SetVisible(false);
|
me->SetVisible(false);
|
||||||
me->SetReactState(REACT_PASSIVE);
|
me->SetReactState(REACT_PASSIVE);
|
||||||
me->SetFaction(FACTION_FRIENDLY);
|
me->SetFaction(FACTION_FRIENDLY);
|
||||||
_events2.Reset();
|
_scheduler.Schedule(5s, [this](TaskContext context)
|
||||||
_events2.ScheduleEvent(EVENT_CHECK_VISIBILITY, 5s);
|
{
|
||||||
|
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)
|
if (me->GetEntry() == NPC_HYAKISS_THE_LURKER)
|
||||||
{
|
{
|
||||||
DoCastSelf(SPELL_SNEAK, true);
|
DoCastSelf(SPELL_SNEAK, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instance->GetData(DATA_SELECTED_RARE) != me->GetEntry())
|
if (instance->GetData(DATA_SELECTED_RARE) != me->GetEntry())
|
||||||
|
{
|
||||||
me->DespawnOrUnsummon(1);
|
me->DespawnOrUnsummon(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JustEngagedWith(Unit* /*who*/) override
|
void JustEngagedWith(Unit* /*who*/) override
|
||||||
@@ -75,18 +71,42 @@ struct boss_servant_quarters : public BossAI
|
|||||||
me->setActive(true);
|
me->setActive(true);
|
||||||
if (me->GetEntry() == NPC_HYAKISS_THE_LURKER)
|
if (me->GetEntry() == NPC_HYAKISS_THE_LURKER)
|
||||||
{
|
{
|
||||||
events.ScheduleEvent(EVENT_SPELL_ACIDIC_FANG, 5s);
|
_scheduler.Schedule(5s, [this](TaskContext context)
|
||||||
events.ScheduleEvent(EVENT_SPELL_HYAKISS_WEB, 9s);
|
{
|
||||||
|
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)
|
else if (me->GetEntry() == NPC_SHADIKITH_THE_GLIDER)
|
||||||
{
|
{
|
||||||
events.ScheduleEvent(EVENT_SPELL_SONIC_BURST, 4s);
|
_scheduler.Schedule(4s, [this](TaskContext context)
|
||||||
events.ScheduleEvent(EVENT_SPELL_WING_BUFFET, 7s);
|
{
|
||||||
events.ScheduleEvent(EVENT_SPELL_DIVE, 10s);
|
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)
|
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
|
void MovementInform(uint32 type, uint32 point) override
|
||||||
{
|
{
|
||||||
if (type == POINT_MOTION_TYPE && point == EVENT_CHARGE)
|
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
|
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())
|
if (!UpdateVictim())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
events.Update(diff);
|
_scheduler.Update(diff);
|
||||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
return;
|
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();
|
DoMeleeAttackIfReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EventMap _events2;
|
TaskScheduler _scheduler;
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddSC_boss_servant_quarters()
|
void AddSC_boss_servant_quarters()
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "ScriptedCreature.h"
|
#include "ScriptedCreature.h"
|
||||||
#include "SpellInfo.h"
|
#include "SpellInfo.h"
|
||||||
#include "karazhan.h"
|
#include "karazhan.h"
|
||||||
|
#include "TaskScheduler.h"
|
||||||
|
|
||||||
enum ShadeOfAran
|
enum ShadeOfAran
|
||||||
{
|
{
|
||||||
@@ -58,9 +59,9 @@ enum ShadeOfAran
|
|||||||
SPELL_SHADOW_PYRO = 29978,
|
SPELL_SHADOW_PYRO = 29978,
|
||||||
|
|
||||||
//Creatures
|
//Creatures
|
||||||
CREATURE_WATER_ELEMENTAL = 17167,
|
NPC_WATER_ELEMENTAL = 17167,
|
||||||
CREATURE_SHADOW_OF_ARAN = 18254,
|
NPC_SHADOW_OF_ARAN = 18254,
|
||||||
CREATURE_ARAN_BLIZZARD = 17161,
|
NPC_ARAN_BLIZZARD = 17161,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SuperSpell
|
enum SuperSpell
|
||||||
@@ -70,560 +71,458 @@ enum SuperSpell
|
|||||||
SUPER_AE,
|
SUPER_AE,
|
||||||
};
|
};
|
||||||
|
|
||||||
class boss_shade_of_aran : public CreatureScript
|
enum Groups
|
||||||
{
|
{
|
||||||
public:
|
GROUP_FLAMEWREATH = 0,
|
||||||
boss_shade_of_aran() : CreatureScript("boss_shade_of_aran") { }
|
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;
|
ScheduleHealthCheckEvent(40, [&]{
|
||||||
uint32 NormalCastTimer;
|
Talk(SAY_ELEMENTALS);
|
||||||
uint32 SuperCastTimer;
|
|
||||||
uint32 BerserkTimer;
|
|
||||||
uint32 CloseDoorTimer; // Don't close the door right on aggro in case some people are still entering.
|
|
||||||
|
|
||||||
uint8 LastSuperSpell;
|
for(Position pos : elementalPos)
|
||||||
|
|
||||||
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)))
|
|
||||||
{
|
{
|
||||||
libraryDoor->SetGoState(GO_STATE_ACTIVE);
|
if(Creature* elemental = me->SummonCreature(NPC_WATER_ELEMENTAL, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000))
|
||||||
libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
{
|
||||||
|
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);
|
void TriggerFrostCooldown()
|
||||||
|
{
|
||||||
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
|
scheduler.Schedule(5s, [this](TaskContext)
|
||||||
{
|
|
||||||
libraryDoor->SetGoState(GO_STATE_ACTIVE);
|
|
||||||
libraryDoor->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JustEngagedWith(Unit* /*who*/) override
|
|
||||||
{
|
{
|
||||||
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)))
|
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
|
||||||
{
|
{
|
||||||
libraryDoor->SetGoState(GO_STATE_READY);
|
libraryDoor->SetGoState(GO_STATE_READY);
|
||||||
libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
||||||
}
|
}
|
||||||
|
}).Schedule(1ms, [this](TaskContext context)
|
||||||
DoZoneInCombat();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlameWreathEffect()
|
|
||||||
{
|
{
|
||||||
std::vector<Unit*> targets;
|
if (!me->IsNonMeleeSpellCast(false))
|
||||||
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());
|
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
|
||||||
//only on alive players
|
if (!target)
|
||||||
if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
|
return;
|
||||||
targets.push_back(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
//cut down to size if we have more than 3 targets
|
uint32 Spells[3];
|
||||||
while (targets.size() > 3)
|
uint8 AvailableSpells = 0;
|
||||||
targets.erase(targets.begin() + rand() % targets.size());
|
|
||||||
|
|
||||||
uint32 i = 0;
|
//Check for what spells are not on cooldown
|
||||||
for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
|
if (_arcaneCooledDown)
|
||||||
{
|
|
||||||
if (*itr)
|
|
||||||
{
|
{
|
||||||
FlameWreathTarget[i] = (*itr)->GetGUID();
|
Spells[AvailableSpells] = SPELL_ARCMISSLE;
|
||||||
FWTargPosX[i] = (*itr)->GetPositionX();
|
++AvailableSpells;
|
||||||
FWTargPosY[i] = (*itr)->GetPositionY();
|
}
|
||||||
DoCast((*itr), SPELL_FLAME_WREATH, true);
|
if (_fireCooledDown)
|
||||||
++i;
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
context.Repeat(10s);
|
||||||
|
}).Schedule(5s, [this](TaskContext context)
|
||||||
void UpdateAI(uint32 diff) override
|
|
||||||
{
|
{
|
||||||
if (!UpdateVictim())
|
switch (urand(0, 1))
|
||||||
return;
|
|
||||||
|
|
||||||
if (CloseDoorTimer)
|
|
||||||
{
|
{
|
||||||
if (CloseDoorTimer <= diff)
|
case 0:
|
||||||
{
|
DoCastSelf(SPELL_AOE_CS);
|
||||||
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
|
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);
|
scheduler.CancelGroup(GROUP_FLAMEWREATH);
|
||||||
libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
}).Schedule(500ms, GROUP_FLAMEWREATH, [this](TaskContext context)
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
Spells[AvailableSpells] = SPELL_ARCMISSLE;
|
for (uint8 i = 0; i < 3; ++i)
|
||||||
++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))
|
|
||||||
{
|
{
|
||||||
pSpawn->SetFaction(me->GetFaction());
|
if (!FlameWreathTarget[i])
|
||||||
pSpawn->CastSpell(pSpawn, SPELL_CIRCULAR_BLIZZARD, false);
|
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);
|
FlameWreathTarget[0].Clear();
|
||||||
}
|
FlameWreathTarget[1].Clear();
|
||||||
else
|
FlameWreathTarget[2].Clear();
|
||||||
SuperCastTimer -= diff;
|
|
||||||
|
|
||||||
if (!ElementalsSpawned && HealthBelowPct(40))
|
FlameWreathEffect();
|
||||||
{
|
break;
|
||||||
ElementalsSpawned = true;
|
|
||||||
|
|
||||||
Creature* ElementalOne = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11168.1f, -1939.29f, 232.092f, 1.46f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000);
|
case SUPER_BLIZZARD:
|
||||||
Creature* ElementalTwo = me->SummonCreature(CREATURE_WATER_ELEMENTAL, -11138.2f, -1915.38f, 232.092f, 3.00f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000);
|
Talk(SAY_BLIZZARD);
|
||||||
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);
|
|
||||||
|
|
||||||
if (ElementalOne)
|
if (Creature* pSpawn = me->SummonCreature(NPC_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000))
|
||||||
{
|
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
unit->Attack(me->GetVictim(), true);
|
pSpawn->SetFaction(me->GetFaction());
|
||||||
unit->SetFaction(me->GetFaction());
|
pSpawn->CastSpell(me, SPELL_CIRCULAR_BLIZZARD, false);
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
|
|
||||||
Talk(SAY_TIMEOVER);
|
|
||||||
|
|
||||||
BerserkTimer = 60000;
|
|
||||||
}
|
}
|
||||||
else
|
context.Repeat(35s, 40s);
|
||||||
BerserkTimer -= diff;
|
}).Schedule(12min, [this](TaskContext context)
|
||||||
|
{
|
||||||
//Flame Wreath check
|
for (uint32 i = 0; i < 5; ++i)
|
||||||
if (FlameWreathTimer)
|
|
||||||
{
|
{
|
||||||
if (FlameWreathTimer >= 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))
|
||||||
FlameWreathTimer -= diff;
|
|
||||||
else
|
|
||||||
FlameWreathTimer = 0;
|
|
||||||
|
|
||||||
if (FlameWreathCheckTime <= diff)
|
|
||||||
{
|
{
|
||||||
for (uint8 i = 0; i < 3; ++i)
|
unit->Attack(me->GetVictim(), true);
|
||||||
{
|
unit->SetFaction(me->GetFaction());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
FlameWreathCheckTime -= diff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ArcaneCooldown && FireCooldown && FrostCooldown)
|
Talk(SAY_TIMEOVER);
|
||||||
DoMeleeAttackIfReady();
|
|
||||||
|
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)
|
if (*itr)
|
||||||
DrinkInturrupted = true;
|
{
|
||||||
|
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
|
Drinking = true;
|
||||||
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);
|
me->InterruptNonMeleeSpells(false);
|
||||||
|
|
||||||
//Normally we would set the cooldown equal to the spell duration
|
Talk(SAY_DRINK);
|
||||||
//but we do not have access to the DurationStore
|
|
||||||
|
|
||||||
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:
|
//check for damage to interrupt
|
||||||
ArcaneCooldown = 5000;
|
if(CheckDamageDuringDrinking(_currentHealth))
|
||||||
break;
|
{
|
||||||
case SPELL_FIREBALL:
|
Drinking = false;
|
||||||
FireCooldown = 5000;
|
me->RemoveAurasDueToSpell(SPELL_DRINK);
|
||||||
break;
|
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||||
case SPELL_FROSTBOLT:
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
FrostCooldown = 5000;
|
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
|
||||||
break;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
return false;
|
||||||
|
|
||||||
CreatureAI* GetAI(Creature* creature) const override
|
|
||||||
{
|
|
||||||
return GetKarazhanAI<boss_aranAI>(creature);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(Creature* creature) : ScriptedAI(creature)
|
||||||
npc_aran_elemental() : CreatureScript("npc_aran_elemental") { }
|
|
||||||
|
|
||||||
CreatureAI* GetAI(Creature* creature) const override
|
|
||||||
{
|
{
|
||||||
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
|
_scheduler.Update(diff);
|
||||||
{
|
}
|
||||||
CastTimer = 2000 + (rand() % 3000);
|
private:
|
||||||
}
|
TaskScheduler _scheduler;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddSC_boss_shade_of_aran()
|
void AddSC_boss_shade_of_aran()
|
||||||
{
|
{
|
||||||
new boss_shade_of_aran();
|
RegisterKarazhanCreatureAI(boss_shade_of_aran);
|
||||||
new npc_aran_elemental();
|
RegisterKarazhanCreatureAI(npc_aran_elemental);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,7 +242,11 @@ struct boss_eye_of_cthun : public BossAI
|
|||||||
{
|
{
|
||||||
scheduler.Schedule(5s, [this](TaskContext task)
|
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.SetGroup(GROUP_BEAM_PHASE);
|
||||||
task.Repeat(3s);
|
task.Repeat(3s);
|
||||||
@@ -284,21 +288,18 @@ struct boss_eye_of_cthun : public BossAI
|
|||||||
|
|
||||||
scheduler.Schedule(1s, [this](TaskContext /*task*/)
|
scheduler.Schedule(1s, [this](TaskContext /*task*/)
|
||||||
{
|
{
|
||||||
//Select random target for dark beam to start on
|
//Select last target that had a beam cast on it
|
||||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
|
//Face our target
|
||||||
{
|
|
||||||
//Face our target
|
|
||||||
DarkGlareAngle = me->GetAngle(target);
|
|
||||||
DarkGlareTick = 0;
|
|
||||||
ClockWise = RAND(true, false);
|
|
||||||
|
|
||||||
//Add red coloration to C'thun
|
DarkGlareTick = 0;
|
||||||
DoCast(me, SPELL_RED_COLORATION, true);
|
ClockWise = RAND(true, false);
|
||||||
|
|
||||||
me->StopMoving();
|
//Add red coloration to C'thun
|
||||||
me->SetFacingToObject(target);
|
DoCast(me, SPELL_RED_COLORATION, true);
|
||||||
me->SetOrientation(DarkGlareAngle);
|
|
||||||
}
|
me->StopMoving();
|
||||||
|
me->SetOrientation(DarkGlareAngle);
|
||||||
|
me->SetFacingTo(DarkGlareAngle);
|
||||||
|
|
||||||
scheduler.Schedule(3s, [this](TaskContext tasker)
|
scheduler.Schedule(3s, [this](TaskContext tasker)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,7 +59,13 @@ enum Spells
|
|||||||
|
|
||||||
enum Groups
|
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
|
class DealDebrisDamage : public BasicEvent
|
||||||
@@ -92,8 +98,10 @@ struct boss_magtheridon : public BossAI
|
|||||||
void Reset() override
|
void Reset() override
|
||||||
{
|
{
|
||||||
BossAI::Reset();
|
BossAI::Reset();
|
||||||
|
_channelersKilled = 0;
|
||||||
_currentPhase = 0;
|
_currentPhase = 0;
|
||||||
_recentlySpoken = false;
|
_recentlySpoken = false;
|
||||||
|
_magReleased = false;
|
||||||
_interruptScheduler.CancelAll();
|
_interruptScheduler.CancelAll();
|
||||||
scheduler.Schedule(90s, [this](TaskContext context)
|
scheduler.Schedule(90s, [this](TaskContext context)
|
||||||
{
|
{
|
||||||
@@ -154,60 +162,86 @@ struct boss_magtheridon : public BossAI
|
|||||||
BossAI::JustDied(killer);
|
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
|
void JustEngagedWith(Unit* who) override
|
||||||
{
|
{
|
||||||
BossAI::JustEngagedWith(who);
|
BossAI::JustEngagedWith(who);
|
||||||
Talk(SAY_EMOTE_BEGIN);
|
Talk(SAY_EMOTE_BEGIN);
|
||||||
|
|
||||||
scheduler.Schedule(60s, [this](TaskContext /*context*/)
|
scheduler.Schedule(60s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/)
|
||||||
{
|
{
|
||||||
Talk(SAY_EMOTE_NEARLY);
|
Talk(SAY_EMOTE_NEARLY);
|
||||||
}).Schedule(120s, [this](TaskContext /*context*/)
|
}).Schedule(120s, GROUP_EARLY_RELEASE_CHECK, [this](TaskContext /*context*/)
|
||||||
{
|
{
|
||||||
Talk(SAY_EMOTE_FREE);
|
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);
|
ScheduleCombatEvents();
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +261,9 @@ struct boss_magtheridon : public BossAI
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool _recentlySpoken;
|
bool _recentlySpoken;
|
||||||
|
bool _magReleased;
|
||||||
uint8 _currentPhase;
|
uint8 _currentPhase;
|
||||||
|
uint8 _channelersKilled;
|
||||||
TaskScheduler _interruptScheduler;
|
TaskScheduler _interruptScheduler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
## npc_kurenai_captive
|
||||||
#####*/
|
#####*/
|
||||||
@@ -608,8 +487,6 @@ void AddSC_nagrand()
|
|||||||
{
|
{
|
||||||
new npc_maghar_captive();
|
new npc_maghar_captive();
|
||||||
new npc_creditmarker_visit_with_ancestors();
|
new npc_creditmarker_visit_with_ancestors();
|
||||||
new npc_corki();
|
|
||||||
new go_corkis_prison();
|
|
||||||
new npc_kurenai_captive();
|
new npc_kurenai_captive();
|
||||||
new go_warmaul_prison();
|
new go_warmaul_prison();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
void AddSC_generic_pet_scripts()
|
||||||
{
|
{
|
||||||
RegisterCreatureAI(npc_pet_gen_soul_trader_beacon);
|
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_toxic_wasteling);
|
||||||
RegisterCreatureAI(npc_pet_gen_fetch_ball);
|
RegisterCreatureAI(npc_pet_gen_fetch_ball);
|
||||||
RegisterCreatureAI(npc_pet_gen_moth);
|
RegisterCreatureAI(npc_pet_gen_moth);
|
||||||
|
RegisterCreatureAI(npc_pet_darting_hatchling);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user