From 984e03db187bc57d0c72b21cbd7a7e39d1bbbabd Mon Sep 17 00:00:00 2001 From: Garashan Date: Mon, 11 Mar 2024 19:25:24 +0100 Subject: [PATCH] Split Ulduar's script files Split Ulduar script .cpp files into .h and .cpp files. --- .../Ulduar/boss_algalon_the_observer.cpp | 1430 +------- .../Ulduar/Ulduar/boss_algalon_the_observer.h | 1447 ++++++++ .../Ulduar/Ulduar/boss_assembly_of_iron.cpp | 895 +---- .../Ulduar/Ulduar/boss_assembly_of_iron.h | 908 +++++ .../Northrend/Ulduar/Ulduar/boss_auriaya.cpp | 467 +-- .../Northrend/Ulduar/Ulduar/boss_auriaya.h | 479 +++ .../Ulduar/Ulduar/boss_flame_leviathan.cpp | 1881 +--------- .../Ulduar/Ulduar/boss_flame_leviathan.h | 1902 +++++++++++ .../Northrend/Ulduar/Ulduar/boss_freya.cpp | 1259 +------ .../Northrend/Ulduar/Ulduar/boss_freya.h | 1271 +++++++ .../Ulduar/Ulduar/boss_general_vezax.cpp | 660 +--- .../Ulduar/Ulduar/boss_general_vezax.h | 676 ++++ .../Northrend/Ulduar/Ulduar/boss_hodir.cpp | 1580 +-------- .../Northrend/Ulduar/Ulduar/boss_hodir.h | 1594 +++++++++ .../Northrend/Ulduar/Ulduar/boss_ignis.cpp | 522 +-- .../Northrend/Ulduar/Ulduar/boss_ignis.h | 537 +++ .../Northrend/Ulduar/Ulduar/boss_kologarn.cpp | 862 +---- .../Northrend/Ulduar/Ulduar/boss_kologarn.h | 876 +++++ .../Northrend/Ulduar/Ulduar/boss_mimiron.cpp | 2457 +------------- .../Northrend/Ulduar/Ulduar/boss_mimiron.h | 2475 ++++++++++++++ .../Ulduar/Ulduar/boss_razorscale.cpp | 1142 +------ .../Northrend/Ulduar/Ulduar/boss_razorscale.h | 1157 +++++++ .../Northrend/Ulduar/Ulduar/boss_thorim.cpp | 1782 +--------- .../Northrend/Ulduar/Ulduar/boss_thorim.h | 1797 ++++++++++ .../Northrend/Ulduar/Ulduar/boss_xt002.cpp | 1051 +----- .../Northrend/Ulduar/Ulduar/boss_xt002.h | 1066 ++++++ .../Ulduar/Ulduar/boss_yoggsaron.cpp | 2993 +--------------- .../Northrend/Ulduar/Ulduar/boss_yoggsaron.h | 3010 +++++++++++++++++ 28 files changed, 19209 insertions(+), 18967 deletions(-) create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.h create mode 100644 src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.h diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 98b1784802b412..0eb2bcab4b3816 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_algalon_the_observer.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "GameObjectAI.h" @@ -29,1435 +30,6 @@ #include "SpellScriptLoader.h" #include "ulduar.h" -enum Spells -{ - // Algalon the Observer - SPELL_ARRIVAL = 64997, - SPELL_RIDE_THE_LIGHTNING = 64986, - SPELL_SUMMON_AZEROTH = 64994, - SPELL_REORIGINATION = 64996, - SPELL_SUPERMASSIVE_FAIL = 65311, - SPELL_QUANTUM_STRIKE = 64395, - SPELL_PHASE_PUNCH = 64412, - SPELL_BIG_BANG = 64443, - SPELL_ASCEND_TO_THE_HEAVENS = 64487, - SPELL_COSMIC_SMASH = 62301, - SPELL_COSMIC_SMASH_TRIGGERED = 62304, - SPELL_COSMIC_SMASH_VISUAL_STATE = 62300, - SPELL_SELF_STUN = 65256, - SPELL_KILL_CREDIT = 65184, - SPELL_TELEPORT = 62940, - SPELL_DUAL_WIELD = 42459, - - // Algalon Stalker - SPELL_TRIGGER_3_ADDS = 62266, // Triggers Living Constellation - - // Living Constellation - SPELL_ARCANE_BARRAGE = 64599, - - // Collapsing Star - SPELL_COLLAPSE = 62018, - SPELL_BLACK_HOLE_SPAWN_VISUAL = 62003, - SPELL_SUMMON_BLACK_HOLE = 62189, - - // Black Hole - SPELL_BLACK_HOLE_TRIGGER = 62185, - SPELL_CONSTELLATION_PHASE_TRIGGER = 65508, - SPELL_CONSTELLATION_PHASE_EFFECT = 65509, - SPELL_BLACK_HOLE_EXPLOSION = 64122, - SPELL_SUMMON_VOID_ZONE_VISUAL = 64470, - SPELL_VOID_ZONE_VISUAL = 64469, - SPELL_BLACK_HOLE_CREDIT = 65312, - SPELL_BLACK_HOLE_DAMAGE = 62169, - - // Worm Hole - SPELL_WORM_HOLE_TRIGGER = 65251, - SPELL_SUMMON_UNLEASHED_DARK_MATTER = 64450, -}; - -enum Actions -{ - //ACTION_INIT_ALGALON = 1, defined in ulduar.h - //ACTION_DESPAWN_ALGALON = 2, defined in ulduar.h - ACTION_START_INTRO = 3, - ACTION_FINISH_INTRO = 4, - ACTION_ACTIVATE_STAR = 5, - ACTION_BIG_BANG = 6, - ACTION_ASCEND = 7, - ACTION_OUTRO = 8, -}; - -enum Misc -{ - POINT_BRANN_INTRO = 0, - MAX_BRANN_WAYPOINTS_INTRO = 11, - POINT_BRANN_OUTRO = 11, - POINT_BRANN_OUTRO_END = 12, - - POINT_ALGALON_LAND = 1, - POINT_ALGALON_OUTRO = 2, - - EVENT_ID_SUPERMASSIVE_START = 21697, - - DATA_HAS_FED_ON_TEARS = 1, - DATA_HERALD_OF_THE_TITANS = 2, -}; - -enum Events -{ - // Celestial Planetarium Access - EVENT_DESPAWN_CONSOLE = 1, - - // Brann Bronzebeard - EVENT_BRANN_MOVE_INTRO = 2, - EVENT_SUMMON_ALGALON = 3, - EVENT_BRANN_OUTRO_1 = 4, - EVENT_BRANN_OUTRO_2 = 5, - - // Algalon the Observer - EVENT_INTRO_1 = 6, - EVENT_INTRO_2 = 7, - EVENT_INTRO_3 = 8, - EVENT_INTRO_FINISH = 9, - EVENT_START_COMBAT = 10, - EVENT_INTRO_TIMER_DONE = 11, - EVENT_QUANTUM_STRIKE = 12, - EVENT_PHASE_PUNCH = 13, - EVENT_SUMMON_COLLAPSING_STAR = 14, - EVENT_BIG_BANG = 15, - EVENT_RESUME_UPDATING = 16, - EVENT_ASCEND_TO_THE_HEAVENS = 17, - EVENT_EVADE = 18, - EVENT_COSMIC_SMASH = 19, - EVENT_UNLOCK_YELL = 20, - EVENT_OUTRO_START = 21, - EVENT_OUTRO_1 = 22, - EVENT_OUTRO_2 = 23, - EVENT_OUTRO_3 = 24, - EVENT_OUTRO_4 = 25, - EVENT_OUTRO_5 = 26, - EVENT_OUTRO_6 = 27, - EVENT_OUTRO_7 = 28, - EVENT_OUTRO_8 = 29, - EVENT_OUTRO_9 = 30, - EVENT_OUTRO_10 = 31, - EVENT_OUTRO_11 = 32, - EVENT_ACTIVATE_LIVING_CONSTELLATION = 33, - EVENT_CHECK_HERALD_ITEMS = 34, - EVENT_REMOVE_UNNATTACKABLE = 35, - EVENT_DESPAWN_ALGALON_1 = 36, - EVENT_DESPAWN_ALGALON_2 = 37, - EVENT_DESPAWN_ALGALON_3 = 38, - EVENT_DESPAWN_ALGALON_4 = 39, - EVENT_DESPAWN_ALGALON_5 = 40, - - // Living Constellation - EVENT_ARCANE_BARRAGE = 41, -}; - -enum EncounterPhases -{ - PHASE_NORMAL = 0, - PHASE_ROLE_PLAY = 1, - PHASE_BIG_BANG = 2, - - PHASE_MASK_NO_UPDATE = (1 << (PHASE_ROLE_PLAY - 1)) | (1 << (PHASE_BIG_BANG - 1)), - PHASE_MASK_NO_CAST_CHECK = 1 << (PHASE_ROLE_PLAY - 1), -}; - -enum Texts -{ - SAY_BRANN_ALGALON_INTRO_1 = 0, - SAY_BRANN_ALGALON_INTRO_2 = 1, - SAY_BRANN_ALGALON_OUTRO = 2, - - SAY_ALGALON_INTRO_1 = 0, - SAY_ALGALON_INTRO_2 = 1, - SAY_ALGALON_INTRO_3 = 2, - SAY_ALGALON_START_TIMER = 3, - SAY_ALGALON_AGGRO = 4, - SAY_ALGALON_COLLAPSING_STAR = 5, - EMOTE_ALGALON_COLLAPSING_STAR = 6, - SAY_ALGALON_BIG_BANG = 7, - EMOTE_ALGALON_BIG_BANG = 8, - SAY_ALGALON_ASCEND = 9, - EMOTE_ALGALON_COSMIC_SMASH = 10, - SAY_ALGALON_PHASE_TWO = 11, - SAY_ALGALON_OUTRO_1 = 12, - SAY_ALGALON_OUTRO_2 = 13, - SAY_ALGALON_OUTRO_3 = 14, - SAY_ALGALON_OUTRO_4 = 15, - SAY_ALGALON_OUTRO_5 = 16, - SAY_ALGALON_DESPAWN_1 = 17, - SAY_ALGALON_DESPAWN_2 = 18, - SAY_ALGALON_DESPAWN_3 = 19, - SAY_ALGALON_KILL = 20, -}; - -uint32 const PhasePunchAlphaId[5] = {64435, 64434, 64428, 64421, 64417}; - -Position const BrannIntroSpawnPos = {1676.277f, -162.5308f, 427.3326f, 3.235537f}; -Position const BrannIntroWaypoint[MAX_BRANN_WAYPOINTS_INTRO] = -{ - {1642.482f, -164.0812f, 427.2602f, 0.0f}, - {1635.000f, -169.5145f, 427.2523f, 0.0f}, - {1632.814f, -173.9334f, 427.2621f, 0.0f}, - {1632.676f, -190.5927f, 427.2631f, 0.0f}, - {1631.497f, -214.2221f, 418.1152f, 0.0f}, - {1636.455f, -263.6647f, 417.3213f, 0.0f}, - {1629.586f, -267.9792f, 417.3219f, 0.0f}, - {1631.497f, -214.2221f, 418.1152f, 0.0f}, - {1632.676f, -190.5927f, 425.8831f, 0.0f}, - {1632.814f, -173.9334f, 427.2621f, 0.0f}, - {1635.000f, -169.5145f, 427.2523f, 0.0f}, -}; - -#define LIVING_CONSTELLATION_COUNT 11 -Position const ConstellationPos[LIVING_CONSTELLATION_COUNT] = -{ - {1625.208f, -267.2771f, 446.4296f, 5.044002f}, - {1593.389f, -299.4325f, 432.4636f, 6.073746f}, - {1668.317f, -324.7676f, 457.9394f, 3.211406f}, - {1685.613f, -300.1219f, 443.2366f, 3.385939f}, - {1592.242f, -325.5323f, 446.9508f, 0.226893f}, - {1658.279f, -262.5490f, 441.9073f, 4.188790f}, - {1635.821f, -363.3442f, 424.3459f, 1.466077f}, - {1591.706f, -263.8201f, 441.4153f, 5.253441f}, - {1672.188f, -357.2484f, 436.7337f, 2.338741f}, - {1678.677f, -276.3280f, 427.7531f, 3.979351f}, - {1615.800f, -348.0065f, 442.9586f, 1.134464f}, -}; - -#define COLLAPSING_STAR_COUNT 4 -Position const CollapsingStarPos[COLLAPSING_STAR_COUNT] = -{ - {1649.438f, -319.8127f, 418.3941f, 1.082104f}, - {1647.005f, -288.6790f, 417.3955f, 3.490659f}, - {1622.451f, -321.1563f, 417.6188f, 4.677482f}, - {1615.060f, -291.6816f, 417.7796f, 3.490659f}, -}; -Position const AlgalonOutroPos = {1633.64f, -317.78f, 417.3211f, 0.0f}; -Position const BrannOutroPos[3] = -{ - {1632.023f, -243.7434f, 417.9118f, 0.0f}, - {1631.986f, -297.7831f, 417.3210f, 0.0f}, - {1633.832f, -216.2948f, 417.0463f, 0.0f}, -}; - -class CosmicSmashDamageEvent : public BasicEvent -{ -public: - CosmicSmashDamageEvent(Unit* caster) : _caster(caster) - { - } - - bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override - { - _caster->CastSpell(_caster, SPELL_COSMIC_SMASH_TRIGGERED, true); - return true; - } - -private: - Unit* _caster; -}; - -class boss_algalon_the_observer : public CreatureScript -{ -public: - boss_algalon_the_observer() : CreatureScript("boss_algalon_the_observer") {} - - struct boss_algalon_the_observerAI : public ScriptedAI - { - boss_algalon_the_observerAI(Creature* creature) : ScriptedAI(creature), summons(me) - { - _fedOnTears = true; - _firstPull = true; - _fightWon = false; - m_pInstance = me->GetInstanceScript(); - } - - EventMap events; - SummonList summons; - InstanceScript* m_pInstance; - - bool _firstPull; - bool _fightWon; - bool _phaseTwo; - bool _fedOnTears; - bool _heraldOfTheTitans; - - bool IsValidHeraldItem(ItemTemplate const* item) - { - if (!item) // should not happen, but checked in GetAverageItemLevel() - return true; - if (item->ItemLevel <= 226 || (item->ItemLevel <= 232 && ( - item->InventoryType == INVTYPE_SHIELD || - item->Class == ITEM_CLASS_WEAPON || - (item->Class == ITEM_CLASS_ARMOR && (item->InventoryType == INVTYPE_RELIC || item->InventoryType == INVTYPE_HOLDABLE)) - ))) - return true; - return false; - } - - bool DoCheckHeraldOfTheTitans() - { - if (!_heraldOfTheTitans) - return true; - - Map::PlayerList const& pl = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - if (Player* plr = itr->GetSource()) - if (!plr->IsGameMaster() && plr->IsInCombat() /*performance*/) - { - for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) // loop through equipped items - if (Item* item = plr->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - if (!IsValidHeraldItem(item->GetTemplate())) - { - _heraldOfTheTitans = false; - return true; - } - } - - return false; - } - - void AttackStart(Unit* who) override - { - if (_fightWon) - return; - ScriptedAI::AttackStart(who); - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_HAS_FED_ON_TEARS) - return _fedOnTears; - if (param == DATA_HERALD_OF_THE_TITANS) - return _heraldOfTheTitans; - return 0; - } - - void CallConstellations() - { - uint8 _count = 0; - for (SummonList::const_iterator i = summons.begin(); i != summons.end(); ) - { - Creature* summon = ObjectAccessor::GetCreature(*me, *i++); - if (summon && summon->GetEntry() == NPC_LIVING_CONSTELLATION && !summon->AI()->GetData(0)) - { - ++_count; - summon->AI()->DoAction(ACTION_ACTIVATE_STAR); - if (_count >= 3) - break; - } - } - } - - void EnterEvadeMode(EvadeReason why) override - { - if (_fightWon) - return; - - if (SelectTargetFromPlayerList(120.0f)) - { - me->SetInCombatWithZone(); - return; - } - else if (events.GetPhaseMask() & PHASE_NORMAL) - { - DoAction(ACTION_ASCEND); - return; - } - - if (m_pInstance) - m_pInstance->SetData(TYPE_ALGALON, FAIL); - - ScriptedAI::EnterEvadeMode(why); - } - - void Reset() override - { - if (_fightWon) - return; - - events.Reset(); - summons.DespawnAll(); - me->SetReactState(REACT_PASSIVE); - me->SetImmuneToPC(false); - me->SetSheath(SHEATH_STATE_UNARMED); - me->SetFaction(190); - me->CastSpell(me, SPELL_DUAL_WIELD, true); - - _phaseTwo = false; - _heraldOfTheTitans = true; - - if (m_pInstance->GetData(TYPE_ALGALON) == FAIL) - { - _firstPull = false; - } - - if (m_pInstance) - m_pInstance->SetData(TYPE_ALGALON, NOT_STARTED); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2)) - return; - - Talk(SAY_ALGALON_KILL); - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_START_INTRO: - { - me->SetImmuneToPC(true); - me->SetUnitFlag2(UNIT_FLAG2_DO_NOT_FADE_IN); - me->SetDisableGravity(true); - me->CastSpell(me, SPELL_ARRIVAL, true); - me->CastSpell(me, SPELL_RIDE_THE_LIGHTNING, true); - me->GetMotionMaster()->MovePoint(POINT_ALGALON_LAND, AlgalonLandPos); - me->SetHomePosition(AlgalonLandPos); - Movement::MoveSplineInit init(me); - init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ()); - init.SetOrientationFixed(true); - init.Launch(); - events.Reset(); - events.SetPhase(PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_INTRO_1, 5s, 0, PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_INTRO_2, 15s, 0, PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_INTRO_3, 23s, 0, PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_INTRO_FINISH, 36s, 0, PHASE_ROLE_PLAY); - break; - } - case ACTION_DESPAWN_ALGALON: - _fightWon = true; - events.Reset(); - summons.DespawnAll(); - events.SetPhase(PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_DESPAWN_ALGALON_1, 5s); - events.ScheduleEvent(EVENT_DESPAWN_ALGALON_2, 17s); - events.ScheduleEvent(EVENT_DESPAWN_ALGALON_3, 26s); - if (me->IsInCombat()) - events.ScheduleEvent(EVENT_DESPAWN_ALGALON_4, 26s); - events.ScheduleEvent(EVENT_DESPAWN_ALGALON_5, 32s); - me->DespawnOrUnsummon(39000); - - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->SetFaction(FACTION_FRIENDLY); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->InterruptNonMeleeSpells(false); - if (m_pInstance) - m_pInstance->SetData(TYPE_ALGALON, NOT_STARTED); - break; - case ACTION_INIT_ALGALON: - _firstPull = false; - _fedOnTears = false; - me->SetImmuneToPC(false); - break; - case ACTION_ASCEND: - summons.DespawnAll(); - events.SetPhase(PHASE_BIG_BANG); - events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 1500ms); - break; - case ACTION_FEEDS_ON_TEARS_FAILED: - _fedOnTears = false; - } - } - - void JustReachedHome() override - { - me->setActive(false); - } - - void JustEngagedWith(Unit*) override - { - if (_fightWon) - return; - - if (!m_pInstance) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - uint32 introDelay = 0; - me->setActive(true); - me->SetInCombatWithZone(); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToNPC(true); - events.Reset(); - events.SetPhase(PHASE_ROLE_PLAY); - - if (!_firstPull) - { - events.ScheduleEvent(EVENT_START_COMBAT, 0ms); - introDelay = 8000; - } - else - { - summons.DespawnEntry(NPC_AZEROTH); - _firstPull = false; - Talk(SAY_ALGALON_START_TIMER); - introDelay = 22000; - events.ScheduleEvent(EVENT_START_COMBAT, 14s); - m_pInstance->SetData(DATA_DESPAWN_ALGALON, 0); - } - - events.ScheduleEvent(EVENT_REMOVE_UNNATTACKABLE, introDelay - 500); - events.ScheduleEvent(EVENT_INTRO_TIMER_DONE, introDelay); - events.ScheduleEvent(EVENT_QUANTUM_STRIKE, 3500 + introDelay); - events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500 + introDelay); - events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 16500 + introDelay); - events.ScheduleEvent(EVENT_COSMIC_SMASH, 25000 + introDelay); - events.ScheduleEvent(EVENT_ACTIVATE_LIVING_CONSTELLATION, 50500 + introDelay); - events.ScheduleEvent(EVENT_BIG_BANG, 90000 + introDelay); - events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 360000 + introDelay); - - events.ScheduleEvent(EVENT_CHECK_HERALD_ITEMS, 5s); - DoCheckHeraldOfTheTitans(); - } - - void MovementInform(uint32 movementType, uint32 pointId) override - { - if (movementType != POINT_MOTION_TYPE) - return; - - if (pointId == POINT_ALGALON_LAND) - me->SetDisableGravity(false); - else if (pointId == POINT_ALGALON_OUTRO) - { - me->SetFacingTo(1.605703f); - events.ScheduleEvent(EVENT_OUTRO_3, 1200ms); - events.ScheduleEvent(EVENT_OUTRO_4, 2400ms); - events.ScheduleEvent(EVENT_OUTRO_5, 8500ms); - events.ScheduleEvent(EVENT_OUTRO_6, 15s + 500ms); - events.ScheduleEvent(EVENT_OUTRO_7, 55s + 500ms); - events.ScheduleEvent(EVENT_OUTRO_8, 73s + 500ms); - events.ScheduleEvent(EVENT_OUTRO_9, 85s + 500ms); - events.ScheduleEvent(EVENT_OUTRO_10, 101s + 500ms); - events.ScheduleEvent(EVENT_OUTRO_11, 117s + 500ms); - } - } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - switch (summon->GetEntry()) - { - case NPC_AZEROTH: - me->CastSpell(summon, SPELL_REORIGINATION, true); - break; - case NPC_BLACK_HOLE: - summon->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_TRIGGER, true); - summon->CastSpell(summon, SPELL_CONSTELLATION_PHASE_TRIGGER, true); - summon->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_EXPLOSION, false); - summon->CastSpell(summon, SPELL_SUMMON_VOID_ZONE_VISUAL, true); - break; - case NPC_ALGALON_VOID_ZONE_VISUAL_STALKER: - summon->CastSpell(summon, SPELL_VOID_ZONE_VISUAL, true); - break; - case NPC_ALGALON_STALKER_ASTEROID_TARGET_01: - summon->CastSpell(summon, SPELL_COSMIC_SMASH_VISUAL_STATE, true); - break; - case NPC_ALGALON_STALKER_ASTEROID_TARGET_02: - { - float x = summon->GetPositionX(); - float y = summon->GetPositionY(); - float z = summon->GetPositionZ() + 35.0f; - float o = summon->GetOrientation(); - - summon->GetMotionMaster()->Clear(); - summon->SetHomePosition(x, y, z, o); - summon->UpdatePosition(x, y, z, o, true); - summon->StopMovingOnCurrentPos(); - summon->m_Events.AddEvent(new CosmicSmashDamageEvent(summon), summon->m_Events.CalculateTime(4000)); - break; - } - case NPC_UNLEASHED_DARK_MATTER: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true)) - if (summon->Attack(target, true)) - summon->GetMotionMaster()->MoveChase(target); - break; - } - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (_fightWon) - { - damage = 0; - return; - } - - if (!_phaseTwo && me->HealthBelowPctDamaged(20, damage)) - { - _phaseTwo = true; - Talk(SAY_ALGALON_PHASE_TWO); - summons.DespawnEntry(NPC_LIVING_CONSTELLATION); - summons.DespawnEntry(NPC_COLLAPSING_STAR); - summons.DespawnEntry(NPC_BLACK_HOLE); - summons.DespawnEntry(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER); - events.CancelEvent(EVENT_SUMMON_COLLAPSING_STAR); - events.CancelEvent(EVENT_ACTIVATE_LIVING_CONSTELLATION); - - for (uint32 i = 0; i < COLLAPSING_STAR_COUNT; ++i) - me->SummonCreature(NPC_WORM_HOLE, CollapsingStarPos[i], TEMPSUMMON_MANUAL_DESPAWN); - } - else if (me->HealthBelowPctDamaged(2, damage) && !_fightWon) - { - _fightWon = true; - damage = 0; - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->SetFaction(FACTION_FRIENDLY); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - events.Reset(); - summons.DespawnAll(); - me->InterruptNonMeleeSpells(false); - events.SetPhase(PHASE_ROLE_PLAY); - events.ScheduleEvent(EVENT_OUTRO_START, 1500ms); - events.ScheduleEvent(EVENT_OUTRO_1, 7200ms); - events.ScheduleEvent(EVENT_OUTRO_2, 8700ms); - } - } - - bool IsInRoom() - { - if (me->GetExactDist2d(&me->GetHomePosition()) > 45.f || me->GetPositionZ() < 410.f) - { - DoAction(ACTION_ASCEND); - return false; - } - - return true; - } - - void UpdateAI(uint32 diff) override - { - if (!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && (!UpdateVictim() || !IsInRoom())) - return; - - events.Update(diff); - if (!(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK) && me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_INTRO_1: - me->RemoveAurasDueToSpell(SPELL_RIDE_THE_LIGHTNING); - Talk(SAY_ALGALON_INTRO_1); - break; - case EVENT_INTRO_2: - me->CastSpell((Unit*)nullptr, SPELL_SUMMON_AZEROTH, true); - Talk(SAY_ALGALON_INTRO_2); - break; - case EVENT_INTRO_3: - Talk(SAY_ALGALON_INTRO_3); - break; - case EVENT_INTRO_FINISH: - events.Reset(); - me->SetImmuneToPC(false); - if (Creature* brann = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_BRANN_BRONZBEARD_ALG))) - brann->AI()->DoAction(ACTION_FINISH_INTRO); - break; - case EVENT_START_COMBAT: - m_pInstance->SetData(TYPE_ALGALON, IN_PROGRESS); - Talk(SAY_ALGALON_AGGRO); - break; - case EVENT_REMOVE_UNNATTACKABLE: - me->SetSheath(SHEATH_STATE_MELEE); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToNPC(false); - break; - case EVENT_INTRO_TIMER_DONE: - events.SetPhase(PHASE_NORMAL); - me->CastSpell((Unit*)nullptr, SPELL_SUPERMASSIVE_FAIL, true); - // Hack: _IsValidTarget failed earlier due to flags, call AttackStart again - me->SetReactState(REACT_AGGRESSIVE); - me->SetFaction(FACTION_MONSTER); - if (Player* target = SelectTargetFromPlayerList(150.0f)) - AttackStart(target); - me->SetInCombatWithZone(); - - for (uint32 i = 0; i < LIVING_CONSTELLATION_COUNT; ++i) - me->SummonCreature(NPC_LIVING_CONSTELLATION, ConstellationPos[i], TEMPSUMMON_DEAD_DESPAWN); - break; - case EVENT_QUANTUM_STRIKE: - me->CastSpell(me->GetVictim(), SPELL_QUANTUM_STRIKE, false); - events.Repeat(3000ms, 4500ms); - break; - case EVENT_PHASE_PUNCH: - me->CastSpell(me->GetVictim(), SPELL_PHASE_PUNCH, false); - events.Repeat(15s + 500ms); - break; - case EVENT_SUMMON_COLLAPSING_STAR: - Talk(SAY_ALGALON_COLLAPSING_STAR); - Talk(EMOTE_ALGALON_COLLAPSING_STAR); - for (uint8 i = 0; i < COLLAPSING_STAR_COUNT; ++i) - me->SummonCreature(NPC_COLLAPSING_STAR, CollapsingStarPos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); - events.Repeat(1min); - break; - case EVENT_COSMIC_SMASH: - Talk(EMOTE_ALGALON_COSMIC_SMASH); - me->CastCustomSpell(SPELL_COSMIC_SMASH, SPELLVALUE_MAX_TARGETS, RAID_MODE(1, 3), (Unit*)nullptr); - events.Repeat(25s + 500ms); - break; - case EVENT_ACTIVATE_LIVING_CONSTELLATION: - { - if (events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) - { - events.Repeat(4s); - break; - } - CallConstellations(); - //me->CastSpell(me, SPELL_TRIGGER_3_ADDS, true); - events.Repeat(50s); - break; - } - case EVENT_BIG_BANG: - { - Talk(SAY_ALGALON_BIG_BANG); - Talk(EMOTE_ALGALON_BIG_BANG); - - EntryCheckPredicate pred(NPC_LIVING_CONSTELLATION); - summons.DoAction(ACTION_BIG_BANG, pred); - - me->CastSpell((Unit*)nullptr, SPELL_BIG_BANG, false); - events.Repeat(90s + 500ms); - break; - } - case EVENT_ASCEND_TO_THE_HEAVENS: - Talk(SAY_ALGALON_ASCEND); - me->CastSpell((Unit*)nullptr, SPELL_ASCEND_TO_THE_HEAVENS, false); - events.ScheduleEvent(EVENT_EVADE, 2500ms); - break; - case EVENT_EVADE: - events.Reset(); - ScriptedAI::EnterEvadeMode(); - return; - case EVENT_OUTRO_START: - if (m_pInstance) - { - m_pInstance->SetData(TYPE_ALGALON, DONE); - m_pInstance->SetData(DATA_ALGALON_DEFEATED, 1); - } - break; - case EVENT_OUTRO_1: - me->RemoveAllAuras(); - me->SetUnitFlag(UNIT_FLAG_RENAME); - break; - case EVENT_OUTRO_2: - { - Player* lootRecipent = me->GetLootRecipient(); - _EnterEvadeMode(); - // LootRecipent is cleared in _EnterEvadeMode, restore it - me->SetLootRecipient(lootRecipent); - me->GetMotionMaster()->MovePoint(POINT_ALGALON_OUTRO, AlgalonOutroPos); - break; - } - case EVENT_OUTRO_3: - me->CastSpell((Unit*)nullptr, SPELL_KILL_CREDIT); - // Summon Chest - if (GameObject* go = me->SummonGameObject(RAID_MODE(GO_ALGALON_CHEST, GO_ALGALON_CHEST_HERO), 1632.1f, -306.561f, 417.321f, 4.69494f, 0, 0, 0, 1, 0)) - { - go->ReplaceAllGameObjectFlags((GameObjectFlags)0); - go->SetLootRecipient(me); - } - break; - case EVENT_OUTRO_4: - me->CastSpell((Unit*)nullptr, SPELL_SUPERMASSIVE_FAIL); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - break; - case EVENT_OUTRO_5: - if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannOutroPos[0], TEMPSUMMON_TIMED_DESPAWN, 131500)) - brann->AI()->DoAction(ACTION_OUTRO); - break; - case EVENT_OUTRO_6: - Talk(SAY_ALGALON_OUTRO_1); - me->SetStandState(UNIT_STAND_STATE_KNEEL); - break; - case EVENT_OUTRO_7: - Talk(SAY_ALGALON_OUTRO_2); - break; - case EVENT_OUTRO_8: - Talk(SAY_ALGALON_OUTRO_3); - break; - case EVENT_OUTRO_9: - Talk(SAY_ALGALON_OUTRO_4); - break; - case EVENT_OUTRO_10: - Talk(SAY_ALGALON_OUTRO_5); - break; - case EVENT_OUTRO_11: - me->SetStandState(UNIT_STAND_STATE_STAND); - me->CastSpell(me, SPELL_TELEPORT, false); - me->DespawnOrUnsummon(3000); - break; - case EVENT_DESPAWN_ALGALON_1: - Talk(SAY_ALGALON_DESPAWN_1); - break; - case EVENT_DESPAWN_ALGALON_2: - Talk(SAY_ALGALON_DESPAWN_2); - break; - case EVENT_DESPAWN_ALGALON_3: - Talk(SAY_ALGALON_DESPAWN_3); - break; - case EVENT_DESPAWN_ALGALON_4: - me->CastSpell((Unit*)nullptr, SPELL_ASCEND_TO_THE_HEAVENS, false); - break; - case EVENT_DESPAWN_ALGALON_5: - me->SetStandState(UNIT_STAND_STATE_STAND); - me->CastSpell(me, SPELL_TELEPORT, false); - me->DespawnOrUnsummon(3000); - break; - case EVENT_CHECK_HERALD_ITEMS: - if (!DoCheckHeraldOfTheTitans()) - events.Repeat(5s); - break; - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); - } -}; - -class npc_brann_bronzebeard_algalon : public CreatureScript -{ -public: - npc_brann_bronzebeard_algalon() : CreatureScript("npc_brann_bronzebeard_algalon") { } - - struct npc_brann_bronzebeard_algalonAI : public CreatureAI - { - npc_brann_bronzebeard_algalonAI(Creature* creature) : CreatureAI(creature) - { - } - - EventMap events; - uint32 _currentPoint; - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_START_INTRO: - me->SetWalk(false); - _currentPoint = 0; - events.Reset(); - events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1ms); - break; - case ACTION_FINISH_INTRO: - Talk(SAY_BRANN_ALGALON_INTRO_2); - events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1ms); - break; - case ACTION_OUTRO: - me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO, BrannOutroPos[1]); - events.ScheduleEvent(EVENT_BRANN_OUTRO_1, 87s + 500ms); - events.ScheduleEvent(EVENT_BRANN_OUTRO_2, 116s + 500ms); - break; - } - } - - void MovementInform(uint32 movementType, uint32 pointId) override - { - if (movementType != POINT_MOTION_TYPE) - return; - - uint32 delay = 1; - _currentPoint = pointId + 1; - switch (pointId) - { - case 2: - delay = 8000; - me->SetWalk(true); - break; - case 6: - me->SetFacingTo(4.6156f); - me->SetWalk(false); - Talk(SAY_BRANN_ALGALON_INTRO_1); - events.ScheduleEvent(EVENT_SUMMON_ALGALON, 7500ms); - return; - case 10: - me->DespawnOrUnsummon(1); - return; - case POINT_BRANN_OUTRO: - case POINT_BRANN_OUTRO_END: - return; - } - - events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, delay); - } - - void UpdateAI(uint32 diff) override - { - UpdateVictim(); - events.Update(diff); - - switch (events.ExecuteEvent()) - { - case EVENT_BRANN_MOVE_INTRO: - if (_currentPoint < MAX_BRANN_WAYPOINTS_INTRO) - me->GetMotionMaster()->MovePoint(_currentPoint, BrannIntroWaypoint[_currentPoint]); - break; - case EVENT_SUMMON_ALGALON: - if (me->GetInstanceScript() && !me->GetInstanceScript()->GetGuidData(TYPE_ALGALON)) - if (Creature* algalon = me->GetMap()->SummonCreature(NPC_ALGALON, AlgalonSummonPos)) - algalon->AI()->DoAction(ACTION_START_INTRO); - break; - case EVENT_BRANN_OUTRO_1: - Talk(SAY_BRANN_ALGALON_OUTRO); - break; - case EVENT_BRANN_OUTRO_2: - me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO_END, BrannOutroPos[2]); - break; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); - } -}; - -class npc_collapsing_star : public CreatureScript -{ -public: - npc_collapsing_star() : CreatureScript("npc_collapsing_star") { } - - struct npc_collapsing_starAI : public NullCreatureAI - { - npc_collapsing_starAI(Creature* creature) : NullCreatureAI(creature) - { - creature->GetMotionMaster()->MoveRandom(25.0f); - creature->CastSpell(creature, SPELL_COLLAPSE, true); - } - - void JustSummoned(Creature* summon) override - { - if (TempSummon* summ = me->ToTempSummon()) - if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID())) - algalon->AI()->JustSummoned(summon); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (damage >= me->GetHealth()) - { - me->CastSpell(me, SPELL_BLACK_HOLE_SPAWN_VISUAL, true); - me->CastSpell(me, SPELL_SUMMON_BLACK_HOLE, true); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); - } -}; - -class npc_living_constellation : public CreatureScript -{ -public: - npc_living_constellation() : CreatureScript("npc_living_constellation") { } - - struct npc_living_constellationAI : public ScriptedAI - { - npc_living_constellationAI(Creature* creature) : ScriptedAI(creature) - { - me->SetReactState(REACT_PASSIVE); - } - - EventMap events; - bool _isActive; - - void Reset() override - { - events.Reset(); - events.ScheduleEvent(EVENT_ARCANE_BARRAGE, 2500ms); - _isActive = false; - } - - uint32 GetData(uint32 /*param*/) const override - { - return _isActive; - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_ACTIVATE_STAR: - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToAll(false); - _isActive = true; - - if (Player* target = SelectTargetFromPlayerList(250.0f)) - { - AttackStart(target); - me->AddThreat(target, 100.0f); - } - me->SetInCombatWithZone(); - break; - case ACTION_BIG_BANG: - events.SetPhase(PHASE_BIG_BANG); - events.DelayEvents(9500); - events.ScheduleEvent(EVENT_RESUME_UPDATING, 9500ms); - break; - } - } - - void SpellHit(Unit* caster, SpellInfo const* spell) override - { - if (spell->Id != SPELL_CONSTELLATION_PHASE_EFFECT || caster->GetTypeId() != TYPEID_UNIT) - return; - - if (InstanceScript* instance = me->GetInstanceScript()) - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_ID_SUPERMASSIVE_START); - - caster->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_CREDIT, TRIGGERED_FULL_MASK); - caster->ToCreature()->DespawnOrUnsummon(1); - me->DespawnOrUnsummon(1); - if (Creature* voidZone = caster->FindNearestCreature(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER, 10.0f)) - voidZone->DespawnOrUnsummon(1); - } - - void UpdateAI(uint32 diff) override - { - if (!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && !UpdateVictim()) - return; - - events.Update(diff); - switch (events.ExecuteEvent()) - { - case EVENT_ARCANE_BARRAGE: - me->CastCustomSpell(SPELL_ARCANE_BARRAGE, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, true); - events.Repeat(2500ms); - break; - case EVENT_RESUME_UPDATING: - events.SetPhase(0); - break; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); - } -}; - -class npc_algalon_worm_hole : public CreatureScript -{ -public: - npc_algalon_worm_hole() : CreatureScript("npc_algalon_worm_hole") { } - - struct npc_algalon_worm_holeAI : public NullCreatureAI - { - npc_algalon_worm_holeAI(Creature* creature) : NullCreatureAI(creature) - { - creature->CastSpell(creature, SPELL_WORM_HOLE_TRIGGER, true); - creature->CastSpell(creature, SPELL_SUMMON_VOID_ZONE_VISUAL, true); - } - - uint32 _summonTimer; - - void Reset() override - { - _summonTimer = urand(22000, 24000); - } - - void JustSummoned(Creature* summon) override - { - if (TempSummon* summ = me->ToTempSummon()) - { - if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID())) - { - algalon->AI()->JustSummoned(summon); - } - } - } - - void UpdateAI(uint32 diff) override - { - _summonTimer += diff; - if (_summonTimer >= 30000) - { - me->CastSpell((Unit*)nullptr, SPELL_SUMMON_UNLEASHED_DARK_MATTER, true); - _summonTimer = 0; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); - } -}; - -class go_celestial_planetarium_access : public GameObjectScript -{ -public: - go_celestial_planetarium_access() : GameObjectScript("go_celestial_planetarium_access") {} - - struct go_celestial_planetarium_accessAI : public GameObjectAI - { - go_celestial_planetarium_accessAI(GameObject* go) : GameObjectAI(go) - { - _locked = false; - } - - EventMap events; - bool _locked; - - bool GossipHello(Player* player, bool /*reportUse*/) override - { - bool hasKey = true; - if (LockEntry const* lock = sLockStore.LookupEntry(me->GetGOInfo()->goober.lockId)) - { - hasKey = false; - for (uint32 i = 0; i < MAX_LOCK_CASE; ++i) - { - if (!lock->Index[i]) - continue; - - if (player->HasItemCount(lock->Index[i])) - { - hasKey = true; - break; - } - } - } - - if (!hasKey) - return false; - - if (_locked) - return false; - _locked = true; - // Start Algalon event - me->SetGameObjectFlag(GO_FLAG_IN_USE); - events.ScheduleEvent(EVENT_DESPAWN_CONSOLE, 5000ms); - if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannIntroSpawnPos)) - brann->AI()->DoAction(ACTION_START_INTRO); - - if (InstanceScript* instance = me->GetInstanceScript()) - { - instance->SetData(DATA_ALGALON_SUMMON_STATE, 1); - if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_DOODAD_UL_SIGILDOOR_01))) - sigil->SetGoState(GO_STATE_ACTIVE); - - if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_DOODAD_UL_SIGILDOOR_02))) - sigil->SetGoState(GO_STATE_ACTIVE); - - if (Map* map = player->GetMap()) - { - if (InstanceMap* instanceMap = map->ToInstanceMap()) - { - instanceMap->PermBindAllPlayers(); - } - } - } - - return false; - } - - void UpdateAI(uint32 diff) override - { - if (events.Empty()) - return; - - events.Update(diff); - switch (events.ExecuteEvent()) - { - case EVENT_DESPAWN_CONSOLE: - me->Delete(); - break; - } - } - }; - - GameObjectAI* GetAI(GameObject* go) const override - { - return new go_celestial_planetarium_accessAI(go); - } -}; - -class spell_algalon_phase_punch : public SpellScriptLoader -{ -public: - spell_algalon_phase_punch() : SpellScriptLoader("spell_algalon_phase_punch") { } - - class spell_algalon_phase_punch_AuraScript : public AuraScript - { - PrepareAuraScript(spell_algalon_phase_punch_AuraScript); - - void HandlePeriodic(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - if (GetStackAmount() != 1) - GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 2]); - GetTarget()->CastSpell(GetTarget(), PhasePunchAlphaId[GetStackAmount() - 1], TRIGGERED_FULL_MASK); - if (GetStackAmount() == 5) - Remove(AURA_REMOVE_BY_DEFAULT); - } - - void OnRemove(AuraEffect const*, AuraEffectHandleModes) - { - if (GetStackAmount() != 5) - GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 1]); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_phase_punch_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - OnEffectRemove += AuraEffectRemoveFn(spell_algalon_phase_punch_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_algalon_phase_punch_AuraScript(); - } -}; - -class spell_algalon_collapse : public SpellScriptLoader -{ -public: - spell_algalon_collapse() : SpellScriptLoader("spell_algalon_collapse") { } - - class spell_algalon_collapse_AuraScript : public AuraScript - { - PrepareAuraScript(spell_algalon_collapse_AuraScript); - - void HandlePeriodic(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - Unit::DealDamage(GetTarget(), GetTarget(), GetTarget()->CountPctFromMaxHealth(1), nullptr, NODAMAGE); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_collapse_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_algalon_collapse_AuraScript(); - } -}; - -class ActiveConstellationFilter -{ -public: - bool operator()(WorldObject* object) const - { - return object->ToUnit()->GetAI()->GetData(0); - } -}; - -class spell_algalon_trigger_3_adds : public SpellScriptLoader -{ -public: - spell_algalon_trigger_3_adds() : SpellScriptLoader("spell_algalon_trigger_3_adds") { } - - class spell_algalon_trigger_3_adds_SpellScript : public SpellScript - { - PrepareSpellScript(spell_algalon_trigger_3_adds_SpellScript); - - void SelectTarget(std::list& targets) - { - targets.remove_if(ActiveConstellationFilter()); - } - - void HandleDummyEffect(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - Creature* target = GetHitCreature(); - if (!target) - return; - - target->AI()->DoAction(ACTION_ACTIVATE_STAR); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_trigger_3_adds_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); - OnEffectHitTarget += SpellEffectFn(spell_algalon_trigger_3_adds_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_algalon_trigger_3_adds_SpellScript(); - } -}; - -class spell_algalon_cosmic_smash_damage : public SpellScriptLoader -{ -public: - spell_algalon_cosmic_smash_damage() : SpellScriptLoader("spell_algalon_cosmic_smash_damage") { } - - class spell_algalon_cosmic_smash_damage_SpellScript : public SpellScript - { - PrepareSpellScript(spell_algalon_cosmic_smash_damage_SpellScript); - - void RecalculateDamage() - { - if (!GetExplTargetDest() || !GetHitUnit()) - return; - - float distance = GetHitUnit()->GetDistance2d(GetExplTargetDest()->GetPositionX(), GetExplTargetDest()->GetPositionY()); - if (distance >= 10.0f) - SetHitDamage(int32(float(GetHitDamage()) / distance)); - else if (distance > 6.0f) - SetHitDamage(int32(float(GetHitDamage()) / distance) * 2); - } - - void Register() override - { - OnHit += SpellHitFn(spell_algalon_cosmic_smash_damage_SpellScript::RecalculateDamage); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_algalon_cosmic_smash_damage_SpellScript(); - } -}; - -class spell_algalon_big_bang : public SpellScriptLoader -{ -public: - spell_algalon_big_bang() : SpellScriptLoader("spell_algalon_big_bang") { } - - class spell_algalon_big_bang_SpellScript : public SpellScript - { - PrepareSpellScript(spell_algalon_big_bang_SpellScript); - - bool Load() override - { - _targetCount = 0; - return true; - } - - void CountTargets(std::list& targets) - { - _targetCount = targets.size(); - } - - void CheckTargets() - { - Unit* caster = GetCaster(); - if (!_targetCount && caster && caster->GetAI()) - caster->GetAI()->DoAction(ACTION_ASCEND); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_big_bang_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - AfterCast += SpellCastFn(spell_algalon_big_bang_SpellScript::CheckTargets); - } - - uint32 _targetCount; - }; - - SpellScript* GetSpellScript() const override - { - return new spell_algalon_big_bang_SpellScript(); - } -}; - -class spell_algalon_remove_phase : public SpellScriptLoader -{ -public: - spell_algalon_remove_phase() : SpellScriptLoader("spell_algalon_remove_phase") { } - - class spell_algalon_remove_phase_AuraScript : public AuraScript - { - PrepareAuraScript(spell_algalon_remove_phase_AuraScript); - - void HandlePeriodic(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - GetTarget()->RemoveAurasByType(SPELL_AURA_PHASE); - GetTarget()->RemoveAurasDueToSpell(SPELL_BLACK_HOLE_DAMAGE); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_remove_phase_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_algalon_remove_phase_AuraScript(); - } -}; - -class spell_algalon_supermassive_fail : public SpellScriptLoader -{ -public: - spell_algalon_supermassive_fail() : SpellScriptLoader("spell_algalon_supermassive_fail") { } - - class spell_algalon_supermassive_fail_SpellScript : public SpellScript - { - PrepareSpellScript(spell_algalon_supermassive_fail_SpellScript); - - void RecalculateDamage() - { - if (!GetHitPlayer()) - return; - - GetHitPlayer()->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_NO_SPELL_HIT, GetSpellInfo()->Id, true); - } - - void Register() override - { - OnHit += SpellHitFn(spell_algalon_supermassive_fail_SpellScript::RecalculateDamage); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_algalon_supermassive_fail_SpellScript(); - } -}; - -class achievement_algalon_he_feeds_on_your_tears : public AchievementCriteriaScript -{ -public: - achievement_algalon_he_feeds_on_your_tears() : AchievementCriteriaScript("achievement_algalon_he_feeds_on_your_tears") { } - - bool OnCheck(Player*, Unit* target /*Algalon*/, uint32 /*criteria_id*/) override - { - return target && target->GetAI()->GetData(DATA_HAS_FED_ON_TEARS); - } -}; - -class achievement_algalon_herald_of_the_titans : public AchievementCriteriaScript -{ -public: - achievement_algalon_herald_of_the_titans() : AchievementCriteriaScript("achievement_algalon_herald_of_the_titans") { } - - bool OnCheck(Player*, Unit* target /*Algalon*/, uint32 /*criteria_id*/) override - { - return target && target->GetAI()->GetData(DATA_HERALD_OF_THE_TITANS); - } -}; - void AddSC_boss_algalon_the_observer() { // NPCs diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.h new file mode 100644 index 00000000000000..bd5ead4a5c7c91 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.h @@ -0,0 +1,1447 @@ +#ifndef BOSS_ALGALON_THE_OBSERVER_H_ +#define BOSS_ALGALON_THE_OBSERVER_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "GameObjectAI.h" +#include "GameObjectScript.h" +#include "MapMgr.h" +#include "MoveSplineInit.h" +#include "ObjectMgr.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "ulduar.h" + +enum Spells +{ + // Algalon the Observer + SPELL_ARRIVAL = 64997, + SPELL_RIDE_THE_LIGHTNING = 64986, + SPELL_SUMMON_AZEROTH = 64994, + SPELL_REORIGINATION = 64996, + SPELL_SUPERMASSIVE_FAIL = 65311, + SPELL_QUANTUM_STRIKE = 64395, + SPELL_PHASE_PUNCH = 64412, + SPELL_BIG_BANG = 64443, + SPELL_ASCEND_TO_THE_HEAVENS = 64487, + SPELL_COSMIC_SMASH = 62301, + SPELL_COSMIC_SMASH_TRIGGERED = 62304, + SPELL_COSMIC_SMASH_VISUAL_STATE = 62300, + SPELL_SELF_STUN = 65256, + SPELL_KILL_CREDIT = 65184, + SPELL_TELEPORT = 62940, + SPELL_DUAL_WIELD = 42459, + + // Algalon Stalker + SPELL_TRIGGER_3_ADDS = 62266, // Triggers Living Constellation + + // Living Constellation + SPELL_ARCANE_BARRAGE = 64599, + + // Collapsing Star + SPELL_COLLAPSE = 62018, + SPELL_BLACK_HOLE_SPAWN_VISUAL = 62003, + SPELL_SUMMON_BLACK_HOLE = 62189, + + // Black Hole + SPELL_BLACK_HOLE_TRIGGER = 62185, + SPELL_CONSTELLATION_PHASE_TRIGGER = 65508, + SPELL_CONSTELLATION_PHASE_EFFECT = 65509, + SPELL_BLACK_HOLE_EXPLOSION = 64122, + SPELL_SUMMON_VOID_ZONE_VISUAL = 64470, + SPELL_VOID_ZONE_VISUAL = 64469, + SPELL_BLACK_HOLE_CREDIT = 65312, + SPELL_BLACK_HOLE_DAMAGE = 62169, + + // Worm Hole + SPELL_WORM_HOLE_TRIGGER = 65251, + SPELL_SUMMON_UNLEASHED_DARK_MATTER = 64450, +}; + +enum Actions +{ + //ACTION_INIT_ALGALON = 1, defined in ulduar.h + //ACTION_DESPAWN_ALGALON = 2, defined in ulduar.h + ACTION_START_INTRO = 3, + ACTION_FINISH_INTRO = 4, + ACTION_ACTIVATE_STAR = 5, + ACTION_BIG_BANG = 6, + ACTION_ASCEND = 7, + ACTION_OUTRO = 8, +}; + +enum Misc +{ + POINT_BRANN_INTRO = 0, + MAX_BRANN_WAYPOINTS_INTRO = 11, + POINT_BRANN_OUTRO = 11, + POINT_BRANN_OUTRO_END = 12, + + POINT_ALGALON_LAND = 1, + POINT_ALGALON_OUTRO = 2, + + EVENT_ID_SUPERMASSIVE_START = 21697, + + DATA_HAS_FED_ON_TEARS = 1, + DATA_HERALD_OF_THE_TITANS = 2, +}; + +enum Events +{ + // Celestial Planetarium Access + EVENT_DESPAWN_CONSOLE = 1, + + // Brann Bronzebeard + EVENT_BRANN_MOVE_INTRO = 2, + EVENT_SUMMON_ALGALON = 3, + EVENT_BRANN_OUTRO_1 = 4, + EVENT_BRANN_OUTRO_2 = 5, + + // Algalon the Observer + EVENT_INTRO_1 = 6, + EVENT_INTRO_2 = 7, + EVENT_INTRO_3 = 8, + EVENT_INTRO_FINISH = 9, + EVENT_START_COMBAT = 10, + EVENT_INTRO_TIMER_DONE = 11, + EVENT_QUANTUM_STRIKE = 12, + EVENT_PHASE_PUNCH = 13, + EVENT_SUMMON_COLLAPSING_STAR = 14, + EVENT_BIG_BANG = 15, + EVENT_RESUME_UPDATING = 16, + EVENT_ASCEND_TO_THE_HEAVENS = 17, + EVENT_EVADE = 18, + EVENT_COSMIC_SMASH = 19, + EVENT_UNLOCK_YELL = 20, + EVENT_OUTRO_START = 21, + EVENT_OUTRO_1 = 22, + EVENT_OUTRO_2 = 23, + EVENT_OUTRO_3 = 24, + EVENT_OUTRO_4 = 25, + EVENT_OUTRO_5 = 26, + EVENT_OUTRO_6 = 27, + EVENT_OUTRO_7 = 28, + EVENT_OUTRO_8 = 29, + EVENT_OUTRO_9 = 30, + EVENT_OUTRO_10 = 31, + EVENT_OUTRO_11 = 32, + EVENT_ACTIVATE_LIVING_CONSTELLATION = 33, + EVENT_CHECK_HERALD_ITEMS = 34, + EVENT_REMOVE_UNNATTACKABLE = 35, + EVENT_DESPAWN_ALGALON_1 = 36, + EVENT_DESPAWN_ALGALON_2 = 37, + EVENT_DESPAWN_ALGALON_3 = 38, + EVENT_DESPAWN_ALGALON_4 = 39, + EVENT_DESPAWN_ALGALON_5 = 40, + + // Living Constellation + EVENT_ARCANE_BARRAGE = 41, +}; + +enum EncounterPhases +{ + PHASE_NORMAL = 0, + PHASE_ROLE_PLAY = 1, + PHASE_BIG_BANG = 2, + + PHASE_MASK_NO_UPDATE = (1 << (PHASE_ROLE_PLAY - 1)) | (1 << (PHASE_BIG_BANG - 1)), + PHASE_MASK_NO_CAST_CHECK = 1 << (PHASE_ROLE_PLAY - 1), +}; + +enum Texts +{ + SAY_BRANN_ALGALON_INTRO_1 = 0, + SAY_BRANN_ALGALON_INTRO_2 = 1, + SAY_BRANN_ALGALON_OUTRO = 2, + + SAY_ALGALON_INTRO_1 = 0, + SAY_ALGALON_INTRO_2 = 1, + SAY_ALGALON_INTRO_3 = 2, + SAY_ALGALON_START_TIMER = 3, + SAY_ALGALON_AGGRO = 4, + SAY_ALGALON_COLLAPSING_STAR = 5, + EMOTE_ALGALON_COLLAPSING_STAR = 6, + SAY_ALGALON_BIG_BANG = 7, + EMOTE_ALGALON_BIG_BANG = 8, + SAY_ALGALON_ASCEND = 9, + EMOTE_ALGALON_COSMIC_SMASH = 10, + SAY_ALGALON_PHASE_TWO = 11, + SAY_ALGALON_OUTRO_1 = 12, + SAY_ALGALON_OUTRO_2 = 13, + SAY_ALGALON_OUTRO_3 = 14, + SAY_ALGALON_OUTRO_4 = 15, + SAY_ALGALON_OUTRO_5 = 16, + SAY_ALGALON_DESPAWN_1 = 17, + SAY_ALGALON_DESPAWN_2 = 18, + SAY_ALGALON_DESPAWN_3 = 19, + SAY_ALGALON_KILL = 20, +}; + +uint32 const PhasePunchAlphaId[5] = {64435, 64434, 64428, 64421, 64417}; + +Position const BrannIntroSpawnPos = {1676.277f, -162.5308f, 427.3326f, 3.235537f}; +Position const BrannIntroWaypoint[MAX_BRANN_WAYPOINTS_INTRO] = +{ + {1642.482f, -164.0812f, 427.2602f, 0.0f}, + {1635.000f, -169.5145f, 427.2523f, 0.0f}, + {1632.814f, -173.9334f, 427.2621f, 0.0f}, + {1632.676f, -190.5927f, 427.2631f, 0.0f}, + {1631.497f, -214.2221f, 418.1152f, 0.0f}, + {1636.455f, -263.6647f, 417.3213f, 0.0f}, + {1629.586f, -267.9792f, 417.3219f, 0.0f}, + {1631.497f, -214.2221f, 418.1152f, 0.0f}, + {1632.676f, -190.5927f, 425.8831f, 0.0f}, + {1632.814f, -173.9334f, 427.2621f, 0.0f}, + {1635.000f, -169.5145f, 427.2523f, 0.0f}, +}; + +#define LIVING_CONSTELLATION_COUNT 11 +Position const ConstellationPos[LIVING_CONSTELLATION_COUNT] = +{ + {1625.208f, -267.2771f, 446.4296f, 5.044002f}, + {1593.389f, -299.4325f, 432.4636f, 6.073746f}, + {1668.317f, -324.7676f, 457.9394f, 3.211406f}, + {1685.613f, -300.1219f, 443.2366f, 3.385939f}, + {1592.242f, -325.5323f, 446.9508f, 0.226893f}, + {1658.279f, -262.5490f, 441.9073f, 4.188790f}, + {1635.821f, -363.3442f, 424.3459f, 1.466077f}, + {1591.706f, -263.8201f, 441.4153f, 5.253441f}, + {1672.188f, -357.2484f, 436.7337f, 2.338741f}, + {1678.677f, -276.3280f, 427.7531f, 3.979351f}, + {1615.800f, -348.0065f, 442.9586f, 1.134464f}, +}; + +#define COLLAPSING_STAR_COUNT 4 +Position const CollapsingStarPos[COLLAPSING_STAR_COUNT] = +{ + {1649.438f, -319.8127f, 418.3941f, 1.082104f}, + {1647.005f, -288.6790f, 417.3955f, 3.490659f}, + {1622.451f, -321.1563f, 417.6188f, 4.677482f}, + {1615.060f, -291.6816f, 417.7796f, 3.490659f}, +}; +Position const AlgalonOutroPos = {1633.64f, -317.78f, 417.3211f, 0.0f}; +Position const BrannOutroPos[3] = +{ + {1632.023f, -243.7434f, 417.9118f, 0.0f}, + {1631.986f, -297.7831f, 417.3210f, 0.0f}, + {1633.832f, -216.2948f, 417.0463f, 0.0f}, +}; + +class CosmicSmashDamageEvent : public BasicEvent +{ +public: + CosmicSmashDamageEvent(Unit* caster) : _caster(caster) + { + } + + bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override + { + _caster->CastSpell(_caster, SPELL_COSMIC_SMASH_TRIGGERED, true); + return true; + } + +private: + Unit* _caster; +}; + +class boss_algalon_the_observer : public CreatureScript +{ +public: + boss_algalon_the_observer() : CreatureScript("boss_algalon_the_observer") {} + + struct boss_algalon_the_observerAI : public ScriptedAI + { + boss_algalon_the_observerAI(Creature* creature) : ScriptedAI(creature), summons(me) + { + _fedOnTears = true; + _firstPull = true; + _fightWon = false; + m_pInstance = me->GetInstanceScript(); + } + + EventMap events; + SummonList summons; + InstanceScript* m_pInstance; + + bool _firstPull; + bool _fightWon; + bool _phaseTwo; + bool _fedOnTears; + bool _heraldOfTheTitans; + + bool IsValidHeraldItem(ItemTemplate const* item) + { + if (!item) // should not happen, but checked in GetAverageItemLevel() + return true; + if (item->ItemLevel <= 226 || (item->ItemLevel <= 232 && ( + item->InventoryType == INVTYPE_SHIELD || + item->Class == ITEM_CLASS_WEAPON || + (item->Class == ITEM_CLASS_ARMOR && (item->InventoryType == INVTYPE_RELIC || item->InventoryType == INVTYPE_HOLDABLE)) + ))) + return true; + return false; + } + + bool DoCheckHeraldOfTheTitans() + { + if (!_heraldOfTheTitans) + return true; + + Map::PlayerList const& pl = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) + if (Player* plr = itr->GetSource()) + if (!plr->IsGameMaster() && plr->IsInCombat() /*performance*/) + { + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) // loop through equipped items + if (Item* item = plr->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + if (!IsValidHeraldItem(item->GetTemplate())) + { + _heraldOfTheTitans = false; + return true; + } + } + + return false; + } + + void AttackStart(Unit* who) override + { + if (_fightWon) + return; + ScriptedAI::AttackStart(who); + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_HAS_FED_ON_TEARS) + return _fedOnTears; + if (param == DATA_HERALD_OF_THE_TITANS) + return _heraldOfTheTitans; + return 0; + } + + void CallConstellations() + { + uint8 _count = 0; + for (SummonList::const_iterator i = summons.begin(); i != summons.end(); ) + { + Creature* summon = ObjectAccessor::GetCreature(*me, *i++); + if (summon && summon->GetEntry() == NPC_LIVING_CONSTELLATION && !summon->AI()->GetData(0)) + { + ++_count; + summon->AI()->DoAction(ACTION_ACTIVATE_STAR); + if (_count >= 3) + break; + } + } + } + + void EnterEvadeMode(EvadeReason why) override + { + if (_fightWon) + return; + + if (SelectTargetFromPlayerList(120.0f)) + { + me->SetInCombatWithZone(); + return; + } + else if (events.GetPhaseMask() & PHASE_NORMAL) + { + DoAction(ACTION_ASCEND); + return; + } + + if (m_pInstance) + m_pInstance->SetData(TYPE_ALGALON, FAIL); + + ScriptedAI::EnterEvadeMode(why); + } + + void Reset() override + { + if (_fightWon) + return; + + events.Reset(); + summons.DespawnAll(); + me->SetReactState(REACT_PASSIVE); + me->SetImmuneToPC(false); + me->SetSheath(SHEATH_STATE_UNARMED); + me->SetFaction(190); + me->CastSpell(me, SPELL_DUAL_WIELD, true); + + _phaseTwo = false; + _heraldOfTheTitans = true; + + if (m_pInstance->GetData(TYPE_ALGALON) == FAIL) + { + _firstPull = false; + } + + if (m_pInstance) + m_pInstance->SetData(TYPE_ALGALON, NOT_STARTED); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2)) + return; + + Talk(SAY_ALGALON_KILL); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_START_INTRO: + { + me->SetImmuneToPC(true); + me->SetUnitFlag2(UNIT_FLAG2_DO_NOT_FADE_IN); + me->SetDisableGravity(true); + me->CastSpell(me, SPELL_ARRIVAL, true); + me->CastSpell(me, SPELL_RIDE_THE_LIGHTNING, true); + me->GetMotionMaster()->MovePoint(POINT_ALGALON_LAND, AlgalonLandPos); + me->SetHomePosition(AlgalonLandPos); + Movement::MoveSplineInit init(me); + init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ()); + init.SetOrientationFixed(true); + init.Launch(); + events.Reset(); + events.SetPhase(PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_INTRO_1, 5s, 0, PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_INTRO_2, 15s, 0, PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_INTRO_3, 23s, 0, PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_INTRO_FINISH, 36s, 0, PHASE_ROLE_PLAY); + break; + } + case ACTION_DESPAWN_ALGALON: + _fightWon = true; + events.Reset(); + summons.DespawnAll(); + events.SetPhase(PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_1, 5s); + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_2, 17s); + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_3, 26s); + if (me->IsInCombat()) + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_4, 26s); + events.ScheduleEvent(EVENT_DESPAWN_ALGALON_5, 32s); + me->DespawnOrUnsummon(39000); + + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->SetFaction(FACTION_FRIENDLY); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->InterruptNonMeleeSpells(false); + if (m_pInstance) + m_pInstance->SetData(TYPE_ALGALON, NOT_STARTED); + break; + case ACTION_INIT_ALGALON: + _firstPull = false; + _fedOnTears = false; + me->SetImmuneToPC(false); + break; + case ACTION_ASCEND: + summons.DespawnAll(); + events.SetPhase(PHASE_BIG_BANG); + events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 1500ms); + break; + case ACTION_FEEDS_ON_TEARS_FAILED: + _fedOnTears = false; + } + } + + void JustReachedHome() override + { + me->setActive(false); + } + + void JustEngagedWith(Unit*) override + { + if (_fightWon) + return; + + if (!m_pInstance) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + uint32 introDelay = 0; + me->setActive(true); + me->SetInCombatWithZone(); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToNPC(true); + events.Reset(); + events.SetPhase(PHASE_ROLE_PLAY); + + if (!_firstPull) + { + events.ScheduleEvent(EVENT_START_COMBAT, 0ms); + introDelay = 8000; + } + else + { + summons.DespawnEntry(NPC_AZEROTH); + _firstPull = false; + Talk(SAY_ALGALON_START_TIMER); + introDelay = 22000; + events.ScheduleEvent(EVENT_START_COMBAT, 14s); + m_pInstance->SetData(DATA_DESPAWN_ALGALON, 0); + } + + events.ScheduleEvent(EVENT_REMOVE_UNNATTACKABLE, introDelay - 500); + events.ScheduleEvent(EVENT_INTRO_TIMER_DONE, introDelay); + events.ScheduleEvent(EVENT_QUANTUM_STRIKE, 3500 + introDelay); + events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500 + introDelay); + events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 16500 + introDelay); + events.ScheduleEvent(EVENT_COSMIC_SMASH, 25000 + introDelay); + events.ScheduleEvent(EVENT_ACTIVATE_LIVING_CONSTELLATION, 50500 + introDelay); + events.ScheduleEvent(EVENT_BIG_BANG, 90000 + introDelay); + events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 360000 + introDelay); + + events.ScheduleEvent(EVENT_CHECK_HERALD_ITEMS, 5s); + DoCheckHeraldOfTheTitans(); + } + + void MovementInform(uint32 movementType, uint32 pointId) override + { + if (movementType != POINT_MOTION_TYPE) + return; + + if (pointId == POINT_ALGALON_LAND) + me->SetDisableGravity(false); + else if (pointId == POINT_ALGALON_OUTRO) + { + me->SetFacingTo(1.605703f); + events.ScheduleEvent(EVENT_OUTRO_3, 1200ms); + events.ScheduleEvent(EVENT_OUTRO_4, 2400ms); + events.ScheduleEvent(EVENT_OUTRO_5, 8500ms); + events.ScheduleEvent(EVENT_OUTRO_6, 15s + 500ms); + events.ScheduleEvent(EVENT_OUTRO_7, 55s + 500ms); + events.ScheduleEvent(EVENT_OUTRO_8, 73s + 500ms); + events.ScheduleEvent(EVENT_OUTRO_9, 85s + 500ms); + events.ScheduleEvent(EVENT_OUTRO_10, 101s + 500ms); + events.ScheduleEvent(EVENT_OUTRO_11, 117s + 500ms); + } + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + switch (summon->GetEntry()) + { + case NPC_AZEROTH: + me->CastSpell(summon, SPELL_REORIGINATION, true); + break; + case NPC_BLACK_HOLE: + summon->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_TRIGGER, true); + summon->CastSpell(summon, SPELL_CONSTELLATION_PHASE_TRIGGER, true); + summon->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_EXPLOSION, false); + summon->CastSpell(summon, SPELL_SUMMON_VOID_ZONE_VISUAL, true); + break; + case NPC_ALGALON_VOID_ZONE_VISUAL_STALKER: + summon->CastSpell(summon, SPELL_VOID_ZONE_VISUAL, true); + break; + case NPC_ALGALON_STALKER_ASTEROID_TARGET_01: + summon->CastSpell(summon, SPELL_COSMIC_SMASH_VISUAL_STATE, true); + break; + case NPC_ALGALON_STALKER_ASTEROID_TARGET_02: + { + float x = summon->GetPositionX(); + float y = summon->GetPositionY(); + float z = summon->GetPositionZ() + 35.0f; + float o = summon->GetOrientation(); + + summon->GetMotionMaster()->Clear(); + summon->SetHomePosition(x, y, z, o); + summon->UpdatePosition(x, y, z, o, true); + summon->StopMovingOnCurrentPos(); + summon->m_Events.AddEvent(new CosmicSmashDamageEvent(summon), summon->m_Events.CalculateTime(4000)); + break; + } + case NPC_UNLEASHED_DARK_MATTER: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true)) + if (summon->Attack(target, true)) + summon->GetMotionMaster()->MoveChase(target); + break; + } + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (_fightWon) + { + damage = 0; + return; + } + + if (!_phaseTwo && me->HealthBelowPctDamaged(20, damage)) + { + _phaseTwo = true; + Talk(SAY_ALGALON_PHASE_TWO); + summons.DespawnEntry(NPC_LIVING_CONSTELLATION); + summons.DespawnEntry(NPC_COLLAPSING_STAR); + summons.DespawnEntry(NPC_BLACK_HOLE); + summons.DespawnEntry(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER); + events.CancelEvent(EVENT_SUMMON_COLLAPSING_STAR); + events.CancelEvent(EVENT_ACTIVATE_LIVING_CONSTELLATION); + + for (uint32 i = 0; i < COLLAPSING_STAR_COUNT; ++i) + me->SummonCreature(NPC_WORM_HOLE, CollapsingStarPos[i], TEMPSUMMON_MANUAL_DESPAWN); + } + else if (me->HealthBelowPctDamaged(2, damage) && !_fightWon) + { + _fightWon = true; + damage = 0; + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->SetFaction(FACTION_FRIENDLY); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + events.Reset(); + summons.DespawnAll(); + me->InterruptNonMeleeSpells(false); + events.SetPhase(PHASE_ROLE_PLAY); + events.ScheduleEvent(EVENT_OUTRO_START, 1500ms); + events.ScheduleEvent(EVENT_OUTRO_1, 7200ms); + events.ScheduleEvent(EVENT_OUTRO_2, 8700ms); + } + } + + bool IsInRoom() + { + if (me->GetExactDist2d(&me->GetHomePosition()) > 45.f || me->GetPositionZ() < 410.f) + { + DoAction(ACTION_ASCEND); + return false; + } + + return true; + } + + void UpdateAI(uint32 diff) override + { + if (!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && (!UpdateVictim() || !IsInRoom())) + return; + + events.Update(diff); + if (!(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK) && me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_INTRO_1: + me->RemoveAurasDueToSpell(SPELL_RIDE_THE_LIGHTNING); + Talk(SAY_ALGALON_INTRO_1); + break; + case EVENT_INTRO_2: + me->CastSpell((Unit*)nullptr, SPELL_SUMMON_AZEROTH, true); + Talk(SAY_ALGALON_INTRO_2); + break; + case EVENT_INTRO_3: + Talk(SAY_ALGALON_INTRO_3); + break; + case EVENT_INTRO_FINISH: + events.Reset(); + me->SetImmuneToPC(false); + if (Creature* brann = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_BRANN_BRONZBEARD_ALG))) + brann->AI()->DoAction(ACTION_FINISH_INTRO); + break; + case EVENT_START_COMBAT: + m_pInstance->SetData(TYPE_ALGALON, IN_PROGRESS); + Talk(SAY_ALGALON_AGGRO); + break; + case EVENT_REMOVE_UNNATTACKABLE: + me->SetSheath(SHEATH_STATE_MELEE); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToNPC(false); + break; + case EVENT_INTRO_TIMER_DONE: + events.SetPhase(PHASE_NORMAL); + me->CastSpell((Unit*)nullptr, SPELL_SUPERMASSIVE_FAIL, true); + // Hack: _IsValidTarget failed earlier due to flags, call AttackStart again + me->SetReactState(REACT_AGGRESSIVE); + me->SetFaction(FACTION_MONSTER); + if (Player* target = SelectTargetFromPlayerList(150.0f)) + AttackStart(target); + me->SetInCombatWithZone(); + + for (uint32 i = 0; i < LIVING_CONSTELLATION_COUNT; ++i) + me->SummonCreature(NPC_LIVING_CONSTELLATION, ConstellationPos[i], TEMPSUMMON_DEAD_DESPAWN); + break; + case EVENT_QUANTUM_STRIKE: + me->CastSpell(me->GetVictim(), SPELL_QUANTUM_STRIKE, false); + events.Repeat(3000ms, 4500ms); + break; + case EVENT_PHASE_PUNCH: + me->CastSpell(me->GetVictim(), SPELL_PHASE_PUNCH, false); + events.Repeat(15s + 500ms); + break; + case EVENT_SUMMON_COLLAPSING_STAR: + Talk(SAY_ALGALON_COLLAPSING_STAR); + Talk(EMOTE_ALGALON_COLLAPSING_STAR); + for (uint8 i = 0; i < COLLAPSING_STAR_COUNT; ++i) + me->SummonCreature(NPC_COLLAPSING_STAR, CollapsingStarPos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); + events.Repeat(1min); + break; + case EVENT_COSMIC_SMASH: + Talk(EMOTE_ALGALON_COSMIC_SMASH); + me->CastCustomSpell(SPELL_COSMIC_SMASH, SPELLVALUE_MAX_TARGETS, RAID_MODE(1, 3), (Unit*)nullptr); + events.Repeat(25s + 500ms); + break; + case EVENT_ACTIVATE_LIVING_CONSTELLATION: + { + if (events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) + { + events.Repeat(4s); + break; + } + CallConstellations(); + //me->CastSpell(me, SPELL_TRIGGER_3_ADDS, true); + events.Repeat(50s); + break; + } + case EVENT_BIG_BANG: + { + Talk(SAY_ALGALON_BIG_BANG); + Talk(EMOTE_ALGALON_BIG_BANG); + + EntryCheckPredicate pred(NPC_LIVING_CONSTELLATION); + summons.DoAction(ACTION_BIG_BANG, pred); + + me->CastSpell((Unit*)nullptr, SPELL_BIG_BANG, false); + events.Repeat(90s + 500ms); + break; + } + case EVENT_ASCEND_TO_THE_HEAVENS: + Talk(SAY_ALGALON_ASCEND); + me->CastSpell((Unit*)nullptr, SPELL_ASCEND_TO_THE_HEAVENS, false); + events.ScheduleEvent(EVENT_EVADE, 2500ms); + break; + case EVENT_EVADE: + events.Reset(); + ScriptedAI::EnterEvadeMode(); + return; + case EVENT_OUTRO_START: + if (m_pInstance) + { + m_pInstance->SetData(TYPE_ALGALON, DONE); + m_pInstance->SetData(DATA_ALGALON_DEFEATED, 1); + } + break; + case EVENT_OUTRO_1: + me->RemoveAllAuras(); + me->SetUnitFlag(UNIT_FLAG_RENAME); + break; + case EVENT_OUTRO_2: + { + Player* lootRecipent = me->GetLootRecipient(); + _EnterEvadeMode(); + // LootRecipent is cleared in _EnterEvadeMode, restore it + me->SetLootRecipient(lootRecipent); + me->GetMotionMaster()->MovePoint(POINT_ALGALON_OUTRO, AlgalonOutroPos); + break; + } + case EVENT_OUTRO_3: + me->CastSpell((Unit*)nullptr, SPELL_KILL_CREDIT); + // Summon Chest + if (GameObject* go = me->SummonGameObject(RAID_MODE(GO_ALGALON_CHEST, GO_ALGALON_CHEST_HERO), 1632.1f, -306.561f, 417.321f, 4.69494f, 0, 0, 0, 1, 0)) + { + go->ReplaceAllGameObjectFlags((GameObjectFlags)0); + go->SetLootRecipient(me); + } + break; + case EVENT_OUTRO_4: + me->CastSpell((Unit*)nullptr, SPELL_SUPERMASSIVE_FAIL); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + break; + case EVENT_OUTRO_5: + if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannOutroPos[0], TEMPSUMMON_TIMED_DESPAWN, 131500)) + brann->AI()->DoAction(ACTION_OUTRO); + break; + case EVENT_OUTRO_6: + Talk(SAY_ALGALON_OUTRO_1); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + break; + case EVENT_OUTRO_7: + Talk(SAY_ALGALON_OUTRO_2); + break; + case EVENT_OUTRO_8: + Talk(SAY_ALGALON_OUTRO_3); + break; + case EVENT_OUTRO_9: + Talk(SAY_ALGALON_OUTRO_4); + break; + case EVENT_OUTRO_10: + Talk(SAY_ALGALON_OUTRO_5); + break; + case EVENT_OUTRO_11: + me->SetStandState(UNIT_STAND_STATE_STAND); + me->CastSpell(me, SPELL_TELEPORT, false); + me->DespawnOrUnsummon(3000); + break; + case EVENT_DESPAWN_ALGALON_1: + Talk(SAY_ALGALON_DESPAWN_1); + break; + case EVENT_DESPAWN_ALGALON_2: + Talk(SAY_ALGALON_DESPAWN_2); + break; + case EVENT_DESPAWN_ALGALON_3: + Talk(SAY_ALGALON_DESPAWN_3); + break; + case EVENT_DESPAWN_ALGALON_4: + me->CastSpell((Unit*)nullptr, SPELL_ASCEND_TO_THE_HEAVENS, false); + break; + case EVENT_DESPAWN_ALGALON_5: + me->SetStandState(UNIT_STAND_STATE_STAND); + me->CastSpell(me, SPELL_TELEPORT, false); + me->DespawnOrUnsummon(3000); + break; + case EVENT_CHECK_HERALD_ITEMS: + if (!DoCheckHeraldOfTheTitans()) + events.Repeat(5s); + break; + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI(creature); + } +}; + +class npc_brann_bronzebeard_algalon : public CreatureScript +{ +public: + npc_brann_bronzebeard_algalon() : CreatureScript("npc_brann_bronzebeard_algalon") { } + + struct npc_brann_bronzebeard_algalonAI : public CreatureAI + { + npc_brann_bronzebeard_algalonAI(Creature* creature) : CreatureAI(creature) + { + } + + EventMap events; + uint32 _currentPoint; + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_START_INTRO: + me->SetWalk(false); + _currentPoint = 0; + events.Reset(); + events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1ms); + break; + case ACTION_FINISH_INTRO: + Talk(SAY_BRANN_ALGALON_INTRO_2); + events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1ms); + break; + case ACTION_OUTRO: + me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO, BrannOutroPos[1]); + events.ScheduleEvent(EVENT_BRANN_OUTRO_1, 87s + 500ms); + events.ScheduleEvent(EVENT_BRANN_OUTRO_2, 116s + 500ms); + break; + } + } + + void MovementInform(uint32 movementType, uint32 pointId) override + { + if (movementType != POINT_MOTION_TYPE) + return; + + uint32 delay = 1; + _currentPoint = pointId + 1; + switch (pointId) + { + case 2: + delay = 8000; + me->SetWalk(true); + break; + case 6: + me->SetFacingTo(4.6156f); + me->SetWalk(false); + Talk(SAY_BRANN_ALGALON_INTRO_1); + events.ScheduleEvent(EVENT_SUMMON_ALGALON, 7500ms); + return; + case 10: + me->DespawnOrUnsummon(1); + return; + case POINT_BRANN_OUTRO: + case POINT_BRANN_OUTRO_END: + return; + } + + events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, delay); + } + + void UpdateAI(uint32 diff) override + { + UpdateVictim(); + events.Update(diff); + + switch (events.ExecuteEvent()) + { + case EVENT_BRANN_MOVE_INTRO: + if (_currentPoint < MAX_BRANN_WAYPOINTS_INTRO) + me->GetMotionMaster()->MovePoint(_currentPoint, BrannIntroWaypoint[_currentPoint]); + break; + case EVENT_SUMMON_ALGALON: + if (me->GetInstanceScript() && !me->GetInstanceScript()->GetGuidData(TYPE_ALGALON)) + if (Creature* algalon = me->GetMap()->SummonCreature(NPC_ALGALON, AlgalonSummonPos)) + algalon->AI()->DoAction(ACTION_START_INTRO); + break; + case EVENT_BRANN_OUTRO_1: + Talk(SAY_BRANN_ALGALON_OUTRO); + break; + case EVENT_BRANN_OUTRO_2: + me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO_END, BrannOutroPos[2]); + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI(creature); + } +}; + +class npc_collapsing_star : public CreatureScript +{ +public: + npc_collapsing_star() : CreatureScript("npc_collapsing_star") { } + + struct npc_collapsing_starAI : public NullCreatureAI + { + npc_collapsing_starAI(Creature* creature) : NullCreatureAI(creature) + { + creature->GetMotionMaster()->MoveRandom(25.0f); + creature->CastSpell(creature, SPELL_COLLAPSE, true); + } + + void JustSummoned(Creature* summon) override + { + if (TempSummon* summ = me->ToTempSummon()) + if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID())) + algalon->AI()->JustSummoned(summon); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage >= me->GetHealth()) + { + me->CastSpell(me, SPELL_BLACK_HOLE_SPAWN_VISUAL, true); + me->CastSpell(me, SPELL_SUMMON_BLACK_HOLE, true); + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI(creature); + } +}; + +class npc_living_constellation : public CreatureScript +{ +public: + npc_living_constellation() : CreatureScript("npc_living_constellation") { } + + struct npc_living_constellationAI : public ScriptedAI + { + npc_living_constellationAI(Creature* creature) : ScriptedAI(creature) + { + me->SetReactState(REACT_PASSIVE); + } + + EventMap events; + bool _isActive; + + void Reset() override + { + events.Reset(); + events.ScheduleEvent(EVENT_ARCANE_BARRAGE, 2500ms); + _isActive = false; + } + + uint32 GetData(uint32 /*param*/) const override + { + return _isActive; + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_ACTIVATE_STAR: + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToAll(false); + _isActive = true; + + if (Player* target = SelectTargetFromPlayerList(250.0f)) + { + AttackStart(target); + me->AddThreat(target, 100.0f); + } + me->SetInCombatWithZone(); + break; + case ACTION_BIG_BANG: + events.SetPhase(PHASE_BIG_BANG); + events.DelayEvents(9500); + events.ScheduleEvent(EVENT_RESUME_UPDATING, 9500ms); + break; + } + } + + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + if (spell->Id != SPELL_CONSTELLATION_PHASE_EFFECT || caster->GetTypeId() != TYPEID_UNIT) + return; + + if (InstanceScript* instance = me->GetInstanceScript()) + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_ID_SUPERMASSIVE_START); + + caster->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_CREDIT, TRIGGERED_FULL_MASK); + caster->ToCreature()->DespawnOrUnsummon(1); + me->DespawnOrUnsummon(1); + if (Creature* voidZone = caster->FindNearestCreature(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER, 10.0f)) + voidZone->DespawnOrUnsummon(1); + } + + void UpdateAI(uint32 diff) override + { + if (!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && !UpdateVictim()) + return; + + events.Update(diff); + switch (events.ExecuteEvent()) + { + case EVENT_ARCANE_BARRAGE: + me->CastCustomSpell(SPELL_ARCANE_BARRAGE, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, true); + events.Repeat(2500ms); + break; + case EVENT_RESUME_UPDATING: + events.SetPhase(0); + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI(creature); + } +}; + +class npc_algalon_worm_hole : public CreatureScript +{ +public: + npc_algalon_worm_hole() : CreatureScript("npc_algalon_worm_hole") { } + + struct npc_algalon_worm_holeAI : public NullCreatureAI + { + npc_algalon_worm_holeAI(Creature* creature) : NullCreatureAI(creature) + { + creature->CastSpell(creature, SPELL_WORM_HOLE_TRIGGER, true); + creature->CastSpell(creature, SPELL_SUMMON_VOID_ZONE_VISUAL, true); + } + + uint32 _summonTimer; + + void Reset() override + { + _summonTimer = urand(22000, 24000); + } + + void JustSummoned(Creature* summon) override + { + if (TempSummon* summ = me->ToTempSummon()) + { + if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID())) + { + algalon->AI()->JustSummoned(summon); + } + } + } + + void UpdateAI(uint32 diff) override + { + _summonTimer += diff; + if (_summonTimer >= 30000) + { + me->CastSpell((Unit*)nullptr, SPELL_SUMMON_UNLEASHED_DARK_MATTER, true); + _summonTimer = 0; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI(creature); + } +}; + +class go_celestial_planetarium_access : public GameObjectScript +{ +public: + go_celestial_planetarium_access() : GameObjectScript("go_celestial_planetarium_access") {} + + struct go_celestial_planetarium_accessAI : public GameObjectAI + { + go_celestial_planetarium_accessAI(GameObject* go) : GameObjectAI(go) + { + _locked = false; + } + + EventMap events; + bool _locked; + + bool GossipHello(Player* player, bool /*reportUse*/) override + { + bool hasKey = true; + if (LockEntry const* lock = sLockStore.LookupEntry(me->GetGOInfo()->goober.lockId)) + { + hasKey = false; + for (uint32 i = 0; i < MAX_LOCK_CASE; ++i) + { + if (!lock->Index[i]) + continue; + + if (player->HasItemCount(lock->Index[i])) + { + hasKey = true; + break; + } + } + } + + if (!hasKey) + return false; + + if (_locked) + return false; + _locked = true; + // Start Algalon event + me->SetGameObjectFlag(GO_FLAG_IN_USE); + events.ScheduleEvent(EVENT_DESPAWN_CONSOLE, 5000ms); + if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannIntroSpawnPos)) + brann->AI()->DoAction(ACTION_START_INTRO); + + if (InstanceScript* instance = me->GetInstanceScript()) + { + instance->SetData(DATA_ALGALON_SUMMON_STATE, 1); + if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_DOODAD_UL_SIGILDOOR_01))) + sigil->SetGoState(GO_STATE_ACTIVE); + + if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_DOODAD_UL_SIGILDOOR_02))) + sigil->SetGoState(GO_STATE_ACTIVE); + + if (Map* map = player->GetMap()) + { + if (InstanceMap* instanceMap = map->ToInstanceMap()) + { + instanceMap->PermBindAllPlayers(); + } + } + } + + return false; + } + + void UpdateAI(uint32 diff) override + { + if (events.Empty()) + return; + + events.Update(diff); + switch (events.ExecuteEvent()) + { + case EVENT_DESPAWN_CONSOLE: + me->Delete(); + break; + } + } + }; + + GameObjectAI* GetAI(GameObject* go) const override + { + return new go_celestial_planetarium_accessAI(go); + } +}; + +class spell_algalon_phase_punch : public SpellScriptLoader +{ +public: + spell_algalon_phase_punch() : SpellScriptLoader("spell_algalon_phase_punch") { } + + class spell_algalon_phase_punch_AuraScript : public AuraScript + { + PrepareAuraScript(spell_algalon_phase_punch_AuraScript); + + void HandlePeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + if (GetStackAmount() != 1) + GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 2]); + GetTarget()->CastSpell(GetTarget(), PhasePunchAlphaId[GetStackAmount() - 1], TRIGGERED_FULL_MASK); + if (GetStackAmount() == 5) + Remove(AURA_REMOVE_BY_DEFAULT); + } + + void OnRemove(AuraEffect const*, AuraEffectHandleModes) + { + if (GetStackAmount() != 5) + GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 1]); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_phase_punch_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + OnEffectRemove += AuraEffectRemoveFn(spell_algalon_phase_punch_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_algalon_phase_punch_AuraScript(); + } +}; + +class spell_algalon_collapse : public SpellScriptLoader +{ +public: + spell_algalon_collapse() : SpellScriptLoader("spell_algalon_collapse") { } + + class spell_algalon_collapse_AuraScript : public AuraScript + { + PrepareAuraScript(spell_algalon_collapse_AuraScript); + + void HandlePeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + Unit::DealDamage(GetTarget(), GetTarget(), GetTarget()->CountPctFromMaxHealth(1), nullptr, NODAMAGE); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_collapse_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_algalon_collapse_AuraScript(); + } +}; + +class ActiveConstellationFilter +{ +public: + bool operator()(WorldObject* object) const + { + return object->ToUnit()->GetAI()->GetData(0); + } +}; + +class spell_algalon_trigger_3_adds : public SpellScriptLoader +{ +public: + spell_algalon_trigger_3_adds() : SpellScriptLoader("spell_algalon_trigger_3_adds") { } + + class spell_algalon_trigger_3_adds_SpellScript : public SpellScript + { + PrepareSpellScript(spell_algalon_trigger_3_adds_SpellScript); + + void SelectTarget(std::list& targets) + { + targets.remove_if(ActiveConstellationFilter()); + } + + void HandleDummyEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + Creature* target = GetHitCreature(); + if (!target) + return; + + target->AI()->DoAction(ACTION_ACTIVATE_STAR); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_trigger_3_adds_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_algalon_trigger_3_adds_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_algalon_trigger_3_adds_SpellScript(); + } +}; + +class spell_algalon_cosmic_smash_damage : public SpellScriptLoader +{ +public: + spell_algalon_cosmic_smash_damage() : SpellScriptLoader("spell_algalon_cosmic_smash_damage") { } + + class spell_algalon_cosmic_smash_damage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_algalon_cosmic_smash_damage_SpellScript); + + void RecalculateDamage() + { + if (!GetExplTargetDest() || !GetHitUnit()) + return; + + float distance = GetHitUnit()->GetDistance2d(GetExplTargetDest()->GetPositionX(), GetExplTargetDest()->GetPositionY()); + if (distance >= 10.0f) + SetHitDamage(int32(float(GetHitDamage()) / distance)); + else if (distance > 6.0f) + SetHitDamage(int32(float(GetHitDamage()) / distance) * 2); + } + + void Register() override + { + OnHit += SpellHitFn(spell_algalon_cosmic_smash_damage_SpellScript::RecalculateDamage); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_algalon_cosmic_smash_damage_SpellScript(); + } +}; + +class spell_algalon_big_bang : public SpellScriptLoader +{ +public: + spell_algalon_big_bang() : SpellScriptLoader("spell_algalon_big_bang") { } + + class spell_algalon_big_bang_SpellScript : public SpellScript + { + PrepareSpellScript(spell_algalon_big_bang_SpellScript); + + bool Load() override + { + _targetCount = 0; + return true; + } + + void CountTargets(std::list& targets) + { + _targetCount = targets.size(); + } + + void CheckTargets() + { + Unit* caster = GetCaster(); + if (!_targetCount && caster && caster->GetAI()) + caster->GetAI()->DoAction(ACTION_ASCEND); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_big_bang_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + AfterCast += SpellCastFn(spell_algalon_big_bang_SpellScript::CheckTargets); + } + + uint32 _targetCount; + }; + + SpellScript* GetSpellScript() const override + { + return new spell_algalon_big_bang_SpellScript(); + } +}; + +class spell_algalon_remove_phase : public SpellScriptLoader +{ +public: + spell_algalon_remove_phase() : SpellScriptLoader("spell_algalon_remove_phase") { } + + class spell_algalon_remove_phase_AuraScript : public AuraScript + { + PrepareAuraScript(spell_algalon_remove_phase_AuraScript); + + void HandlePeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + GetTarget()->RemoveAurasByType(SPELL_AURA_PHASE); + GetTarget()->RemoveAurasDueToSpell(SPELL_BLACK_HOLE_DAMAGE); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_remove_phase_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_algalon_remove_phase_AuraScript(); + } +}; + +class spell_algalon_supermassive_fail : public SpellScriptLoader +{ +public: + spell_algalon_supermassive_fail() : SpellScriptLoader("spell_algalon_supermassive_fail") { } + + class spell_algalon_supermassive_fail_SpellScript : public SpellScript + { + PrepareSpellScript(spell_algalon_supermassive_fail_SpellScript); + + void RecalculateDamage() + { + if (!GetHitPlayer()) + return; + + GetHitPlayer()->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_NO_SPELL_HIT, GetSpellInfo()->Id, true); + } + + void Register() override + { + OnHit += SpellHitFn(spell_algalon_supermassive_fail_SpellScript::RecalculateDamage); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_algalon_supermassive_fail_SpellScript(); + } +}; + +class achievement_algalon_he_feeds_on_your_tears : public AchievementCriteriaScript +{ +public: + achievement_algalon_he_feeds_on_your_tears() : AchievementCriteriaScript("achievement_algalon_he_feeds_on_your_tears") { } + + bool OnCheck(Player*, Unit* target /*Algalon*/, uint32 /*criteria_id*/) override + { + return target && target->GetAI()->GetData(DATA_HAS_FED_ON_TEARS); + } +}; + +class achievement_algalon_herald_of_the_titans : public AchievementCriteriaScript +{ +public: + achievement_algalon_herald_of_the_titans() : AchievementCriteriaScript("achievement_algalon_herald_of_the_titans") { } + + bool OnCheck(Player*, Unit* target /*Algalon*/, uint32 /*criteria_id*/) override + { + return target && target->GetAI()->GetData(DATA_HERALD_OF_THE_TITANS); + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp index c8f049a5039dc2..4c159fa8eb365c 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_assembly_of_iron.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "Player.h" @@ -24,123 +25,6 @@ #include "SpellScriptLoader.h" #include "ulduar.h" -enum AssemblySpells -{ - // Any boss - SPELL_SUPERCHARGE = 61920, - SPELL_BERSERK = 47008, - - // Steelbreaker - SPELL_HIGH_VOLTAGE_10 = 61890, - SPELL_HIGH_VOLTAGE_25 = 63498, - SPELL_FUSION_PUNCH_10 = 61903, - SPELL_FUSION_PUNCH_25 = 63493, - SPELL_STATIC_DISRUPTION_10 = 61911, - SPELL_STATIC_DISRUPTION_25 = 63495, - SPELL_OVERWHELMING_POWER_10 = 64637, - SPELL_OVERWHELMING_POWER_25 = 61888, - SPELL_ELECTRICAL_CHARGE = 61902, - - // Runemaster Molgeim - SPELL_SHIELD_OF_RUNES_BUFF = 62277, - SPELL_SHIELD_OF_RUNES_10 = 62274, - SPELL_SHIELD_OF_RUNES_25 = 63489, - SPELL_RUNE_OF_POWER = 61973, - SPELL_RUNE_OF_DEATH_10 = 62269, - SPELL_RUNE_OF_DEATH_25 = 63490, - SPELL_RUNE_OF_SUMMONING = 62273, - SPELL_RUNE_OF_SUMMONING_SUMMON = 62020, - SPELL_LIGHTNING_BLAST_10 = 62054, - SPELL_LIGHTNING_BLAST_25 = 63491, - CREATURE_LIGHTNING_ELEMENTAL = 32958, - CREATURE_RUNE_OF_SUMMONING = 33051, - SPELL_RUNE_OF_POWER_OOC_CHANNEL = 61975, - - // Stormcaller Brundir - SPELL_CHAIN_LIGHTNING_10 = 61879, - SPELL_CHAIN_LIGHTNING_25 = 63479, - SPELL_OVERLOAD_10 = 61869, - SPELL_OVERLOAD_25 = 63481, - SPELL_LIGHTNING_WHIRL_10 = 61915, - SPELL_LIGHTNING_WHIRL_25 = 63483, - SPELL_LIGHTNING_TENDRILS_10 = 61887, - SPELL_LIGHTNING_TENDRILS_25 = 63486, - SPELL_STORMSHIELD = 64187, - SPELL_LIGHTNING_CHANNEL_PRE = 61942, -}; - -#define SPELL_HIGH_VOLTAGE RAID_MODE(SPELL_HIGH_VOLTAGE_10, SPELL_HIGH_VOLTAGE_25) -#define SPELL_FUSION_PUNCH RAID_MODE(SPELL_FUSION_PUNCH_10, SPELL_FUSION_PUNCH_25) -#define SPELL_STATIC_DISRUPTION RAID_MODE(SPELL_STATIC_DISRUPTION_10, SPELL_STATIC_DISRUPTION_25) -#define SPELL_OVERWHELMING_POWER RAID_MODE(SPELL_OVERWHELMING_POWER_10, SPELL_OVERWHELMING_POWER_25) -#define SPELL_SHIELD_OF_RUNES RAID_MODE(SPELL_SHIELD_OF_RUNES_10, SPELL_SHIELD_OF_RUNES_25) -#define SPELL_RUNE_OF_DEATH RAID_MODE(SPELL_RUNE_OF_DEATH_10, SPELL_RUNE_OF_DEATH_25) -#define SPELL_LIGHTNING_BLAST RAID_MODE(SPELL_LIGHTNING_BLAST_10, SPELL_LIGHTNING_BLAST_25) -#define SPELL_CHAIN_LIGHTNING RAID_MODE(SPELL_CHAIN_LIGHTNING_10, SPELL_CHAIN_LIGHTNING_25) -#define SPELL_OVERLOAD RAID_MODE(SPELL_OVERLOAD_10, SPELL_OVERLOAD_25) -#define SPELL_LIGHTNING_WHIRL RAID_MODE(SPELL_LIGHTNING_WHIRL_10, SPELL_LIGHTNING_WHIRL_25) -#define SPELL_LIGHTNING_TENDRILS RAID_MODE(SPELL_LIGHTNING_TENDRILS_10, SPELL_LIGHTNING_TENDRILS_25) - -enum eEnums -{ - // Steelbreaker - EVENT_FUSION_PUNCH = 1, - EVENT_STATIC_DISRUPTION = 2, - EVENT_OVERWHELMING_POWER = 3, - //EVENT_CHECK_MAIN_TANK = 4, - - // Molgeim - EVENT_RUNE_OF_POWER = 11, - EVENT_SHIELD_OF_RUNES = 12, - EVENT_RUNE_OF_DEATH = 13, - EVENT_RUNE_OF_SUMMONING = 14, - EVENT_LIGHTNING_BLAST = 15, - - // Brundir - EVENT_CHAIN_LIGHTNING = 21, - EVENT_OVERLOAD = 22, - EVENT_LIGHTNING_WHIRL = 23, - EVENT_LIGHTNING_TENDRILS = 24, - EVENT_LIGHTNING_LAND = 25, - EVENT_LAND_LAND = 26, - EVENT_LIGHTNING_FLIGHT = 27, - - EVENT_ENRAGE = 30 -}; - -enum AssemblyYells -{ - SAY_STEELBREAKER_AGGRO = 0, - SAY_STEELBREAKER_SLAY = 1, - SAY_STEELBREAKER_POWER = 2, - SAY_STEELBREAKER_DEATH = 3, - SAY_STEELBREAKER_ENCOUNTER_DEFEATED = 4, - SAY_STEELBREAKER_BERSERK = 5, - - SAY_MOLGEIM_AGGRO = 0, - SAY_MOLGEIM_SLAY = 1, - SAY_MOLGEIM_RUNE_DEATH = 2, - SAY_MOLGEIM_SUMMON = 3, - SAY_MOLGEIM_DEATH = 4, - SAY_MOLGEIM_ENCOUNTER_DEFEATED = 5, - SAY_MOLGEIM_BERSERK = 6, - - SAY_BRUNDIR_AGGRO = 0, - SAY_BRUNDIR_SLAY = 1, - SAY_BRUNDIR_SPECIAL = 2, - SAY_BRUNDIR_FLIGHT = 3, - SAY_BRUNDIR_DEATH = 4, - SAY_BRUNDIR_ENCOUNTER_DEFEATED = 5, - SAY_BRUNDIR_BERSERK = 6, - EMOTE_BRUNDIR_OVERLOAD = 7 -}; - -enum Misc -{ - ACTION_ADD_CHARGE = 1, - POINT_CHANNEL_STEELBREAKER = 1 -}; - bool IsEncounterComplete(InstanceScript* pInstance, Creature* me) { if (!pInstance || !me) @@ -193,783 +77,6 @@ void RestoreAssemblyHealth(ObjectGuid guid1, ObjectGuid guid2, Creature* me) cr2->SetHealth(cr2->GetMaxHealth()); } -class boss_steelbreaker : public CreatureScript -{ -public: - boss_steelbreaker() : CreatureScript("boss_steelbreaker") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_steelbreakerAI : public ScriptedAI - { - boss_steelbreakerAI(Creature* c) : ScriptedAI(c) - { - pInstance = c->GetInstanceScript(); - } - - EventMap events; - InstanceScript* pInstance; - uint8 _phase; - - void Reset() override - { - me->SetLootMode(0); - RespawnAssemblyOfIron(pInstance, me); - - _phase = 0; - events.Reset(); - if (pInstance) - pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); - } - - void JustReachedHome() override - { - me->setActive(false); - me->RemoveAllAuras(); - } - - void JustEngagedWith(Unit* who) override - { - if (pInstance) - pInstance->SetData(TYPE_ASSEMBLY, IN_PROGRESS); - - me->setActive(true); - me->SetInCombatWithZone(); - me->CastSpell(me, SPELL_HIGH_VOLTAGE, true); - events.ScheduleEvent(EVENT_ENRAGE, 15min); - UpdatePhase(); - - if (!pInstance) - return; - - if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + urand(0, 2)))) - { - switch (boss->GetEntry()) - { - case NPC_STEELBREAKER: - boss->AI()->Talk(SAY_STEELBREAKER_AGGRO); - break; - case NPC_MOLGEIM: - boss->AI()->Talk(SAY_MOLGEIM_AGGRO); - break; - case NPC_BRUNDIR: - boss->AI()->Talk(SAY_BRUNDIR_AGGRO); - break; - } - } - - for (uint8 i = 0; i < 3; ++i) - if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i))) - if (!boss->IsInCombat()) - boss->AI()->AttackStart(who); - } - - void UpdatePhase() - { - if (_phase >= 3) - return; - - ++_phase; - - switch (_phase) - { - case 1: - events.RescheduleEvent(EVENT_FUSION_PUNCH, 15s); - break; - case 2: - events.RescheduleEvent(EVENT_STATIC_DISRUPTION, 20s); - break; - case 3: - me->ResetLootMode(); - events.RescheduleEvent(EVENT_OVERWHELMING_POWER, 8s); - break; - } - } - - void JustDied(Unit* /*Killer*/) override - { - if (!pInstance) - return; - - if (IsEncounterComplete(pInstance, me)) - { - pInstance->SetData(TYPE_ASSEMBLY, DONE); - me->CastSpell(me, 65195, true); // credit - Talk(SAY_STEELBREAKER_ENCOUNTER_DEFEATED); - } - else - { - RestoreAssemblyHealth(pInstance->GetGuidData(DATA_BRUNDIR), pInstance->GetGuidData(DATA_MOLGEIM), me); - me->CastSpell(me, SPELL_SUPERCHARGE, true); - Talk(SAY_STEELBREAKER_DEATH); - } - } - - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() != TYPEID_PLAYER) - return; - - if (_phase == 3) - me->CastSpell(me, SPELL_ELECTRICAL_CHARGE, true); - - Talk(SAY_STEELBREAKER_SLAY); - } - - void DoAction(int32 param) override - { - if (param == ACTION_ADD_CHARGE) - me->CastSpell(me, SPELL_ELECTRICAL_CHARGE, true); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_SUPERCHARGE) - UpdatePhase(); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch(events.ExecuteEvent()) - { - case EVENT_FUSION_PUNCH: - me->CastSpell(me->GetVictim(), SPELL_FUSION_PUNCH, false); - events.Repeat(15s, 20s); - break; - case EVENT_STATIC_DISRUPTION: - if (Unit* pTarget = SelectTarget(SelectTargetMethod::MinDistance, 0, 0, true)) - me->CastSpell(pTarget, SPELL_STATIC_DISRUPTION, false); - - events.Repeat(20s, 40s); - break; - case EVENT_OVERWHELMING_POWER: - Talk(SAY_STEELBREAKER_POWER); - me->CastSpell(me->GetVictim(), SPELL_OVERWHELMING_POWER, true); - events.RepeatEvent(RAID_MODE(61000, 36000)); - break; - case EVENT_ENRAGE: - Talk(SAY_STEELBREAKER_BERSERK); - me->CastSpell(me, SPELL_BERSERK, true); - break; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class CastRunesEvent : public BasicEvent -{ -public: - CastRunesEvent(Creature& owner) : BasicEvent(), _owner(owner) { } - - bool Execute(uint64 /*eventTime*/, uint32 /*diff*/) override - { - if (!_owner.IsInCombat()) - _owner.CastSpell(&_owner, SPELL_RUNE_OF_POWER_OOC_CHANNEL, true); - return true; - } - -private: - Creature& _owner; -}; - -class boss_runemaster_molgeim : public CreatureScript -{ -public: - boss_runemaster_molgeim() : CreatureScript("boss_runemaster_molgeim") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_runemaster_molgeimAI : public ScriptedAI - { - boss_runemaster_molgeimAI(Creature* c) : ScriptedAI(c), summons(me) - { - pInstance = c->GetInstanceScript(); - } - - InstanceScript* pInstance; - SummonList summons; - EventMap events; - uint8 _phase; - - void Reset() override - { - me->SetLootMode(0); - RespawnAssemblyOfIron(pInstance, me); - - _phase = 0; - events.Reset(); - summons.DespawnAll(); - - if (pInstance) - pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); - - me->m_Events.AddEvent(new CastRunesEvent(*me), me->m_Events.CalculateTime(8000)); - } - - void JustReachedHome() override - { - me->setActive(false); - me->RemoveAllAuras(); - } - - void JustEngagedWith(Unit* who) override - { - me->InterruptNonMeleeSpells(false); - me->setActive(true); - me->SetInCombatWithZone(); - events.ScheduleEvent(EVENT_ENRAGE, 15min); - UpdatePhase(); - - if (!pInstance) - return; - - for (uint8 i = 0; i < 3; ++i) - if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i))) - if (!boss->IsInCombat()) - boss->AI()->AttackStart(who); - } - - void UpdatePhase() - { - if (_phase >= 3) - return; - - ++_phase; - - switch (_phase) - { - case 1: - events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 20s); - events.RescheduleEvent(EVENT_RUNE_OF_POWER, 30s); - break; - case 2: - events.RescheduleEvent(EVENT_RUNE_OF_DEATH, 35s); - break; - case 3: - me->ResetLootMode(); - events.RescheduleEvent(EVENT_RUNE_OF_SUMMONING, 20s, 30s); - break; - } - } - - void JustDied(Unit* /*killer*/) override - { - if (!pInstance) - return; - - if (IsEncounterComplete(pInstance, me)) - { - pInstance->SetData(TYPE_ASSEMBLY, DONE); - me->CastSpell(me, 65195, true); // credit - Talk(SAY_MOLGEIM_ENCOUNTER_DEFEATED); - } - else - { - RestoreAssemblyHealth(pInstance->GetGuidData(DATA_STEELBREAKER), pInstance->GetGuidData(DATA_BRUNDIR), me); - me->CastSpell(me, SPELL_SUPERCHARGE, true); - Talk(SAY_MOLGEIM_DEATH); - } - } - - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() != TYPEID_PLAYER) - return; - - Talk(SAY_MOLGEIM_SLAY); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_SUPERCHARGE) - UpdatePhase(); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch(events.ExecuteEvent()) - { - case EVENT_RUNE_OF_POWER: - { - Unit* target = DoSelectLowestHpFriendly(60); - if (!target || !target->IsAlive()) - target = me; - - me->CastSpell(target, SPELL_RUNE_OF_POWER, true); - events.Repeat(1min); - break; - } - case EVENT_SHIELD_OF_RUNES: - me->CastSpell(me, SPELL_SHIELD_OF_RUNES, false); - events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 27s, 34s); - break; - case EVENT_RUNE_OF_DEATH: - if (Unit* target = SelectTarget(SelectTargetMethod::Random)) - me->CastSpell(target, SPELL_RUNE_OF_DEATH, true); - - Talk(SAY_MOLGEIM_RUNE_DEATH); - events.Repeat(30s, 40s); - break; - case EVENT_RUNE_OF_SUMMONING: - Talk(SAY_MOLGEIM_SUMMON); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_RUNE_OF_SUMMONING); - events.Repeat(30s, 45s); - break; - case EVENT_ENRAGE: - me->CastSpell(me, SPELL_BERSERK, true); - Talk(SAY_MOLGEIM_BERSERK); - break; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class npc_assembly_lightning : public CreatureScript -{ -public: - npc_assembly_lightning() : CreatureScript("npc_assembly_lightning") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_assembly_lightningAI : public ScriptedAI - { - npc_assembly_lightningAI(Creature* c) : ScriptedAI(c) - { - _boomed = false; - } - - void MoveInLineOfSight(Unit*) override {} - void AttackStart(Unit*) override {} - void UpdateAI(uint32) override {} - void EnterEvadeMode(EvadeReason /* why */) override {} - void OnCharmed(bool /*apply*/) override {} - - bool _boomed; - - void Reset() override - { - if (Player* target = SelectTargetFromPlayerList(150)) - me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f); - else - me->DespawnOrUnsummon(1); - } - - void MovementInform(uint32 type, uint32 /*id*/) override - { - if (type == FOLLOW_MOTION_TYPE && !_boomed) - { - _boomed = true; - me->CastSpell(me, SPELL_LIGHTNING_BLAST, true); - me->DespawnOrUnsummon(1000); - } - } - }; -}; - -class boss_stormcaller_brundir : public CreatureScript -{ -public: - boss_stormcaller_brundir() : CreatureScript("boss_stormcaller_brundir") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_stormcaller_brundirAI : public ScriptedAI - { - boss_stormcaller_brundirAI(Creature* c) : ScriptedAI(c) - { - pInstance = c->GetInstanceScript(); - } - - EventMap events; - InstanceScript* pInstance; - uint32 _phase; - ObjectGuid _flyTargetGUID; - uint32 _channelTimer; - - bool _stunnedAchievement; - - void Reset() override - { - me->SetLootMode(0); - RespawnAssemblyOfIron(pInstance, me); - - _channelTimer = 0; - _phase = 0; - _flyTargetGUID.Clear(); - _stunnedAchievement = true; - - events.Reset(); - - me->SetDisableGravity(false); - me->SetRegeneratingHealth(true); - me->SetReactState(REACT_AGGRESSIVE); - if (pInstance) - pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); - } - - void JustReachedHome() override - { - me->setActive(false); - me->RemoveAllAuras(); - } - - void JustEngagedWith(Unit* who) override - { - me->InterruptNonMeleeSpells(false); - me->setActive(true); - me->SetInCombatWithZone(); - events.ScheduleEvent(EVENT_ENRAGE, 15min); - UpdatePhase(); - - if (!pInstance) - return; - - for (uint8 i = 0; i < 3; ++i) - if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i))) - if (!boss->IsInCombat()) - boss->AI()->AttackStart(who); - } - - void UpdatePhase() - { - if (_phase >= 3) - return; - - ++_phase; - - switch (_phase) - { - case 1: - events.RescheduleEvent(EVENT_CHAIN_LIGHTNING, 9s, 17s); - events.RescheduleEvent(EVENT_OVERLOAD, 25s, 40s); - break; - case 2: - events.RescheduleEvent(EVENT_LIGHTNING_WHIRL, 20s, 40s); - break; - case 3: - me->ResetLootMode(); - me->CastSpell(me, SPELL_STORMSHIELD, true); - events.RescheduleEvent(EVENT_LIGHTNING_TENDRILS, 15s, 16s); - break; - } - } - - void JustDied(Unit* /*Killer*/) override - { - if (!pInstance) - return; - me->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), 427.5, me->GetOrientation()); - if (IsEncounterComplete(pInstance, me)) - { - pInstance->SetData(TYPE_ASSEMBLY, DONE); - me->CastSpell(me, 65195, true); // credit - Talk(SAY_BRUNDIR_ENCOUNTER_DEFEATED); - } - else - { - RestoreAssemblyHealth(pInstance->GetGuidData(DATA_STEELBREAKER), pInstance->GetGuidData(DATA_MOLGEIM), me); - me->CastSpell(me, SPELL_SUPERCHARGE, true); - Talk(SAY_BRUNDIR_DEATH); - } - } - - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() != TYPEID_PLAYER || urand(0, 2)) - return; - - Talk(SAY_BRUNDIR_SLAY); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_SUPERCHARGE) - UpdatePhase(); - } - - void SpellHitTarget(Unit* /*target*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_CHAIN_LIGHTNING || spellInfo->Id == uint32(RAID_MODE(61916, 63482))) // Lightning Whirl triggered - _stunnedAchievement = false; - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_BRUNDIR) - return _stunnedAchievement; - - return 0; - } - - void MovementInform(uint32 type, uint32 point) override - { - if (type == POINT_MOTION_TYPE && point == POINT_CHANNEL_STEELBREAKER) - me->CastSpell(me, SPELL_LIGHTNING_CHANNEL_PRE, true); - } - - void UpdateAI(uint32 diff) override - { - if (!me->IsInCombat() && me->GetReactState() == REACT_AGGRESSIVE) - { - _channelTimer += diff; - if (_channelTimer >= 10000) - { - _channelTimer = 0; - float o = urand(0, 5) * M_PI / 3.0f; - me->InterruptNonMeleeSpells(false); - me->GetMotionMaster()->MovePoint(POINT_CHANNEL_STEELBREAKER, 1587.18f + 10.0f * cos(o), 121.02f + 10.0f * std::sin(o), 427.3f); - } - } - - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_CHAIN_LIGHTNING: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_CHAIN_LIGHTNING, false); - - events.Repeat(9s, 17s); - break; - case EVENT_OVERLOAD: - Talk(EMOTE_BRUNDIR_OVERLOAD); - me->CastSpell(me, SPELL_OVERLOAD, true); - events.RescheduleEvent(EVENT_OVERLOAD, 25s, 40s); - break; - case EVENT_LIGHTNING_WHIRL: - Talk(SAY_BRUNDIR_SPECIAL); - me->CastSpell(me, SPELL_LIGHTNING_WHIRL, true); - events.Repeat(10s, 25s); - break; - case EVENT_LIGHTNING_TENDRILS: - { - // Reschedule old - events.Repeat(35s); - events.DelayEvents(18s); - Talk(SAY_BRUNDIR_FLIGHT); - - Unit* oldVictim = me->GetVictim(); - _flyTargetGUID = oldVictim->GetGUID(); - me->SetRegeneratingHealth(false); - me->SetDisableGravity(true); - me->SetHover(true); - - me->CombatStop(); - me->StopMoving(); - me->SetReactState(REACT_PASSIVE); - me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty); - me->SetUnitFlag(UNIT_FLAG_STUNNED); - - me->CastSpell(me, SPELL_LIGHTNING_TENDRILS, true); - me->CastSpell(me, 61883, true); - events.ScheduleEvent(EVENT_LIGHTNING_LAND, 16s); - events.ScheduleEvent(EVENT_LIGHTNING_FLIGHT, 1s); - break; - } - case EVENT_LIGHTNING_LAND: - { - float speed = me->GetDistance(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()) / (1000.0f * 0.001f); - me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), speed); - events.ScheduleEvent(EVENT_LAND_LAND, 1s); - break; - } - case EVENT_LAND_LAND: - me->SetCanFly(false); - me->SetHover(false); - me->SetReactState(REACT_AGGRESSIVE); - me->SetDisableGravity(false); - if (Unit* flyTarget = ObjectAccessor::GetUnit(*me, _flyTargetGUID)) - { - me->Attack(flyTarget, false); - } - - me->SetRegeneratingHealth(true); - _flyTargetGUID.Clear(); - me->RemoveAura(SPELL_LIGHTNING_TENDRILS); - me->RemoveAura(61883); - DoResetThreatList(); - events.CancelEvent(EVENT_LIGHTNING_FLIGHT); - break; - case EVENT_ENRAGE: - Talk(SAY_BRUNDIR_BERSERK); - me->CastSpell(me, SPELL_BERSERK, true); - break; - case EVENT_LIGHTNING_FLIGHT: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) - { - me->GetMotionMaster()->MovePoint(0, *target); - } - events.ScheduleEvent(EVENT_LIGHTNING_FLIGHT, 6s); - break; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class spell_shield_of_runes : public SpellScriptLoader -{ -public: - spell_shield_of_runes() : SpellScriptLoader("spell_shield_of_runes") { } - - class spell_shield_of_runes_AuraScript : public AuraScript - { - PrepareAuraScript(spell_shield_of_runes_AuraScript); - - void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - if (Unit* owner = GetUnitOwner()) - if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL && aurEff->GetAmount() <= 0) - owner->CastSpell(owner, SPELL_SHIELD_OF_RUNES_BUFF, false); - } - - void Register() override - { - AfterEffectRemove += AuraEffectRemoveFn(spell_shield_of_runes_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_shield_of_runes_AuraScript(); - } -}; - -class spell_assembly_meltdown : public SpellScriptLoader -{ -public: - spell_assembly_meltdown() : SpellScriptLoader("spell_assembly_meltdown") { } - - class spell_assembly_meltdown_SpellScript : public SpellScript - { - PrepareSpellScript(spell_assembly_meltdown_SpellScript); - - void HandleInstaKill(SpellEffIndex /*effIndex*/) - { - if (InstanceScript* instance = GetCaster()->GetInstanceScript()) - if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_STEELBREAKER))) - Steelbreaker->AI()->DoAction(ACTION_ADD_CHARGE); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_assembly_meltdown_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_assembly_meltdown_SpellScript(); - } -}; - -class spell_assembly_rune_of_summoning : public SpellScriptLoader -{ -public: - spell_assembly_rune_of_summoning() : SpellScriptLoader("spell_assembly_rune_of_summoning") { } - - class spell_assembly_rune_of_summoning_AuraScript : public AuraScript - { - PrepareAuraScript(spell_assembly_rune_of_summoning_AuraScript); - - void OnPeriodic(AuraEffect const* aurEff) - { - PreventDefaultAction(); - if (aurEff->GetTickNumber() % 2 == 0) - GetTarget()->CastSpell(GetTarget(), SPELL_RUNE_OF_SUMMONING_SUMMON, true, nullptr, aurEff, GetTarget()->IsSummon() ? GetTarget()->ToTempSummon()->GetSummonerGUID() : ObjectGuid::Empty); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (TempSummon* summ = GetTarget()->ToTempSummon()) - summ->DespawnOrUnsummon(1); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_assembly_rune_of_summoning_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - OnEffectRemove += AuraEffectRemoveFn(spell_assembly_rune_of_summoning_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_assembly_rune_of_summoning_AuraScript(); - } -}; - -class achievement_assembly_of_iron : public AchievementCriteriaScript -{ -public: - achievement_assembly_of_iron(char const* name, uint32 entry) : AchievementCriteriaScript(name), - _targetEntry(entry) - { - } - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetAuraCount(SPELL_SUPERCHARGE) >= 2 && (!_targetEntry || target->GetEntry() == _targetEntry); - } - -private: - uint32 const _targetEntry; -}; - -class achievement_cant_do_that_while_stunned : public AchievementCriteriaScript -{ -public: - achievement_cant_do_that_while_stunned() : AchievementCriteriaScript("achievement_cant_do_that_while_stunned") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - bool allow = target && target->GetAuraCount(SPELL_SUPERCHARGE) >= 2; - if (!allow) - return false; - - if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(DATA_BRUNDIR))) - return cr->AI()->GetData(DATA_BRUNDIR); - - return false; - } -}; void AddSC_boss_assembly_of_iron() { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.h new file mode 100644 index 00000000000000..988d1207765070 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.h @@ -0,0 +1,908 @@ +#ifndef BOSS_ASSEMBLY_OF_IRON_H_ +#define BOSS_ASSEMBLY_OF_IRON_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "ulduar.h" + +enum AssemblySpells +{ + // Any boss + SPELL_SUPERCHARGE = 61920, + SPELL_BERSERK = 47008, + + // Steelbreaker + SPELL_HIGH_VOLTAGE_10 = 61890, + SPELL_HIGH_VOLTAGE_25 = 63498, + SPELL_FUSION_PUNCH_10 = 61903, + SPELL_FUSION_PUNCH_25 = 63493, + SPELL_STATIC_DISRUPTION_10 = 61911, + SPELL_STATIC_DISRUPTION_25 = 63495, + SPELL_OVERWHELMING_POWER_10 = 64637, + SPELL_OVERWHELMING_POWER_25 = 61888, + SPELL_ELECTRICAL_CHARGE = 61902, + + // Runemaster Molgeim + SPELL_SHIELD_OF_RUNES_BUFF = 62277, + SPELL_SHIELD_OF_RUNES_10 = 62274, + SPELL_SHIELD_OF_RUNES_25 = 63489, + SPELL_RUNE_OF_POWER = 61973, + SPELL_RUNE_OF_DEATH_10 = 62269, + SPELL_RUNE_OF_DEATH_25 = 63490, + SPELL_RUNE_OF_SUMMONING = 62273, + SPELL_RUNE_OF_SUMMONING_SUMMON = 62020, + SPELL_LIGHTNING_BLAST_10 = 62054, + SPELL_LIGHTNING_BLAST_25 = 63491, + CREATURE_LIGHTNING_ELEMENTAL = 32958, + CREATURE_RUNE_OF_SUMMONING = 33051, + SPELL_RUNE_OF_POWER_OOC_CHANNEL = 61975, + + // Stormcaller Brundir + SPELL_CHAIN_LIGHTNING_10 = 61879, + SPELL_CHAIN_LIGHTNING_25 = 63479, + SPELL_OVERLOAD_10 = 61869, + SPELL_OVERLOAD_25 = 63481, + SPELL_LIGHTNING_WHIRL_10 = 61915, + SPELL_LIGHTNING_WHIRL_25 = 63483, + SPELL_LIGHTNING_TENDRILS_10 = 61887, + SPELL_LIGHTNING_TENDRILS_25 = 63486, + SPELL_STORMSHIELD = 64187, + SPELL_LIGHTNING_CHANNEL_PRE = 61942, +}; + +#define SPELL_HIGH_VOLTAGE RAID_MODE(SPELL_HIGH_VOLTAGE_10, SPELL_HIGH_VOLTAGE_25) +#define SPELL_FUSION_PUNCH RAID_MODE(SPELL_FUSION_PUNCH_10, SPELL_FUSION_PUNCH_25) +#define SPELL_STATIC_DISRUPTION RAID_MODE(SPELL_STATIC_DISRUPTION_10, SPELL_STATIC_DISRUPTION_25) +#define SPELL_OVERWHELMING_POWER RAID_MODE(SPELL_OVERWHELMING_POWER_10, SPELL_OVERWHELMING_POWER_25) +#define SPELL_SHIELD_OF_RUNES RAID_MODE(SPELL_SHIELD_OF_RUNES_10, SPELL_SHIELD_OF_RUNES_25) +#define SPELL_RUNE_OF_DEATH RAID_MODE(SPELL_RUNE_OF_DEATH_10, SPELL_RUNE_OF_DEATH_25) +#define SPELL_LIGHTNING_BLAST RAID_MODE(SPELL_LIGHTNING_BLAST_10, SPELL_LIGHTNING_BLAST_25) +#define SPELL_CHAIN_LIGHTNING RAID_MODE(SPELL_CHAIN_LIGHTNING_10, SPELL_CHAIN_LIGHTNING_25) +#define SPELL_OVERLOAD RAID_MODE(SPELL_OVERLOAD_10, SPELL_OVERLOAD_25) +#define SPELL_LIGHTNING_WHIRL RAID_MODE(SPELL_LIGHTNING_WHIRL_10, SPELL_LIGHTNING_WHIRL_25) +#define SPELL_LIGHTNING_TENDRILS RAID_MODE(SPELL_LIGHTNING_TENDRILS_10, SPELL_LIGHTNING_TENDRILS_25) + +enum eEnums +{ + // Steelbreaker + EVENT_FUSION_PUNCH = 1, + EVENT_STATIC_DISRUPTION = 2, + EVENT_OVERWHELMING_POWER = 3, + //EVENT_CHECK_MAIN_TANK = 4, + + // Molgeim + EVENT_RUNE_OF_POWER = 11, + EVENT_SHIELD_OF_RUNES = 12, + EVENT_RUNE_OF_DEATH = 13, + EVENT_RUNE_OF_SUMMONING = 14, + EVENT_LIGHTNING_BLAST = 15, + + // Brundir + EVENT_CHAIN_LIGHTNING = 21, + EVENT_OVERLOAD = 22, + EVENT_LIGHTNING_WHIRL = 23, + EVENT_LIGHTNING_TENDRILS = 24, + EVENT_LIGHTNING_LAND = 25, + EVENT_LAND_LAND = 26, + EVENT_LIGHTNING_FLIGHT = 27, + + EVENT_ENRAGE = 30 +}; + +enum AssemblyYells +{ + SAY_STEELBREAKER_AGGRO = 0, + SAY_STEELBREAKER_SLAY = 1, + SAY_STEELBREAKER_POWER = 2, + SAY_STEELBREAKER_DEATH = 3, + SAY_STEELBREAKER_ENCOUNTER_DEFEATED = 4, + SAY_STEELBREAKER_BERSERK = 5, + + SAY_MOLGEIM_AGGRO = 0, + SAY_MOLGEIM_SLAY = 1, + SAY_MOLGEIM_RUNE_DEATH = 2, + SAY_MOLGEIM_SUMMON = 3, + SAY_MOLGEIM_DEATH = 4, + SAY_MOLGEIM_ENCOUNTER_DEFEATED = 5, + SAY_MOLGEIM_BERSERK = 6, + + SAY_BRUNDIR_AGGRO = 0, + SAY_BRUNDIR_SLAY = 1, + SAY_BRUNDIR_SPECIAL = 2, + SAY_BRUNDIR_FLIGHT = 3, + SAY_BRUNDIR_DEATH = 4, + SAY_BRUNDIR_ENCOUNTER_DEFEATED = 5, + SAY_BRUNDIR_BERSERK = 6, + EMOTE_BRUNDIR_OVERLOAD = 7 +}; + +enum Misc +{ + ACTION_ADD_CHARGE = 1, + POINT_CHANNEL_STEELBREAKER = 1 +}; + +class boss_steelbreaker : public CreatureScript +{ +public: + boss_steelbreaker() : CreatureScript("boss_steelbreaker") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_steelbreakerAI : public ScriptedAI + { + boss_steelbreakerAI(Creature* c) : ScriptedAI(c) + { + pInstance = c->GetInstanceScript(); + } + + EventMap events; + InstanceScript* pInstance; + uint8 _phase; + + void Reset() override + { + me->SetLootMode(0); + RespawnAssemblyOfIron(pInstance, me); + + _phase = 0; + events.Reset(); + if (pInstance) + pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); + } + + void JustReachedHome() override + { + me->setActive(false); + me->RemoveAllAuras(); + } + + void JustEngagedWith(Unit* who) override + { + if (pInstance) + pInstance->SetData(TYPE_ASSEMBLY, IN_PROGRESS); + + me->setActive(true); + me->SetInCombatWithZone(); + me->CastSpell(me, SPELL_HIGH_VOLTAGE, true); + events.ScheduleEvent(EVENT_ENRAGE, 15min); + UpdatePhase(); + + if (!pInstance) + return; + + if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + urand(0, 2)))) + { + switch (boss->GetEntry()) + { + case NPC_STEELBREAKER: + boss->AI()->Talk(SAY_STEELBREAKER_AGGRO); + break; + case NPC_MOLGEIM: + boss->AI()->Talk(SAY_MOLGEIM_AGGRO); + break; + case NPC_BRUNDIR: + boss->AI()->Talk(SAY_BRUNDIR_AGGRO); + break; + } + } + + for (uint8 i = 0; i < 3; ++i) + if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i))) + if (!boss->IsInCombat()) + boss->AI()->AttackStart(who); + } + + void UpdatePhase() + { + if (_phase >= 3) + return; + + ++_phase; + + switch (_phase) + { + case 1: + events.RescheduleEvent(EVENT_FUSION_PUNCH, 15s); + break; + case 2: + events.RescheduleEvent(EVENT_STATIC_DISRUPTION, 20s); + break; + case 3: + me->ResetLootMode(); + events.RescheduleEvent(EVENT_OVERWHELMING_POWER, 8s); + break; + } + } + + void JustDied(Unit* /*Killer*/) override + { + if (!pInstance) + return; + + if (IsEncounterComplete(pInstance, me)) + { + pInstance->SetData(TYPE_ASSEMBLY, DONE); + me->CastSpell(me, 65195, true); // credit + Talk(SAY_STEELBREAKER_ENCOUNTER_DEFEATED); + } + else + { + RestoreAssemblyHealth(pInstance->GetGuidData(DATA_BRUNDIR), pInstance->GetGuidData(DATA_MOLGEIM), me); + me->CastSpell(me, SPELL_SUPERCHARGE, true); + Talk(SAY_STEELBREAKER_DEATH); + } + } + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() != TYPEID_PLAYER) + return; + + if (_phase == 3) + me->CastSpell(me, SPELL_ELECTRICAL_CHARGE, true); + + Talk(SAY_STEELBREAKER_SLAY); + } + + void DoAction(int32 param) override + { + if (param == ACTION_ADD_CHARGE) + me->CastSpell(me, SPELL_ELECTRICAL_CHARGE, true); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_SUPERCHARGE) + UpdatePhase(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch(events.ExecuteEvent()) + { + case EVENT_FUSION_PUNCH: + me->CastSpell(me->GetVictim(), SPELL_FUSION_PUNCH, false); + events.Repeat(15s, 20s); + break; + case EVENT_STATIC_DISRUPTION: + if (Unit* pTarget = SelectTarget(SelectTargetMethod::MinDistance, 0, 0, true)) + me->CastSpell(pTarget, SPELL_STATIC_DISRUPTION, false); + + events.Repeat(20s, 40s); + break; + case EVENT_OVERWHELMING_POWER: + Talk(SAY_STEELBREAKER_POWER); + me->CastSpell(me->GetVictim(), SPELL_OVERWHELMING_POWER, true); + events.RepeatEvent(RAID_MODE(61000, 36000)); + break; + case EVENT_ENRAGE: + Talk(SAY_STEELBREAKER_BERSERK); + me->CastSpell(me, SPELL_BERSERK, true); + break; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class CastRunesEvent : public BasicEvent +{ +public: + CastRunesEvent(Creature& owner) : BasicEvent(), _owner(owner) { } + + bool Execute(uint64 /*eventTime*/, uint32 /*diff*/) override + { + if (!_owner.IsInCombat()) + _owner.CastSpell(&_owner, SPELL_RUNE_OF_POWER_OOC_CHANNEL, true); + return true; + } + +private: + Creature& _owner; +}; + +class boss_runemaster_molgeim : public CreatureScript +{ +public: + boss_runemaster_molgeim() : CreatureScript("boss_runemaster_molgeim") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_runemaster_molgeimAI : public ScriptedAI + { + boss_runemaster_molgeimAI(Creature* c) : ScriptedAI(c), summons(me) + { + pInstance = c->GetInstanceScript(); + } + + InstanceScript* pInstance; + SummonList summons; + EventMap events; + uint8 _phase; + + void Reset() override + { + me->SetLootMode(0); + RespawnAssemblyOfIron(pInstance, me); + + _phase = 0; + events.Reset(); + summons.DespawnAll(); + + if (pInstance) + pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); + + me->m_Events.AddEvent(new CastRunesEvent(*me), me->m_Events.CalculateTime(8000)); + } + + void JustReachedHome() override + { + me->setActive(false); + me->RemoveAllAuras(); + } + + void JustEngagedWith(Unit* who) override + { + me->InterruptNonMeleeSpells(false); + me->setActive(true); + me->SetInCombatWithZone(); + events.ScheduleEvent(EVENT_ENRAGE, 15min); + UpdatePhase(); + + if (!pInstance) + return; + + for (uint8 i = 0; i < 3; ++i) + if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i))) + if (!boss->IsInCombat()) + boss->AI()->AttackStart(who); + } + + void UpdatePhase() + { + if (_phase >= 3) + return; + + ++_phase; + + switch (_phase) + { + case 1: + events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 20s); + events.RescheduleEvent(EVENT_RUNE_OF_POWER, 30s); + break; + case 2: + events.RescheduleEvent(EVENT_RUNE_OF_DEATH, 35s); + break; + case 3: + me->ResetLootMode(); + events.RescheduleEvent(EVENT_RUNE_OF_SUMMONING, 20s, 30s); + break; + } + } + + void JustDied(Unit* /*killer*/) override + { + if (!pInstance) + return; + + if (IsEncounterComplete(pInstance, me)) + { + pInstance->SetData(TYPE_ASSEMBLY, DONE); + me->CastSpell(me, 65195, true); // credit + Talk(SAY_MOLGEIM_ENCOUNTER_DEFEATED); + } + else + { + RestoreAssemblyHealth(pInstance->GetGuidData(DATA_STEELBREAKER), pInstance->GetGuidData(DATA_BRUNDIR), me); + me->CastSpell(me, SPELL_SUPERCHARGE, true); + Talk(SAY_MOLGEIM_DEATH); + } + } + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() != TYPEID_PLAYER) + return; + + Talk(SAY_MOLGEIM_SLAY); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_SUPERCHARGE) + UpdatePhase(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch(events.ExecuteEvent()) + { + case EVENT_RUNE_OF_POWER: + { + Unit* target = DoSelectLowestHpFriendly(60); + if (!target || !target->IsAlive()) + target = me; + + me->CastSpell(target, SPELL_RUNE_OF_POWER, true); + events.Repeat(1min); + break; + } + case EVENT_SHIELD_OF_RUNES: + me->CastSpell(me, SPELL_SHIELD_OF_RUNES, false); + events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 27s, 34s); + break; + case EVENT_RUNE_OF_DEATH: + if (Unit* target = SelectTarget(SelectTargetMethod::Random)) + me->CastSpell(target, SPELL_RUNE_OF_DEATH, true); + + Talk(SAY_MOLGEIM_RUNE_DEATH); + events.Repeat(30s, 40s); + break; + case EVENT_RUNE_OF_SUMMONING: + Talk(SAY_MOLGEIM_SUMMON); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_RUNE_OF_SUMMONING); + events.Repeat(30s, 45s); + break; + case EVENT_ENRAGE: + me->CastSpell(me, SPELL_BERSERK, true); + Talk(SAY_MOLGEIM_BERSERK); + break; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class npc_assembly_lightning : public CreatureScript +{ +public: + npc_assembly_lightning() : CreatureScript("npc_assembly_lightning") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_assembly_lightningAI : public ScriptedAI + { + npc_assembly_lightningAI(Creature* c) : ScriptedAI(c) + { + _boomed = false; + } + + void MoveInLineOfSight(Unit*) override {} + void AttackStart(Unit*) override {} + void UpdateAI(uint32) override {} + void EnterEvadeMode(EvadeReason /* why */) override {} + void OnCharmed(bool /*apply*/) override {} + + bool _boomed; + + void Reset() override + { + if (Player* target = SelectTargetFromPlayerList(150)) + me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f); + else + me->DespawnOrUnsummon(1); + } + + void MovementInform(uint32 type, uint32 /*id*/) override + { + if (type == FOLLOW_MOTION_TYPE && !_boomed) + { + _boomed = true; + me->CastSpell(me, SPELL_LIGHTNING_BLAST, true); + me->DespawnOrUnsummon(1000); + } + } + }; +}; + +class boss_stormcaller_brundir : public CreatureScript +{ +public: + boss_stormcaller_brundir() : CreatureScript("boss_stormcaller_brundir") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_stormcaller_brundirAI : public ScriptedAI + { + boss_stormcaller_brundirAI(Creature* c) : ScriptedAI(c) + { + pInstance = c->GetInstanceScript(); + } + + EventMap events; + InstanceScript* pInstance; + uint32 _phase; + ObjectGuid _flyTargetGUID; + uint32 _channelTimer; + + bool _stunnedAchievement; + + void Reset() override + { + me->SetLootMode(0); + RespawnAssemblyOfIron(pInstance, me); + + _channelTimer = 0; + _phase = 0; + _flyTargetGUID.Clear(); + _stunnedAchievement = true; + + events.Reset(); + + me->SetDisableGravity(false); + me->SetRegeneratingHealth(true); + me->SetReactState(REACT_AGGRESSIVE); + if (pInstance) + pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); + } + + void JustReachedHome() override + { + me->setActive(false); + me->RemoveAllAuras(); + } + + void JustEngagedWith(Unit* who) override + { + me->InterruptNonMeleeSpells(false); + me->setActive(true); + me->SetInCombatWithZone(); + events.ScheduleEvent(EVENT_ENRAGE, 15min); + UpdatePhase(); + + if (!pInstance) + return; + + for (uint8 i = 0; i < 3; ++i) + if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i))) + if (!boss->IsInCombat()) + boss->AI()->AttackStart(who); + } + + void UpdatePhase() + { + if (_phase >= 3) + return; + + ++_phase; + + switch (_phase) + { + case 1: + events.RescheduleEvent(EVENT_CHAIN_LIGHTNING, 9s, 17s); + events.RescheduleEvent(EVENT_OVERLOAD, 25s, 40s); + break; + case 2: + events.RescheduleEvent(EVENT_LIGHTNING_WHIRL, 20s, 40s); + break; + case 3: + me->ResetLootMode(); + me->CastSpell(me, SPELL_STORMSHIELD, true); + events.RescheduleEvent(EVENT_LIGHTNING_TENDRILS, 15s, 16s); + break; + } + } + + void JustDied(Unit* /*Killer*/) override + { + if (!pInstance) + return; + me->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), 427.5, me->GetOrientation()); + if (IsEncounterComplete(pInstance, me)) + { + pInstance->SetData(TYPE_ASSEMBLY, DONE); + me->CastSpell(me, 65195, true); // credit + Talk(SAY_BRUNDIR_ENCOUNTER_DEFEATED); + } + else + { + RestoreAssemblyHealth(pInstance->GetGuidData(DATA_STEELBREAKER), pInstance->GetGuidData(DATA_MOLGEIM), me); + me->CastSpell(me, SPELL_SUPERCHARGE, true); + Talk(SAY_BRUNDIR_DEATH); + } + } + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() != TYPEID_PLAYER || urand(0, 2)) + return; + + Talk(SAY_BRUNDIR_SLAY); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_SUPERCHARGE) + UpdatePhase(); + } + + void SpellHitTarget(Unit* /*target*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_CHAIN_LIGHTNING || spellInfo->Id == uint32(RAID_MODE(61916, 63482))) // Lightning Whirl triggered + _stunnedAchievement = false; + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_BRUNDIR) + return _stunnedAchievement; + + return 0; + } + + void MovementInform(uint32 type, uint32 point) override + { + if (type == POINT_MOTION_TYPE && point == POINT_CHANNEL_STEELBREAKER) + me->CastSpell(me, SPELL_LIGHTNING_CHANNEL_PRE, true); + } + + void UpdateAI(uint32 diff) override + { + if (!me->IsInCombat() && me->GetReactState() == REACT_AGGRESSIVE) + { + _channelTimer += diff; + if (_channelTimer >= 10000) + { + _channelTimer = 0; + float o = urand(0, 5) * M_PI / 3.0f; + me->InterruptNonMeleeSpells(false); + me->GetMotionMaster()->MovePoint(POINT_CHANNEL_STEELBREAKER, 1587.18f + 10.0f * cos(o), 121.02f + 10.0f * std::sin(o), 427.3f); + } + } + + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_CHAIN_LIGHTNING: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_CHAIN_LIGHTNING, false); + + events.Repeat(9s, 17s); + break; + case EVENT_OVERLOAD: + Talk(EMOTE_BRUNDIR_OVERLOAD); + me->CastSpell(me, SPELL_OVERLOAD, true); + events.RescheduleEvent(EVENT_OVERLOAD, 25s, 40s); + break; + case EVENT_LIGHTNING_WHIRL: + Talk(SAY_BRUNDIR_SPECIAL); + me->CastSpell(me, SPELL_LIGHTNING_WHIRL, true); + events.Repeat(10s, 25s); + break; + case EVENT_LIGHTNING_TENDRILS: + { + // Reschedule old + events.Repeat(35s); + events.DelayEvents(18s); + Talk(SAY_BRUNDIR_FLIGHT); + + Unit* oldVictim = me->GetVictim(); + _flyTargetGUID = oldVictim->GetGUID(); + me->SetRegeneratingHealth(false); + me->SetDisableGravity(true); + me->SetHover(true); + + me->CombatStop(); + me->StopMoving(); + me->SetReactState(REACT_PASSIVE); + me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty); + me->SetUnitFlag(UNIT_FLAG_STUNNED); + + me->CastSpell(me, SPELL_LIGHTNING_TENDRILS, true); + me->CastSpell(me, 61883, true); + events.ScheduleEvent(EVENT_LIGHTNING_LAND, 16s); + events.ScheduleEvent(EVENT_LIGHTNING_FLIGHT, 1s); + break; + } + case EVENT_LIGHTNING_LAND: + { + float speed = me->GetDistance(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()) / (1000.0f * 0.001f); + me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), speed); + events.ScheduleEvent(EVENT_LAND_LAND, 1s); + break; + } + case EVENT_LAND_LAND: + me->SetCanFly(false); + me->SetHover(false); + me->SetReactState(REACT_AGGRESSIVE); + me->SetDisableGravity(false); + if (Unit* flyTarget = ObjectAccessor::GetUnit(*me, _flyTargetGUID)) + { + me->Attack(flyTarget, false); + } + + me->SetRegeneratingHealth(true); + _flyTargetGUID.Clear(); + me->RemoveAura(SPELL_LIGHTNING_TENDRILS); + me->RemoveAura(61883); + DoResetThreatList(); + events.CancelEvent(EVENT_LIGHTNING_FLIGHT); + break; + case EVENT_ENRAGE: + Talk(SAY_BRUNDIR_BERSERK); + me->CastSpell(me, SPELL_BERSERK, true); + break; + case EVENT_LIGHTNING_FLIGHT: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) + { + me->GetMotionMaster()->MovePoint(0, *target); + } + events.ScheduleEvent(EVENT_LIGHTNING_FLIGHT, 6s); + break; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class spell_shield_of_runes : public SpellScriptLoader +{ +public: + spell_shield_of_runes() : SpellScriptLoader("spell_shield_of_runes") { } + + class spell_shield_of_runes_AuraScript : public AuraScript + { + PrepareAuraScript(spell_shield_of_runes_AuraScript); + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Unit* owner = GetUnitOwner()) + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL && aurEff->GetAmount() <= 0) + owner->CastSpell(owner, SPELL_SHIELD_OF_RUNES_BUFF, false); + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_shield_of_runes_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_shield_of_runes_AuraScript(); + } +}; + +class spell_assembly_meltdown : public SpellScriptLoader +{ +public: + spell_assembly_meltdown() : SpellScriptLoader("spell_assembly_meltdown") { } + + class spell_assembly_meltdown_SpellScript : public SpellScript + { + PrepareSpellScript(spell_assembly_meltdown_SpellScript); + + void HandleInstaKill(SpellEffIndex /*effIndex*/) + { + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_STEELBREAKER))) + Steelbreaker->AI()->DoAction(ACTION_ADD_CHARGE); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_assembly_meltdown_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_assembly_meltdown_SpellScript(); + } +}; + +class spell_assembly_rune_of_summoning : public SpellScriptLoader +{ +public: + spell_assembly_rune_of_summoning() : SpellScriptLoader("spell_assembly_rune_of_summoning") { } + + class spell_assembly_rune_of_summoning_AuraScript : public AuraScript + { + PrepareAuraScript(spell_assembly_rune_of_summoning_AuraScript); + + void OnPeriodic(AuraEffect const* aurEff) + { + PreventDefaultAction(); + if (aurEff->GetTickNumber() % 2 == 0) + GetTarget()->CastSpell(GetTarget(), SPELL_RUNE_OF_SUMMONING_SUMMON, true, nullptr, aurEff, GetTarget()->IsSummon() ? GetTarget()->ToTempSummon()->GetSummonerGUID() : ObjectGuid::Empty); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (TempSummon* summ = GetTarget()->ToTempSummon()) + summ->DespawnOrUnsummon(1); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_assembly_rune_of_summoning_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + OnEffectRemove += AuraEffectRemoveFn(spell_assembly_rune_of_summoning_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_assembly_rune_of_summoning_AuraScript(); + } +}; + +class achievement_assembly_of_iron : public AchievementCriteriaScript +{ +public: + achievement_assembly_of_iron(char const* name, uint32 entry) : AchievementCriteriaScript(name), + _targetEntry(entry) + { + } + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetAuraCount(SPELL_SUPERCHARGE) >= 2 && (!_targetEntry || target->GetEntry() == _targetEntry); + } + +private: + uint32 const _targetEntry; +}; + +class achievement_cant_do_that_while_stunned : public AchievementCriteriaScript +{ +public: + achievement_cant_do_that_while_stunned() : AchievementCriteriaScript("achievement_cant_do_that_while_stunned") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + bool allow = target && target->GetAuraCount(SPELL_SUPERCHARGE) >= 2; + if (!allow) + return false; + + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(DATA_BRUNDIR))) + return cr->AI()->GetData(DATA_BRUNDIR); + + return false; + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp index 904e01a8fd44c6..6c3308f663e46e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_auriaya.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "Player.h" @@ -24,472 +25,6 @@ #include "SpellScriptLoader.h" #include "ulduar.h" -enum AuriayaSpells -{ - // BASIC - SPELL_TERRIFYING_SCREECH = 64386, - SPELL_SENTINEL_BLAST_10 = 64389, - SPELL_SENTINEL_BLAST_25 = 64678, - SPELL_SONIC_SCREECH_10 = 64422, - SPELL_SONIC_SCREECH_25 = 64688, - SPELL_GUARDIAN_SWARM = 64396, - SPELL_ENRAGE = 47008, - SPELL_ACTIVATE_FERAL_DEFENDER = 64449, - - // Sanctum Sentry - SPELL_SAVAGE_POUNCE_10 = 64666, - SPELL_SAVAGE_POUNCE_25 = 64374, - SPELL_RIP_FLESH_10 = 64375, - SPELL_RIP_FLESH_25 = 64667, - SPELL_STRENGTH_OF_THE_PACK = 64369, - - // Feral Defender - SPELL_FERAL_ESSENCE = 64455, - SPELL_FERAL_POUNCE_10 = 64478, - SPELL_FERAL_POUNCE_25 = 64669, - SPELL_FERAL_RUSH_10 = 64496, - SPELL_FERAL_RUSH_25 = 64674, - //SPELL_SEEPING_FERAL_ESSENCE_SUMMON = 64457, - SPELL_SEEPING_FERAL_ESSENCE_10 = 64458, - SPELL_SEEPING_FERAL_ESSENCE_25 = 64676, -}; - -#define SPELL_SONIC_SCREECH RAID_MODE(SPELL_SONIC_SCREECH_10, SPELL_SONIC_SCREECH_25) -#define SPELL_SENTINEL_BLAST RAID_MODE(SPELL_SENTINEL_BLAST_10, SPELL_SENTINEL_BLAST_25) -#define SPELL_SAVAGE_POUNCE RAID_MODE(SPELL_SAVAGE_POUNCE_10, SPELL_SAVAGE_POUNCE_25) -#define SPELL_RIP_FLESH RAID_MODE(SPELL_RIP_FLESH_10, SPELL_RIP_FLESH_25) -#define SPELL_FERAL_POUNCE RAID_MODE(SPELL_FERAL_POUNCE_10, SPELL_FERAL_POUNCE_25) -#define SPELL_FERAL_RUSH RAID_MODE(SPELL_FERAL_RUSH_10, SPELL_FERAL_RUSH_25) -//#define SPELL_SEEPING_FERAL_ESSENCE RAID_MODE(SPELL_SEEPING_FERAL_ESSENCE_10, SPELL_SEEPING_FERAL_ESSENCE_25) - -enum AuriayaNPC -{ - NPC_FERAL_DEFENDER = 34035, - NPC_SANCTUM_SENTRY = 34014, - NPC_SEEPING_FERAL_ESSENCE = 34098, -}; - -enum AuriayaEvents -{ - EVENT_SUMMON_FERAL_DEFENDER = 1, - EVENT_TERRIFYING_SCREECH = 2, - EVENT_SONIC_SCREECH = 3, - EVENT_GUARDIAN_SWARM = 4, - EVENT_SENTINEL_BLAST = 5, - EVENT_REMOVE_IMMUNE = 6, - - EVENT_RESPAWN_FERAL_DEFENDER = 9, - EVENT_ENRAGE = 10, -}; - -enum Texts -{ - SAY_AGGRO = 0, - SAY_SLAY = 1, - SAY_BERSERK = 2, - EMOTE_DEATH = 3, - EMOTE_FEAR = 4, - EMOTE_DEFFENDER = 5, -}; - -enum Misc -{ - ACTION_FERAL_RESPAWN = 1, - ACTION_FERAL_DEATH = 2, - ACTION_DESPAWN_ADDS = 3, - ACTION_FERAL_DEATH_WITH_STACK = 4, - - DATA_CRAZY_CAT = 10, - DATA_NINE_LIVES = 11, -}; - -class boss_auriaya : public CreatureScript -{ -public: - boss_auriaya() : CreatureScript("boss_auriaya") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_auriayaAI : public ScriptedAI - { - boss_auriayaAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) - { - m_pInstance = pCreature->GetInstanceScript(); - } - - InstanceScript* m_pInstance; - EventMap events; - SummonList summons; - - bool _feralDied; - bool _nineLives; - - void Reset() override - { - _feralDied = false; - _nineLives = false; - - events.Reset(); - EntryCheckPredicate pred(NPC_FERAL_DEFENDER); - summons.DoAction(ACTION_DESPAWN_ADDS, pred); - summons.DespawnAll(); - - if (m_pInstance) - m_pInstance->SetData(TYPE_AURIAYA, NOT_STARTED); - - for (uint8 i = 0; i < RAID_MODE(2, 4); ++i) - me->SummonCreature(NPC_SANCTUM_SENTRY, me->GetPositionX() + urand(4, 12), me->GetPositionY() + urand(4, 12), me->GetPositionZ()); - - me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false); - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_CRAZY_CAT) - return !_feralDied; - else if (param == DATA_NINE_LIVES) - return _nineLives; - - return 0; - } - - void JustSummoned(Creature* cr) override - { - if (cr->GetEntry() == NPC_SANCTUM_SENTRY) - cr->GetMotionMaster()->MoveFollow(me, 6, rand_norm() * 2 * 3.14f); - else - cr->SetInCombatWithZone(); - - summons.Summon(cr); - } - - void SummonedCreatureDies(Creature* cr, Unit*) override - { - if (cr->GetEntry() == NPC_SANCTUM_SENTRY) - _feralDied = true; - } - - void JustReachedHome() override { me->setActive(false); } - - void JustEngagedWith(Unit* /*who*/) override - { - if (m_pInstance) - m_pInstance->SetData(TYPE_AURIAYA, IN_PROGRESS); - - events.ScheduleEvent(EVENT_TERRIFYING_SCREECH, 35s); - events.ScheduleEvent(EVENT_SONIC_SCREECH, 45s); - events.ScheduleEvent(EVENT_GUARDIAN_SWARM, 70s); - events.ScheduleEvent(EVENT_SUMMON_FERAL_DEFENDER, 60s); - events.ScheduleEvent(EVENT_SENTINEL_BLAST, 36s); - events.ScheduleEvent(EVENT_ENRAGE, 10min); - - summons.DoZoneInCombat(NPC_SANCTUM_SENTRY); - - Talk(SAY_AGGRO); - me->setActive(true); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2)) - return; - - Talk(SAY_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - if (m_pInstance) - m_pInstance->SetData(TYPE_AURIAYA, DONE); - - EntryCheckPredicate pred(NPC_FERAL_DEFENDER); - summons.DoAction(ACTION_DESPAWN_ADDS, pred); - summons.DespawnAll(); - Talk(EMOTE_DEATH); - } - - void DoAction(int32 param) override - { - if (param == ACTION_FERAL_DEATH_WITH_STACK) - events.ScheduleEvent(EVENT_RESPAWN_FERAL_DEFENDER, 25s); - else if (param == ACTION_FERAL_DEATH) - _nineLives = true; - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SUMMON_FERAL_DEFENDER: - Talk(EMOTE_DEFFENDER); - me->CastSpell(me, SPELL_ACTIVATE_FERAL_DEFENDER, true); - me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); - events.ScheduleEvent(EVENT_REMOVE_IMMUNE, 3s); - break; - case EVENT_REMOVE_IMMUNE: - me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false); - break; - case EVENT_TERRIFYING_SCREECH: - Talk(EMOTE_FEAR); - me->CastSpell(me, SPELL_TERRIFYING_SCREECH, false); - events.Repeat(35s); - break; - case EVENT_SONIC_SCREECH: - me->CastSpell(me, SPELL_SONIC_SCREECH, false); - events.Repeat(50s); - break; - case EVENT_GUARDIAN_SWARM: - me->CastSpell(me->GetVictim(), SPELL_GUARDIAN_SWARM, false); - events.Repeat(40s); - break; - case EVENT_SENTINEL_BLAST: - me->CastSpell(me, SPELL_SENTINEL_BLAST, false); - events.Repeat(35s); - events.DelayEvents(5000, 0); - break; - case EVENT_RESPAWN_FERAL_DEFENDER: - { - EntryCheckPredicate pred(NPC_FERAL_DEFENDER); - summons.DoAction(ACTION_FERAL_RESPAWN, pred); - break; - } - case EVENT_ENRAGE: - Talk(SAY_BERSERK); - me->CastSpell(me, SPELL_ENRAGE, true); - break; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class npc_auriaya_sanctum_sentry : public CreatureScript -{ -public: - npc_auriaya_sanctum_sentry() : CreatureScript("npc_auriaya_sanctum_sentry") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_auriaya_sanctum_sentryAI : public ScriptedAI - { - npc_auriaya_sanctum_sentryAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - uint32 _savagePounceTimer; - uint32 _ripFleshTimer; - - void JustEngagedWith(Unit*) override - { - if (me->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_AURIAYA))) - cr->SetInCombatWithZone(); - } - - void Reset() override - { - _savagePounceTimer = 5000; - _ripFleshTimer = 0; - - me->CastSpell(me, SPELL_STRENGTH_OF_THE_PACK, true); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - _savagePounceTimer += diff; - _ripFleshTimer += diff; - - if (_savagePounceTimer >= 5000) - { - float dist = me->GetDistance(me->GetVictim()); - if (dist >= 8 && dist < 25 && me->IsWithinLOSInMap(me->GetVictim())) - { - me->CastSpell(me->GetVictim(), SPELL_SAVAGE_POUNCE, false); - _savagePounceTimer = 0; - return; - } - _savagePounceTimer = 200; - } - else if (_ripFleshTimer >= 10000) - { - me->CastSpell(me->GetVictim(), SPELL_RIP_FLESH, false); - _ripFleshTimer = 0; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class npc_auriaya_feral_defender : public CreatureScript -{ -public: - npc_auriaya_feral_defender() : CreatureScript("npc_auriaya_feral_defender") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_auriaya_feral_defenderAI : public ScriptedAI - { - npc_auriaya_feral_defenderAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) { } - - int32 _feralRushTimer; - int32 _feralPounceTimer; - uint8 _feralEssenceStack; - SummonList summons; - - void Reset() override - { - summons.DespawnAll(); - _feralRushTimer = 3000; - _feralPounceTimer = 0; - _feralEssenceStack = 8; - - if (Aura* aur = me->AddAura(SPELL_FERAL_ESSENCE, me)) - aur->SetStackAmount(_feralEssenceStack); - } - - void JustDied(Unit*) override - { - // inform about our death, start timer - if (me->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_AURIAYA))) - cr->AI()->DoAction(_feralEssenceStack ? ACTION_FERAL_DEATH_WITH_STACK : ACTION_FERAL_DEATH); - - if (_feralEssenceStack) - { - if (Creature* cr = me->SummonCreature(NPC_SEEPING_FERAL_ESSENCE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.0f)) - summons.Summon(cr); - - --_feralEssenceStack; - } - } - - void DoAction(int32 param) override - { - if (param == ACTION_FERAL_RESPAWN) - { - me->setDeathState(DeathState::JustRespawned); - - if (Player* target = SelectTargetFromPlayerList(200)) - AttackStart(target); - else - { - summons.DespawnAll(); - me->DespawnOrUnsummon(1); - } - - if (_feralEssenceStack) - if (Aura* aur = me->AddAura(SPELL_FERAL_ESSENCE, me)) - aur->SetStackAmount(_feralEssenceStack); - } - else if (param == ACTION_DESPAWN_ADDS) - summons.DespawnAll(); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - _feralRushTimer += diff; - _feralPounceTimer += diff; - - if (_feralRushTimer >= 6000) - { - DoResetThreatList(); - if (!UpdateVictim()) - return; - - me->CastSpell(me->GetVictim(), SPELL_FERAL_RUSH, true); - _feralRushTimer = 0; - } - else if (_feralPounceTimer >= 6000) - { - me->CastSpell(me->GetVictim(), SPELL_FERAL_POUNCE, false); - _feralPounceTimer = 0; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class spell_auriaya_sentinel_blast : public SpellScriptLoader -{ -public: - spell_auriaya_sentinel_blast() : SpellScriptLoader("spell_auriaya_sentinel_blast") { } - - class spell_auriaya_sentinel_blast_SpellScript : public SpellScript - { - PrepareSpellScript(spell_auriaya_sentinel_blast_SpellScript); - - void FilterTargets(std::list& unitList) - { - unitList.remove_if(PlayerOrPetCheck()); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_auriaya_sentinel_blast_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_auriaya_sentinel_blast_SpellScript(); - } -}; - -class achievement_auriaya_crazy_cat_lady : public AchievementCriteriaScript -{ -public: - achievement_auriaya_crazy_cat_lady() : AchievementCriteriaScript("achievement_auriaya_crazy_cat_lady") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - if (target) - if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_AURIAYA))) - return cr->AI()->GetData(DATA_CRAZY_CAT); - - return false; - } -}; - -class achievement_auriaya_nine_lives : public AchievementCriteriaScript -{ -public: - achievement_auriaya_nine_lives() : AchievementCriteriaScript("achievement_auriaya_nine_lives") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - if (target) - if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_AURIAYA))) - return cr->AI()->GetData(DATA_NINE_LIVES); - - return false; - } -}; - void AddSC_boss_auriaya() { new boss_auriaya(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.h new file mode 100644 index 00000000000000..69813f14dc2a71 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.h @@ -0,0 +1,479 @@ +#ifndef BOSS_AURIAYA_H_ +#define BOSS_AURIAYA_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "ulduar.h" + +enum AuriayaSpells +{ + // BASIC + SPELL_TERRIFYING_SCREECH = 64386, + SPELL_SENTINEL_BLAST_10 = 64389, + SPELL_SENTINEL_BLAST_25 = 64678, + SPELL_SONIC_SCREECH_10 = 64422, + SPELL_SONIC_SCREECH_25 = 64688, + SPELL_GUARDIAN_SWARM = 64396, + SPELL_ENRAGE = 47008, + SPELL_ACTIVATE_FERAL_DEFENDER = 64449, + + // Sanctum Sentry + SPELL_SAVAGE_POUNCE_10 = 64666, + SPELL_SAVAGE_POUNCE_25 = 64374, + SPELL_RIP_FLESH_10 = 64375, + SPELL_RIP_FLESH_25 = 64667, + SPELL_STRENGTH_OF_THE_PACK = 64369, + + // Feral Defender + SPELL_FERAL_ESSENCE = 64455, + SPELL_FERAL_POUNCE_10 = 64478, + SPELL_FERAL_POUNCE_25 = 64669, + SPELL_FERAL_RUSH_10 = 64496, + SPELL_FERAL_RUSH_25 = 64674, + //SPELL_SEEPING_FERAL_ESSENCE_SUMMON = 64457, + SPELL_SEEPING_FERAL_ESSENCE_10 = 64458, + SPELL_SEEPING_FERAL_ESSENCE_25 = 64676, +}; + +#define SPELL_SONIC_SCREECH RAID_MODE(SPELL_SONIC_SCREECH_10, SPELL_SONIC_SCREECH_25) +#define SPELL_SENTINEL_BLAST RAID_MODE(SPELL_SENTINEL_BLAST_10, SPELL_SENTINEL_BLAST_25) +#define SPELL_SAVAGE_POUNCE RAID_MODE(SPELL_SAVAGE_POUNCE_10, SPELL_SAVAGE_POUNCE_25) +#define SPELL_RIP_FLESH RAID_MODE(SPELL_RIP_FLESH_10, SPELL_RIP_FLESH_25) +#define SPELL_FERAL_POUNCE RAID_MODE(SPELL_FERAL_POUNCE_10, SPELL_FERAL_POUNCE_25) +#define SPELL_FERAL_RUSH RAID_MODE(SPELL_FERAL_RUSH_10, SPELL_FERAL_RUSH_25) +//#define SPELL_SEEPING_FERAL_ESSENCE RAID_MODE(SPELL_SEEPING_FERAL_ESSENCE_10, SPELL_SEEPING_FERAL_ESSENCE_25) + +enum AuriayaNPC +{ + NPC_FERAL_DEFENDER = 34035, + NPC_SANCTUM_SENTRY = 34014, + NPC_SEEPING_FERAL_ESSENCE = 34098, +}; + +enum AuriayaEvents +{ + EVENT_SUMMON_FERAL_DEFENDER = 1, + EVENT_TERRIFYING_SCREECH = 2, + EVENT_SONIC_SCREECH = 3, + EVENT_GUARDIAN_SWARM = 4, + EVENT_SENTINEL_BLAST = 5, + EVENT_REMOVE_IMMUNE = 6, + + EVENT_RESPAWN_FERAL_DEFENDER = 9, + EVENT_ENRAGE = 10, +}; + +enum Texts +{ + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_BERSERK = 2, + EMOTE_DEATH = 3, + EMOTE_FEAR = 4, + EMOTE_DEFFENDER = 5, +}; + +enum Misc +{ + ACTION_FERAL_RESPAWN = 1, + ACTION_FERAL_DEATH = 2, + ACTION_DESPAWN_ADDS = 3, + ACTION_FERAL_DEATH_WITH_STACK = 4, + + DATA_CRAZY_CAT = 10, + DATA_NINE_LIVES = 11, +}; + +class boss_auriaya : public CreatureScript +{ +public: + boss_auriaya() : CreatureScript("boss_auriaya") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_auriayaAI : public ScriptedAI + { + boss_auriayaAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) + { + m_pInstance = pCreature->GetInstanceScript(); + } + + InstanceScript* m_pInstance; + EventMap events; + SummonList summons; + + bool _feralDied; + bool _nineLives; + + void Reset() override + { + _feralDied = false; + _nineLives = false; + + events.Reset(); + EntryCheckPredicate pred(NPC_FERAL_DEFENDER); + summons.DoAction(ACTION_DESPAWN_ADDS, pred); + summons.DespawnAll(); + + if (m_pInstance) + m_pInstance->SetData(TYPE_AURIAYA, NOT_STARTED); + + for (uint8 i = 0; i < RAID_MODE(2, 4); ++i) + me->SummonCreature(NPC_SANCTUM_SENTRY, me->GetPositionX() + urand(4, 12), me->GetPositionY() + urand(4, 12), me->GetPositionZ()); + + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false); + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_CRAZY_CAT) + return !_feralDied; + else if (param == DATA_NINE_LIVES) + return _nineLives; + + return 0; + } + + void JustSummoned(Creature* cr) override + { + if (cr->GetEntry() == NPC_SANCTUM_SENTRY) + cr->GetMotionMaster()->MoveFollow(me, 6, rand_norm() * 2 * 3.14f); + else + cr->SetInCombatWithZone(); + + summons.Summon(cr); + } + + void SummonedCreatureDies(Creature* cr, Unit*) override + { + if (cr->GetEntry() == NPC_SANCTUM_SENTRY) + _feralDied = true; + } + + void JustReachedHome() override { me->setActive(false); } + + void JustEngagedWith(Unit* /*who*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_AURIAYA, IN_PROGRESS); + + events.ScheduleEvent(EVENT_TERRIFYING_SCREECH, 35s); + events.ScheduleEvent(EVENT_SONIC_SCREECH, 45s); + events.ScheduleEvent(EVENT_GUARDIAN_SWARM, 70s); + events.ScheduleEvent(EVENT_SUMMON_FERAL_DEFENDER, 60s); + events.ScheduleEvent(EVENT_SENTINEL_BLAST, 36s); + events.ScheduleEvent(EVENT_ENRAGE, 10min); + + summons.DoZoneInCombat(NPC_SANCTUM_SENTRY); + + Talk(SAY_AGGRO); + me->setActive(true); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2)) + return; + + Talk(SAY_SLAY); + } + + void JustDied(Unit* /*killer*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_AURIAYA, DONE); + + EntryCheckPredicate pred(NPC_FERAL_DEFENDER); + summons.DoAction(ACTION_DESPAWN_ADDS, pred); + summons.DespawnAll(); + Talk(EMOTE_DEATH); + } + + void DoAction(int32 param) override + { + if (param == ACTION_FERAL_DEATH_WITH_STACK) + events.ScheduleEvent(EVENT_RESPAWN_FERAL_DEFENDER, 25s); + else if (param == ACTION_FERAL_DEATH) + _nineLives = true; + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_SUMMON_FERAL_DEFENDER: + Talk(EMOTE_DEFFENDER); + me->CastSpell(me, SPELL_ACTIVATE_FERAL_DEFENDER, true); + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true); + events.ScheduleEvent(EVENT_REMOVE_IMMUNE, 3s); + break; + case EVENT_REMOVE_IMMUNE: + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false); + break; + case EVENT_TERRIFYING_SCREECH: + Talk(EMOTE_FEAR); + me->CastSpell(me, SPELL_TERRIFYING_SCREECH, false); + events.Repeat(35s); + break; + case EVENT_SONIC_SCREECH: + me->CastSpell(me, SPELL_SONIC_SCREECH, false); + events.Repeat(50s); + break; + case EVENT_GUARDIAN_SWARM: + me->CastSpell(me->GetVictim(), SPELL_GUARDIAN_SWARM, false); + events.Repeat(40s); + break; + case EVENT_SENTINEL_BLAST: + me->CastSpell(me, SPELL_SENTINEL_BLAST, false); + events.Repeat(35s); + events.DelayEvents(5000, 0); + break; + case EVENT_RESPAWN_FERAL_DEFENDER: + { + EntryCheckPredicate pred(NPC_FERAL_DEFENDER); + summons.DoAction(ACTION_FERAL_RESPAWN, pred); + break; + } + case EVENT_ENRAGE: + Talk(SAY_BERSERK); + me->CastSpell(me, SPELL_ENRAGE, true); + break; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class npc_auriaya_sanctum_sentry : public CreatureScript +{ +public: + npc_auriaya_sanctum_sentry() : CreatureScript("npc_auriaya_sanctum_sentry") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_auriaya_sanctum_sentryAI : public ScriptedAI + { + npc_auriaya_sanctum_sentryAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + uint32 _savagePounceTimer; + uint32 _ripFleshTimer; + + void JustEngagedWith(Unit*) override + { + if (me->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_AURIAYA))) + cr->SetInCombatWithZone(); + } + + void Reset() override + { + _savagePounceTimer = 5000; + _ripFleshTimer = 0; + + me->CastSpell(me, SPELL_STRENGTH_OF_THE_PACK, true); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _savagePounceTimer += diff; + _ripFleshTimer += diff; + + if (_savagePounceTimer >= 5000) + { + float dist = me->GetDistance(me->GetVictim()); + if (dist >= 8 && dist < 25 && me->IsWithinLOSInMap(me->GetVictim())) + { + me->CastSpell(me->GetVictim(), SPELL_SAVAGE_POUNCE, false); + _savagePounceTimer = 0; + return; + } + _savagePounceTimer = 200; + } + else if (_ripFleshTimer >= 10000) + { + me->CastSpell(me->GetVictim(), SPELL_RIP_FLESH, false); + _ripFleshTimer = 0; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class npc_auriaya_feral_defender : public CreatureScript +{ +public: + npc_auriaya_feral_defender() : CreatureScript("npc_auriaya_feral_defender") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_auriaya_feral_defenderAI : public ScriptedAI + { + npc_auriaya_feral_defenderAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) { } + + int32 _feralRushTimer; + int32 _feralPounceTimer; + uint8 _feralEssenceStack; + SummonList summons; + + void Reset() override + { + summons.DespawnAll(); + _feralRushTimer = 3000; + _feralPounceTimer = 0; + _feralEssenceStack = 8; + + if (Aura* aur = me->AddAura(SPELL_FERAL_ESSENCE, me)) + aur->SetStackAmount(_feralEssenceStack); + } + + void JustDied(Unit*) override + { + // inform about our death, start timer + if (me->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_AURIAYA))) + cr->AI()->DoAction(_feralEssenceStack ? ACTION_FERAL_DEATH_WITH_STACK : ACTION_FERAL_DEATH); + + if (_feralEssenceStack) + { + if (Creature* cr = me->SummonCreature(NPC_SEEPING_FERAL_ESSENCE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.0f)) + summons.Summon(cr); + + --_feralEssenceStack; + } + } + + void DoAction(int32 param) override + { + if (param == ACTION_FERAL_RESPAWN) + { + me->setDeathState(DeathState::JustRespawned); + + if (Player* target = SelectTargetFromPlayerList(200)) + AttackStart(target); + else + { + summons.DespawnAll(); + me->DespawnOrUnsummon(1); + } + + if (_feralEssenceStack) + if (Aura* aur = me->AddAura(SPELL_FERAL_ESSENCE, me)) + aur->SetStackAmount(_feralEssenceStack); + } + else if (param == ACTION_DESPAWN_ADDS) + summons.DespawnAll(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _feralRushTimer += diff; + _feralPounceTimer += diff; + + if (_feralRushTimer >= 6000) + { + DoResetThreatList(); + if (!UpdateVictim()) + return; + + me->CastSpell(me->GetVictim(), SPELL_FERAL_RUSH, true); + _feralRushTimer = 0; + } + else if (_feralPounceTimer >= 6000) + { + me->CastSpell(me->GetVictim(), SPELL_FERAL_POUNCE, false); + _feralPounceTimer = 0; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class spell_auriaya_sentinel_blast : public SpellScriptLoader +{ +public: + spell_auriaya_sentinel_blast() : SpellScriptLoader("spell_auriaya_sentinel_blast") { } + + class spell_auriaya_sentinel_blast_SpellScript : public SpellScript + { + PrepareSpellScript(spell_auriaya_sentinel_blast_SpellScript); + + void FilterTargets(std::list& unitList) + { + unitList.remove_if(PlayerOrPetCheck()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_auriaya_sentinel_blast_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_auriaya_sentinel_blast_SpellScript(); + } +}; + +class achievement_auriaya_crazy_cat_lady : public AchievementCriteriaScript +{ +public: + achievement_auriaya_crazy_cat_lady() : AchievementCriteriaScript("achievement_auriaya_crazy_cat_lady") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + if (target) + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_AURIAYA))) + return cr->AI()->GetData(DATA_CRAZY_CAT); + + return false; + } +}; + +class achievement_auriaya_nine_lives : public AchievementCriteriaScript +{ +public: + achievement_auriaya_nine_lives() : AchievementCriteriaScript("achievement_auriaya_nine_lives") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + if (target) + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_AURIAYA))) + return cr->AI()->GetData(DATA_NINE_LIVES); + + return false; + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 02b7569b726882..af453be0826dfd 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_flame_leviathan.h" #include "AchievementCriteriaScript.h" #include "CombatAI.h" #include "CreatureScript.h" @@ -33,467 +34,6 @@ #include "Vehicle.h" #include "ulduar.h" -enum LeviathanSpells -{ - // Leviathan basic - SPELL_PURSUED = 62374, - SPELL_GATHERING_SPEED = 62375, - SPELL_BATTERING_RAM = 62376, - SPELL_FLAME_VENTS = 62396, - SPELL_MISSILE_BARRAGE = 62400, - SPELL_NAPALM_10 = 63666, - SPELL_NAPALM_25 = 65026, - SPELL_INVIS_AND_STEALTH_DETECT = 18950, - SPELL_TRANSITUS_SHIELD_IMPACT = 48387, - - // Shutdown spells - SPELL_SYSTEMS_SHUTDOWN = 62475, - SPELL_OVERLOAD_CIRCUIT = 62399, - - // hard mode - SPELL_TOWER_OF_STORMS = 65076, - SPELL_TOWER_OF_FLAMES = 65075, - SPELL_TOWER_OF_FROST = 65077, - SPELL_TOWER_OF_LIFE = 64482, - - SPELL_HODIRS_FURY = 62533, - SPELL_FREYA_WARD = 62906, // removed spawn effect - SPELL_MIMIRONS_INFERNO = 62909, - SPELL_THORIMS_HAMMER = 62911, - - SPELL_FREYA_DUMMY_BLUE = 63294, - SPELL_FREYA_DUMMY_GREEN = 63295, - SPELL_FREYA_DUMMY_YELLOW = 63292, - - // Leviathan turret spell - SPELL_SEARING_FLAME = 62402, - // On turret Destory - SPELL_SMOKE_TRAIL = 63575, - - // Pool of tar blaze - SPELL_BLAZE = 62292, - - // Pyrite - SPELL_LIQUID_PYRITE = 62494, - SPELL_DUSTY_EXPLOSION = 63360, - SPELL_DUST_CLOUD_IMPACT = 54740, -}; - -enum GosNpcs -{ - NPC_FLAME_LEVIATHAN_TURRET = 33139, - NPC_SEAT = 33114, - NPC_MECHANOLIFT = 33214, - NPC_LIQUID = 33189, - - // Starting event - NPC_ULDUAR_COLOSSUS = 33237, - NPC_BRANN_RADIO = 34054, - NPC_ULDUAR_GAUNTLET_GENERATOR = 33571, - NPC_DEFENDER_GENERATED = 33572, - - // Hard Mode - NPC_THORIM_HAMMER_TARGET = 33364, - NPC_THORIM_HAMMER = 33365, - NPC_FREYA_WARD_TARGET = 33366, - NPC_FREYA_WARD = 33367, - NPC_MIMIRONS_INFERNO_TARGET = 33369, - NPC_MIMIRONS_INFERNO = 33370, - NPC_HODIRS_FURY_TARGET = 33108, - NPC_HODIRS_FURY = 33212, -}; - -enum Events -{ - EVENT_PURSUE = 1, - EVENT_MISSILE = 2, - EVENT_VENT = 3, - EVENT_SPEED = 4, - EVENT_SUMMON = 5, - EVENT_REINSTALL = 6, - EVENT_HODIRS_FURY = 7, - EVENT_FREYA = 8, - EVENT_MIMIRONS_INFERNO = 9, - EVENT_THORIMS_HAMMER = 10, - EVENT_SOUND_BEGINNING = 11, - EVENT_POSITION_CHECK = 12, -}; - -enum Texts -{ - FLAME_LEVIATHAN_SAY_AGGRO = 0, - FLAME_LEVIATHAN_SAY_SLAY = 1, - FLAME_LEVIATHAN_SAY_DEATH = 2, - FLAME_LEVIATHAN_SAY_PURSUE = 3, - FLAME_LEVIATHAN_SAY_HARDMODE = 4, - FLAME_LEVIATHAN_SAY_TOWER_NONE = 5, - FLAME_LEVIATHAN_SAY_TOWER_FROST = 6, - FLAME_LEVIATHAN_SAY_TOWER_FLAME = 7, - FLAME_LEVIATHAN_SAY_TOWER_NATURE = 8, - FLAME_LEVIATHAN_SAY_TOWER_STORM = 9, - FLAME_LEVIATHAN_SAY_PLAYER_RIDING = 10, - FLAME_LEVIATHAN_SAY_OVERLOAD = 11, - FLAME_LEVIATHAN_EMOTE_PURSUE = 12, - FLAME_LEVIATHAN_EMOTE_OVERLOAD = 13, - FLAME_LEVIATHAN_EMOTE_REPAIR = 14, - FLAME_LEVIATHAN_EMOTE_FROST = 15, - FLAME_LEVIATHAN_EMOTE_FLAME = 16, - FLAME_LEVIATHAN_EMOTE_NATURE = 17, - FLAME_LEVIATHAN_EMOTE_STORM = 18, - FLAME_LEVIATHAN_EMOTE_REACTIVATE = 19, - - // NPC_BRANN_RADIO - BRANN_RADIO_SAY_FL_START_0 = 0, - BRANN_RADIO_SAY_FL_START_1 = 1, - BRANN_RADIO_SAY_FL_START_2 = 2, - BRANN_RADIO_SAY_GENERATORS = 3, - BRANN_RADIO_SAY_STATIONS = 4, - BRANN_RADIO_SAY_TOWER_THORIM = 5, - BRANN_RADIO_SAY_TOWER_HODIR = 6, - BRANN_RADIO_SAY_TOWER_FREYA = 7, - BRANN_RADIO_SAY_TOWER_MIMIRON = 8, - - // Vehicle Repair - Said by a spell, BroadcastTextID, same as FLAME_LEVIATHAN_EMOTE_REPAIR - VEHICLE_EMOTE_REPAIR = 33538, -}; - -enum Seats -{ - SEAT_PLAYER = 0, - SEAT_TURRET = 1, - SEAT_DEVICE = 2, - SEAT_CANNON = 7, -}; - -enum Misc -{ - DATA_EVENT_STARTED = 1, - DATA_GET_TOWER_COUNT = 2, - DATA_GET_SHUTDOWN = 3, - - TOWER_OF_STORMS = 2, - TOWER_OF_FLAMES = 1, - TOWER_OF_FROST = 3, - TOWER_OF_LIFE = 0, - - ACTION_START_NORGANNON_EVENT = 1, - ACTION_START_NORGANNON_BRANN = 2, - ACTION_START_BRANN_EVENT = 3, - ACTION_DESPAWN_ADDS = 4, - ACTION_DELAY_CANNON = 5, - ACTION_DESTROYED_TURRET = 6, -}; - -const Position homePos = {322.39f, -14.5f, 409.8f, 3.14f}; - -class boss_flame_leviathan : public CreatureScript -{ -public: - boss_flame_leviathan() : CreatureScript("boss_flame_leviathan") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_flame_leviathanAI : public ScriptedAI - { - boss_flame_leviathanAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me) - { - m_pInstance = pCreature->GetInstanceScript(); - assert(vehicle); - } - - InstanceScript* m_pInstance; - Vehicle* vehicle; - EventMap events; - SummonList summons; - - uint32 _startTimer; - uint32 _speakTimer; - uint8 _towersCount; - bool _shutdown; - uint32 _destroyedTurretCount; - - // Custom - void BindPlayers(); - void RadioSay(uint8 textid); - void ActivateTowers(); - void TurnGates(bool _start, bool _death); - void TurnHealStations(bool _apply); - void ScheduleEvents(); - void SummonTowerHelpers(uint8 towerId); - - // Original - void JustReachedHome() override - { - // For achievement - if (m_pInstance) - m_pInstance->SetData(DATA_UNBROKEN_ACHIEVEMENT, 0); - me->setActive(false); - } - - void MoveInLineOfSight(Unit*) override {} - void JustSummoned(Creature* cr) override - { - if (cr->GetEntry() != NPC_FLAME_LEVIATHAN_TURRET && cr->GetEntry() != NPC_SEAT) - summons.Summon(cr); - } - - void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } - void SpellHit(Unit* caster, SpellInfo const* spellInfo) override; - void JustDied(Unit*) override; - void KilledUnit(Unit* who) override; - void SpellHitTarget(Unit* target, SpellInfo const* spell) override; - - void AttackStart(Unit* who) override - { - if (Unit* veh = who->GetVehicleBase()) - ScriptedAI::AttackStart(veh); - else - ScriptedAI::AttackStart(who); - } - - void JustEngagedWith(Unit*) override - { - ScheduleEvents(); - Talk(FLAME_LEVIATHAN_SAY_AGGRO); - - me->setActive(true); - me->SetHomePosition(homePos); - TurnHealStations(false); - ActivateTowers(); - if (m_pInstance) - m_pInstance->SetData(TYPE_LEVIATHAN, SPECIAL); - - BindPlayers(); - me->SetInCombatWithZone(); - - if (!_startTimer) - { - TurnGates(true, false); - } - } - - void InitializeAI() override - { - if (m_pInstance && m_pInstance->GetData(TYPE_LEVIATHAN) == SPECIAL) - { - me->SetHomePosition(homePos); - me->UpdatePosition(homePos); - me->StopMovingOnCurrentPos(); - } - - ScriptedAI::InitializeAI(); - } - - void Reset() override - { - // Special immunity case - me->CastSpell(me, SPELL_INVIS_AND_STEALTH_DETECT, true); - me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED, true); - - summons.DoAction(ACTION_DESPAWN_ADDS); - summons.DespawnAll(); - events.Reset(); - - _shutdown = false; - _startTimer = 1; - _speakTimer = 0; - _towersCount = 0; - _destroyedTurretCount = 0; - - if (m_pInstance) - { - if (m_pInstance->GetData(TYPE_LEVIATHAN) != SPECIAL) - { - m_pInstance->SetData(TYPE_LEVIATHAN, NOT_STARTED); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - } - else - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - m_pInstance->SetData(DATA_VEHICLE_SPAWN, VEHICLE_POS_LEVIATHAN); - _startTimer = 0; - } - } - - TurnGates(false, false); - TurnHealStations(true); - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_GET_TOWER_COUNT) - return _towersCount; - if (param == DATA_GET_SHUTDOWN) - return !_shutdown; - - return 0; - } - - void UpdateAI(uint32 diff) override - { - // THIS IS USED ONLY FOR FIRST ENGAGE! - if (_startTimer) - { - _startTimer += diff; - if (_startTimer >= 4000) - { - // Colossus dead, players in range - if (me->FindNearestCreature(NPC_ULDUAR_COLOSSUS, 250.0f, true) || !SelectTargetFromPlayerList(250.0f)) - _startTimer = 1; - else - { - _startTimer = 0; - _speakTimer = 1; - } - } - return; - } - - if (_speakTimer) - { - _speakTimer += diff; - if (_speakTimer <= 10000) - { - _speakTimer = 10000; - RadioSay(BRANN_RADIO_SAY_FL_START_0); - } - else if (_speakTimer > 16000 && _speakTimer < 20000) - { - _speakTimer = 20000; - RadioSay(BRANN_RADIO_SAY_FL_START_1); - } - else if (_speakTimer > 24000 && _speakTimer < 40000) - { - _speakTimer = 40000; - RadioSay(BRANN_RADIO_SAY_FL_START_2); - } - else if (_speakTimer > 41000 && _speakTimer < 60000) - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - TurnGates(true, false); - me->MonsterMoveWithSpeed(homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), 100.0f); - me->UpdatePosition(homePos); - _speakTimer = 60000; - } - else if (_speakTimer > 63500) - { - me->SetInCombatWithZone(); - if (!me->GetVictim()) - { - me->CastSpell(me, SPELL_PURSUED, false); - events.RescheduleEvent(EVENT_PURSUE, 31s); - } - _speakTimer = 0; - } - return; - } - - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_POSITION_CHECK: - if (me->GetPositionX() > 450 || me->GetPositionX() < 120) - { - EnterEvadeMode(); - return; - } - events.Repeat(5s); - break; - case EVENT_PURSUE: - Talk(FLAME_LEVIATHAN_SAY_PURSUE); - me->CastSpell(me, SPELL_PURSUED, false); - events.RescheduleEvent(EVENT_PURSUE, 31s); - return; - case EVENT_SPEED: - me->CastSpell(me, SPELL_GATHERING_SPEED, false); - events.Repeat(15s); - return; - case EVENT_MISSILE: - me->CastSpell(me, SPELL_MISSILE_BARRAGE, true); - events.Repeat(4s); - return; - case EVENT_VENT: - me->CastSpell(me, SPELL_FLAME_VENTS, false); - events.Repeat(20s); - return; - case EVENT_SUMMON: - if(summons.size() < 20) - if (Creature* lift = DoSummonFlyer(NPC_MECHANOLIFT, me, 30.0f, 50.0f, 0)) - lift->GetMotionMaster()->MoveRandom(100); - - events.Repeat(4s); - return; - case EVENT_SOUND_BEGINNING: - if (_towersCount) - Talk(FLAME_LEVIATHAN_SAY_HARDMODE); - else - Talk(FLAME_LEVIATHAN_SAY_TOWER_NONE); - return; - case EVENT_REINSTALL: - for (uint8 i = RAID_MODE(0, 2); i < 4; ++i) - if (Unit* seat = vehicle->GetPassenger(i)) - if (seat->GetTypeId() == TYPEID_UNIT) - seat->ToCreature()->AI()->EnterEvadeMode(); - Talk(FLAME_LEVIATHAN_EMOTE_REACTIVATE); - return; - case EVENT_THORIMS_HAMMER: - SummonTowerHelpers(TOWER_OF_STORMS); - events.Repeat(1min, 2min); - Talk(FLAME_LEVIATHAN_EMOTE_STORM); - Talk(FLAME_LEVIATHAN_SAY_TOWER_STORM); - return; - case EVENT_FREYA: - SummonTowerHelpers(TOWER_OF_LIFE); - Talk(FLAME_LEVIATHAN_EMOTE_NATURE); - Talk(FLAME_LEVIATHAN_SAY_TOWER_NATURE); - return; - case EVENT_MIMIRONS_INFERNO: - SummonTowerHelpers(TOWER_OF_FLAMES); - Talk(FLAME_LEVIATHAN_EMOTE_FLAME); - Talk(FLAME_LEVIATHAN_SAY_TOWER_FLAME); - return; - case EVENT_HODIRS_FURY: - SummonTowerHelpers(TOWER_OF_FROST); - Talk(FLAME_LEVIATHAN_EMOTE_FROST); - Talk(FLAME_LEVIATHAN_SAY_TOWER_FROST); - return; - } - - if(me->isAttackReady() && !me->HasUnitState(UNIT_STATE_STUNNED)) - { - if(me->IsWithinCombatRange(me->GetVictim(), 15.0f)) - { - me->CastSpell(me->GetVictim(), SPELL_BATTERING_RAM, false); - me->resetAttackTimer(); - } - } - } - - void DoAction(int32 action) override - { - if (action == ACTION_DESTROYED_TURRET) - { - ++_destroyedTurretCount; - - if (_destroyedTurretCount == RAID_MODE(2, 4)) - { - _destroyedTurretCount = 0; - me->CastSpell(me, SPELL_SYSTEMS_SHUTDOWN, true); - } - } - } - }; -}; - void boss_flame_leviathan::boss_flame_leviathanAI::BindPlayers() { me->GetMap()->ToInstanceMap()->PermBindAllPlayers(); @@ -700,1425 +240,6 @@ void boss_flame_leviathan::boss_flame_leviathanAI::SpellHitTarget(Unit* target, } } -class boss_flame_leviathan_seat : public CreatureScript -{ -public: - boss_flame_leviathan_seat() : CreatureScript("boss_flame_leviathan_seat") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_flame_leviathan_seatAI : public VehicleAI - { - boss_flame_leviathan_seatAI(Creature* creature) : VehicleAI(creature), vehicle(creature->GetVehicleKit()) - { - ASSERT(vehicle); - me->SetReactState(REACT_PASSIVE); - } - - Vehicle* vehicle; - uint32 _despawnTimer; - - void EnterEvadeMode(EvadeReason /*why*/) override - { - vehicle->InstallAllAccessories(false); - } - - void Reset() override - { - _despawnTimer = !me->GetMap()->Is25ManRaid(); - } - - void UpdateAI(uint32 diff) override - { - if (_despawnTimer) - { - _despawnTimer += diff; - if (_despawnTimer >= 2000) - { - _despawnTimer = 0; - if (Vehicle* veh = me->GetVehicle()) - if (veh->GetPassenger(0) == me || veh->GetPassenger(1) == me) - me->DespawnOrUnsummon(1); - } - } - - VehicleAI::UpdateAI(diff); - } - - void AttackStart(Unit*) override { } - - void PassengerBoarded(Unit* who, int8 seatId, bool apply) override - { - if (who->GetTypeId() != TYPEID_PLAYER || !me->GetVehicle()) - return; - - who->ApplySpellImmune(63847, IMMUNITY_ID, 63847, apply); // SPELL_FLAME_VENTS_TRIGGER - who->ApplySpellImmune(SPELL_MISSILE_BARRAGE, IMMUNITY_ID, SPELL_MISSILE_BARRAGE, apply); - who->ApplySpellImmune(SPELL_BATTERING_RAM, IMMUNITY_ID, SPELL_BATTERING_RAM, apply); - - if (seatId == SEAT_PLAYER) - { - if (Unit* turret = me->GetVehicleKit()->GetPassenger(SEAT_TURRET)) - { - if (apply) - { - turret->ReplaceAllUnitFlags(UNIT_FLAG_NONE); - turret->GetAI()->AttackStart(who); - if (Creature* leviathan = me->GetVehicleCreatureBase()) - leviathan->AI()->Talk(FLAME_LEVIATHAN_SAY_PLAYER_RIDING); - } - else - { - turret->ReplaceAllUnitFlags(UNIT_FLAG_NOT_SELECTABLE); - turret->SetImmuneToAll(true); - if (turret->GetTypeId() == TYPEID_UNIT) - turret->ToCreature()->AI()->EnterEvadeMode(); - } - } - } - } - }; -}; - -class boss_flame_leviathan_defense_turret : public CreatureScript -{ -public: - boss_flame_leviathan_defense_turret() : CreatureScript("boss_flame_leviathan_defense_turret") { } - - struct boss_flame_leviathan_defense_turretAI : public TurretAI - { - boss_flame_leviathan_defense_turretAI(Creature* creature) : TurretAI(creature) - { - _setHealth = false; - _instance = creature->GetInstanceScript(); - } - - InstanceScript* _instance; - - bool _setHealth; - void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (!CanAIAttack(who)) - { - _setHealth = true; - damage = 0; - } - } - - void JustDied(Unit* killer) override - { - if (Player* player = killer->ToPlayer()) - player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, me); - - if (Vehicle* vehicle = me->GetVehicle()) - if (Unit* device = vehicle->GetPassenger(SEAT_DEVICE)) - device->ReplaceAllUnitFlags(UNIT_FLAG_NONE); // unselectable - - if (Creature* leviathan = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(TYPE_LEVIATHAN))) - leviathan->AI()->DoAction(ACTION_DESTROYED_TURRET); - } - - bool CanAIAttack(Unit const* who) const override - { - if (!who || who->GetTypeId() != TYPEID_PLAYER || !who->GetVehicle() || who->GetVehicleBase()->GetEntry() != NPC_SEAT) - return false; - return true; - } - - void UpdateAI(uint32 diff) override - { - if (_setHealth) - { - me->SetHealth(std::min(me->GetHealth() + 1, me->GetMaxHealth())); - _setHealth = false; - } - - TurretAI::UpdateAI(diff); - } - - void KilledUnit(Unit* who) override - { - if (Player* plr = who->ToPlayer()) // make sure that there's no death player on the seat. - if (plr->GetVehicle()) - plr->ExitVehicle(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); - } -}; - -class boss_flame_leviathan_overload_device : public CreatureScript -{ -public: - boss_flame_leviathan_overload_device() : CreatureScript("boss_flame_leviathan_overload_device") { } - - struct boss_flame_leviathan_overload_deviceAI : public NullCreatureAI - { - boss_flame_leviathan_overload_deviceAI(Creature* creature) : NullCreatureAI(creature) - { - } - - void OnSpellClick(Unit* /*clicker*/, bool& result) override - { - if (!result) - return; - - if (me->GetVehicle()) - { - me->RemoveNpcFlag(UNIT_NPC_FLAG_SPELLCLICK); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - - if (Unit* player = me->GetVehicle()->GetPassenger(SEAT_PLAYER)) - { - me->GetVehicleBase()->CastSpell(player, SPELL_SMOKE_TRAIL, true); - player->ExitVehicle(); - } - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); - } -}; - -class npc_freya_ward : public CreatureScript -{ -public: - npc_freya_ward() : CreatureScript("npc_freya_ward") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_freya_wardAI : public NullCreatureAI - { - npc_freya_wardAI(Creature* c) : NullCreatureAI(c), summons(c) - { - } - - SummonList summons; - uint32 _castTimer; - bool _summoned; - - void Reset() override - { - _summoned = false; - _castTimer = 25000; - summons.DespawnAll(); - if (Creature* cr = me->FindNearestCreature(NPC_FREYA_WARD_TARGET, 60.0f, true)) - if (Aura* aur = cr->AddAura(SPELL_FREYA_DUMMY_GREEN, cr)) - { - aur->SetMaxDuration(-1); - aur->SetDuration(-1); - } - } - - void JustSummoned(Creature* cr) override - { - _summoned = true; - summons.Summon(cr); - } - - void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } - - void UpdateAI(uint32 diff) override - { - if (_summoned) - { - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end();) - { - Creature* summon = ObjectAccessor::GetCreature(*me, *itr); - ++itr; - if (summon) - { - summon->ToTempSummon()->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN); - if (Unit* target = summon->SelectNearestTarget(200.0f)) - summon->AI()->AttackStart(target); - } - } - _summoned = false; - } - - _castTimer += diff; - if (_castTimer >= 29 * IN_MILLISECONDS) - { - if (Creature* cr = me->FindNearestCreature(NPC_FREYA_WARD_TARGET, 60.0f, true)) - { - me->CastSpell(cr, SPELL_FREYA_WARD, false); - me->CastSpell(cr, 62947 /*SPELL_FREYA_WARD_SECOND_SUMMON*/, false); - } - - _castTimer = 0; - } - } - - void DoAction(int32 param) override - { - if (param == ACTION_DESPAWN_ADDS) - summons.DespawnAll(); - } - }; -}; - -class npc_hodirs_fury : public CreatureScript -{ -public: - npc_hodirs_fury() : CreatureScript("npc_hodirs_fury") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_hodirs_furyAI : public NullCreatureAI - { - npc_hodirs_furyAI(Creature* c) : NullCreatureAI(c) - { - } - - uint32 _timeToHit; - uint32 _switchTargetTimer; - - void Reset() override - { - _timeToHit = 0; - _switchTargetTimer = 30000; - me->SetWalk(true); - - if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_BLUE, me)) - { - aur->SetMaxDuration(-1); - aur->SetDuration(-1); - } - } - - void MovementInform(uint32 type, uint32 /*param*/) override - { - if (type == FOLLOW_MOTION_TYPE && !_timeToHit) - { - _timeToHit = 1; - _switchTargetTimer = 0; - me->SetControlled(true, UNIT_STATE_STUNNED); - } - } - - void UpdateAI(uint32 diff) override - { - if (_timeToHit) - { - _timeToHit += diff; - if (_timeToHit >= 5000) - { - if (Creature* cr = me->SummonCreature(NPC_HODIRS_FURY, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40, 0, TEMPSUMMON_TIMED_DESPAWN, 10000)) - cr->CastSpell(me, SPELL_HODIRS_FURY, true); - - _switchTargetTimer = 25000; // Switch target soon - _timeToHit = 0; - } - return; - } - - _switchTargetTimer += diff; - if (_switchTargetTimer >= 30000) - { - if(Unit* target = me->SelectNearbyTarget(nullptr, 200.0f)) - { - if (target->GetVehicleBase() && target->GetVehicleBase()->GetEntry() == NPC_SEAT) - { - _switchTargetTimer = 20000; - return; - } - me->SetControlled(false, UNIT_STATE_STUNNED); - me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f); - _switchTargetTimer = 0; - } - else - _switchTargetTimer = 25000; - } - } - }; -}; - -class npc_mimirons_inferno : public CreatureScript -{ -public: - npc_mimirons_inferno() : CreatureScript("npc_mimirons_inferno") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); - } - - struct npc_mimirons_infernoAI : public npc_escortAI - { - npc_mimirons_infernoAI(Creature* creature) : npc_escortAI(creature), summons(me) - { - me->SetReactState(REACT_PASSIVE); - } - - SummonList summons; - uint32 _spellTimer; - uint32 _recastTimer; - - void AttackStart(Unit*) override { } - void MoveInLineOfSight(Unit*) override { } - void WaypointReached(uint32 /*waypointId*/) override { } - - void DoAction(int32 param) override - { - if (param == ACTION_DESPAWN_ADDS) - summons.DespawnAll(); - } - - void Reset() override - { - summons.DespawnAll(); - _spellTimer = 0; - Start(false, false, ObjectGuid::Empty, nullptr, false, true); - if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_YELLOW, me)) - { - aur->SetMaxDuration(-1); - aur->SetDuration(-1); - } - } - - void JustSummoned(Creature* cr) override { summons.Summon(cr); } - void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } - - void UpdateAI(uint32 diff) override - { - npc_escortAI::UpdateAI(diff); - - _spellTimer += diff; - if (_spellTimer >= 2000) - { - if (Creature* cr = me->SummonCreature(NPC_MIMIRONS_INFERNO, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000)) - cr->CastSpell(me, SPELL_MIMIRONS_INFERNO, true); - - _spellTimer = 0; - } - } - }; -}; - -class npc_thorims_hammer : public CreatureScript -{ -public: - npc_thorims_hammer() : CreatureScript("npc_thorims_hammer") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_thorims_hammerAI : public NullCreatureAI - { - npc_thorims_hammerAI(Creature* c) : NullCreatureAI(c) - { - } - - uint32 _beamTimer; - uint32 _finishTime; - uint32 _removeTimer; - - void Reset() override - { - _finishTime = 5000 + rand() % 15000; - _beamTimer = 1; - _removeTimer = 0; - me->CastSpell(me, SPELL_FREYA_DUMMY_BLUE, true); - } - - void UpdateAI(uint32 diff) override - { - if (_beamTimer) - { - _beamTimer += diff; - if (_beamTimer >= _finishTime) - { - if (Creature* cr = me->SummonCreature(NPC_THORIM_HAMMER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40, 0, TEMPSUMMON_TIMED_DESPAWN, 5000)) - cr->CastSpell(me, SPELL_THORIMS_HAMMER, false); - - _beamTimer = 0; - _removeTimer = 1; - me->DespawnOrUnsummon(5 * IN_MILLISECONDS); - } - } - if (_removeTimer) - { - _removeTimer += diff; - if (_removeTimer >= 3 * IN_MILLISECONDS) - { - _removeTimer = 0; - me->RemoveAura(SPELL_FREYA_DUMMY_BLUE); - } - } - } - }; -}; - -class npc_pool_of_tar : public CreatureScript -{ -public: - npc_pool_of_tar() : CreatureScript("npc_pool_of_tar") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_pool_of_tarAI : public NullCreatureAI - { - npc_pool_of_tarAI(Creature* c) : NullCreatureAI(c) - { - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - damage = 0; - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->SchoolMask & SPELL_SCHOOL_MASK_FIRE && !me->HasAura(SPELL_BLAZE)) - me->CastSpell(me, SPELL_BLAZE, true); - } - }; -}; - -class npc_brann_radio : public CreatureScript -{ -public: - npc_brann_radio() : CreatureScript("npc_brann_radio") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_brann_radioAI : public NullCreatureAI - { - npc_brann_radioAI(Creature* c) : NullCreatureAI(c) - { - _lock = (me->GetInstanceScript() && me->GetInstanceScript()->GetData(TYPE_LEVIATHAN) > NOT_STARTED); - _helpLock = _lock; - } - - bool _lock; - bool _helpLock; - - void Reset() override - { - me->SetReactState(REACT_AGGRESSIVE); - } - - void MoveInLineOfSight(Unit* who) override - { - if (!_lock) - { - if (who->GetTypeId() != TYPEID_PLAYER && !who->IsVehicle()) - return; - - // MIMIRON - else if (me->GetDistance2d(-81.9207f, 111.432f) < 5.0f) - { - if (me->GetDistance2d(who) <= 60.0f && who->GetPositionZ() > 430.0f) - { - Talk(BRANN_RADIO_SAY_TOWER_MIMIRON); - _lock = true; - } - } - // FREYA - else if (me->GetDistance2d(-221.475f, -271.087f) < 5.0f) - { - if (me->GetDistance2d(who) <= 60.0f && who->GetPositionZ() < 380.0f) - { - Talk(BRANN_RADIO_SAY_TOWER_FREYA); - _lock = true; - } - } - // STATIONS - else if (me->GetDistance2d(73.8978f, -29.3306f) < 5.0f) - { - if (me->GetDistance2d(who) <= 40.0f) - { - Talk(BRANN_RADIO_SAY_STATIONS); - _lock = true; - } - } - // HODIR - else if (me->GetDistance2d(68.7679f, -325.026f) < 5.0f) - { - if (me->GetDistance2d(who) <= 40.0f) - { - Talk(BRANN_RADIO_SAY_TOWER_HODIR); - _lock = true; - } - } - // THORIM - else if (me->GetDistance2d(174.442f, 345.679f) < 5.0f) - { - if (me->GetDistance2d(who) <= 60.0f) - { - Talk(BRANN_RADIO_SAY_TOWER_THORIM); - _lock = true; - } - } - // COME A BIT CLOSER - else if (me->GetDistance2d(-508.898f, -32.9631f) < 5.0f) - { - if (who->GetPositionX() >= -480.0f) - { - Talk(BRANN_RADIO_SAY_GENERATORS); - _lock = true; - } - } - } - } - }; -}; - -class npc_storm_beacon_spawn : public CreatureScript -{ -public: - npc_storm_beacon_spawn() : CreatureScript("npc_storm_beacon_spawn") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_storm_beacon_spawnAI : public NullCreatureAI - { - npc_storm_beacon_spawnAI(Creature* c) : NullCreatureAI(c) - { - _amount = 0; - _checkTimer = 0; - } - - uint8 _amount; - uint32 _checkTimer; - - void UpdateAI(uint32 diff) override - { - if (_amount < 40) - { - _checkTimer += diff; - if (_checkTimer >= 4000) - { - _checkTimer = 0; - if (Unit* target = me->SelectNearbyTarget(nullptr, 80.0f)) - { - ++_amount; - if (Creature* cr = me->SummonCreature(NPC_DEFENDER_GENERATED, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 4, me->GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 900000)) - cr->AI()->AttackStart(target); - } - } - } - } - }; -}; - -class boss_flame_leviathan_safety_container : public CreatureScript -{ -public: - boss_flame_leviathan_safety_container() : CreatureScript("boss_flame_leviathan_safety_container") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_flame_leviathan_safety_containerAI : public NullCreatureAI - { - boss_flame_leviathan_safety_containerAI(Creature* c) : NullCreatureAI(c) - { - _allowTimer = 0; - } - - uint32 _allowTimer; - - void MovementInform(uint32 /*type*/, uint32 id) override - { - if (id == me->GetEntry()) - { - if (Creature* liquid = me->SummonCreature(NPC_LIQUID, *me)) - { - liquid->CastSpell(liquid, SPELL_LIQUID_PYRITE, true); - liquid->CastSpell(liquid, SPELL_DUST_CLOUD_IMPACT, true); - } - - me->DespawnOrUnsummon(1); - } - } - - void UpdateAI(uint32 diff) override - { - _allowTimer += diff; - if (_allowTimer >= 5000 && !me->GetVehicle() && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) - { - float x, y, z; - me->GetPosition(x, y, z); - z = me->GetMapHeight(x, y, z); - me->GetMotionMaster()->MovePoint(me->GetEntry(), x, y, z); - me->SetPosition(x, y, z, 0); - } - } - }; -}; - -class npc_mechanolift : public CreatureScript -{ -public: - npc_mechanolift() : CreatureScript("npc_mechanolift") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_mechanoliftAI : public NullCreatureAI - { - npc_mechanoliftAI(Creature* c) : NullCreatureAI(c) - { - me->SetSpeed(MOVE_RUN, rand_norm() + 0.5f); - } - - int32 _startTimer; - uint32 _evadeTimer; - - void Reset() override - { - _startTimer = urand(1, 5000); - _evadeTimer = 0; - } - - void UpdateAI(uint32 diff) override - { - if (_startTimer) - { - _startTimer -= diff; - if (_startTimer <= 0) - { - me->GetMotionMaster()->MovePath(3000000 + urand(0, 11), true); - _startTimer = 0; - } - } - - _evadeTimer += diff; - if (_evadeTimer >= 10000) - { - _EnterEvadeMode(); - _evadeTimer = 0; - } - } - }; -}; - -class go_ulduar_tower : public GameObjectScript -{ -public: - go_ulduar_tower() : GameObjectScript("go_ulduar_tower") { } - - void OnDestroyed(GameObject* go, Player* /*player*/) override - { - Creature* trigger = go->FindNearestCreature(NPC_ULDUAR_GAUNTLET_GENERATOR, 15.0f, true); - if (trigger) - trigger->DisappearAndDie(); - } -}; - -class spell_load_into_catapult : public SpellScriptLoader -{ - enum Spells - { - SPELL_PASSENGER_LOADED = 62340, - }; - -public: - spell_load_into_catapult() : SpellScriptLoader("spell_load_into_catapult") { } - - class spell_load_into_catapult_AuraScript : public AuraScript - { - PrepareAuraScript(spell_load_into_catapult_AuraScript); - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* owner = GetOwner()->ToUnit(); - if (!owner) - return; - - owner->CastSpell(owner, SPELL_PASSENGER_LOADED, true); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* owner = GetOwner()->ToUnit(); - if (!owner) - return; - - owner->RemoveAurasDueToSpell(SPELL_PASSENGER_LOADED); - } - - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_load_into_catapult_AuraScript::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); - OnEffectRemove += AuraEffectRemoveFn(spell_load_into_catapult_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_load_into_catapult_AuraScript(); - } -}; - -class spell_auto_repair : public SpellScriptLoader -{ - enum Spells - { - SPELL_AUTO_REPAIR = 62705, - }; - -public: - spell_auto_repair() : SpellScriptLoader("spell_auto_repair") {} - - class spell_auto_repair_SpellScript : public SpellScript - { - PrepareSpellScript(spell_auto_repair_SpellScript); - - void FilterTargets(std::list& targets) - { - std::list tmplist; - for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) - if (!(*itr)->ToUnit()->HasAura(SPELL_AUTO_REPAIR)) - tmplist.push_back(*itr); - - targets.clear(); - for (std::list::iterator itr = tmplist.begin(); itr != tmplist.end(); ++itr) - targets.push_back(*itr); - } - - void HandleScript(SpellEffIndex /*eff*/) - { - Vehicle* vehicle = GetHitUnit()->GetVehicleKit(); - if (!vehicle) - return; - - Unit* driver = vehicle->GetPassenger(0); - if (!driver) - return; - - //driver->TextEmote(VEHICLE_EMOTE_REPAIR, driver, true); // No source - - // Actually should/could use basepoints (100) for this spell effect as percentage of health, but oh well. - vehicle->GetBase()->SetFullHealth(); - - // Achievement - if (InstanceScript* instance = vehicle->GetBase()->GetInstanceScript()) - instance->SetData(DATA_UNBROKEN_ACHIEVEMENT, 0); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_auto_repair_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENTRY); - OnEffectHitTarget += SpellEffectFn(spell_auto_repair_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_auto_repair_SpellScript(); - } -}; - -class spell_systems_shutdown : public SpellScriptLoader -{ -public: - spell_systems_shutdown() : SpellScriptLoader("spell_systems_shutdown") { } - - class spell_systems_shutdown_AuraScript : public AuraScript - { - PrepareAuraScript(spell_systems_shutdown_AuraScript); - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Creature* owner = GetOwner()->ToCreature(); - if (!owner) - return; - - owner->SetControlled(true, UNIT_STATE_STUNNED); - owner->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED); - if (Vehicle* veh = owner->GetVehicleKit()) - if (Unit* cannon = veh->GetPassenger(SEAT_CANNON)) - cannon->GetAI()->DoAction(ACTION_DELAY_CANNON); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Creature* owner = GetOwner()->ToCreature(); - if (!owner) - return; - - owner->SetControlled(false, UNIT_STATE_STUNNED); - } - - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_systems_shutdown_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); - OnEffectRemove += AuraEffectRemoveFn(spell_systems_shutdown_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_systems_shutdown_AuraScript(); - } -}; - -class FlameLeviathanPursuedTargetSelector -{ - enum Area - { - AREA_FORMATION_GROUNDS = 4652, - }; - -public: - explicit FlameLeviathanPursuedTargetSelector() {}; - - bool operator()(WorldObject* target) const - { - //! No players, only vehicles (todo: check if blizzlike) - Creature* creatureTarget = target->ToCreature(); - if (!creatureTarget) - return true; - - //! NPC entries must match - if (creatureTarget->GetEntry() != NPC_SALVAGED_DEMOLISHER && creatureTarget->GetEntry() != NPC_SALVAGED_SIEGE_ENGINE) - return true; - - //! NPC must be a valid vehicle installation - Vehicle* vehicle = creatureTarget->GetVehicleKit(); - if (!vehicle) - return true; - - //! Entity needs to be in appropriate area - if (target->GetAreaId() != AREA_FORMATION_GROUNDS) - return true; - - //! Vehicle must be in use by player - bool playerFound = false; - for (SeatMap::const_iterator itr = vehicle->Seats.begin(); itr != vehicle->Seats.end() && !playerFound; ++itr) - if (itr->second.Passenger.Guid.IsPlayer()) - playerFound = true; - - return !playerFound; - } -}; - -class spell_pursue : public SpellScriptLoader -{ -public: - spell_pursue() : SpellScriptLoader("spell_pursue") {} - - class spell_pursue_SpellScript : public SpellScript - { - PrepareSpellScript(spell_pursue_SpellScript); - - void FilterTargets(std::list& targets) - { - targets.remove_if(FlameLeviathanPursuedTargetSelector()); - if (targets.empty()) - { - if (Creature* caster = GetCaster()->ToCreature()) - caster->AI()->EnterEvadeMode(); - } - else - { - //! In the end, only one target should be selected - WorldObject* _target = Acore::Containers::SelectRandomContainerElement(targets); - targets.clear(); - if (_target) - targets.push_back(_target); - } - } - - void HandleScript(SpellEffIndex /*eff*/) - { - Creature* target = GetHitCreature(); - Unit* caster = GetCaster(); - if (!target || !caster) - return; - - caster->GetThreatMgr().ResetAllThreat(); - caster->GetAI()->AttackStart(target); // Chase target - caster->AddThreat(target, 10000000.0f); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_pursue_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); - OnEffectHitTarget += SpellEffectFn(spell_pursue_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_pursue_SpellScript(); - } -}; - -class spell_vehicle_throw_passenger : public SpellScriptLoader -{ -public: - spell_vehicle_throw_passenger() : SpellScriptLoader("spell_vehicle_throw_passenger") {} - - class spell_vehicle_throw_passenger_SpellScript : public SpellScript - { - PrepareSpellScript(spell_vehicle_throw_passenger_SpellScript); - void HandleScript() - { - Spell* baseSpell = GetSpell(); - SpellCastTargets targets = baseSpell->m_targets; - if (Vehicle* vehicle = GetCaster()->GetVehicleKit()) - if (Unit* passenger = vehicle->GetPassenger(3)) - { - // use 99 because it is 3d search - std::list targetList; - Acore::WorldObjectSpellAreaTargetCheck check(99, GetExplTargetDest(), GetCaster(), GetCaster(), GetSpellInfo(), TARGET_CHECK_DEFAULT, nullptr); - Acore::WorldObjectListSearcher searcher(GetCaster(), targetList, check); - Cell::VisitAllObjects(GetCaster(), searcher, 99.0f); - float minDist = 99 * 99; - Unit* target = nullptr; - for (std::list::iterator itr = targetList.begin(); itr != targetList.end(); ++itr) - { - if (Unit* unit = (*itr)->ToUnit()) - if (unit->GetEntry() == NPC_SEAT) - if (Vehicle* seat = unit->GetVehicleKit()) - if (!seat->GetPassenger(0)) - if (Unit* device = seat->GetPassenger(2)) - if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - { - float dist = unit->GetExactDistSq(targets.GetDstPos()); - if (dist < minDist) - { - minDist = dist; - target = unit; - } - } - } - if (target && target->IsWithinDist2d(targets.GetDstPos(), GetSpellInfo()->Effects[EFFECT_0].CalcRadius() * 2)) // now we use *2 because the location of the seat is not correct - { - passenger->ExitVehicle(); - passenger->EnterVehicle(target, 0); - } - else - { - passenger->ExitVehicle(); - float x, y, z; - targets.GetDstPos()->GetPosition(x, y, z); - passenger->GetMotionMaster()->MoveJump(x, y, z, targets.GetSpeedXY(), targets.GetSpeedZ()); - } - } - } - - void Register() override - { - AfterCast += SpellCastFn(spell_vehicle_throw_passenger_SpellScript::HandleScript); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_vehicle_throw_passenger_SpellScript(); - } -}; - -class spell_tar_blaze : public SpellScriptLoader -{ -public: - spell_tar_blaze() : SpellScriptLoader("spell_tar_blaze") { } - - class spell_tar_blaze_AuraScript : public AuraScript - { - PrepareAuraScript(spell_tar_blaze_AuraScript); - - void OnPeriodic(AuraEffect const* aurEff) - { - GetUnitOwner()->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_tar_blaze_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_tar_blaze_AuraScript(); - } -}; - -class spell_vehicle_grab_pyrite : public SpellScriptLoader -{ -public: - spell_vehicle_grab_pyrite() : SpellScriptLoader("spell_vehicle_grab_pyrite") {} - - class spell_vehicle_grab_pyrite_SpellScript : public SpellScript - { - PrepareSpellScript(spell_vehicle_grab_pyrite_SpellScript); - void HandleScript(SpellEffIndex /*effIndex*/) - { - if (Unit* target = GetHitUnit()) - if (Unit* seat = GetCaster()->GetVehicleBase()) - { - if (Vehicle* vSeat = seat->GetVehicleKit()) - if (Unit* pyrite = vSeat->GetPassenger(1)) - pyrite->ExitVehicle(); - - if (Unit* parent = seat->GetVehicleBase()) - { - GetCaster()->CastSpell(parent, 62496 /*SPELL_ADD_PYRITE*/, true); - target->CastSpell(seat, GetEffectValue()); - - if (target->GetTypeId() == TYPEID_UNIT) - target->ToCreature()->DespawnOrUnsummon(1300); - } - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_vehicle_grab_pyrite_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_vehicle_grab_pyrite_SpellScript(); - } -}; - -class spell_vehicle_circuit_overload : public SpellScriptLoader -{ -public: - spell_vehicle_circuit_overload() : SpellScriptLoader("spell_vehicle_circuit_overload") { } - - class spell_vehicle_circuit_overload_AuraScript : public AuraScript - { - PrepareAuraScript(spell_vehicle_circuit_overload_AuraScript); - - void OnPeriodic(AuraEffect const* /*aurEff*/) - { - if (Unit* target = GetTarget()) - if (int(target->GetAppliedAuras().count(SPELL_OVERLOAD_CIRCUIT)) >= (target->GetMap()->Is25ManRaid() ? 4 : 2)) - { - target->CastSpell(target, SPELL_SYSTEMS_SHUTDOWN, true); - target->RemoveAurasDueToSpell(SPELL_OVERLOAD_CIRCUIT); - } - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_vehicle_circuit_overload_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_vehicle_circuit_overload_AuraScript(); - } -}; - -class spell_orbital_supports : public SpellScriptLoader -{ -public: - spell_orbital_supports() : SpellScriptLoader("spell_orbital_supports") { } - - class spell_orbital_supports_AuraScript : public AuraScript - { - PrepareAuraScript(spell_orbital_supports_AuraScript); - - bool CheckAreaTarget(Unit* target) - { - return target->GetEntry() == NPC_LEVIATHAN; - } - void Register() override - { - DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_orbital_supports_AuraScript::CheckAreaTarget); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_orbital_supports_AuraScript(); - } -}; - -class spell_thorims_hammer : public SpellScriptLoader -{ -public: - spell_thorims_hammer() : SpellScriptLoader("spell_thorims_hammer") { } - - class spell_thorims_hammer_SpellScript : public SpellScript - { - PrepareSpellScript(spell_thorims_hammer_SpellScript); - - void RecalculateDamage(SpellEffIndex effIndex) - { - if (!GetHitUnit() || effIndex == EFFECT_1) - { - PreventHitDefaultEffect(effIndex); - return; - } - - float dist = GetHitUnit()->GetExactDist2d(GetCaster()); - if (dist <= 7.0f) - { - SetHitDamage(GetSpellInfo()->Effects[EFFECT_1].CalcValue()); - } - else - { - dist -= 6.0f; - SetHitDamage(int32(GetSpellInfo()->Effects[EFFECT_1].CalcValue() / std::max(dist, 1.0f))); - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_thorims_hammer_SpellScript::RecalculateDamage, EFFECT_ALL, SPELL_EFFECT_SCHOOL_DAMAGE); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_thorims_hammer_SpellScript(); - } -}; - -class spell_transitus_shield_beam : public SpellScriptLoader -{ -public: - spell_transitus_shield_beam() : SpellScriptLoader("spell_transitus_shield_beam") { } - - class spell_transitus_shield_beam_AuraScript : public AuraScript - { - PrepareAuraScript(spell_transitus_shield_beam_AuraScript); - - void HandleOnEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - Unit* caster = GetCaster(); - if (!caster) - { - return; - } - - Unit* target = GetTarget(); - - if (!target) - { - return; - } - - switch (aurEff->GetEffIndex()) - { - case EFFECT_0: - caster->AddAura(SPELL_TRANSITUS_SHIELD_IMPACT, target); - break; - } - } - - void HandleOnEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* caster = GetCaster(); - - if (!caster) - { - return; - } - - Unit* target = GetTarget(); - - if (target) - { - target->RemoveAurasDueToSpell(SPELL_TRANSITUS_SHIELD_IMPACT); - } - } - - void Register() - { - OnEffectApply += AuraEffectApplyFn(spell_transitus_shield_beam_AuraScript::HandleOnEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); - OnEffectRemove += AuraEffectRemoveFn(spell_transitus_shield_beam_AuraScript::HandleOnEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_transitus_shield_beam_AuraScript(); - } -}; - -class spell_shield_generator : public SpellScriptLoader -{ -public: - spell_shield_generator() : SpellScriptLoader("spell_shield_generator") { } - - class spell_shield_generator_AuraScript : public AuraScript - { - PrepareAuraScript(spell_shield_generator_AuraScript); - - uint32 absorbPct; - - bool Load() override - { - absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster()); - return true; - } - - void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) - { - // Set absorbtion amount to unlimited - amount = -1; - } - - void Absorb(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& absorbAmount) - { - absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct); - } - - void Register() override - { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_shield_generator_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); - OnEffectAbsorb += AuraEffectAbsorbFn(spell_shield_generator_AuraScript::Absorb, EFFECT_0); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_shield_generator_AuraScript(); - } -}; - -class spell_demolisher_ride_vehicle : public SpellScriptLoader -{ -public: - spell_demolisher_ride_vehicle() : SpellScriptLoader("spell_demolisher_ride_vehicle") {} - - class spell_demolisher_ride_vehicle_SpellScript : public SpellScript - { - PrepareSpellScript(spell_demolisher_ride_vehicle_SpellScript); - - SpellCastResult CheckCast() - { - if (GetCaster()->GetTypeId() != TYPEID_PLAYER) - return SPELL_CAST_OK; - - Unit* target = this->GetExplTargetUnit(); - if (!target || target->GetEntry() != NPC_SALVAGED_DEMOLISHER) - return SPELL_FAILED_DONT_REPORT; - - Vehicle* veh = target->GetVehicleKit(); - if (veh && veh->GetPassenger(0)) - if (Unit* target2 = veh->GetPassenger(1)) - if (Vehicle* veh2 = target2->GetVehicleKit()) - { - if (!veh2->GetPassenger(0)) - target2->HandleSpellClick(GetCaster()); - - return SPELL_FAILED_DONT_REPORT; - } - - return SPELL_CAST_OK; - } - - void Register() override - { - OnCheckCast += SpellCheckCastFn(spell_demolisher_ride_vehicle_SpellScript::CheckCast); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_demolisher_ride_vehicle_SpellScript(); - } -}; - -class achievement_flame_leviathan_towers : public AchievementCriteriaScript -{ -public: - achievement_flame_leviathan_towers(char const* name, uint32 count) : AchievementCriteriaScript(name), - _towerCount(count) - { - } - - bool OnCheck(Player* /*player*/, Unit* target /*Flame Leviathan*/, uint32 /*criteria_id*/) override - { - return target && _towerCount <= target->GetAI()->GetData(DATA_GET_TOWER_COUNT); - } - -private: - uint32 const _towerCount; -}; - -class achievement_flame_leviathan_shutout : public AchievementCriteriaScript -{ -public: - achievement_flame_leviathan_shutout() : AchievementCriteriaScript("achievement_flame_leviathan_shutout") {} - - bool OnCheck(Player* /*player*/, Unit* target /*Flame Leviathan*/, uint32 /*criteria_id*/) override - { - if (target) - if (target->GetAI()->GetData(DATA_GET_SHUTDOWN)) - return true; - return false; - } -}; - -class achievement_flame_leviathan_garage : public AchievementCriteriaScript -{ -public: - achievement_flame_leviathan_garage(char const* name, uint32 entry1, uint32 entry2) : AchievementCriteriaScript(name), - _entry1(entry1), _entry2(entry2) - { - } - - bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override - { - if (Vehicle* vehicle = player->GetVehicle()) - if (vehicle->GetCreatureEntry() == _entry1 || vehicle->GetCreatureEntry() == _entry2) - return true; - return false; - } - -private: - uint32 const _entry1; - uint32 const _entry2; -}; - -class achievement_flame_leviathan_unbroken : public AchievementCriteriaScript -{ -public: - achievement_flame_leviathan_unbroken() : AchievementCriteriaScript("achievement_flame_leviathan_unbroken") {} - - bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override - { - if (player->GetInstanceScript()) - if (player->GetInstanceScript()->GetData(DATA_UNBROKEN_ACHIEVEMENT)) - return true; - return false; - } -}; - void AddSC_boss_flame_leviathan() { new boss_flame_leviathan(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.h new file mode 100644 index 00000000000000..ce05709d31fa83 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.h @@ -0,0 +1,1902 @@ +#ifndef BOSS_FLAME_LEVIATHAN_H_ +#define BOSS_FLAME_LEVIATHAN_H_ + +#include "AchievementCriteriaScript.h" +#include "CombatAI.h" +#include "CreatureScript.h" +#include "GameObjectScript.h" +#include "GridNotifiers.h" +#include "Opcodes.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "ScriptedEscortAI.h" +#include "Spell.h" +#include "SpellAuraEffects.h" +#include "SpellAuras.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "Vehicle.h" +#include "ulduar.h" + +enum LeviathanSpells +{ + // Leviathan basic + SPELL_PURSUED = 62374, + SPELL_GATHERING_SPEED = 62375, + SPELL_BATTERING_RAM = 62376, + SPELL_FLAME_VENTS = 62396, + SPELL_MISSILE_BARRAGE = 62400, + SPELL_NAPALM_10 = 63666, + SPELL_NAPALM_25 = 65026, + SPELL_INVIS_AND_STEALTH_DETECT = 18950, + SPELL_TRANSITUS_SHIELD_IMPACT = 48387, + + // Shutdown spells + SPELL_SYSTEMS_SHUTDOWN = 62475, + SPELL_OVERLOAD_CIRCUIT = 62399, + + // hard mode + SPELL_TOWER_OF_STORMS = 65076, + SPELL_TOWER_OF_FLAMES = 65075, + SPELL_TOWER_OF_FROST = 65077, + SPELL_TOWER_OF_LIFE = 64482, + + SPELL_HODIRS_FURY = 62533, + SPELL_FREYA_WARD = 62906, // removed spawn effect + SPELL_MIMIRONS_INFERNO = 62909, + SPELL_THORIMS_HAMMER = 62911, + + SPELL_FREYA_DUMMY_BLUE = 63294, + SPELL_FREYA_DUMMY_GREEN = 63295, + SPELL_FREYA_DUMMY_YELLOW = 63292, + + // Leviathan turret spell + SPELL_SEARING_FLAME = 62402, + // On turret Destory + SPELL_SMOKE_TRAIL = 63575, + + // Pool of tar blaze + SPELL_BLAZE = 62292, + + // Pyrite + SPELL_LIQUID_PYRITE = 62494, + SPELL_DUSTY_EXPLOSION = 63360, + SPELL_DUST_CLOUD_IMPACT = 54740, +}; + +enum GosNpcs +{ + NPC_FLAME_LEVIATHAN_TURRET = 33139, + NPC_SEAT = 33114, + NPC_MECHANOLIFT = 33214, + NPC_LIQUID = 33189, + + // Starting event + NPC_ULDUAR_COLOSSUS = 33237, + NPC_BRANN_RADIO = 34054, + NPC_ULDUAR_GAUNTLET_GENERATOR = 33571, + NPC_DEFENDER_GENERATED = 33572, + + // Hard Mode + NPC_THORIM_HAMMER_TARGET = 33364, + NPC_THORIM_HAMMER = 33365, + NPC_FREYA_WARD_TARGET = 33366, + NPC_FREYA_WARD = 33367, + NPC_MIMIRONS_INFERNO_TARGET = 33369, + NPC_MIMIRONS_INFERNO = 33370, + NPC_HODIRS_FURY_TARGET = 33108, + NPC_HODIRS_FURY = 33212, +}; + +enum Events +{ + EVENT_PURSUE = 1, + EVENT_MISSILE = 2, + EVENT_VENT = 3, + EVENT_SPEED = 4, + EVENT_SUMMON = 5, + EVENT_REINSTALL = 6, + EVENT_HODIRS_FURY = 7, + EVENT_FREYA = 8, + EVENT_MIMIRONS_INFERNO = 9, + EVENT_THORIMS_HAMMER = 10, + EVENT_SOUND_BEGINNING = 11, + EVENT_POSITION_CHECK = 12, +}; + +enum Texts +{ + FLAME_LEVIATHAN_SAY_AGGRO = 0, + FLAME_LEVIATHAN_SAY_SLAY = 1, + FLAME_LEVIATHAN_SAY_DEATH = 2, + FLAME_LEVIATHAN_SAY_PURSUE = 3, + FLAME_LEVIATHAN_SAY_HARDMODE = 4, + FLAME_LEVIATHAN_SAY_TOWER_NONE = 5, + FLAME_LEVIATHAN_SAY_TOWER_FROST = 6, + FLAME_LEVIATHAN_SAY_TOWER_FLAME = 7, + FLAME_LEVIATHAN_SAY_TOWER_NATURE = 8, + FLAME_LEVIATHAN_SAY_TOWER_STORM = 9, + FLAME_LEVIATHAN_SAY_PLAYER_RIDING = 10, + FLAME_LEVIATHAN_SAY_OVERLOAD = 11, + FLAME_LEVIATHAN_EMOTE_PURSUE = 12, + FLAME_LEVIATHAN_EMOTE_OVERLOAD = 13, + FLAME_LEVIATHAN_EMOTE_REPAIR = 14, + FLAME_LEVIATHAN_EMOTE_FROST = 15, + FLAME_LEVIATHAN_EMOTE_FLAME = 16, + FLAME_LEVIATHAN_EMOTE_NATURE = 17, + FLAME_LEVIATHAN_EMOTE_STORM = 18, + FLAME_LEVIATHAN_EMOTE_REACTIVATE = 19, + + // NPC_BRANN_RADIO + BRANN_RADIO_SAY_FL_START_0 = 0, + BRANN_RADIO_SAY_FL_START_1 = 1, + BRANN_RADIO_SAY_FL_START_2 = 2, + BRANN_RADIO_SAY_GENERATORS = 3, + BRANN_RADIO_SAY_STATIONS = 4, + BRANN_RADIO_SAY_TOWER_THORIM = 5, + BRANN_RADIO_SAY_TOWER_HODIR = 6, + BRANN_RADIO_SAY_TOWER_FREYA = 7, + BRANN_RADIO_SAY_TOWER_MIMIRON = 8, + + // Vehicle Repair - Said by a spell, BroadcastTextID, same as FLAME_LEVIATHAN_EMOTE_REPAIR + VEHICLE_EMOTE_REPAIR = 33538, +}; + +enum Seats +{ + SEAT_PLAYER = 0, + SEAT_TURRET = 1, + SEAT_DEVICE = 2, + SEAT_CANNON = 7, +}; + +enum Misc +{ + DATA_EVENT_STARTED = 1, + DATA_GET_TOWER_COUNT = 2, + DATA_GET_SHUTDOWN = 3, + + TOWER_OF_STORMS = 2, + TOWER_OF_FLAMES = 1, + TOWER_OF_FROST = 3, + TOWER_OF_LIFE = 0, + + ACTION_START_NORGANNON_EVENT = 1, + ACTION_START_NORGANNON_BRANN = 2, + ACTION_START_BRANN_EVENT = 3, + ACTION_DESPAWN_ADDS = 4, + ACTION_DELAY_CANNON = 5, + ACTION_DESTROYED_TURRET = 6, +}; + +const Position homePos = {322.39f, -14.5f, 409.8f, 3.14f}; + +class boss_flame_leviathan : public CreatureScript +{ +public: + boss_flame_leviathan() : CreatureScript("boss_flame_leviathan") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_flame_leviathanAI : public ScriptedAI + { + boss_flame_leviathanAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me) + { + m_pInstance = pCreature->GetInstanceScript(); + assert(vehicle); + } + + InstanceScript* m_pInstance; + Vehicle* vehicle; + EventMap events; + SummonList summons; + + uint32 _startTimer; + uint32 _speakTimer; + uint8 _towersCount; + bool _shutdown; + uint32 _destroyedTurretCount; + + // Custom + void BindPlayers(); + void RadioSay(uint8 textid); + void ActivateTowers(); + void TurnGates(bool _start, bool _death); + void TurnHealStations(bool _apply); + void ScheduleEvents(); + void SummonTowerHelpers(uint8 towerId); + + // Original + void JustReachedHome() override + { + // For achievement + if (m_pInstance) + m_pInstance->SetData(DATA_UNBROKEN_ACHIEVEMENT, 0); + me->setActive(false); + } + + void MoveInLineOfSight(Unit*) override {} + void JustSummoned(Creature* cr) override + { + if (cr->GetEntry() != NPC_FLAME_LEVIATHAN_TURRET && cr->GetEntry() != NPC_SEAT) + summons.Summon(cr); + } + + void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } + void SpellHit(Unit* caster, SpellInfo const* spellInfo) override; + void JustDied(Unit*) override; + void KilledUnit(Unit* who) override; + void SpellHitTarget(Unit* target, SpellInfo const* spell) override; + + void AttackStart(Unit* who) override + { + if (Unit* veh = who->GetVehicleBase()) + ScriptedAI::AttackStart(veh); + else + ScriptedAI::AttackStart(who); + } + + void JustEngagedWith(Unit*) override + { + ScheduleEvents(); + Talk(FLAME_LEVIATHAN_SAY_AGGRO); + + me->setActive(true); + me->SetHomePosition(homePos); + TurnHealStations(false); + ActivateTowers(); + if (m_pInstance) + m_pInstance->SetData(TYPE_LEVIATHAN, SPECIAL); + + BindPlayers(); + me->SetInCombatWithZone(); + + if (!_startTimer) + { + TurnGates(true, false); + } + } + + void InitializeAI() override + { + if (m_pInstance && m_pInstance->GetData(TYPE_LEVIATHAN) == SPECIAL) + { + me->SetHomePosition(homePos); + me->UpdatePosition(homePos); + me->StopMovingOnCurrentPos(); + } + + ScriptedAI::InitializeAI(); + } + + void Reset() override + { + // Special immunity case + me->CastSpell(me, SPELL_INVIS_AND_STEALTH_DETECT, true); + me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED, true); + + summons.DoAction(ACTION_DESPAWN_ADDS); + summons.DespawnAll(); + events.Reset(); + + _shutdown = false; + _startTimer = 1; + _speakTimer = 0; + _towersCount = 0; + _destroyedTurretCount = 0; + + if (m_pInstance) + { + if (m_pInstance->GetData(TYPE_LEVIATHAN) != SPECIAL) + { + m_pInstance->SetData(TYPE_LEVIATHAN, NOT_STARTED); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + } + else + { + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + m_pInstance->SetData(DATA_VEHICLE_SPAWN, VEHICLE_POS_LEVIATHAN); + _startTimer = 0; + } + } + + TurnGates(false, false); + TurnHealStations(true); + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_GET_TOWER_COUNT) + return _towersCount; + if (param == DATA_GET_SHUTDOWN) + return !_shutdown; + + return 0; + } + + void UpdateAI(uint32 diff) override + { + // THIS IS USED ONLY FOR FIRST ENGAGE! + if (_startTimer) + { + _startTimer += diff; + if (_startTimer >= 4000) + { + // Colossus dead, players in range + if (me->FindNearestCreature(NPC_ULDUAR_COLOSSUS, 250.0f, true) || !SelectTargetFromPlayerList(250.0f)) + _startTimer = 1; + else + { + _startTimer = 0; + _speakTimer = 1; + } + } + return; + } + + if (_speakTimer) + { + _speakTimer += diff; + if (_speakTimer <= 10000) + { + _speakTimer = 10000; + RadioSay(BRANN_RADIO_SAY_FL_START_0); + } + else if (_speakTimer > 16000 && _speakTimer < 20000) + { + _speakTimer = 20000; + RadioSay(BRANN_RADIO_SAY_FL_START_1); + } + else if (_speakTimer > 24000 && _speakTimer < 40000) + { + _speakTimer = 40000; + RadioSay(BRANN_RADIO_SAY_FL_START_2); + } + else if (_speakTimer > 41000 && _speakTimer < 60000) + { + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + TurnGates(true, false); + me->MonsterMoveWithSpeed(homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), 100.0f); + me->UpdatePosition(homePos); + _speakTimer = 60000; + } + else if (_speakTimer > 63500) + { + me->SetInCombatWithZone(); + if (!me->GetVictim()) + { + me->CastSpell(me, SPELL_PURSUED, false); + events.RescheduleEvent(EVENT_PURSUE, 31s); + } + _speakTimer = 0; + } + return; + } + + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_POSITION_CHECK: + if (me->GetPositionX() > 450 || me->GetPositionX() < 120) + { + EnterEvadeMode(); + return; + } + events.Repeat(5s); + break; + case EVENT_PURSUE: + Talk(FLAME_LEVIATHAN_SAY_PURSUE); + me->CastSpell(me, SPELL_PURSUED, false); + events.RescheduleEvent(EVENT_PURSUE, 31s); + return; + case EVENT_SPEED: + me->CastSpell(me, SPELL_GATHERING_SPEED, false); + events.Repeat(15s); + return; + case EVENT_MISSILE: + me->CastSpell(me, SPELL_MISSILE_BARRAGE, true); + events.Repeat(4s); + return; + case EVENT_VENT: + me->CastSpell(me, SPELL_FLAME_VENTS, false); + events.Repeat(20s); + return; + case EVENT_SUMMON: + if(summons.size() < 20) + if (Creature* lift = DoSummonFlyer(NPC_MECHANOLIFT, me, 30.0f, 50.0f, 0)) + lift->GetMotionMaster()->MoveRandom(100); + + events.Repeat(4s); + return; + case EVENT_SOUND_BEGINNING: + if (_towersCount) + Talk(FLAME_LEVIATHAN_SAY_HARDMODE); + else + Talk(FLAME_LEVIATHAN_SAY_TOWER_NONE); + return; + case EVENT_REINSTALL: + for (uint8 i = RAID_MODE(0, 2); i < 4; ++i) + if (Unit* seat = vehicle->GetPassenger(i)) + if (seat->GetTypeId() == TYPEID_UNIT) + seat->ToCreature()->AI()->EnterEvadeMode(); + Talk(FLAME_LEVIATHAN_EMOTE_REACTIVATE); + return; + case EVENT_THORIMS_HAMMER: + SummonTowerHelpers(TOWER_OF_STORMS); + events.Repeat(1min, 2min); + Talk(FLAME_LEVIATHAN_EMOTE_STORM); + Talk(FLAME_LEVIATHAN_SAY_TOWER_STORM); + return; + case EVENT_FREYA: + SummonTowerHelpers(TOWER_OF_LIFE); + Talk(FLAME_LEVIATHAN_EMOTE_NATURE); + Talk(FLAME_LEVIATHAN_SAY_TOWER_NATURE); + return; + case EVENT_MIMIRONS_INFERNO: + SummonTowerHelpers(TOWER_OF_FLAMES); + Talk(FLAME_LEVIATHAN_EMOTE_FLAME); + Talk(FLAME_LEVIATHAN_SAY_TOWER_FLAME); + return; + case EVENT_HODIRS_FURY: + SummonTowerHelpers(TOWER_OF_FROST); + Talk(FLAME_LEVIATHAN_EMOTE_FROST); + Talk(FLAME_LEVIATHAN_SAY_TOWER_FROST); + return; + } + + if(me->isAttackReady() && !me->HasUnitState(UNIT_STATE_STUNNED)) + { + if(me->IsWithinCombatRange(me->GetVictim(), 15.0f)) + { + me->CastSpell(me->GetVictim(), SPELL_BATTERING_RAM, false); + me->resetAttackTimer(); + } + } + } + + void DoAction(int32 action) override + { + if (action == ACTION_DESTROYED_TURRET) + { + ++_destroyedTurretCount; + + if (_destroyedTurretCount == RAID_MODE(2, 4)) + { + _destroyedTurretCount = 0; + me->CastSpell(me, SPELL_SYSTEMS_SHUTDOWN, true); + } + } + } + }; +}; + +class boss_flame_leviathan_seat : public CreatureScript +{ +public: + boss_flame_leviathan_seat() : CreatureScript("boss_flame_leviathan_seat") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_flame_leviathan_seatAI : public VehicleAI + { + boss_flame_leviathan_seatAI(Creature* creature) : VehicleAI(creature), vehicle(creature->GetVehicleKit()) + { + ASSERT(vehicle); + me->SetReactState(REACT_PASSIVE); + } + + Vehicle* vehicle; + uint32 _despawnTimer; + + void EnterEvadeMode(EvadeReason /*why*/) override + { + vehicle->InstallAllAccessories(false); + } + + void Reset() override + { + _despawnTimer = !me->GetMap()->Is25ManRaid(); + } + + void UpdateAI(uint32 diff) override + { + if (_despawnTimer) + { + _despawnTimer += diff; + if (_despawnTimer >= 2000) + { + _despawnTimer = 0; + if (Vehicle* veh = me->GetVehicle()) + if (veh->GetPassenger(0) == me || veh->GetPassenger(1) == me) + me->DespawnOrUnsummon(1); + } + } + + VehicleAI::UpdateAI(diff); + } + + void AttackStart(Unit*) override { } + + void PassengerBoarded(Unit* who, int8 seatId, bool apply) override + { + if (who->GetTypeId() != TYPEID_PLAYER || !me->GetVehicle()) + return; + + who->ApplySpellImmune(63847, IMMUNITY_ID, 63847, apply); // SPELL_FLAME_VENTS_TRIGGER + who->ApplySpellImmune(SPELL_MISSILE_BARRAGE, IMMUNITY_ID, SPELL_MISSILE_BARRAGE, apply); + who->ApplySpellImmune(SPELL_BATTERING_RAM, IMMUNITY_ID, SPELL_BATTERING_RAM, apply); + + if (seatId == SEAT_PLAYER) + { + if (Unit* turret = me->GetVehicleKit()->GetPassenger(SEAT_TURRET)) + { + if (apply) + { + turret->ReplaceAllUnitFlags(UNIT_FLAG_NONE); + turret->GetAI()->AttackStart(who); + if (Creature* leviathan = me->GetVehicleCreatureBase()) + leviathan->AI()->Talk(FLAME_LEVIATHAN_SAY_PLAYER_RIDING); + } + else + { + turret->ReplaceAllUnitFlags(UNIT_FLAG_NOT_SELECTABLE); + turret->SetImmuneToAll(true); + if (turret->GetTypeId() == TYPEID_UNIT) + turret->ToCreature()->AI()->EnterEvadeMode(); + } + } + } + } + }; +}; + +class boss_flame_leviathan_defense_turret : public CreatureScript +{ +public: + boss_flame_leviathan_defense_turret() : CreatureScript("boss_flame_leviathan_defense_turret") { } + + struct boss_flame_leviathan_defense_turretAI : public TurretAI + { + boss_flame_leviathan_defense_turretAI(Creature* creature) : TurretAI(creature) + { + _setHealth = false; + _instance = creature->GetInstanceScript(); + } + + InstanceScript* _instance; + + bool _setHealth; + void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (!CanAIAttack(who)) + { + _setHealth = true; + damage = 0; + } + } + + void JustDied(Unit* killer) override + { + if (Player* player = killer->ToPlayer()) + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, me); + + if (Vehicle* vehicle = me->GetVehicle()) + if (Unit* device = vehicle->GetPassenger(SEAT_DEVICE)) + device->ReplaceAllUnitFlags(UNIT_FLAG_NONE); // unselectable + + if (Creature* leviathan = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(TYPE_LEVIATHAN))) + leviathan->AI()->DoAction(ACTION_DESTROYED_TURRET); + } + + bool CanAIAttack(Unit const* who) const override + { + if (!who || who->GetTypeId() != TYPEID_PLAYER || !who->GetVehicle() || who->GetVehicleBase()->GetEntry() != NPC_SEAT) + return false; + return true; + } + + void UpdateAI(uint32 diff) override + { + if (_setHealth) + { + me->SetHealth(std::min(me->GetHealth() + 1, me->GetMaxHealth())); + _setHealth = false; + } + + TurretAI::UpdateAI(diff); + } + + void KilledUnit(Unit* who) override + { + if (Player* plr = who->ToPlayer()) // make sure that there's no death player on the seat. + if (plr->GetVehicle()) + plr->ExitVehicle(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI(creature); + } +}; + +class boss_flame_leviathan_overload_device : public CreatureScript +{ +public: + boss_flame_leviathan_overload_device() : CreatureScript("boss_flame_leviathan_overload_device") { } + + struct boss_flame_leviathan_overload_deviceAI : public NullCreatureAI + { + boss_flame_leviathan_overload_deviceAI(Creature* creature) : NullCreatureAI(creature) + { + } + + void OnSpellClick(Unit* /*clicker*/, bool& result) override + { + if (!result) + return; + + if (me->GetVehicle()) + { + me->RemoveNpcFlag(UNIT_NPC_FLAG_SPELLCLICK); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + + if (Unit* player = me->GetVehicle()->GetPassenger(SEAT_PLAYER)) + { + me->GetVehicleBase()->CastSpell(player, SPELL_SMOKE_TRAIL, true); + player->ExitVehicle(); + } + } + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI(creature); + } +}; + +class npc_freya_ward : public CreatureScript +{ +public: + npc_freya_ward() : CreatureScript("npc_freya_ward") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_freya_wardAI : public NullCreatureAI + { + npc_freya_wardAI(Creature* c) : NullCreatureAI(c), summons(c) + { + } + + SummonList summons; + uint32 _castTimer; + bool _summoned; + + void Reset() override + { + _summoned = false; + _castTimer = 25000; + summons.DespawnAll(); + if (Creature* cr = me->FindNearestCreature(NPC_FREYA_WARD_TARGET, 60.0f, true)) + if (Aura* aur = cr->AddAura(SPELL_FREYA_DUMMY_GREEN, cr)) + { + aur->SetMaxDuration(-1); + aur->SetDuration(-1); + } + } + + void JustSummoned(Creature* cr) override + { + _summoned = true; + summons.Summon(cr); + } + + void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } + + void UpdateAI(uint32 diff) override + { + if (_summoned) + { + for (SummonList::const_iterator itr = summons.begin(); itr != summons.end();) + { + Creature* summon = ObjectAccessor::GetCreature(*me, *itr); + ++itr; + if (summon) + { + summon->ToTempSummon()->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN); + if (Unit* target = summon->SelectNearestTarget(200.0f)) + summon->AI()->AttackStart(target); + } + } + _summoned = false; + } + + _castTimer += diff; + if (_castTimer >= 29 * IN_MILLISECONDS) + { + if (Creature* cr = me->FindNearestCreature(NPC_FREYA_WARD_TARGET, 60.0f, true)) + { + me->CastSpell(cr, SPELL_FREYA_WARD, false); + me->CastSpell(cr, 62947 /*SPELL_FREYA_WARD_SECOND_SUMMON*/, false); + } + + _castTimer = 0; + } + } + + void DoAction(int32 param) override + { + if (param == ACTION_DESPAWN_ADDS) + summons.DespawnAll(); + } + }; +}; + +class npc_hodirs_fury : public CreatureScript +{ +public: + npc_hodirs_fury() : CreatureScript("npc_hodirs_fury") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_hodirs_furyAI : public NullCreatureAI + { + npc_hodirs_furyAI(Creature* c) : NullCreatureAI(c) + { + } + + uint32 _timeToHit; + uint32 _switchTargetTimer; + + void Reset() override + { + _timeToHit = 0; + _switchTargetTimer = 30000; + me->SetWalk(true); + + if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_BLUE, me)) + { + aur->SetMaxDuration(-1); + aur->SetDuration(-1); + } + } + + void MovementInform(uint32 type, uint32 /*param*/) override + { + if (type == FOLLOW_MOTION_TYPE && !_timeToHit) + { + _timeToHit = 1; + _switchTargetTimer = 0; + me->SetControlled(true, UNIT_STATE_STUNNED); + } + } + + void UpdateAI(uint32 diff) override + { + if (_timeToHit) + { + _timeToHit += diff; + if (_timeToHit >= 5000) + { + if (Creature* cr = me->SummonCreature(NPC_HODIRS_FURY, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40, 0, TEMPSUMMON_TIMED_DESPAWN, 10000)) + cr->CastSpell(me, SPELL_HODIRS_FURY, true); + + _switchTargetTimer = 25000; // Switch target soon + _timeToHit = 0; + } + return; + } + + _switchTargetTimer += diff; + if (_switchTargetTimer >= 30000) + { + if(Unit* target = me->SelectNearbyTarget(nullptr, 200.0f)) + { + if (target->GetVehicleBase() && target->GetVehicleBase()->GetEntry() == NPC_SEAT) + { + _switchTargetTimer = 20000; + return; + } + me->SetControlled(false, UNIT_STATE_STUNNED); + me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f); + _switchTargetTimer = 0; + } + else + _switchTargetTimer = 25000; + } + } + }; +}; + +class npc_mimirons_inferno : public CreatureScript +{ +public: + npc_mimirons_inferno() : CreatureScript("npc_mimirons_inferno") { } + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI(creature); + } + + struct npc_mimirons_infernoAI : public npc_escortAI + { + npc_mimirons_infernoAI(Creature* creature) : npc_escortAI(creature), summons(me) + { + me->SetReactState(REACT_PASSIVE); + } + + SummonList summons; + uint32 _spellTimer; + uint32 _recastTimer; + + void AttackStart(Unit*) override { } + void MoveInLineOfSight(Unit*) override { } + void WaypointReached(uint32 /*waypointId*/) override { } + + void DoAction(int32 param) override + { + if (param == ACTION_DESPAWN_ADDS) + summons.DespawnAll(); + } + + void Reset() override + { + summons.DespawnAll(); + _spellTimer = 0; + Start(false, false, ObjectGuid::Empty, nullptr, false, true); + if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_YELLOW, me)) + { + aur->SetMaxDuration(-1); + aur->SetDuration(-1); + } + } + + void JustSummoned(Creature* cr) override { summons.Summon(cr); } + void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } + + void UpdateAI(uint32 diff) override + { + npc_escortAI::UpdateAI(diff); + + _spellTimer += diff; + if (_spellTimer >= 2000) + { + if (Creature* cr = me->SummonCreature(NPC_MIMIRONS_INFERNO, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000)) + cr->CastSpell(me, SPELL_MIMIRONS_INFERNO, true); + + _spellTimer = 0; + } + } + }; +}; + +class npc_thorims_hammer : public CreatureScript +{ +public: + npc_thorims_hammer() : CreatureScript("npc_thorims_hammer") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_thorims_hammerAI : public NullCreatureAI + { + npc_thorims_hammerAI(Creature* c) : NullCreatureAI(c) + { + } + + uint32 _beamTimer; + uint32 _finishTime; + uint32 _removeTimer; + + void Reset() override + { + _finishTime = 5000 + rand() % 15000; + _beamTimer = 1; + _removeTimer = 0; + me->CastSpell(me, SPELL_FREYA_DUMMY_BLUE, true); + } + + void UpdateAI(uint32 diff) override + { + if (_beamTimer) + { + _beamTimer += diff; + if (_beamTimer >= _finishTime) + { + if (Creature* cr = me->SummonCreature(NPC_THORIM_HAMMER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40, 0, TEMPSUMMON_TIMED_DESPAWN, 5000)) + cr->CastSpell(me, SPELL_THORIMS_HAMMER, false); + + _beamTimer = 0; + _removeTimer = 1; + me->DespawnOrUnsummon(5 * IN_MILLISECONDS); + } + } + if (_removeTimer) + { + _removeTimer += diff; + if (_removeTimer >= 3 * IN_MILLISECONDS) + { + _removeTimer = 0; + me->RemoveAura(SPELL_FREYA_DUMMY_BLUE); + } + } + } + }; +}; + +class npc_pool_of_tar : public CreatureScript +{ +public: + npc_pool_of_tar() : CreatureScript("npc_pool_of_tar") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_pool_of_tarAI : public NullCreatureAI + { + npc_pool_of_tarAI(Creature* c) : NullCreatureAI(c) + { + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + damage = 0; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->SchoolMask & SPELL_SCHOOL_MASK_FIRE && !me->HasAura(SPELL_BLAZE)) + me->CastSpell(me, SPELL_BLAZE, true); + } + }; +}; + +class npc_brann_radio : public CreatureScript +{ +public: + npc_brann_radio() : CreatureScript("npc_brann_radio") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_brann_radioAI : public NullCreatureAI + { + npc_brann_radioAI(Creature* c) : NullCreatureAI(c) + { + _lock = (me->GetInstanceScript() && me->GetInstanceScript()->GetData(TYPE_LEVIATHAN) > NOT_STARTED); + _helpLock = _lock; + } + + bool _lock; + bool _helpLock; + + void Reset() override + { + me->SetReactState(REACT_AGGRESSIVE); + } + + void MoveInLineOfSight(Unit* who) override + { + if (!_lock) + { + if (who->GetTypeId() != TYPEID_PLAYER && !who->IsVehicle()) + return; + + // MIMIRON + else if (me->GetDistance2d(-81.9207f, 111.432f) < 5.0f) + { + if (me->GetDistance2d(who) <= 60.0f && who->GetPositionZ() > 430.0f) + { + Talk(BRANN_RADIO_SAY_TOWER_MIMIRON); + _lock = true; + } + } + // FREYA + else if (me->GetDistance2d(-221.475f, -271.087f) < 5.0f) + { + if (me->GetDistance2d(who) <= 60.0f && who->GetPositionZ() < 380.0f) + { + Talk(BRANN_RADIO_SAY_TOWER_FREYA); + _lock = true; + } + } + // STATIONS + else if (me->GetDistance2d(73.8978f, -29.3306f) < 5.0f) + { + if (me->GetDistance2d(who) <= 40.0f) + { + Talk(BRANN_RADIO_SAY_STATIONS); + _lock = true; + } + } + // HODIR + else if (me->GetDistance2d(68.7679f, -325.026f) < 5.0f) + { + if (me->GetDistance2d(who) <= 40.0f) + { + Talk(BRANN_RADIO_SAY_TOWER_HODIR); + _lock = true; + } + } + // THORIM + else if (me->GetDistance2d(174.442f, 345.679f) < 5.0f) + { + if (me->GetDistance2d(who) <= 60.0f) + { + Talk(BRANN_RADIO_SAY_TOWER_THORIM); + _lock = true; + } + } + // COME A BIT CLOSER + else if (me->GetDistance2d(-508.898f, -32.9631f) < 5.0f) + { + if (who->GetPositionX() >= -480.0f) + { + Talk(BRANN_RADIO_SAY_GENERATORS); + _lock = true; + } + } + } + } + }; +}; + +class npc_storm_beacon_spawn : public CreatureScript +{ +public: + npc_storm_beacon_spawn() : CreatureScript("npc_storm_beacon_spawn") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_storm_beacon_spawnAI : public NullCreatureAI + { + npc_storm_beacon_spawnAI(Creature* c) : NullCreatureAI(c) + { + _amount = 0; + _checkTimer = 0; + } + + uint8 _amount; + uint32 _checkTimer; + + void UpdateAI(uint32 diff) override + { + if (_amount < 40) + { + _checkTimer += diff; + if (_checkTimer >= 4000) + { + _checkTimer = 0; + if (Unit* target = me->SelectNearbyTarget(nullptr, 80.0f)) + { + ++_amount; + if (Creature* cr = me->SummonCreature(NPC_DEFENDER_GENERATED, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 4, me->GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 900000)) + cr->AI()->AttackStart(target); + } + } + } + } + }; +}; + +class boss_flame_leviathan_safety_container : public CreatureScript +{ +public: + boss_flame_leviathan_safety_container() : CreatureScript("boss_flame_leviathan_safety_container") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_flame_leviathan_safety_containerAI : public NullCreatureAI + { + boss_flame_leviathan_safety_containerAI(Creature* c) : NullCreatureAI(c) + { + _allowTimer = 0; + } + + uint32 _allowTimer; + + void MovementInform(uint32 /*type*/, uint32 id) override + { + if (id == me->GetEntry()) + { + if (Creature* liquid = me->SummonCreature(NPC_LIQUID, *me)) + { + liquid->CastSpell(liquid, SPELL_LIQUID_PYRITE, true); + liquid->CastSpell(liquid, SPELL_DUST_CLOUD_IMPACT, true); + } + + me->DespawnOrUnsummon(1); + } + } + + void UpdateAI(uint32 diff) override + { + _allowTimer += diff; + if (_allowTimer >= 5000 && !me->GetVehicle() && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) + { + float x, y, z; + me->GetPosition(x, y, z); + z = me->GetMapHeight(x, y, z); + me->GetMotionMaster()->MovePoint(me->GetEntry(), x, y, z); + me->SetPosition(x, y, z, 0); + } + } + }; +}; + +class npc_mechanolift : public CreatureScript +{ +public: + npc_mechanolift() : CreatureScript("npc_mechanolift") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_mechanoliftAI : public NullCreatureAI + { + npc_mechanoliftAI(Creature* c) : NullCreatureAI(c) + { + me->SetSpeed(MOVE_RUN, rand_norm() + 0.5f); + } + + int32 _startTimer; + uint32 _evadeTimer; + + void Reset() override + { + _startTimer = urand(1, 5000); + _evadeTimer = 0; + } + + void UpdateAI(uint32 diff) override + { + if (_startTimer) + { + _startTimer -= diff; + if (_startTimer <= 0) + { + me->GetMotionMaster()->MovePath(3000000 + urand(0, 11), true); + _startTimer = 0; + } + } + + _evadeTimer += diff; + if (_evadeTimer >= 10000) + { + _EnterEvadeMode(); + _evadeTimer = 0; + } + } + }; +}; + +class go_ulduar_tower : public GameObjectScript +{ +public: + go_ulduar_tower() : GameObjectScript("go_ulduar_tower") { } + + void OnDestroyed(GameObject* go, Player* /*player*/) override + { + Creature* trigger = go->FindNearestCreature(NPC_ULDUAR_GAUNTLET_GENERATOR, 15.0f, true); + if (trigger) + trigger->DisappearAndDie(); + } +}; + +class spell_load_into_catapult : public SpellScriptLoader +{ + enum Spells + { + SPELL_PASSENGER_LOADED = 62340, + }; + +public: + spell_load_into_catapult() : SpellScriptLoader("spell_load_into_catapult") { } + + class spell_load_into_catapult_AuraScript : public AuraScript + { + PrepareAuraScript(spell_load_into_catapult_AuraScript); + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* owner = GetOwner()->ToUnit(); + if (!owner) + return; + + owner->CastSpell(owner, SPELL_PASSENGER_LOADED, true); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* owner = GetOwner()->ToUnit(); + if (!owner) + return; + + owner->RemoveAurasDueToSpell(SPELL_PASSENGER_LOADED); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_load_into_catapult_AuraScript::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_load_into_catapult_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_load_into_catapult_AuraScript(); + } +}; + +class spell_auto_repair : public SpellScriptLoader +{ + enum Spells + { + SPELL_AUTO_REPAIR = 62705, + }; + +public: + spell_auto_repair() : SpellScriptLoader("spell_auto_repair") {} + + class spell_auto_repair_SpellScript : public SpellScript + { + PrepareSpellScript(spell_auto_repair_SpellScript); + + void FilterTargets(std::list& targets) + { + std::list tmplist; + for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) + if (!(*itr)->ToUnit()->HasAura(SPELL_AUTO_REPAIR)) + tmplist.push_back(*itr); + + targets.clear(); + for (std::list::iterator itr = tmplist.begin(); itr != tmplist.end(); ++itr) + targets.push_back(*itr); + } + + void HandleScript(SpellEffIndex /*eff*/) + { + Vehicle* vehicle = GetHitUnit()->GetVehicleKit(); + if (!vehicle) + return; + + Unit* driver = vehicle->GetPassenger(0); + if (!driver) + return; + + //driver->TextEmote(VEHICLE_EMOTE_REPAIR, driver, true); // No source + + // Actually should/could use basepoints (100) for this spell effect as percentage of health, but oh well. + vehicle->GetBase()->SetFullHealth(); + + // Achievement + if (InstanceScript* instance = vehicle->GetBase()->GetInstanceScript()) + instance->SetData(DATA_UNBROKEN_ACHIEVEMENT, 0); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_auto_repair_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_auto_repair_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_auto_repair_SpellScript(); + } +}; + +class spell_systems_shutdown : public SpellScriptLoader +{ +public: + spell_systems_shutdown() : SpellScriptLoader("spell_systems_shutdown") { } + + class spell_systems_shutdown_AuraScript : public AuraScript + { + PrepareAuraScript(spell_systems_shutdown_AuraScript); + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Creature* owner = GetOwner()->ToCreature(); + if (!owner) + return; + + owner->SetControlled(true, UNIT_STATE_STUNNED); + owner->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED); + if (Vehicle* veh = owner->GetVehicleKit()) + if (Unit* cannon = veh->GetPassenger(SEAT_CANNON)) + cannon->GetAI()->DoAction(ACTION_DELAY_CANNON); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Creature* owner = GetOwner()->ToCreature(); + if (!owner) + return; + + owner->SetControlled(false, UNIT_STATE_STUNNED); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_systems_shutdown_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_systems_shutdown_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_systems_shutdown_AuraScript(); + } +}; + +class FlameLeviathanPursuedTargetSelector +{ + enum Area + { + AREA_FORMATION_GROUNDS = 4652, + }; + +public: + explicit FlameLeviathanPursuedTargetSelector() {}; + + bool operator()(WorldObject* target) const + { + //! No players, only vehicles (todo: check if blizzlike) + Creature* creatureTarget = target->ToCreature(); + if (!creatureTarget) + return true; + + //! NPC entries must match + if (creatureTarget->GetEntry() != NPC_SALVAGED_DEMOLISHER && creatureTarget->GetEntry() != NPC_SALVAGED_SIEGE_ENGINE) + return true; + + //! NPC must be a valid vehicle installation + Vehicle* vehicle = creatureTarget->GetVehicleKit(); + if (!vehicle) + return true; + + //! Entity needs to be in appropriate area + if (target->GetAreaId() != AREA_FORMATION_GROUNDS) + return true; + + //! Vehicle must be in use by player + bool playerFound = false; + for (SeatMap::const_iterator itr = vehicle->Seats.begin(); itr != vehicle->Seats.end() && !playerFound; ++itr) + if (itr->second.Passenger.Guid.IsPlayer()) + playerFound = true; + + return !playerFound; + } +}; + +class spell_pursue : public SpellScriptLoader +{ +public: + spell_pursue() : SpellScriptLoader("spell_pursue") {} + + class spell_pursue_SpellScript : public SpellScript + { + PrepareSpellScript(spell_pursue_SpellScript); + + void FilterTargets(std::list& targets) + { + targets.remove_if(FlameLeviathanPursuedTargetSelector()); + if (targets.empty()) + { + if (Creature* caster = GetCaster()->ToCreature()) + caster->AI()->EnterEvadeMode(); + } + else + { + //! In the end, only one target should be selected + WorldObject* _target = Acore::Containers::SelectRandomContainerElement(targets); + targets.clear(); + if (_target) + targets.push_back(_target); + } + } + + void HandleScript(SpellEffIndex /*eff*/) + { + Creature* target = GetHitCreature(); + Unit* caster = GetCaster(); + if (!target || !caster) + return; + + caster->GetThreatMgr().ResetAllThreat(); + caster->GetAI()->AttackStart(target); // Chase target + caster->AddThreat(target, 10000000.0f); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_pursue_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_pursue_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_pursue_SpellScript(); + } +}; + +class spell_vehicle_throw_passenger : public SpellScriptLoader +{ +public: + spell_vehicle_throw_passenger() : SpellScriptLoader("spell_vehicle_throw_passenger") {} + + class spell_vehicle_throw_passenger_SpellScript : public SpellScript + { + PrepareSpellScript(spell_vehicle_throw_passenger_SpellScript); + void HandleScript() + { + Spell* baseSpell = GetSpell(); + SpellCastTargets targets = baseSpell->m_targets; + if (Vehicle* vehicle = GetCaster()->GetVehicleKit()) + if (Unit* passenger = vehicle->GetPassenger(3)) + { + // use 99 because it is 3d search + std::list targetList; + Acore::WorldObjectSpellAreaTargetCheck check(99, GetExplTargetDest(), GetCaster(), GetCaster(), GetSpellInfo(), TARGET_CHECK_DEFAULT, nullptr); + Acore::WorldObjectListSearcher searcher(GetCaster(), targetList, check); + Cell::VisitAllObjects(GetCaster(), searcher, 99.0f); + float minDist = 99 * 99; + Unit* target = nullptr; + for (std::list::iterator itr = targetList.begin(); itr != targetList.end(); ++itr) + { + if (Unit* unit = (*itr)->ToUnit()) + if (unit->GetEntry() == NPC_SEAT) + if (Vehicle* seat = unit->GetVehicleKit()) + if (!seat->GetPassenger(0)) + if (Unit* device = seat->GetPassenger(2)) + if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + { + float dist = unit->GetExactDistSq(targets.GetDstPos()); + if (dist < minDist) + { + minDist = dist; + target = unit; + } + } + } + if (target && target->IsWithinDist2d(targets.GetDstPos(), GetSpellInfo()->Effects[EFFECT_0].CalcRadius() * 2)) // now we use *2 because the location of the seat is not correct + { + passenger->ExitVehicle(); + passenger->EnterVehicle(target, 0); + } + else + { + passenger->ExitVehicle(); + float x, y, z; + targets.GetDstPos()->GetPosition(x, y, z); + passenger->GetMotionMaster()->MoveJump(x, y, z, targets.GetSpeedXY(), targets.GetSpeedZ()); + } + } + } + + void Register() override + { + AfterCast += SpellCastFn(spell_vehicle_throw_passenger_SpellScript::HandleScript); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_vehicle_throw_passenger_SpellScript(); + } +}; + +class spell_tar_blaze : public SpellScriptLoader +{ +public: + spell_tar_blaze() : SpellScriptLoader("spell_tar_blaze") { } + + class spell_tar_blaze_AuraScript : public AuraScript + { + PrepareAuraScript(spell_tar_blaze_AuraScript); + + void OnPeriodic(AuraEffect const* aurEff) + { + GetUnitOwner()->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_tar_blaze_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_tar_blaze_AuraScript(); + } +}; + +class spell_vehicle_grab_pyrite : public SpellScriptLoader +{ +public: + spell_vehicle_grab_pyrite() : SpellScriptLoader("spell_vehicle_grab_pyrite") {} + + class spell_vehicle_grab_pyrite_SpellScript : public SpellScript + { + PrepareSpellScript(spell_vehicle_grab_pyrite_SpellScript); + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + if (Unit* seat = GetCaster()->GetVehicleBase()) + { + if (Vehicle* vSeat = seat->GetVehicleKit()) + if (Unit* pyrite = vSeat->GetPassenger(1)) + pyrite->ExitVehicle(); + + if (Unit* parent = seat->GetVehicleBase()) + { + GetCaster()->CastSpell(parent, 62496 /*SPELL_ADD_PYRITE*/, true); + target->CastSpell(seat, GetEffectValue()); + + if (target->GetTypeId() == TYPEID_UNIT) + target->ToCreature()->DespawnOrUnsummon(1300); + } + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_vehicle_grab_pyrite_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_vehicle_grab_pyrite_SpellScript(); + } +}; + +class spell_vehicle_circuit_overload : public SpellScriptLoader +{ +public: + spell_vehicle_circuit_overload() : SpellScriptLoader("spell_vehicle_circuit_overload") { } + + class spell_vehicle_circuit_overload_AuraScript : public AuraScript + { + PrepareAuraScript(spell_vehicle_circuit_overload_AuraScript); + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + if (Unit* target = GetTarget()) + if (int(target->GetAppliedAuras().count(SPELL_OVERLOAD_CIRCUIT)) >= (target->GetMap()->Is25ManRaid() ? 4 : 2)) + { + target->CastSpell(target, SPELL_SYSTEMS_SHUTDOWN, true); + target->RemoveAurasDueToSpell(SPELL_OVERLOAD_CIRCUIT); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_vehicle_circuit_overload_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_vehicle_circuit_overload_AuraScript(); + } +}; + +class spell_orbital_supports : public SpellScriptLoader +{ +public: + spell_orbital_supports() : SpellScriptLoader("spell_orbital_supports") { } + + class spell_orbital_supports_AuraScript : public AuraScript + { + PrepareAuraScript(spell_orbital_supports_AuraScript); + + bool CheckAreaTarget(Unit* target) + { + return target->GetEntry() == NPC_LEVIATHAN; + } + void Register() override + { + DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_orbital_supports_AuraScript::CheckAreaTarget); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_orbital_supports_AuraScript(); + } +}; + +class spell_thorims_hammer : public SpellScriptLoader +{ +public: + spell_thorims_hammer() : SpellScriptLoader("spell_thorims_hammer") { } + + class spell_thorims_hammer_SpellScript : public SpellScript + { + PrepareSpellScript(spell_thorims_hammer_SpellScript); + + void RecalculateDamage(SpellEffIndex effIndex) + { + if (!GetHitUnit() || effIndex == EFFECT_1) + { + PreventHitDefaultEffect(effIndex); + return; + } + + float dist = GetHitUnit()->GetExactDist2d(GetCaster()); + if (dist <= 7.0f) + { + SetHitDamage(GetSpellInfo()->Effects[EFFECT_1].CalcValue()); + } + else + { + dist -= 6.0f; + SetHitDamage(int32(GetSpellInfo()->Effects[EFFECT_1].CalcValue() / std::max(dist, 1.0f))); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_thorims_hammer_SpellScript::RecalculateDamage, EFFECT_ALL, SPELL_EFFECT_SCHOOL_DAMAGE); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_thorims_hammer_SpellScript(); + } +}; + +class spell_transitus_shield_beam : public SpellScriptLoader +{ +public: + spell_transitus_shield_beam() : SpellScriptLoader("spell_transitus_shield_beam") { } + + class spell_transitus_shield_beam_AuraScript : public AuraScript + { + PrepareAuraScript(spell_transitus_shield_beam_AuraScript); + + void HandleOnEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + if (!caster) + { + return; + } + + Unit* target = GetTarget(); + + if (!target) + { + return; + } + + switch (aurEff->GetEffIndex()) + { + case EFFECT_0: + caster->AddAura(SPELL_TRANSITUS_SHIELD_IMPACT, target); + break; + } + } + + void HandleOnEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + + if (!caster) + { + return; + } + + Unit* target = GetTarget(); + + if (target) + { + target->RemoveAurasDueToSpell(SPELL_TRANSITUS_SHIELD_IMPACT); + } + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_transitus_shield_beam_AuraScript::HandleOnEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + OnEffectRemove += AuraEffectRemoveFn(spell_transitus_shield_beam_AuraScript::HandleOnEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_transitus_shield_beam_AuraScript(); + } +}; + +class spell_shield_generator : public SpellScriptLoader +{ +public: + spell_shield_generator() : SpellScriptLoader("spell_shield_generator") { } + + class spell_shield_generator_AuraScript : public AuraScript + { + PrepareAuraScript(spell_shield_generator_AuraScript); + + uint32 absorbPct; + + bool Load() override + { + absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster()); + return true; + } + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + { + // Set absorbtion amount to unlimited + amount = -1; + } + + void Absorb(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& absorbAmount) + { + absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct); + } + + void Register() override + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_shield_generator_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_shield_generator_AuraScript::Absorb, EFFECT_0); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_shield_generator_AuraScript(); + } +}; + +class spell_demolisher_ride_vehicle : public SpellScriptLoader +{ +public: + spell_demolisher_ride_vehicle() : SpellScriptLoader("spell_demolisher_ride_vehicle") {} + + class spell_demolisher_ride_vehicle_SpellScript : public SpellScript + { + PrepareSpellScript(spell_demolisher_ride_vehicle_SpellScript); + + SpellCastResult CheckCast() + { + if (GetCaster()->GetTypeId() != TYPEID_PLAYER) + return SPELL_CAST_OK; + + Unit* target = this->GetExplTargetUnit(); + if (!target || target->GetEntry() != NPC_SALVAGED_DEMOLISHER) + return SPELL_FAILED_DONT_REPORT; + + Vehicle* veh = target->GetVehicleKit(); + if (veh && veh->GetPassenger(0)) + if (Unit* target2 = veh->GetPassenger(1)) + if (Vehicle* veh2 = target2->GetVehicleKit()) + { + if (!veh2->GetPassenger(0)) + target2->HandleSpellClick(GetCaster()); + + return SPELL_FAILED_DONT_REPORT; + } + + return SPELL_CAST_OK; + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_demolisher_ride_vehicle_SpellScript::CheckCast); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_demolisher_ride_vehicle_SpellScript(); + } +}; + +class achievement_flame_leviathan_towers : public AchievementCriteriaScript +{ +public: + achievement_flame_leviathan_towers(char const* name, uint32 count) : AchievementCriteriaScript(name), + _towerCount(count) + { + } + + bool OnCheck(Player* /*player*/, Unit* target /*Flame Leviathan*/, uint32 /*criteria_id*/) override + { + return target && _towerCount <= target->GetAI()->GetData(DATA_GET_TOWER_COUNT); + } + +private: + uint32 const _towerCount; +}; + +class achievement_flame_leviathan_shutout : public AchievementCriteriaScript +{ +public: + achievement_flame_leviathan_shutout() : AchievementCriteriaScript("achievement_flame_leviathan_shutout") {} + + bool OnCheck(Player* /*player*/, Unit* target /*Flame Leviathan*/, uint32 /*criteria_id*/) override + { + if (target) + if (target->GetAI()->GetData(DATA_GET_SHUTDOWN)) + return true; + return false; + } +}; + +class achievement_flame_leviathan_garage : public AchievementCriteriaScript +{ +public: + achievement_flame_leviathan_garage(char const* name, uint32 entry1, uint32 entry2) : AchievementCriteriaScript(name), + _entry1(entry1), _entry2(entry2) + { + } + + bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override + { + if (Vehicle* vehicle = player->GetVehicle()) + if (vehicle->GetCreatureEntry() == _entry1 || vehicle->GetCreatureEntry() == _entry2) + return true; + return false; + } + +private: + uint32 const _entry1; + uint32 const _entry2; +}; + +class achievement_flame_leviathan_unbroken : public AchievementCriteriaScript +{ +public: + achievement_flame_leviathan_unbroken() : AchievementCriteriaScript("achievement_flame_leviathan_unbroken") {} + + bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override + { + if (player->GetInstanceScript()) + if (player->GetInstanceScript()->GetData(DATA_UNBROKEN_ACHIEVEMENT)) + return true; + return false; + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index 4d3610adba6889..3ade61219aeeb0 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_freya.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "PassiveAI.h" @@ -23,1264 +24,6 @@ #include "SpellAuras.h" #include "ulduar.h" -enum FreyaSpells -{ - // LIFEBINDER - SPELL_AUTO_GROW = 62559, - SPELL_LIFEBINDER_PHERONOMES = 62619, - SPELL_LIFEBINDER_VISUAL = 62579, - SPELL_LIFEBINDER_HEAL_10 = 62584, - SPELL_LIFEBINDER_HEAL_25 = 64185, - - // FREYA - SPELL_TOUCH_OF_EONAR_10 = 62528, - SPELL_TOUCH_OF_EONAR_25 = 62892, - SPELL_ATTUNED_TO_NATURE = 62519, - SPELL_SUMMON_LIFEBINDER = 62870, - SPELL_SUNBEAM_10 = 62623, - SPELL_SUNBEAM_25 = 62872, - SPELL_NATURE_BOMB_FLIGHT = 64648, - SPELL_NATURE_BOMB_DAMAGE_10 = 64587, - SPELL_NATURE_BOMB_DAMAGE_25 = 64650, - SPELL_GREEN_BANISH_STATE = 32567, - SPELL_BERSERK = 47008, - - // HARD MODE - SPELL_GROUND_TREMOR_FREYA_10 = 62437, - SPELL_GROUND_TREMOR_FREYA_25 = 62859, - SPELL_IRON_ROOTS_FREYA_10 = 62862, - SPELL_IRON_ROOTS_FREYA_25 = 62439, - SPELL_IRON_ROOTS_FREYA_DAMAGE_10 = 62861, - SPELL_IRON_ROOTS_FREYA_DAMAGE_25 = 62438, - SPELL_UNSTABLE_SUN_FREYA_DAMAGE_10 = 62451, - SPELL_UNSTABLE_SUN_FREYA_DAMAGE_25 = 62865, - SPELL_UNSTABLE_SUN_VISUAL = 62216, - - // ELDERS - SPELL_DRAINED_OF_POWER = 62467, - SPELL_STONEBARK_ESSENCE = 62483, - SPELL_IRONBRANCH_ESSENCE = 62484, - SPELL_BRIGHTLEAF_ESSENCE = 62485, - - // BRIGHTLEAF - SPELL_BRIGHTLEAF_FLUX = 62239, - SPELL_SOLAR_FLARE_10 = 62240, - SPELL_SOLAR_FLARE_25 = 64087, - SPELL_UNSTABLE_SUN_BEAM_AURA = 62211, - SPELL_PHOTOSYNTHESIS = 62209, - SPELL_UNSTABLE_SUN_DAMAGE_10 = 62217, - SPELL_UNSTABLE_SUN_DAMAGE_25 = 62922, - - // IRONBRANCH - SPELL_IMPALE_10 = 62310, - SPELL_IMPALE_25 = 62928, - SPELL_IRON_ROOTS_10 = 62275, - SPELL_IRON_ROOTS_25 = 62929, - SPELL_IRON_ROOTS_DAMAGE_10 = 62283, - SPELL_IRON_ROOTS_DAMAGE_25 = 62930, - SPELL_THORN_SWARM_10 = 62285, - SPELL_THORN_SWARM_25 = 62931, - - // STONEBARK - SPELL_FISTS_OF_STONE = 62344, - SPELL_GROUND_TREMOR_10 = 62325, - SPELL_GROUND_TREMOR_25 = 62932, - SPELL_PETRIFIED_BARK_10 = 62337, - SPELL_PETRIFIED_BARK_25 = 62933, - - // SNAPLASHER - SPELL_HARDENED_BARK_10 = 62664, - SPELL_HARDENED_BARK_25 = 64191, - - // ANCIENT WATER SPIRIT - SPELL_TIDAL_WAVE_10 = 62653, - SPELL_TIDAL_WAVE_25 = 62935, - SPELL_TIDAL_WAVE_DAMAGE_10 = 62654, - SPELL_TIDAL_WAVE_DAMAGE_25 = 62936, - SPELL_TIDAL_WAVE_AURA = 62655, - - // STORM LASHER - SPELL_LIGHTNING_LASH_10 = 62648, - SPELL_LIGHTNING_LASH_25 = 62939, - SPELL_STORMBOLT_10 = 62649, - SPELL_STORMBOLT_25 = 62938, - - // ANCIENT CONSERVATOR - SPELL_CONSERVATOR_GRIP = 62532, - SPELL_NATURE_FURY_10 = 62589, - SPELL_NATURE_FURY_25 = 63571, - SPELL_POTENT_PHEROMONES = 62541, - SPELL_HEALTHY_SPORE_VISUAL = 62538, - SPELL_HEALTHY_SPORE_SUMMON = 62566, - - // DETONATING LASHER - SPELL_DETONATE_10 = 62598, - SPELL_DETONATE_25 = 62937, - SPELL_FLAME_LASH = 62608, - - // ACHIEVEMENT - SPELL_DEFORESTATION_CREDIT = 65015, -}; - -#define SPELL_GROUND_TREMOR RAID_MODE(SPELL_GROUND_TREMOR_10, SPELL_GROUND_TREMOR_25) -#define SPELL_PETRIFIED_BARK RAID_MODE(SPELL_PETRIFIED_BARK_10, SPELL_PETRIFIED_BARK_25) -#define SPELL_IRON_ROOTS RAID_MODE(SPELL_IRON_ROOTS_10, SPELL_IRON_ROOTS_25) -#define SPELL_IMPALE RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25) -#define SPELL_THORN_SWARM RAID_MODE(SPELL_THORN_SWARM_10, SPELL_THORN_SWARM_25) -#define SPELL_UNSTABLE_SUN_DAMAGE RAID_MODE(SPELL_UNSTABLE_SUN_DAMAGE_10, SPELL_UNSTABLE_SUN_DAMAGE_25) -#define SPELL_SOLAR_FLARE RAID_MODE(SPELL_SOLAR_FLARE_10, SPELL_SOLAR_FLARE_25) -#define SPELL_TOUCH_OF_EONAR RAID_MODE(SPELL_TOUCH_OF_EONAR_10, SPELL_TOUCH_OF_EONAR_25) -#define SPELL_LIFEBINDER_HEAL RAID_MODE(SPELL_LIFEBINDER_HEAL_10, SPELL_LIFEBINDER_HEAL_25) -#define SPELL_TIDAL_WAVE RAID_MODE(SPELL_TIDAL_WAVE_10, SPELL_TIDAL_WAVE_25) -#define SPELL_TIDAL_WAVE_DAMAGE RAID_MODE(SPELL_TIDAL_WAVE_DAMAGE_10, SPELL_TIDAL_WAVE_DAMAGE_25) -#define SPELL_NATURE_FURY RAID_MODE(SPELL_NATURE_FURY_10, SPELL_NATURE_FURY_25) -#define SPELL_HARDENED_BARK RAID_MODE(SPELL_HARDENED_BARK_10, SPELL_HARDENED_BARK_25) -#define SPELL_DETONATE RAID_MODE(SPELL_DETONATE_10, SPELL_DETONATE_25) -//#define SPELL_NATURE_BOMB_DAMAGE RAID_MODE(SPELL_NATURE_BOMB_DAMAGE_10, SPELL_NATURE_BOMB_DAMAGE_25) -#define SPELL_SUNBEAM RAID_MODE(SPELL_SUNBEAM_10, SPELL_SUNBEAM_25) -#define SPELL_GROUND_TREMOR_FREYA RAID_MODE(SPELL_GROUND_TREMOR_FREYA_10, SPELL_GROUND_TREMOR_FREYA_25) -#define SPELL_IRON_ROOTS_FREYA RAID_MODE(SPELL_IRON_ROOTS_FREYA_10, SPELL_IRON_ROOTS_FREYA_25) -#define SPELL_UNSTABLE_SUN_FREYA_DAMAGE RAID_MODE(SPELL_UNSTABLE_SUN_FREYA_DAMAGE_10, SPELL_UNSTABLE_SUN_FREYA_DAMAGE_25) -#define SPELL_LIGHTNING_LASH RAID_MODE(SPELL_LIGHTNING_LASH_10, SPELL_LIGHTNING_LASH_25) -#define SPELL_STORMBOLT RAID_MODE(SPELL_STORMBOLT_10, SPELL_STORMBOLT_25) - -enum FreyaEvents -{ - // FREYA - EVENT_FREYA_ADDS_SPAM = 1, - EVENT_FREYA_LIFEBINDER = 2, - EVENT_FREYA_NATURE_BOMB = 3, - EVENT_FREYA_SUNBEAM = 4, - EVENT_FREYA_BERSERK = 5, - // HARD MODE - EVENT_FREYA_GROUND_TREMOR = 6, - EVENT_FREYA_IRON_ROOT = 7, - EVENT_FREYA_UNSTABLE_SUN_BEAM = 8, - EVENT_FREYA_RESPAWN_TRIO = 9, - - // STONEBARK - EVENT_STONEBARK_FISTS_OF_STONE = 10, - EVENT_STONEBARK_GROUND_TREMOR = 11, - EVENT_STONEBARK_PETRIFIED_BARK = 12, - - // BRIGHTLEAF - EVENT_BRIGHTLEAF_FLUX = 20, - EVENT_BRIGHTLEAF_SOLAR_FLARE = 21, - EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM = 22, - EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM = 23, - - // IRONBRANCH - EVENT_IRONBRANCH_IMPALE = 30, - EVENT_IRONBRANCH_IRON_ROOT = 31, - EVENT_IRONBRANCH_THORN_SWARM = 32, - - // SUMMONS - EVENT_ANCIENT_CONSERVATOR_NATURE_FURY = 40, - EVENT_ANCIENT_CONSERVATOR_GRIP = 41, - EVENT_WATER_SPIRIT_CHARGE = 45, - EVENT_WATER_SPIRIT_DAMAGE = 46, - EVENT_STORM_LASHER_LIGHTNING_LASH = 50, - EVENT_STORM_LASHER_STORMBOLT = 51, - EVENT_DETONATING_LASHER_FLAME_LASH = 55, -}; - -enum Texts -{ - // Elder Brightleaf / Elder Ironbranch / Elder Stonebark - SAY_ELDER_AGGRO = 0, - SAY_ELDER_SLAY = 1, - SAY_ELDER_DEATH = 2, - - // Freya - SAY_AGGRO = 0, - SAY_AGGRO_WITH_ELDER = 1, - SAY_SLAY = 2, - SAY_DEATH = 3, - SAY_BERSERK = 4, - SAY_SUMMON_CONSERVATOR = 5, - SAY_SUMMON_TRIO = 6, - SAY_SUMMON_LASHERS = 7, - EMOTE_LIFEBINDERS_GIFT = 8, - EMOTE_ALLIES_OF_NATURE = 9, - EMOTE_GROUND_TREMOR = 10, - EMOTE_IRON_ROOTS = 11, -}; - -enum FreyaNPCs -{ - NPC_NATURE_BOMB = 34129, - NPC_IRON_ROOT_TRIGGER = 33088, - NPC_FREYA_UNSTABLE_SUN_BEAM = 33170, - NPC_UNSTABLE_SUN_BRIGHTLEAF = 33050, // 10 SECS? - - // FIRST WAVE - NPC_STORM_LASHER = 32919, - NPC_ANCIENT_WATER_SPIRIT = 33202, - NPC_SNAPLASHER = 32916, - - // SEC WAVE - NPC_ANCIENT_CONSERVATOR = 33203, - NPC_HEALTHY_SPORE = 33215, - - // THIRD WAVE - NPC_DETONATING_LASHER = 32918, -}; - -enum Misc -{ - ACTION_REMOVE_10_STACK = 10, - ACTION_REMOVE_25_STACK = 25, - ACTION_REMOVE_2_STACK = 2, - ACTION_RESPAWN_TRIO = 1, - ACTION_LUMBERJACKED = -1, - - EVENT_PHASE_ADDS = 1, - EVENT_PHASE_FINAL = 2, - - DATA_GET_ELDER_COUNT = 1, - DATA_BACK_TO_NATURE = 2, - - CRITERIA_LUMBERJACKED = 21686, -}; - -class boss_freya : public CreatureScript -{ -public: - boss_freya() : CreatureScript("boss_freya") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_freyaAI : public ScriptedAI - { - boss_freyaAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) - { - m_pInstance = pCreature->GetInstanceScript(); - if (!me->IsAlive()) - if (m_pInstance) - m_pInstance->SetData(TYPE_FREYA, DONE); - } - - InstanceScript* m_pInstance; - EventMap events; - SummonList summons; - - uint8 _waveNumber; - uint8 _trioKilled; - uint8 _spawnedAmount; - uint8 _lumberjacked; - bool _respawningTrio; - bool _backToNature; - uint8 _deforestation; - - ObjectGuid _elderGUID[3]; - - void Reset() override - { - if (m_pInstance && m_pInstance->GetData(TYPE_FREYA) != DONE) - m_pInstance->SetData(TYPE_FREYA, NOT_STARTED); - - events.Reset(); - summons.DespawnAll(); - - for (uint8 i = 0; i < 3; ++i) - { - if (!_elderGUID[i]) - continue; - - if (Creature* elder = ObjectAccessor::GetCreature(*me, _elderGUID[i])) - elder->AI()->EnterEvadeMode(); - - _elderGUID[i].Clear(); - } - - _lumberjacked = 0; - _spawnedAmount = 0; - _trioKilled = 0; - _waveNumber = urand(1, 3); - _respawningTrio = false; - _backToNature = true; - _deforestation = 0; - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2)) - return; - - Talk(SAY_SLAY); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (damage >= me->GetHealth()) - { - damage = 0; - if (m_pInstance->GetData(TYPE_FREYA) != DONE) - { - Talk(SAY_DEATH); - - me->SetReactState(REACT_PASSIVE); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetFaction(FACTION_FRIENDLY); - me->RemoveAllAuras(); - me->AttackStop(); - events.Reset(); - - summons.DespawnAll(); - events.Reset(); - - uint8 _elderCount = 0; - for (uint8 i = 0; i < 3; ++i) - { - if (!_elderGUID[i]) - continue; - - if (Creature* e = ObjectAccessor::GetCreature(*me, _elderGUID[i])) - e->DespawnOrUnsummon(); - - ++_elderCount; - } - - uint32 chestId = RAID_MODE(GO_FREYA_CHEST, GO_FREYA_CHEST_HERO); - chestId -= 2 * _elderCount; // offset - - me->DespawnOrUnsummon(5000); - if (GameObject* go = me->SummonGameObject(chestId, 2345.61f, -71.20f, 425.104f, 3.0f, 0, 0, 0, 0, 0)) - { - go->ReplaceAllGameObjectFlags((GameObjectFlags)0); - go->SetLootRecipient(me->GetMap()); - } - - // Defeat credit - if (m_pInstance) - { - me->CastSpell(me, 65074, true); // credit - m_pInstance->SetData(TYPE_FREYA, DONE); - } - } - } - } - - void JustSummoned(Creature* cr) override - { - if (cr->GetEntry() == NPC_FREYA_UNSTABLE_SUN_BEAM) - { - cr->CastSpell(cr, SPELL_UNSTABLE_SUN_VISUAL, true); - cr->CastSpell(cr, SPELL_UNSTABLE_SUN_FREYA_DAMAGE, true); - } - summons.Summon(cr); - } - - void SpawnWave() - { - _waveNumber = _waveNumber == 1 ? 3 : _waveNumber - 1; - Talk(EMOTE_ALLIES_OF_NATURE); - - // Wave of three - if (_waveNumber == 1) - { - Talk(SAY_SUMMON_TRIO); - me->SummonCreature(NPC_ANCIENT_WATER_SPIRIT, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ())); - me->SummonCreature(NPC_STORM_LASHER, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ())); - me->SummonCreature(NPC_SNAPLASHER, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ())); - } - // Ancient Conservator - else if (_waveNumber == 2) - { - Talk(SAY_SUMMON_CONSERVATOR); - me->SummonCreature(NPC_ANCIENT_CONSERVATOR, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_CORPSE_DESPAWN); - } - // Detonating Lashers - else if (_waveNumber == 3) - { - Talk(SAY_SUMMON_LASHERS); - for (uint8 i = 0; i < 10; ++i) - me->SummonCreature(NPC_DETONATING_LASHER, me->GetPositionX() + urand(5, 20), me->GetPositionY() + urand(5, 20), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_CORPSE_DESPAWN); - } - } - - void DoAction(int32 param) override - { - if (param == ACTION_LUMBERJACKED) - { - if (!m_pInstance) - return; - - ++_lumberjacked; - if (_lumberjacked == 1) - m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_LUMBERJACKED); - else if (_lumberjacked == 3) - m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 65296 /*SPELL_LUMBERJACKED*/, 0, me); - return; - } - - if (param == ACTION_RESPAWN_TRIO) - { - if (!_respawningTrio) - { - _respawningTrio = true; - events.ScheduleEvent(EVENT_FREYA_RESPAWN_TRIO, 10s); - } - - ++_trioKilled; - return; - } - - // Deforestation Achievement Counter - if (param == ACTION_REMOVE_10_STACK) - { - ++_deforestation; - if (_deforestation >= 6 && m_pInstance) - m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_DEFORESTATION_CREDIT, 0, me); - // do not return - } - - if (Aura* aur = me->GetAura(SPELL_ATTUNED_TO_NATURE)) - { - // Back to Nature achievement - if (aur->GetStackAmount() - param < 25) - _backToNature = false; - - if (aur->GetStackAmount() > param) - aur->SetStackAmount(aur->GetStackAmount() - param); - else // Aura out of stack - { - events.ScheduleEvent(EVENT_FREYA_NATURE_BOMB, 5s); - events.SetPhase(EVENT_PHASE_FINAL); - aur->Remove(); - return; - } - } - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_GET_ELDER_COUNT) - { - uint8 _count = 0; - for (uint8 i = 0; i < 3; ++i) - if (_elderGUID[i]) - ++_count; - - return _count; - } - if (param == DATA_BACK_TO_NATURE) - return _backToNature; - - return 0; - } - - void JustReachedHome() override { me->setActive(false); } - - void JustEngagedWith(Unit*) override - { - me->setActive(true); - me->SetInCombatWithZone(); - me->CastSpell(me, SPELL_TOUCH_OF_EONAR, true); - if (Aura* aur = me->AddAura(SPELL_ATTUNED_TO_NATURE, me)) - aur->SetStackAmount(150); - - events.ScheduleEvent(EVENT_FREYA_ADDS_SPAM, 10s, 0, EVENT_PHASE_ADDS); - events.ScheduleEvent(EVENT_FREYA_LIFEBINDER, 30s); - events.ScheduleEvent(EVENT_FREYA_SUNBEAM, 17s); - events.ScheduleEvent(EVENT_FREYA_BERSERK, 10min); - events.SetPhase(EVENT_PHASE_ADDS); - - if( !m_pInstance ) - return; - - if (m_pInstance->GetData(TYPE_FREYA) != DONE) - m_pInstance->SetData(TYPE_FREYA, IN_PROGRESS); - - // HARD MODE CHECKS - Creature* elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_STONEBARK)); - if (elder && elder->IsAlive()) - { - elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true); - elder->CastSpell(elder, SPELL_STONEBARK_ESSENCE, true); - elder->SetInCombatWithZone(); - - events.ScheduleEvent(EVENT_FREYA_GROUND_TREMOR, 35s); - _elderGUID[0] = elder->GetGUID(); - } - - elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_IRONBRANCH)); - if (elder && elder->IsAlive()) - { - elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true); - elder->CastSpell(elder, SPELL_IRONBRANCH_ESSENCE, true); - elder->SetInCombatWithZone(); - - events.ScheduleEvent(EVENT_FREYA_IRON_ROOT, 20s); - _elderGUID[1] = elder->GetGUID(); - } - - elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_BRIGHTLEAF)); - if (elder && elder->IsAlive()) - { - elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true); - elder->CastSpell(elder, SPELL_BRIGHTLEAF_ESSENCE, true); - elder->SetInCombatWithZone(); - - events.ScheduleEvent(EVENT_FREYA_UNSTABLE_SUN_BEAM, 1min); - _elderGUID[2] = elder->GetGUID(); - } - - if (_elderGUID[0] || _elderGUID[1] || _elderGUID[2]) - { - Talk(SAY_AGGRO_WITH_ELDER); - } - else - { - Talk(SAY_AGGRO); - } - } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) override - { - if (spell->Id == SPELL_NATURE_BOMB_FLIGHT) - me->SummonCreature(NPC_NATURE_BOMB, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_FREYA_ADDS_SPAM: - if (_spawnedAmount < 6) - SpawnWave(); - else if (me->GetAura(SPELL_ATTUNED_TO_NATURE)) - { - me->RemoveAura(SPELL_ATTUNED_TO_NATURE); - events.ScheduleEvent(EVENT_FREYA_NATURE_BOMB, 5s); - events.SetPhase(EVENT_PHASE_FINAL); - return; - } - _spawnedAmount++; - events.Repeat(1min); - break; - case EVENT_FREYA_LIFEBINDER: - { - Talk(EMOTE_LIFEBINDERS_GIFT); - events.Repeat(45s); - float x, y, z; - for (uint8 i = 0; i < 10; ++i) - { - x = me->GetPositionX() + urand(7, 25); - y = me->GetPositionY() + urand(7, 25); - z = me->GetMapHeight(x, y, me->GetPositionZ()); - if (me->IsWithinLOS(x, y, z)) - { - me->CastSpell(x, y, z, SPELL_SUMMON_LIFEBINDER, true); - return; - } - } - - me->CastSpell(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), SPELL_SUMMON_LIFEBINDER, true); - break; - } - case EVENT_FREYA_SUNBEAM: - if (Unit* target = SelectTarget(SelectTargetMethod::Random)) - me->CastSpell(target, SPELL_SUNBEAM, false); - events.Repeat(15s, 20s); - break; - case EVENT_FREYA_RESPAWN_TRIO: - _deforestation = 0; - _respawningTrio = false; - if (_trioKilled < 3) - summons.DoAction(ACTION_RESPAWN_TRIO); - - _trioKilled = 0; - break; - case EVENT_FREYA_NATURE_BOMB: - { - uint8 _minCount = me->GetMap()->Is25ManRaid() ? urand(7, 10) : urand(3, 4); - Map::PlayerList const& pList = me->GetMap()->GetPlayers(); - for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) - { - if (me->GetDistance(itr->GetSource()) > 70 || !itr->GetSource()->IsAlive()) - continue; - - me->CastSpell(itr->GetSource(), SPELL_NATURE_BOMB_FLIGHT, true); - - if (!(--_minCount)) - break; - } - events.Repeat(18s); - break; - } - case EVENT_FREYA_BERSERK: - Talk(SAY_BERSERK); - me->CastSpell(me, SPELL_BERSERK, true); - break; - case EVENT_FREYA_GROUND_TREMOR: - Talk(EMOTE_GROUND_TREMOR); - me->CastSpell(me, SPELL_GROUND_TREMOR_FREYA, false); - events.Repeat(25s, 35s); - break; - case EVENT_FREYA_IRON_ROOT: - Talk(EMOTE_IRON_ROOTS); - me->CastCustomSpell(SPELL_IRON_ROOTS_FREYA, SPELLVALUE_MAX_TARGETS, 1, me, false); - events.Repeat(45s, 55s); - break; - case EVENT_FREYA_UNSTABLE_SUN_BEAM: - me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); - if (Is25ManRaid()) - { - me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); - me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); - } - events.Repeat(38s, 48s); - break; - } - - DoMeleeAttackIfReady(); - } - - bool CheckEvadeIfOutOfCombatArea() const override - { - return me->GetPositionX() < 2135.0f; - } - }; -}; - -class boss_freya_elder_stonebark : public CreatureScript -{ -public: - boss_freya_elder_stonebark() : CreatureScript("boss_freya_elder_stonebark") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_freya_elder_stonebarkAI : public ScriptedAI - { - boss_freya_elder_stonebarkAI(Creature* pCreature) : ScriptedAI(pCreature) - { - } - - EventMap events; - uint8 _chargesCount; - - void Reset() override - { - events.Reset(); - _chargesCount = 0; - } - - void KilledUnit(Unit*) override - { - if (urand(0, 1)) - return; - - Talk(SAY_ELDER_SLAY); - } - - void JustDied(Unit* killer) override - { - if (killer && me->GetEntry() == killer->GetEntry()) - return; - Talk(SAY_ELDER_DEATH); - - // Lumberjacked - if (me->GetInstanceScript()) - if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA))) - freya->AI()->DoAction(ACTION_LUMBERJACKED); - } - - void JustEngagedWith(Unit*) override - { - events.ScheduleEvent(EVENT_STONEBARK_FISTS_OF_STONE, 40s); - events.ScheduleEvent(EVENT_STONEBARK_GROUND_TREMOR, 5s); - events.ScheduleEvent(EVENT_STONEBARK_PETRIFIED_BARK, 20s); - - if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation - Talk(SAY_ELDER_AGGRO); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType damageType, SpellSchoolMask damageSchoolMask) override - { - if ((damageType == DIRECT_DAMAGE || (damageType == SPELL_DIRECT_DAMAGE && damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)) && _chargesCount) - { - --_chargesCount; - damage = 0; - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_STONEBARK_FISTS_OF_STONE: - me->CastSpell(me, SPELL_FISTS_OF_STONE, false); - events.Repeat(1min); - break; - case EVENT_STONEBARK_GROUND_TREMOR: - if (!me->HasAura(SPELL_FISTS_OF_STONE)) - me->CastSpell(me, SPELL_GROUND_TREMOR, false); - events.Repeat(20s); - break; - case EVENT_STONEBARK_PETRIFIED_BARK: - _chargesCount = RAID_MODE(60, 120); - me->CastSpell(me, SPELL_PETRIFIED_BARK, false); - events.Repeat(30s); - break; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_freya_elder_brightleaf : public CreatureScript -{ -public: - boss_freya_elder_brightleaf() : CreatureScript("boss_freya_elder_brightleaf") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_freya_elder_brightleafAI : public ScriptedAI - { - boss_freya_elder_brightleafAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) - { - } - - EventMap events; - SummonList summons; - - void Reset() override - { - events.Reset(); - summons.DespawnAll(); - } - - void KilledUnit(Unit*) override - { - if (urand(0, 1)) - return; - - Talk(SAY_ELDER_SLAY); - } - - void JustDied(Unit* killer) override - { - if (killer && me->GetEntry() == killer->GetEntry()) - return; - Talk(SAY_ELDER_DEATH); - - // Lumberjacked - if (me->GetInstanceScript()) - if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA))) - freya->AI()->DoAction(ACTION_LUMBERJACKED); - } - - void JustEngagedWith(Unit*) override - { - events.ScheduleEvent(EVENT_BRIGHTLEAF_FLUX, 10s); - events.ScheduleEvent(EVENT_BRIGHTLEAF_SOLAR_FLARE, 5s); - events.ScheduleEvent(EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM, 8s); - - if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation - Talk(SAY_ELDER_AGGRO); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_BRIGHTLEAF_FLUX: - if (Aura* aur = me->AddAura(SPELL_BRIGHTLEAF_FLUX, me)) - aur->SetStackAmount(urand(1, 10)); - events.Repeat(10s); - break; - case EVENT_BRIGHTLEAF_SOLAR_FLARE: - if (Aura* aur = me->GetAura(SPELL_BRIGHTLEAF_FLUX)) - { - me->CastCustomSpell(SPELL_SOLAR_FLARE, SPELLVALUE_MAX_TARGETS, aur->GetStackAmount(), me, false); - me->RemoveAura(aur); - } - events.Repeat(15s); - break; - case EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM: - events.ScheduleEvent(EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM, 15s); - if (Creature* beam = me->SummonCreature(NPC_UNSTABLE_SUN_BRIGHTLEAF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ())) - { - beam->CastSpell(beam, SPELL_UNSTABLE_SUN_BEAM_AURA, true); - beam->CastSpell(beam, SPELL_PHOTOSYNTHESIS, true); - summons.Summon(beam); - } - if (Creature* beam = me->SummonCreature(NPC_UNSTABLE_SUN_BRIGHTLEAF, me->GetPositionX() + 8, me->GetPositionY() + 8, me->GetPositionZ())) - { - beam->CastSpell(beam, SPELL_UNSTABLE_SUN_BEAM_AURA, true); - beam->CastSpell(beam, SPELL_PHOTOSYNTHESIS, true); - summons.Summon(beam); - } - events.Repeat(20s); - break; - case EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM: - for (SummonList::iterator i = summons.begin(); i != summons.end();) - { - Creature* summon = ObjectAccessor::GetCreature(*me, *i); - ++i; - if (summon) - summon->CastSpell(summon, SPELL_UNSTABLE_SUN_DAMAGE, false); - } - - summons.DespawnAll(); - break; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_freya_elder_ironbranch : public CreatureScript -{ -public: - boss_freya_elder_ironbranch() : CreatureScript("boss_freya_elder_ironbranch") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_freya_elder_ironbranchAI : public ScriptedAI - { - boss_freya_elder_ironbranchAI(Creature* pCreature) : ScriptedAI(pCreature) - { - } - - EventMap events; - - void Reset() override - { - events.Reset(); - } - - void KilledUnit(Unit*) override - { - if (urand(0, 1)) - return; - - Talk(SAY_ELDER_SLAY); - } - - void JustDied(Unit* killer) override - { - if (killer && me->GetEntry() == killer->GetEntry()) - return; - Talk(SAY_ELDER_DEATH); - - // Lumberjacked - if (me->GetInstanceScript()) - if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA))) - freya->AI()->DoAction(ACTION_LUMBERJACKED); - } - - void JustEngagedWith(Unit*) override - { - events.ScheduleEvent(EVENT_IRONBRANCH_IMPALE, 10s); - events.ScheduleEvent(EVENT_IRONBRANCH_IRON_ROOT, 15s); - events.ScheduleEvent(EVENT_IRONBRANCH_THORN_SWARM, 3s); - - if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation - Talk(SAY_ELDER_AGGRO); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_IRONBRANCH_IMPALE: - me->CastSpell(me->GetVictim(), SPELL_IMPALE, false); - events.Repeat(17s); - break; - case EVENT_IRONBRANCH_IRON_ROOT: - me->CastCustomSpell(SPELL_IRON_ROOTS, SPELLVALUE_MAX_TARGETS, 1, me, false); - events.Repeat(20s); - break; - case EVENT_IRONBRANCH_THORN_SWARM: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_THORN_SWARM, false); - events.Repeat(14s); - break; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_freya_iron_root : public CreatureScript -{ -public: - boss_freya_iron_root() : CreatureScript("boss_freya_iron_root") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_freya_iron_rootAI : public NullCreatureAI - { - boss_freya_iron_rootAI(Creature* pCreature) : NullCreatureAI(pCreature) { } - - void JustDied(Unit* /*killer*/) override - { - if (!me->IsSummon()) - return; - - if (Unit* target = ObjectAccessor::GetUnit(*me, me->ToTempSummon()->GetSummonerGUID())) - { - if (me->GetEntry() == NPC_IRON_ROOT_TRIGGER) // Iron Branch spell - target->RemoveAura(target->GetMap()->Is25ManRaid() ? SPELL_IRON_ROOTS_DAMAGE_25 : SPELL_IRON_ROOTS_DAMAGE_10); - else - target->RemoveAura(target->GetMap()->Is25ManRaid() ? SPELL_IRON_ROOTS_FREYA_DAMAGE_25 : SPELL_IRON_ROOTS_FREYA_DAMAGE_10); - } - } - }; -}; - -class boss_freya_lifebinder : public CreatureScript -{ -public: - boss_freya_lifebinder() : CreatureScript("boss_freya_lifebinder") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_freya_lifebinderAI : public NullCreatureAI - { - boss_freya_lifebinderAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - } - - uint32 _healTimer; - - void Reset() override - { - me->CastSpell(me, SPELL_LIFEBINDER_VISUAL, true); - me->CastSpell(me, SPELL_LIFEBINDER_PHERONOMES, true); - me->CastSpell(me, SPELL_AUTO_GROW, true); - _healTimer = 0; - } - - void UpdateAI(uint32 diff) override - { - _healTimer += diff; - if (_healTimer >= 12000) - { - me->RemoveAurasDueToSpell(SPELL_AUTO_GROW); - me->CastSpell(me, me->GetMap()->Is25ManRaid() ? SPELL_LIFEBINDER_HEAL_25 : SPELL_LIFEBINDER_HEAL_10, true); - me->DespawnOrUnsummon(2000); - _healTimer = 0; - } - } - }; -}; - -class boss_freya_healthy_spore : public CreatureScript -{ -public: - boss_freya_healthy_spore() : CreatureScript("boss_freya_healthy_spore") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_freya_healthy_sporeAI : public NullCreatureAI - { - boss_freya_healthy_sporeAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - } - - uint32 _despawnTimer; - - void Reset() override - { - me->CastSpell(me, SPELL_POTENT_PHEROMONES, true); - me->CastSpell(me, SPELL_HEALTHY_SPORE_VISUAL, true); - me->CastSpell(me, SPELL_AUTO_GROW, true); - _despawnTimer = 0; - } - - void UpdateAI(uint32 diff) override - { - _despawnTimer += diff; - if (_despawnTimer >= 22000) - { - me->RemoveAurasDueToSpell(SPELL_AUTO_GROW); - me->DespawnOrUnsummon(2200); - _despawnTimer = 0; - } - } - }; -}; - -class boss_freya_summons : public CreatureScript -{ -public: - boss_freya_summons() : CreatureScript("boss_freya_summons") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_freya_summonsAI : public ScriptedAI - { - boss_freya_summonsAI(Creature* pCreature) : ScriptedAI(pCreature) - { - _freyaGUID = me->GetInstanceScript() ? me->GetInstanceScript()->GetGuidData(TYPE_FREYA) : ObjectGuid::Empty; - _isTrio = me->GetEntry() == NPC_ANCIENT_WATER_SPIRIT || me->GetEntry() == NPC_STORM_LASHER || me->GetEntry() == NPC_SNAPLASHER; - _hasDied = false; - } - - EventMap events; - ObjectGuid _freyaGUID; - uint8 _stackCount; - bool _hasDied; - bool _isTrio; - - void Reset() override - { - _stackCount = 0; - events.Reset(); - if (Unit* target = SelectTargetFromPlayerList(70)) - AttackStart(target); - } - - void JustDied(Unit* /*killer*/) override - { - if (Creature* freya = ObjectAccessor::GetCreature(*me, _freyaGUID)) - { - if (!_hasDied) - freya->AI()->DoAction(_stackCount); - - if (_isTrio) - { - freya->AI()->DoAction(ACTION_RESPAWN_TRIO); - _hasDied = true; - } - } - if (me->GetEntry() == NPC_DETONATING_LASHER) - me->CastSpell(me, SPELL_DETONATE, true); - } - - void DoAction(int32 param) override - { - if (_isTrio && param == ACTION_RESPAWN_TRIO) - { - me->setDeathState(DeathState::JustRespawned); - Reset(); - } - } - - void JustEngagedWith(Unit*) override - { - if (me->GetEntry() == NPC_ANCIENT_CONSERVATOR) - { - me->CastSpell(me, SPELL_HEALTHY_SPORE_SUMMON, true); - events.ScheduleEvent(EVENT_ANCIENT_CONSERVATOR_GRIP, 6s); - events.ScheduleEvent(EVENT_ANCIENT_CONSERVATOR_NATURE_FURY, 14s); - _stackCount = ACTION_REMOVE_25_STACK; - } - else if (me->GetEntry() == NPC_ANCIENT_WATER_SPIRIT) - { - events.ScheduleEvent(EVENT_WATER_SPIRIT_CHARGE, 12s); - _stackCount = ACTION_REMOVE_10_STACK; - } - else if (me->GetEntry() == NPC_STORM_LASHER) - { - events.ScheduleEvent(EVENT_STORM_LASHER_LIGHTNING_LASH, 10s); - events.ScheduleEvent(EVENT_STORM_LASHER_STORMBOLT, 6s); - _stackCount = ACTION_REMOVE_10_STACK; - } - else if (me->GetEntry() == NPC_DETONATING_LASHER) - { - events.ScheduleEvent(EVENT_DETONATING_LASHER_FLAME_LASH, 10s); - _stackCount = ACTION_REMOVE_2_STACK; - } - else if (me->GetEntry() == NPC_SNAPLASHER) - { - me->CastSpell(me, SPELL_HARDENED_BARK, true); - _stackCount = ACTION_REMOVE_10_STACK; - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_ANCIENT_CONSERVATOR_NATURE_FURY: - me->CastSpell(me->GetVictim(), SPELL_NATURE_FURY, false); - events.Repeat(14s); - break; - case EVENT_ANCIENT_CONSERVATOR_GRIP: - me->CastSpell(me, SPELL_CONSERVATOR_GRIP, true); - break; - case EVENT_WATER_SPIRIT_CHARGE: - me->CastSpell(me, SPELL_TIDAL_WAVE_AURA, true); - me->CastSpell(me->GetVictim(), SPELL_TIDAL_WAVE, false); - events.Repeat(12s); - events.ScheduleEvent(EVENT_WATER_SPIRIT_DAMAGE, 3s); - break; - case EVENT_WATER_SPIRIT_DAMAGE: - me->CastSpell(me, SPELL_TIDAL_WAVE_DAMAGE, false); - break; - case EVENT_STORM_LASHER_LIGHTNING_LASH: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_LIGHTNING_LASH, false); - events.Repeat(10s); - break; - case EVENT_STORM_LASHER_STORMBOLT: - me->CastSpell(me->GetVictim(), SPELL_STORMBOLT, false); - events.Repeat(6s); - break; - case EVENT_DETONATING_LASHER_FLAME_LASH: - me->CastSpell(me->GetVictim(), SPELL_FLAME_LASH, false); - DoResetThreatList(); - if (Unit* target = SelectTargetFromPlayerList(80)) - AttackStart(target); - else - me->DespawnOrUnsummon(1); - events.Repeat(10s); - break; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_freya_nature_bomb : public CreatureScript -{ -public: - boss_freya_nature_bomb() : CreatureScript("boss_freya_nature_bomb") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_freya_nature_bombAI : public NullCreatureAI - { - boss_freya_nature_bombAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - _goGUID.Clear(); - } - - ObjectGuid _goGUID; - uint32 _explodeTimer; - - void Reset() override - { - me->SetObjectScale(0.5f); - me->CastSpell(me, SPELL_GREEN_BANISH_STATE, true); - - _explodeTimer = 0; - if (GameObject* go = me->SummonGameObject(194902 /*GO_NATURE_BOMB*/, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, 0, 0, 0, 0, 0)) - _goGUID = go->GetGUID(); - } - - uint32 Timer; - void UpdateAI(uint32 diff) override - { - _explodeTimer += diff; - if (_explodeTimer >= 11000) - { - me->CastSpell(me, me->GetMap()->Is25ManRaid() ? SPELL_NATURE_BOMB_DAMAGE_25 : SPELL_NATURE_BOMB_DAMAGE_10, false); - me->DespawnOrUnsummon(1000); - _explodeTimer = 0; - } - - // Delay explosion a little, visual - if (_explodeTimer >= 5000 && _explodeTimer < 10000) - { - _explodeTimer = 10000; - if (GameObject* go = me->GetMap()->GetGameObject(_goGUID)) - go->SetGoState(GO_STATE_ACTIVE); - } - } - }; -}; - -class achievement_freya_getting_back_to_nature : public AchievementCriteriaScript -{ -public: - achievement_freya_getting_back_to_nature() : AchievementCriteriaScript("achievement_freya_getting_back_to_nature") {} - - bool OnCheck(Player* /*player*/, Unit* target /*Freya*/, uint32 /*criteria_id*/) override - { - if (target) - if (target->GetAI()->GetData(DATA_BACK_TO_NATURE)) - return true; - return false; - } -}; - -class achievement_freya_knock_on_wood : public AchievementCriteriaScript -{ -public: - achievement_freya_knock_on_wood(char const* name, uint32 count) : AchievementCriteriaScript(name), - _elderCount(count) - { - } - - bool OnCheck(Player* /*player*/, Unit* target /*Freya*/, uint32 /*criteria_id*/) override - { - return target && _elderCount <= target->GetAI()->GetData(DATA_GET_ELDER_COUNT); - } - -private: - uint32 const _elderCount; -}; void AddSC_boss_freya() { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.h new file mode 100644 index 00000000000000..415fd07cac1d2c --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.h @@ -0,0 +1,1271 @@ +#ifndef BOSS_FREYA_H_ +#define BOSS_FREYA_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellAuras.h" +#include "ulduar.h" + +enum FreyaSpells +{ + // LIFEBINDER + SPELL_AUTO_GROW = 62559, + SPELL_LIFEBINDER_PHERONOMES = 62619, + SPELL_LIFEBINDER_VISUAL = 62579, + SPELL_LIFEBINDER_HEAL_10 = 62584, + SPELL_LIFEBINDER_HEAL_25 = 64185, + + // FREYA + SPELL_TOUCH_OF_EONAR_10 = 62528, + SPELL_TOUCH_OF_EONAR_25 = 62892, + SPELL_ATTUNED_TO_NATURE = 62519, + SPELL_SUMMON_LIFEBINDER = 62870, + SPELL_SUNBEAM_10 = 62623, + SPELL_SUNBEAM_25 = 62872, + SPELL_NATURE_BOMB_FLIGHT = 64648, + SPELL_NATURE_BOMB_DAMAGE_10 = 64587, + SPELL_NATURE_BOMB_DAMAGE_25 = 64650, + SPELL_GREEN_BANISH_STATE = 32567, + SPELL_BERSERK = 47008, + + // HARD MODE + SPELL_GROUND_TREMOR_FREYA_10 = 62437, + SPELL_GROUND_TREMOR_FREYA_25 = 62859, + SPELL_IRON_ROOTS_FREYA_10 = 62862, + SPELL_IRON_ROOTS_FREYA_25 = 62439, + SPELL_IRON_ROOTS_FREYA_DAMAGE_10 = 62861, + SPELL_IRON_ROOTS_FREYA_DAMAGE_25 = 62438, + SPELL_UNSTABLE_SUN_FREYA_DAMAGE_10 = 62451, + SPELL_UNSTABLE_SUN_FREYA_DAMAGE_25 = 62865, + SPELL_UNSTABLE_SUN_VISUAL = 62216, + + // ELDERS + SPELL_DRAINED_OF_POWER = 62467, + SPELL_STONEBARK_ESSENCE = 62483, + SPELL_IRONBRANCH_ESSENCE = 62484, + SPELL_BRIGHTLEAF_ESSENCE = 62485, + + // BRIGHTLEAF + SPELL_BRIGHTLEAF_FLUX = 62239, + SPELL_SOLAR_FLARE_10 = 62240, + SPELL_SOLAR_FLARE_25 = 64087, + SPELL_UNSTABLE_SUN_BEAM_AURA = 62211, + SPELL_PHOTOSYNTHESIS = 62209, + SPELL_UNSTABLE_SUN_DAMAGE_10 = 62217, + SPELL_UNSTABLE_SUN_DAMAGE_25 = 62922, + + // IRONBRANCH + SPELL_IMPALE_10 = 62310, + SPELL_IMPALE_25 = 62928, + SPELL_IRON_ROOTS_10 = 62275, + SPELL_IRON_ROOTS_25 = 62929, + SPELL_IRON_ROOTS_DAMAGE_10 = 62283, + SPELL_IRON_ROOTS_DAMAGE_25 = 62930, + SPELL_THORN_SWARM_10 = 62285, + SPELL_THORN_SWARM_25 = 62931, + + // STONEBARK + SPELL_FISTS_OF_STONE = 62344, + SPELL_GROUND_TREMOR_10 = 62325, + SPELL_GROUND_TREMOR_25 = 62932, + SPELL_PETRIFIED_BARK_10 = 62337, + SPELL_PETRIFIED_BARK_25 = 62933, + + // SNAPLASHER + SPELL_HARDENED_BARK_10 = 62664, + SPELL_HARDENED_BARK_25 = 64191, + + // ANCIENT WATER SPIRIT + SPELL_TIDAL_WAVE_10 = 62653, + SPELL_TIDAL_WAVE_25 = 62935, + SPELL_TIDAL_WAVE_DAMAGE_10 = 62654, + SPELL_TIDAL_WAVE_DAMAGE_25 = 62936, + SPELL_TIDAL_WAVE_AURA = 62655, + + // STORM LASHER + SPELL_LIGHTNING_LASH_10 = 62648, + SPELL_LIGHTNING_LASH_25 = 62939, + SPELL_STORMBOLT_10 = 62649, + SPELL_STORMBOLT_25 = 62938, + + // ANCIENT CONSERVATOR + SPELL_CONSERVATOR_GRIP = 62532, + SPELL_NATURE_FURY_10 = 62589, + SPELL_NATURE_FURY_25 = 63571, + SPELL_POTENT_PHEROMONES = 62541, + SPELL_HEALTHY_SPORE_VISUAL = 62538, + SPELL_HEALTHY_SPORE_SUMMON = 62566, + + // DETONATING LASHER + SPELL_DETONATE_10 = 62598, + SPELL_DETONATE_25 = 62937, + SPELL_FLAME_LASH = 62608, + + // ACHIEVEMENT + SPELL_DEFORESTATION_CREDIT = 65015, +}; + +#define SPELL_GROUND_TREMOR RAID_MODE(SPELL_GROUND_TREMOR_10, SPELL_GROUND_TREMOR_25) +#define SPELL_PETRIFIED_BARK RAID_MODE(SPELL_PETRIFIED_BARK_10, SPELL_PETRIFIED_BARK_25) +#define SPELL_IRON_ROOTS RAID_MODE(SPELL_IRON_ROOTS_10, SPELL_IRON_ROOTS_25) +#define SPELL_IMPALE RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25) +#define SPELL_THORN_SWARM RAID_MODE(SPELL_THORN_SWARM_10, SPELL_THORN_SWARM_25) +#define SPELL_UNSTABLE_SUN_DAMAGE RAID_MODE(SPELL_UNSTABLE_SUN_DAMAGE_10, SPELL_UNSTABLE_SUN_DAMAGE_25) +#define SPELL_SOLAR_FLARE RAID_MODE(SPELL_SOLAR_FLARE_10, SPELL_SOLAR_FLARE_25) +#define SPELL_TOUCH_OF_EONAR RAID_MODE(SPELL_TOUCH_OF_EONAR_10, SPELL_TOUCH_OF_EONAR_25) +#define SPELL_LIFEBINDER_HEAL RAID_MODE(SPELL_LIFEBINDER_HEAL_10, SPELL_LIFEBINDER_HEAL_25) +#define SPELL_TIDAL_WAVE RAID_MODE(SPELL_TIDAL_WAVE_10, SPELL_TIDAL_WAVE_25) +#define SPELL_TIDAL_WAVE_DAMAGE RAID_MODE(SPELL_TIDAL_WAVE_DAMAGE_10, SPELL_TIDAL_WAVE_DAMAGE_25) +#define SPELL_NATURE_FURY RAID_MODE(SPELL_NATURE_FURY_10, SPELL_NATURE_FURY_25) +#define SPELL_HARDENED_BARK RAID_MODE(SPELL_HARDENED_BARK_10, SPELL_HARDENED_BARK_25) +#define SPELL_DETONATE RAID_MODE(SPELL_DETONATE_10, SPELL_DETONATE_25) +//#define SPELL_NATURE_BOMB_DAMAGE RAID_MODE(SPELL_NATURE_BOMB_DAMAGE_10, SPELL_NATURE_BOMB_DAMAGE_25) +#define SPELL_SUNBEAM RAID_MODE(SPELL_SUNBEAM_10, SPELL_SUNBEAM_25) +#define SPELL_GROUND_TREMOR_FREYA RAID_MODE(SPELL_GROUND_TREMOR_FREYA_10, SPELL_GROUND_TREMOR_FREYA_25) +#define SPELL_IRON_ROOTS_FREYA RAID_MODE(SPELL_IRON_ROOTS_FREYA_10, SPELL_IRON_ROOTS_FREYA_25) +#define SPELL_UNSTABLE_SUN_FREYA_DAMAGE RAID_MODE(SPELL_UNSTABLE_SUN_FREYA_DAMAGE_10, SPELL_UNSTABLE_SUN_FREYA_DAMAGE_25) +#define SPELL_LIGHTNING_LASH RAID_MODE(SPELL_LIGHTNING_LASH_10, SPELL_LIGHTNING_LASH_25) +#define SPELL_STORMBOLT RAID_MODE(SPELL_STORMBOLT_10, SPELL_STORMBOLT_25) + +enum FreyaEvents +{ + // FREYA + EVENT_FREYA_ADDS_SPAM = 1, + EVENT_FREYA_LIFEBINDER = 2, + EVENT_FREYA_NATURE_BOMB = 3, + EVENT_FREYA_SUNBEAM = 4, + EVENT_FREYA_BERSERK = 5, + // HARD MODE + EVENT_FREYA_GROUND_TREMOR = 6, + EVENT_FREYA_IRON_ROOT = 7, + EVENT_FREYA_UNSTABLE_SUN_BEAM = 8, + EVENT_FREYA_RESPAWN_TRIO = 9, + + // STONEBARK + EVENT_STONEBARK_FISTS_OF_STONE = 10, + EVENT_STONEBARK_GROUND_TREMOR = 11, + EVENT_STONEBARK_PETRIFIED_BARK = 12, + + // BRIGHTLEAF + EVENT_BRIGHTLEAF_FLUX = 20, + EVENT_BRIGHTLEAF_SOLAR_FLARE = 21, + EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM = 22, + EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM = 23, + + // IRONBRANCH + EVENT_IRONBRANCH_IMPALE = 30, + EVENT_IRONBRANCH_IRON_ROOT = 31, + EVENT_IRONBRANCH_THORN_SWARM = 32, + + // SUMMONS + EVENT_ANCIENT_CONSERVATOR_NATURE_FURY = 40, + EVENT_ANCIENT_CONSERVATOR_GRIP = 41, + EVENT_WATER_SPIRIT_CHARGE = 45, + EVENT_WATER_SPIRIT_DAMAGE = 46, + EVENT_STORM_LASHER_LIGHTNING_LASH = 50, + EVENT_STORM_LASHER_STORMBOLT = 51, + EVENT_DETONATING_LASHER_FLAME_LASH = 55, +}; + +enum Texts +{ + // Elder Brightleaf / Elder Ironbranch / Elder Stonebark + SAY_ELDER_AGGRO = 0, + SAY_ELDER_SLAY = 1, + SAY_ELDER_DEATH = 2, + + // Freya + SAY_AGGRO = 0, + SAY_AGGRO_WITH_ELDER = 1, + SAY_SLAY = 2, + SAY_DEATH = 3, + SAY_BERSERK = 4, + SAY_SUMMON_CONSERVATOR = 5, + SAY_SUMMON_TRIO = 6, + SAY_SUMMON_LASHERS = 7, + EMOTE_LIFEBINDERS_GIFT = 8, + EMOTE_ALLIES_OF_NATURE = 9, + EMOTE_GROUND_TREMOR = 10, + EMOTE_IRON_ROOTS = 11, +}; + +enum FreyaNPCs +{ + NPC_NATURE_BOMB = 34129, + NPC_IRON_ROOT_TRIGGER = 33088, + NPC_FREYA_UNSTABLE_SUN_BEAM = 33170, + NPC_UNSTABLE_SUN_BRIGHTLEAF = 33050, // 10 SECS? + + // FIRST WAVE + NPC_STORM_LASHER = 32919, + NPC_ANCIENT_WATER_SPIRIT = 33202, + NPC_SNAPLASHER = 32916, + + // SEC WAVE + NPC_ANCIENT_CONSERVATOR = 33203, + NPC_HEALTHY_SPORE = 33215, + + // THIRD WAVE + NPC_DETONATING_LASHER = 32918, +}; + +enum Misc +{ + ACTION_REMOVE_10_STACK = 10, + ACTION_REMOVE_25_STACK = 25, + ACTION_REMOVE_2_STACK = 2, + ACTION_RESPAWN_TRIO = 1, + ACTION_LUMBERJACKED = -1, + + EVENT_PHASE_ADDS = 1, + EVENT_PHASE_FINAL = 2, + + DATA_GET_ELDER_COUNT = 1, + DATA_BACK_TO_NATURE = 2, + + CRITERIA_LUMBERJACKED = 21686, +}; + +class boss_freya : public CreatureScript +{ +public: + boss_freya() : CreatureScript("boss_freya") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_freyaAI : public ScriptedAI + { + boss_freyaAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + { + m_pInstance = pCreature->GetInstanceScript(); + if (!me->IsAlive()) + if (m_pInstance) + m_pInstance->SetData(TYPE_FREYA, DONE); + } + + InstanceScript* m_pInstance; + EventMap events; + SummonList summons; + + uint8 _waveNumber; + uint8 _trioKilled; + uint8 _spawnedAmount; + uint8 _lumberjacked; + bool _respawningTrio; + bool _backToNature; + uint8 _deforestation; + + ObjectGuid _elderGUID[3]; + + void Reset() override + { + if (m_pInstance && m_pInstance->GetData(TYPE_FREYA) != DONE) + m_pInstance->SetData(TYPE_FREYA, NOT_STARTED); + + events.Reset(); + summons.DespawnAll(); + + for (uint8 i = 0; i < 3; ++i) + { + if (!_elderGUID[i]) + continue; + + if (Creature* elder = ObjectAccessor::GetCreature(*me, _elderGUID[i])) + elder->AI()->EnterEvadeMode(); + + _elderGUID[i].Clear(); + } + + _lumberjacked = 0; + _spawnedAmount = 0; + _trioKilled = 0; + _waveNumber = urand(1, 3); + _respawningTrio = false; + _backToNature = true; + _deforestation = 0; + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2)) + return; + + Talk(SAY_SLAY); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage >= me->GetHealth()) + { + damage = 0; + if (m_pInstance->GetData(TYPE_FREYA) != DONE) + { + Talk(SAY_DEATH); + + me->SetReactState(REACT_PASSIVE); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetFaction(FACTION_FRIENDLY); + me->RemoveAllAuras(); + me->AttackStop(); + events.Reset(); + + summons.DespawnAll(); + events.Reset(); + + uint8 _elderCount = 0; + for (uint8 i = 0; i < 3; ++i) + { + if (!_elderGUID[i]) + continue; + + if (Creature* e = ObjectAccessor::GetCreature(*me, _elderGUID[i])) + e->DespawnOrUnsummon(); + + ++_elderCount; + } + + uint32 chestId = RAID_MODE(GO_FREYA_CHEST, GO_FREYA_CHEST_HERO); + chestId -= 2 * _elderCount; // offset + + me->DespawnOrUnsummon(5000); + if (GameObject* go = me->SummonGameObject(chestId, 2345.61f, -71.20f, 425.104f, 3.0f, 0, 0, 0, 0, 0)) + { + go->ReplaceAllGameObjectFlags((GameObjectFlags)0); + go->SetLootRecipient(me->GetMap()); + } + + // Defeat credit + if (m_pInstance) + { + me->CastSpell(me, 65074, true); // credit + m_pInstance->SetData(TYPE_FREYA, DONE); + } + } + } + } + + void JustSummoned(Creature* cr) override + { + if (cr->GetEntry() == NPC_FREYA_UNSTABLE_SUN_BEAM) + { + cr->CastSpell(cr, SPELL_UNSTABLE_SUN_VISUAL, true); + cr->CastSpell(cr, SPELL_UNSTABLE_SUN_FREYA_DAMAGE, true); + } + summons.Summon(cr); + } + + void SpawnWave() + { + _waveNumber = _waveNumber == 1 ? 3 : _waveNumber - 1; + Talk(EMOTE_ALLIES_OF_NATURE); + + // Wave of three + if (_waveNumber == 1) + { + Talk(SAY_SUMMON_TRIO); + me->SummonCreature(NPC_ANCIENT_WATER_SPIRIT, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ())); + me->SummonCreature(NPC_STORM_LASHER, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ())); + me->SummonCreature(NPC_SNAPLASHER, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ())); + } + // Ancient Conservator + else if (_waveNumber == 2) + { + Talk(SAY_SUMMON_CONSERVATOR); + me->SummonCreature(NPC_ANCIENT_CONSERVATOR, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_CORPSE_DESPAWN); + } + // Detonating Lashers + else if (_waveNumber == 3) + { + Talk(SAY_SUMMON_LASHERS); + for (uint8 i = 0; i < 10; ++i) + me->SummonCreature(NPC_DETONATING_LASHER, me->GetPositionX() + urand(5, 20), me->GetPositionY() + urand(5, 20), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_CORPSE_DESPAWN); + } + } + + void DoAction(int32 param) override + { + if (param == ACTION_LUMBERJACKED) + { + if (!m_pInstance) + return; + + ++_lumberjacked; + if (_lumberjacked == 1) + m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_LUMBERJACKED); + else if (_lumberjacked == 3) + m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 65296 /*SPELL_LUMBERJACKED*/, 0, me); + return; + } + + if (param == ACTION_RESPAWN_TRIO) + { + if (!_respawningTrio) + { + _respawningTrio = true; + events.ScheduleEvent(EVENT_FREYA_RESPAWN_TRIO, 10s); + } + + ++_trioKilled; + return; + } + + // Deforestation Achievement Counter + if (param == ACTION_REMOVE_10_STACK) + { + ++_deforestation; + if (_deforestation >= 6 && m_pInstance) + m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_DEFORESTATION_CREDIT, 0, me); + // do not return + } + + if (Aura* aur = me->GetAura(SPELL_ATTUNED_TO_NATURE)) + { + // Back to Nature achievement + if (aur->GetStackAmount() - param < 25) + _backToNature = false; + + if (aur->GetStackAmount() > param) + aur->SetStackAmount(aur->GetStackAmount() - param); + else // Aura out of stack + { + events.ScheduleEvent(EVENT_FREYA_NATURE_BOMB, 5s); + events.SetPhase(EVENT_PHASE_FINAL); + aur->Remove(); + return; + } + } + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_GET_ELDER_COUNT) + { + uint8 _count = 0; + for (uint8 i = 0; i < 3; ++i) + if (_elderGUID[i]) + ++_count; + + return _count; + } + if (param == DATA_BACK_TO_NATURE) + return _backToNature; + + return 0; + } + + void JustReachedHome() override { me->setActive(false); } + + void JustEngagedWith(Unit*) override + { + me->setActive(true); + me->SetInCombatWithZone(); + me->CastSpell(me, SPELL_TOUCH_OF_EONAR, true); + if (Aura* aur = me->AddAura(SPELL_ATTUNED_TO_NATURE, me)) + aur->SetStackAmount(150); + + events.ScheduleEvent(EVENT_FREYA_ADDS_SPAM, 10s, 0, EVENT_PHASE_ADDS); + events.ScheduleEvent(EVENT_FREYA_LIFEBINDER, 30s); + events.ScheduleEvent(EVENT_FREYA_SUNBEAM, 17s); + events.ScheduleEvent(EVENT_FREYA_BERSERK, 10min); + events.SetPhase(EVENT_PHASE_ADDS); + + if( !m_pInstance ) + return; + + if (m_pInstance->GetData(TYPE_FREYA) != DONE) + m_pInstance->SetData(TYPE_FREYA, IN_PROGRESS); + + // HARD MODE CHECKS + Creature* elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_STONEBARK)); + if (elder && elder->IsAlive()) + { + elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true); + elder->CastSpell(elder, SPELL_STONEBARK_ESSENCE, true); + elder->SetInCombatWithZone(); + + events.ScheduleEvent(EVENT_FREYA_GROUND_TREMOR, 35s); + _elderGUID[0] = elder->GetGUID(); + } + + elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_IRONBRANCH)); + if (elder && elder->IsAlive()) + { + elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true); + elder->CastSpell(elder, SPELL_IRONBRANCH_ESSENCE, true); + elder->SetInCombatWithZone(); + + events.ScheduleEvent(EVENT_FREYA_IRON_ROOT, 20s); + _elderGUID[1] = elder->GetGUID(); + } + + elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_BRIGHTLEAF)); + if (elder && elder->IsAlive()) + { + elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true); + elder->CastSpell(elder, SPELL_BRIGHTLEAF_ESSENCE, true); + elder->SetInCombatWithZone(); + + events.ScheduleEvent(EVENT_FREYA_UNSTABLE_SUN_BEAM, 1min); + _elderGUID[2] = elder->GetGUID(); + } + + if (_elderGUID[0] || _elderGUID[1] || _elderGUID[2]) + { + Talk(SAY_AGGRO_WITH_ELDER); + } + else + { + Talk(SAY_AGGRO); + } + } + + void SpellHitTarget(Unit* target, SpellInfo const* spell) override + { + if (spell->Id == SPELL_NATURE_BOMB_FLIGHT) + me->SummonCreature(NPC_NATURE_BOMB, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_FREYA_ADDS_SPAM: + if (_spawnedAmount < 6) + SpawnWave(); + else if (me->GetAura(SPELL_ATTUNED_TO_NATURE)) + { + me->RemoveAura(SPELL_ATTUNED_TO_NATURE); + events.ScheduleEvent(EVENT_FREYA_NATURE_BOMB, 5s); + events.SetPhase(EVENT_PHASE_FINAL); + return; + } + _spawnedAmount++; + events.Repeat(1min); + break; + case EVENT_FREYA_LIFEBINDER: + { + Talk(EMOTE_LIFEBINDERS_GIFT); + events.Repeat(45s); + float x, y, z; + for (uint8 i = 0; i < 10; ++i) + { + x = me->GetPositionX() + urand(7, 25); + y = me->GetPositionY() + urand(7, 25); + z = me->GetMapHeight(x, y, me->GetPositionZ()); + if (me->IsWithinLOS(x, y, z)) + { + me->CastSpell(x, y, z, SPELL_SUMMON_LIFEBINDER, true); + return; + } + } + + me->CastSpell(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), SPELL_SUMMON_LIFEBINDER, true); + break; + } + case EVENT_FREYA_SUNBEAM: + if (Unit* target = SelectTarget(SelectTargetMethod::Random)) + me->CastSpell(target, SPELL_SUNBEAM, false); + events.Repeat(15s, 20s); + break; + case EVENT_FREYA_RESPAWN_TRIO: + _deforestation = 0; + _respawningTrio = false; + if (_trioKilled < 3) + summons.DoAction(ACTION_RESPAWN_TRIO); + + _trioKilled = 0; + break; + case EVENT_FREYA_NATURE_BOMB: + { + uint8 _minCount = me->GetMap()->Is25ManRaid() ? urand(7, 10) : urand(3, 4); + Map::PlayerList const& pList = me->GetMap()->GetPlayers(); + for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) + { + if (me->GetDistance(itr->GetSource()) > 70 || !itr->GetSource()->IsAlive()) + continue; + + me->CastSpell(itr->GetSource(), SPELL_NATURE_BOMB_FLIGHT, true); + + if (!(--_minCount)) + break; + } + events.Repeat(18s); + break; + } + case EVENT_FREYA_BERSERK: + Talk(SAY_BERSERK); + me->CastSpell(me, SPELL_BERSERK, true); + break; + case EVENT_FREYA_GROUND_TREMOR: + Talk(EMOTE_GROUND_TREMOR); + me->CastSpell(me, SPELL_GROUND_TREMOR_FREYA, false); + events.Repeat(25s, 35s); + break; + case EVENT_FREYA_IRON_ROOT: + Talk(EMOTE_IRON_ROOTS); + me->CastCustomSpell(SPELL_IRON_ROOTS_FREYA, SPELLVALUE_MAX_TARGETS, 1, me, false); + events.Repeat(45s, 55s); + break; + case EVENT_FREYA_UNSTABLE_SUN_BEAM: + me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); + if (Is25ManRaid()) + { + me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); + me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); + } + events.Repeat(38s, 48s); + break; + } + + DoMeleeAttackIfReady(); + } + + bool CheckEvadeIfOutOfCombatArea() const override + { + return me->GetPositionX() < 2135.0f; + } + }; +}; + +class boss_freya_elder_stonebark : public CreatureScript +{ +public: + boss_freya_elder_stonebark() : CreatureScript("boss_freya_elder_stonebark") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_freya_elder_stonebarkAI : public ScriptedAI + { + boss_freya_elder_stonebarkAI(Creature* pCreature) : ScriptedAI(pCreature) + { + } + + EventMap events; + uint8 _chargesCount; + + void Reset() override + { + events.Reset(); + _chargesCount = 0; + } + + void KilledUnit(Unit*) override + { + if (urand(0, 1)) + return; + + Talk(SAY_ELDER_SLAY); + } + + void JustDied(Unit* killer) override + { + if (killer && me->GetEntry() == killer->GetEntry()) + return; + Talk(SAY_ELDER_DEATH); + + // Lumberjacked + if (me->GetInstanceScript()) + if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA))) + freya->AI()->DoAction(ACTION_LUMBERJACKED); + } + + void JustEngagedWith(Unit*) override + { + events.ScheduleEvent(EVENT_STONEBARK_FISTS_OF_STONE, 40s); + events.ScheduleEvent(EVENT_STONEBARK_GROUND_TREMOR, 5s); + events.ScheduleEvent(EVENT_STONEBARK_PETRIFIED_BARK, 20s); + + if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation + Talk(SAY_ELDER_AGGRO); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType damageType, SpellSchoolMask damageSchoolMask) override + { + if ((damageType == DIRECT_DAMAGE || (damageType == SPELL_DIRECT_DAMAGE && damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)) && _chargesCount) + { + --_chargesCount; + damage = 0; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_STONEBARK_FISTS_OF_STONE: + me->CastSpell(me, SPELL_FISTS_OF_STONE, false); + events.Repeat(1min); + break; + case EVENT_STONEBARK_GROUND_TREMOR: + if (!me->HasAura(SPELL_FISTS_OF_STONE)) + me->CastSpell(me, SPELL_GROUND_TREMOR, false); + events.Repeat(20s); + break; + case EVENT_STONEBARK_PETRIFIED_BARK: + _chargesCount = RAID_MODE(60, 120); + me->CastSpell(me, SPELL_PETRIFIED_BARK, false); + events.Repeat(30s); + break; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_freya_elder_brightleaf : public CreatureScript +{ +public: + boss_freya_elder_brightleaf() : CreatureScript("boss_freya_elder_brightleaf") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_freya_elder_brightleafAI : public ScriptedAI + { + boss_freya_elder_brightleafAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) + { + } + + EventMap events; + SummonList summons; + + void Reset() override + { + events.Reset(); + summons.DespawnAll(); + } + + void KilledUnit(Unit*) override + { + if (urand(0, 1)) + return; + + Talk(SAY_ELDER_SLAY); + } + + void JustDied(Unit* killer) override + { + if (killer && me->GetEntry() == killer->GetEntry()) + return; + Talk(SAY_ELDER_DEATH); + + // Lumberjacked + if (me->GetInstanceScript()) + if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA))) + freya->AI()->DoAction(ACTION_LUMBERJACKED); + } + + void JustEngagedWith(Unit*) override + { + events.ScheduleEvent(EVENT_BRIGHTLEAF_FLUX, 10s); + events.ScheduleEvent(EVENT_BRIGHTLEAF_SOLAR_FLARE, 5s); + events.ScheduleEvent(EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM, 8s); + + if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation + Talk(SAY_ELDER_AGGRO); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_BRIGHTLEAF_FLUX: + if (Aura* aur = me->AddAura(SPELL_BRIGHTLEAF_FLUX, me)) + aur->SetStackAmount(urand(1, 10)); + events.Repeat(10s); + break; + case EVENT_BRIGHTLEAF_SOLAR_FLARE: + if (Aura* aur = me->GetAura(SPELL_BRIGHTLEAF_FLUX)) + { + me->CastCustomSpell(SPELL_SOLAR_FLARE, SPELLVALUE_MAX_TARGETS, aur->GetStackAmount(), me, false); + me->RemoveAura(aur); + } + events.Repeat(15s); + break; + case EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM: + events.ScheduleEvent(EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM, 15s); + if (Creature* beam = me->SummonCreature(NPC_UNSTABLE_SUN_BRIGHTLEAF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ())) + { + beam->CastSpell(beam, SPELL_UNSTABLE_SUN_BEAM_AURA, true); + beam->CastSpell(beam, SPELL_PHOTOSYNTHESIS, true); + summons.Summon(beam); + } + if (Creature* beam = me->SummonCreature(NPC_UNSTABLE_SUN_BRIGHTLEAF, me->GetPositionX() + 8, me->GetPositionY() + 8, me->GetPositionZ())) + { + beam->CastSpell(beam, SPELL_UNSTABLE_SUN_BEAM_AURA, true); + beam->CastSpell(beam, SPELL_PHOTOSYNTHESIS, true); + summons.Summon(beam); + } + events.Repeat(20s); + break; + case EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM: + for (SummonList::iterator i = summons.begin(); i != summons.end();) + { + Creature* summon = ObjectAccessor::GetCreature(*me, *i); + ++i; + if (summon) + summon->CastSpell(summon, SPELL_UNSTABLE_SUN_DAMAGE, false); + } + + summons.DespawnAll(); + break; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_freya_elder_ironbranch : public CreatureScript +{ +public: + boss_freya_elder_ironbranch() : CreatureScript("boss_freya_elder_ironbranch") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_freya_elder_ironbranchAI : public ScriptedAI + { + boss_freya_elder_ironbranchAI(Creature* pCreature) : ScriptedAI(pCreature) + { + } + + EventMap events; + + void Reset() override + { + events.Reset(); + } + + void KilledUnit(Unit*) override + { + if (urand(0, 1)) + return; + + Talk(SAY_ELDER_SLAY); + } + + void JustDied(Unit* killer) override + { + if (killer && me->GetEntry() == killer->GetEntry()) + return; + Talk(SAY_ELDER_DEATH); + + // Lumberjacked + if (me->GetInstanceScript()) + if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA))) + freya->AI()->DoAction(ACTION_LUMBERJACKED); + } + + void JustEngagedWith(Unit*) override + { + events.ScheduleEvent(EVENT_IRONBRANCH_IMPALE, 10s); + events.ScheduleEvent(EVENT_IRONBRANCH_IRON_ROOT, 15s); + events.ScheduleEvent(EVENT_IRONBRANCH_THORN_SWARM, 3s); + + if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation + Talk(SAY_ELDER_AGGRO); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_IRONBRANCH_IMPALE: + me->CastSpell(me->GetVictim(), SPELL_IMPALE, false); + events.Repeat(17s); + break; + case EVENT_IRONBRANCH_IRON_ROOT: + me->CastCustomSpell(SPELL_IRON_ROOTS, SPELLVALUE_MAX_TARGETS, 1, me, false); + events.Repeat(20s); + break; + case EVENT_IRONBRANCH_THORN_SWARM: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_THORN_SWARM, false); + events.Repeat(14s); + break; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_freya_iron_root : public CreatureScript +{ +public: + boss_freya_iron_root() : CreatureScript("boss_freya_iron_root") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_freya_iron_rootAI : public NullCreatureAI + { + boss_freya_iron_rootAI(Creature* pCreature) : NullCreatureAI(pCreature) { } + + void JustDied(Unit* /*killer*/) override + { + if (!me->IsSummon()) + return; + + if (Unit* target = ObjectAccessor::GetUnit(*me, me->ToTempSummon()->GetSummonerGUID())) + { + if (me->GetEntry() == NPC_IRON_ROOT_TRIGGER) // Iron Branch spell + target->RemoveAura(target->GetMap()->Is25ManRaid() ? SPELL_IRON_ROOTS_DAMAGE_25 : SPELL_IRON_ROOTS_DAMAGE_10); + else + target->RemoveAura(target->GetMap()->Is25ManRaid() ? SPELL_IRON_ROOTS_FREYA_DAMAGE_25 : SPELL_IRON_ROOTS_FREYA_DAMAGE_10); + } + } + }; +}; + +class boss_freya_lifebinder : public CreatureScript +{ +public: + boss_freya_lifebinder() : CreatureScript("boss_freya_lifebinder") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_freya_lifebinderAI : public NullCreatureAI + { + boss_freya_lifebinderAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + } + + uint32 _healTimer; + + void Reset() override + { + me->CastSpell(me, SPELL_LIFEBINDER_VISUAL, true); + me->CastSpell(me, SPELL_LIFEBINDER_PHERONOMES, true); + me->CastSpell(me, SPELL_AUTO_GROW, true); + _healTimer = 0; + } + + void UpdateAI(uint32 diff) override + { + _healTimer += diff; + if (_healTimer >= 12000) + { + me->RemoveAurasDueToSpell(SPELL_AUTO_GROW); + me->CastSpell(me, me->GetMap()->Is25ManRaid() ? SPELL_LIFEBINDER_HEAL_25 : SPELL_LIFEBINDER_HEAL_10, true); + me->DespawnOrUnsummon(2000); + _healTimer = 0; + } + } + }; +}; + +class boss_freya_healthy_spore : public CreatureScript +{ +public: + boss_freya_healthy_spore() : CreatureScript("boss_freya_healthy_spore") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_freya_healthy_sporeAI : public NullCreatureAI + { + boss_freya_healthy_sporeAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + } + + uint32 _despawnTimer; + + void Reset() override + { + me->CastSpell(me, SPELL_POTENT_PHEROMONES, true); + me->CastSpell(me, SPELL_HEALTHY_SPORE_VISUAL, true); + me->CastSpell(me, SPELL_AUTO_GROW, true); + _despawnTimer = 0; + } + + void UpdateAI(uint32 diff) override + { + _despawnTimer += diff; + if (_despawnTimer >= 22000) + { + me->RemoveAurasDueToSpell(SPELL_AUTO_GROW); + me->DespawnOrUnsummon(2200); + _despawnTimer = 0; + } + } + }; +}; + +class boss_freya_summons : public CreatureScript +{ +public: + boss_freya_summons() : CreatureScript("boss_freya_summons") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_freya_summonsAI : public ScriptedAI + { + boss_freya_summonsAI(Creature* pCreature) : ScriptedAI(pCreature) + { + _freyaGUID = me->GetInstanceScript() ? me->GetInstanceScript()->GetGuidData(TYPE_FREYA) : ObjectGuid::Empty; + _isTrio = me->GetEntry() == NPC_ANCIENT_WATER_SPIRIT || me->GetEntry() == NPC_STORM_LASHER || me->GetEntry() == NPC_SNAPLASHER; + _hasDied = false; + } + + EventMap events; + ObjectGuid _freyaGUID; + uint8 _stackCount; + bool _hasDied; + bool _isTrio; + + void Reset() override + { + _stackCount = 0; + events.Reset(); + if (Unit* target = SelectTargetFromPlayerList(70)) + AttackStart(target); + } + + void JustDied(Unit* /*killer*/) override + { + if (Creature* freya = ObjectAccessor::GetCreature(*me, _freyaGUID)) + { + if (!_hasDied) + freya->AI()->DoAction(_stackCount); + + if (_isTrio) + { + freya->AI()->DoAction(ACTION_RESPAWN_TRIO); + _hasDied = true; + } + } + if (me->GetEntry() == NPC_DETONATING_LASHER) + me->CastSpell(me, SPELL_DETONATE, true); + } + + void DoAction(int32 param) override + { + if (_isTrio && param == ACTION_RESPAWN_TRIO) + { + me->setDeathState(DeathState::JustRespawned); + Reset(); + } + } + + void JustEngagedWith(Unit*) override + { + if (me->GetEntry() == NPC_ANCIENT_CONSERVATOR) + { + me->CastSpell(me, SPELL_HEALTHY_SPORE_SUMMON, true); + events.ScheduleEvent(EVENT_ANCIENT_CONSERVATOR_GRIP, 6s); + events.ScheduleEvent(EVENT_ANCIENT_CONSERVATOR_NATURE_FURY, 14s); + _stackCount = ACTION_REMOVE_25_STACK; + } + else if (me->GetEntry() == NPC_ANCIENT_WATER_SPIRIT) + { + events.ScheduleEvent(EVENT_WATER_SPIRIT_CHARGE, 12s); + _stackCount = ACTION_REMOVE_10_STACK; + } + else if (me->GetEntry() == NPC_STORM_LASHER) + { + events.ScheduleEvent(EVENT_STORM_LASHER_LIGHTNING_LASH, 10s); + events.ScheduleEvent(EVENT_STORM_LASHER_STORMBOLT, 6s); + _stackCount = ACTION_REMOVE_10_STACK; + } + else if (me->GetEntry() == NPC_DETONATING_LASHER) + { + events.ScheduleEvent(EVENT_DETONATING_LASHER_FLAME_LASH, 10s); + _stackCount = ACTION_REMOVE_2_STACK; + } + else if (me->GetEntry() == NPC_SNAPLASHER) + { + me->CastSpell(me, SPELL_HARDENED_BARK, true); + _stackCount = ACTION_REMOVE_10_STACK; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_ANCIENT_CONSERVATOR_NATURE_FURY: + me->CastSpell(me->GetVictim(), SPELL_NATURE_FURY, false); + events.Repeat(14s); + break; + case EVENT_ANCIENT_CONSERVATOR_GRIP: + me->CastSpell(me, SPELL_CONSERVATOR_GRIP, true); + break; + case EVENT_WATER_SPIRIT_CHARGE: + me->CastSpell(me, SPELL_TIDAL_WAVE_AURA, true); + me->CastSpell(me->GetVictim(), SPELL_TIDAL_WAVE, false); + events.Repeat(12s); + events.ScheduleEvent(EVENT_WATER_SPIRIT_DAMAGE, 3s); + break; + case EVENT_WATER_SPIRIT_DAMAGE: + me->CastSpell(me, SPELL_TIDAL_WAVE_DAMAGE, false); + break; + case EVENT_STORM_LASHER_LIGHTNING_LASH: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_LIGHTNING_LASH, false); + events.Repeat(10s); + break; + case EVENT_STORM_LASHER_STORMBOLT: + me->CastSpell(me->GetVictim(), SPELL_STORMBOLT, false); + events.Repeat(6s); + break; + case EVENT_DETONATING_LASHER_FLAME_LASH: + me->CastSpell(me->GetVictim(), SPELL_FLAME_LASH, false); + DoResetThreatList(); + if (Unit* target = SelectTargetFromPlayerList(80)) + AttackStart(target); + else + me->DespawnOrUnsummon(1); + events.Repeat(10s); + break; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_freya_nature_bomb : public CreatureScript +{ +public: + boss_freya_nature_bomb() : CreatureScript("boss_freya_nature_bomb") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_freya_nature_bombAI : public NullCreatureAI + { + boss_freya_nature_bombAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + _goGUID.Clear(); + } + + ObjectGuid _goGUID; + uint32 _explodeTimer; + + void Reset() override + { + me->SetObjectScale(0.5f); + me->CastSpell(me, SPELL_GREEN_BANISH_STATE, true); + + _explodeTimer = 0; + if (GameObject* go = me->SummonGameObject(194902 /*GO_NATURE_BOMB*/, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, 0, 0, 0, 0, 0)) + _goGUID = go->GetGUID(); + } + + uint32 Timer; + void UpdateAI(uint32 diff) override + { + _explodeTimer += diff; + if (_explodeTimer >= 11000) + { + me->CastSpell(me, me->GetMap()->Is25ManRaid() ? SPELL_NATURE_BOMB_DAMAGE_25 : SPELL_NATURE_BOMB_DAMAGE_10, false); + me->DespawnOrUnsummon(1000); + _explodeTimer = 0; + } + + // Delay explosion a little, visual + if (_explodeTimer >= 5000 && _explodeTimer < 10000) + { + _explodeTimer = 10000; + if (GameObject* go = me->GetMap()->GetGameObject(_goGUID)) + go->SetGoState(GO_STATE_ACTIVE); + } + } + }; +}; + +class achievement_freya_getting_back_to_nature : public AchievementCriteriaScript +{ +public: + achievement_freya_getting_back_to_nature() : AchievementCriteriaScript("achievement_freya_getting_back_to_nature") {} + + bool OnCheck(Player* /*player*/, Unit* target /*Freya*/, uint32 /*criteria_id*/) override + { + if (target) + if (target->GetAI()->GetData(DATA_BACK_TO_NATURE)) + return true; + return false; + } +}; + +class achievement_freya_knock_on_wood : public AchievementCriteriaScript +{ +public: + achievement_freya_knock_on_wood(char const* name, uint32 count) : AchievementCriteriaScript(name), + _elderCount(count) + { + } + + bool OnCheck(Player* /*player*/, Unit* target /*Freya*/, uint32 /*criteria_id*/) override + { + return target && _elderCount <= target->GetAI()->GetData(DATA_GET_ELDER_COUNT); + } + +private: + uint32 const _elderCount; +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp index 2fa09a60471447..d4df0803222b21 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_general_vezax.h" #include "AccountMgr.h" #include "AchievementCriteriaScript.h" #include "BanMgr.h" @@ -28,665 +29,6 @@ #include "WorldSession.h" #include "ulduar.h" -enum VezaxSpellData -{ - SPELL_VEZAX_BERSERK = 26662, - - SPELL_VEZAX_SHADOW_CRASH = 62660, - SPELL_VEZAX_SHADOW_CRASH_DMG = 62659, - SPELL_VEZAX_SHADOW_CRASH_AREA_AURA = 63277, - SPELL_VEZAX_SHADOW_CRASH_AURA = 65269, - - SPELL_SEARING_FLAMES = 62661, - - SPELL_SURGE_OF_DARKNESS = 62662, - - SPELL_MARK_OF_THE_FACELESS_AURA = 63276, - SPELL_MARK_OF_THE_FACELESS_EFFECT = 63278, - - SPELL_AURA_OF_DESPAIR_1 = 62692, - SPELL_AURA_OF_DESPAIR_2 = 64848, - SPELL_CORRUPTED_RAGE = 68415, - SPELL_CORRUPTED_WISDOM = 64646, - SPELL_SHAMANISTIC_RAGE = 30823, - SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 = 31876, - - SPELL_SUMMON_SARONITE_VAPORS = 63081, - NPC_SARONITE_VAPORS = 33488, - SPELL_SARONITE_VAPORS_DMG = 63338, - SPELL_SARONITE_VAPORS_ENERGIZE = 63337, - SPELL_SARONITE_VAPORS_AURA = 63323, - SPELL_SARONITE_VAPORS_DUMMYAURA = 63322, - - SPELL_SARONITE_ANIMUS_FORMATION_VISUAL = 63319, - SPELL_SUMMON_SARONITE_ANIMUS = 63145, - SPELL_SARONITE_BARRIER = 63364, - SPELL_PROFOUND_DARKNESS = 63420, -}; - -enum VezaxNpcs -{ - // NPC_VEZAX = 33271, - // NPC_VEZAX_BUNNY = 33500, - NPC_SARONITE_ANIMUS = 33524, -}; - -enum VezaxGOs -{ - // GO_VEZAX_DOOR = 194750, -}; - -enum VezaxEvents -{ - EVENT_SPELL_VEZAX_SHADOW_CRASH = 1, - EVENT_SPELL_SEARING_FLAMES = 2, - EVENT_SPELL_SURGE_OF_DARKNESS = 3, - EVENT_SPELL_MARK_OF_THE_FACELESS = 4, - EVENT_SPELL_SUMMON_SARONITE_VAPORS = 5, - EVENT_SARONITE_VAPORS_SWIRL = 6, - EVENT_SPELL_SUMMON_SARONITE_ANIMUS = 7, - EVENT_DESPAWN_SARONITE_VAPORS = 8, - EVENT_SPELL_PROFOUND_DARKNESS = 9, - EVENT_BERSERK = 10, - EVENT_RESTORE_TARGET = 11, -}; - -enum VezaxText -{ - SAY_AGGRO = 0, - SAY_SLAY = 1, - SAY_SURGE_OF_DARKNESS = 2, - SAY_DEATH = 3, - SAY_BERSERK = 4, - SAY_HARDMODE = 5, - SAY_EMOTE_ANIMUS = 6, - SAY_EMOTE_BARRIER = 7, - SAY_EMOTE_SURGE_OF_DARKNESS = 8, -}; - -enum VaporsText -{ - SAY_EMOTE_VAPORS = 0, -}; - -class boss_vezax : public CreatureScript -{ -public: - boss_vezax() : CreatureScript("boss_vezax") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_vezaxAI : public ScriptedAI - { - boss_vezaxAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) - { - pInstance = pCreature->GetInstanceScript(); - } - - EventMap events; - SummonList summons; - uint8 vaporsCount; - bool hardmodeAvailable; - bool berserk; - bool bAchievShadowdodger; - - InstanceScript* pInstance; - - void Reset() override - { - vaporsCount = 0; - hardmodeAvailable = true; - berserk = false; - bAchievShadowdodger = true; - events.Reset(); - summons.DespawnAll(); - me->SetLootMode(1); - - if (pInstance) - pInstance->SetData(TYPE_VEZAX, NOT_STARTED); - } - - void JustReachedHome() override - { - me->setActive(false); - } - - void JustEngagedWith(Unit* /*pWho*/) override - { - me->setActive(true); - me->SetInCombatWithZone(); - - events.Reset(); - events.RescheduleEvent(EVENT_SPELL_VEZAX_SHADOW_CRASH, 13s); - events.RescheduleEvent(EVENT_SPELL_SEARING_FLAMES, 10s, 1); - events.RescheduleEvent(EVENT_SPELL_SURGE_OF_DARKNESS, 63s); - events.RescheduleEvent(EVENT_SPELL_MARK_OF_THE_FACELESS, 20s); - events.RescheduleEvent(EVENT_SPELL_SUMMON_SARONITE_VAPORS, 30s); - events.RescheduleEvent(EVENT_BERSERK, 10min); - - Talk(SAY_AGGRO); - - if (pInstance) - pInstance->SetData(TYPE_VEZAX, IN_PROGRESS); - - me->CastSpell(me, SPELL_AURA_OF_DESPAIR_1, true); - } - - void DoAction(int32 param) override - { - switch( param ) - { - case 1: - hardmodeAvailable = false; - break; - case 2: - me->RemoveAura(SPELL_SARONITE_BARRIER); - me->SetLootMode(3); - break; - } - } - - uint32 GetData(uint32 id) const override - { - switch (id) - { - case 1: - return (me->GetLootMode() == 3 ? 1 : 0); - case 2: - return (bAchievShadowdodger ? 1 : 0); - } - return 0; - } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) override - { - if (target && spell && target->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_VEZAX_SHADOW_CRASH_DMG) - bAchievShadowdodger = false; - } - - void UpdateAI(uint32 diff) override - { - if( !UpdateVictim() ) - return; - - if( !berserk && (me->GetPositionX() < 1720.0f || me->GetPositionX() > 1940.0f || me->GetPositionY() < 20.0f || me->GetPositionY() > 210.0f) ) - events.RescheduleEvent(EVENT_BERSERK, 1ms); - - events.Update(diff); - - if( me->HasUnitState(UNIT_STATE_CASTING) ) - return; - - switch( events.ExecuteEvent() ) - { - case 0: - break; - case EVENT_BERSERK: - berserk = true; - me->CastSpell(me, SPELL_VEZAX_BERSERK, true); - Talk(SAY_BERSERK); - break; - case EVENT_SPELL_VEZAX_SHADOW_CRASH: - { - events.Repeat(10s); - - std::vector players; - Map::PlayerList const& pl = me->GetMap()->GetPlayers(); - for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) - { - Player* temp = itr->GetSource(); - if( temp->IsAlive() && temp->GetDistance(me) > 15.0f ) - players.push_back(temp); - } - if (!players.empty()) - { - me->setAttackTimer(BASE_ATTACK, 2000); - Player* target = players.at(urand(0, players.size() - 1)); - me->SetGuidValue(UNIT_FIELD_TARGET, target->GetGUID()); - me->CastSpell(target, SPELL_VEZAX_SHADOW_CRASH, false); - events.ScheduleEvent(EVENT_RESTORE_TARGET, 750ms); - } - } - break; - case EVENT_RESTORE_TARGET: - if (me->GetVictim()) - me->SetGuidValue(UNIT_FIELD_TARGET, me->GetVictim()->GetGUID()); - break; - case EVENT_SPELL_SEARING_FLAMES: - if(!me->HasAura(SPELL_SARONITE_BARRIER)) - me->CastSpell(me->GetVictim(), SPELL_SEARING_FLAMES, false); - events.Repeat(me->GetMap()->Is25ManRaid() ? 8s : 15s); - break; - case EVENT_SPELL_SURGE_OF_DARKNESS: - Talk(SAY_SURGE_OF_DARKNESS); - Talk(SAY_EMOTE_SURGE_OF_DARKNESS); - me->CastSpell(me, SPELL_SURGE_OF_DARKNESS, false); - events.Repeat(63s); - events.DelayEvents(10000, 1); - break; - case EVENT_SPELL_MARK_OF_THE_FACELESS: - { - std::vector outside; - std::vector inside; - Map::PlayerList const& pl = me->GetMap()->GetPlayers(); - for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) - if( Player* tmp = itr->GetSource() ) - if( tmp->IsAlive() ) - { - if( tmp->GetDistance(me) > 15.0f ) - outside.push_back(tmp); - else - inside.push_back(tmp); - } - - Player* t = nullptr; - if( outside.size() >= uint8(me->GetMap()->Is25ManRaid() ? 9 : 4) ) - t = outside.at(urand(0, outside.size() - 1)); - else if( !inside.empty() ) - t = inside.at(urand(0, inside.size() - 1)); - - if (t) - me->CastSpell(t, SPELL_MARK_OF_THE_FACELESS_AURA, false); - - events.Repeat(40s); - } - break; - case EVENT_SPELL_SUMMON_SARONITE_VAPORS: - { - vaporsCount++; - me->CastSpell(me, SPELL_SUMMON_SARONITE_VAPORS, false); - - if( vaporsCount < 6 || !hardmodeAvailable ) - events.Repeat(30s); - else - { - for (ObjectGuid const& guid : summons) - if (Creature* sv = ObjectAccessor::GetCreature(*me, guid)) - { - sv->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - sv->GetMotionMaster()->MoveIdle(); - sv->GetMotionMaster()->MoveCharge(1852.78f, 81.38f, 342.461f, 28.0f); - } - - events.DelayEvents(12000, 0); - events.DelayEvents(12000, 1); - events.ScheduleEvent(EVENT_SARONITE_VAPORS_SWIRL, 6s); - } - } - break; - case EVENT_SARONITE_VAPORS_SWIRL: - if (summons.size()) - { - Talk(SAY_EMOTE_ANIMUS); - if( Creature* sv = ObjectAccessor::GetCreature(*me, *(summons.begin())) ) - sv->CastSpell(sv, SPELL_SARONITE_ANIMUS_FORMATION_VISUAL, true); - - events.ScheduleEvent(EVENT_SPELL_SUMMON_SARONITE_ANIMUS, 2s); - break; - } - break; - case EVENT_SPELL_SUMMON_SARONITE_ANIMUS: - if (summons.size()) - { - Talk(SAY_HARDMODE); - Talk(SAY_EMOTE_BARRIER); - me->CastSpell(me, SPELL_SARONITE_BARRIER, true); - if( Creature* sv = ObjectAccessor::GetCreature(*me, *(summons.begin())) ) - sv->CastSpell(sv, SPELL_SUMMON_SARONITE_ANIMUS, true); - - events.ScheduleEvent(EVENT_DESPAWN_SARONITE_VAPORS, 2500ms); - break; - } - break; - case EVENT_DESPAWN_SARONITE_VAPORS: - summons.DespawnEntry(NPC_SARONITE_VAPORS); - break; - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - summons.DespawnAll(); - if (pInstance) - pInstance->SetData(TYPE_VEZAX, DONE); - - Talk(SAY_DEATH); - - if( GameObject* door = me->FindNearestGameObject(GO_VEZAX_DOOR, 500.0f) ) - if( door->GetGoState() != GO_STATE_ACTIVE ) - { - door->SetLootState(GO_READY); - door->UseDoorOrButton(0, false); - } - } - - void KilledUnit(Unit* who) override - { - if( who->GetTypeId() == TYPEID_PLAYER ) - Talk(SAY_SLAY); - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - } - - void SummonedCreatureDespawn(Creature* s) override - { - summons.Despawn(s); - } - }; -}; - -class npc_ulduar_saronite_vapors : public CreatureScript -{ -public: - npc_ulduar_saronite_vapors() : CreatureScript("npc_ulduar_saronite_vapors") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_saronite_vaporsAI : public NullCreatureAI - { - npc_ulduar_saronite_vaporsAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - pInstance = pCreature->GetInstanceScript(); - me->GetMotionMaster()->MoveRandom(4.0f); - } - - InstanceScript* pInstance; - - void JustDied(Unit* /*killer*/) override - { - me->CastSpell(me, SPELL_SARONITE_VAPORS_AURA, true); - - // killed saronite vapors, hard mode unavailable - if( pInstance ) - if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) ) - vezax->AI()->DoAction(1); - } - - void IsSummonedBy(WorldObject* /*summoner*/) override - { - Talk(SAY_EMOTE_VAPORS); - } - }; -}; - -class npc_ulduar_saronite_animus : public CreatureScript -{ -public: - npc_ulduar_saronite_animus() : CreatureScript("npc_ulduar_saronite_animus") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_saronite_animusAI : public ScriptedAI - { - npc_ulduar_saronite_animusAI(Creature* pCreature) : ScriptedAI(pCreature) - { - pInstance = pCreature->GetInstanceScript(); - if( pInstance ) - if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) ) - vezax->AI()->JustSummoned(me); - timer = 0; - me->SetInCombatWithZone(); - } - - InstanceScript* pInstance; - uint16 timer; - - void JustDied(Unit* /*killer*/) override - { - me->DespawnOrUnsummon(3000); - - if( pInstance ) - if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) ) - vezax->AI()->DoAction(2); - } - - void UpdateAI(uint32 diff) override - { - UpdateVictim(); - - timer += diff; - if (timer >= 2000) - { - me->CastSpell(me, SPELL_PROFOUND_DARKNESS, true); - timer -= 2000; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class spell_aura_of_despair : public SpellScriptLoader -{ -public: - spell_aura_of_despair() : SpellScriptLoader("spell_aura_of_despair") { } - - class spell_aura_of_despair_AuraScript : public AuraScript - { - PrepareAuraScript(spell_aura_of_despair_AuraScript) - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* caster = GetCaster()) - if (Unit* target = GetTarget()) - { - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - target->CastSpell(target, SPELL_AURA_OF_DESPAIR_2, true); - if( target->HasSpell(SPELL_SHAMANISTIC_RAGE) ) - caster->CastSpell(target, SPELL_CORRUPTED_RAGE, true); - else if( target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1) || target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 + 1) || target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 + 2) ) - caster->CastSpell(target, SPELL_CORRUPTED_WISDOM, true); - } - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* target = GetTarget()) - { - target->RemoveAurasDueToSpell(SPELL_AURA_OF_DESPAIR_2); - target->RemoveAurasDueToSpell(SPELL_CORRUPTED_RAGE); - target->RemoveAurasDueToSpell(SPELL_CORRUPTED_WISDOM); - } - } - - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_aura_of_despair_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PREVENT_REGENERATE_POWER, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_aura_of_despair_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PREVENT_REGENERATE_POWER, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_aura_of_despair_AuraScript(); - } -}; - -class spell_mark_of_the_faceless_periodic : public SpellScriptLoader -{ -public: - spell_mark_of_the_faceless_periodic() : SpellScriptLoader("spell_mark_of_the_faceless_periodic") { } - - class spell_mark_of_the_faceless_periodic_AuraScript : public AuraScript - { - PrepareAuraScript(spell_mark_of_the_faceless_periodic_AuraScript) - - void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) - { - if (Unit* caster = GetCaster()) - if (Unit* target = GetTarget()) - if (target->GetMapId() == 603) - { - int32 dmg = 5000; - caster->CastCustomSpell(target, SPELL_MARK_OF_THE_FACELESS_EFFECT, 0, &dmg, 0, true); - } - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_mark_of_the_faceless_periodic_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_mark_of_the_faceless_periodic_AuraScript(); - } -}; - -class spell_mark_of_the_faceless_drainhealth : public SpellScriptLoader -{ -public: - spell_mark_of_the_faceless_drainhealth() : SpellScriptLoader("spell_mark_of_the_faceless_drainhealth") { } - - class spell_mark_of_the_faceless_drainhealth_SpellScript : public SpellScript - { - PrepareSpellScript(spell_mark_of_the_faceless_drainhealth_SpellScript); - - void FilterTargets(std::list& targets) - { - targets.remove(GetExplTargetUnit()); - if (targets.empty()) - Cancel(); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mark_of_the_faceless_drainhealth_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_DEST_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_mark_of_the_faceless_drainhealth_SpellScript(); - } -}; - -class spell_saronite_vapors_dummy : public SpellScriptLoader -{ -public: - spell_saronite_vapors_dummy() : SpellScriptLoader("spell_saronite_vapors_dummy") { } - - class spell_saronite_vapors_dummy_AuraScript : public AuraScript - { - PrepareAuraScript(spell_saronite_vapors_dummy_AuraScript) - - void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* caster = GetCaster()) - { - int32 damage = 100 * pow(2.0f, (float)GetStackAmount()); - caster->CastCustomSpell(GetTarget(), SPELL_SARONITE_VAPORS_DMG, &damage, nullptr, nullptr, true); - } - } - - void Register() override - { - AfterEffectApply += AuraEffectApplyFn(spell_saronite_vapors_dummy_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_saronite_vapors_dummy_AuraScript(); - } -}; - -class spell_saronite_vapors_damage : public SpellScriptLoader -{ -public: - spell_saronite_vapors_damage() : SpellScriptLoader("spell_saronite_vapors_damage") { } - - class spell_saronite_vapors_damage_SpellScript : public SpellScript - { - PrepareSpellScript(spell_saronite_vapors_damage_SpellScript); - - void HandleAfterHit() - { - if (Unit* caster = GetCaster()) - if (GetHitDamage() > 2) - { - int32 mana = GetHitDamage() / 2; - if (Unit* t = GetHitUnit()) - caster->CastCustomSpell(t, SPELL_SARONITE_VAPORS_ENERGIZE, &mana, nullptr, nullptr, true); - } - } - - void Register() override - { - AfterHit += SpellHitFn(spell_saronite_vapors_damage_SpellScript::HandleAfterHit); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_saronite_vapors_damage_SpellScript(); - } -}; - -class achievement_smell_saronite : public AchievementCriteriaScript -{ -public: - achievement_smell_saronite() : AchievementCriteriaScript("achievement_smell_saronite") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_VEZAX && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1); - } -}; - -class achievement_shadowdodger : public AchievementCriteriaScript -{ -public: - achievement_shadowdodger() : AchievementCriteriaScript("achievement_shadowdodger") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_VEZAX && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(2); - } -}; - -class go_ulduar_pure_saronite_deposit : public GameObjectScript -{ -public: - go_ulduar_pure_saronite_deposit() : GameObjectScript("go_ulduar_pure_saronite_deposit") { } - - bool OnGossipHello(Player* plr, GameObject* go) override - { - if (plr->IsGameMaster()) - return false; - - if (InstanceScript* pInstance = go->GetInstanceScript()) - if (pInstance->GetData(TYPE_XT002) != DONE && pInstance->GetData(TYPE_MIMIRON) != DONE && pInstance->GetData(TYPE_THORIM) != DONE && pInstance->GetData(TYPE_FREYA) != DONE && pInstance->GetData(TYPE_HODIR) != DONE) - { - std::string accountName; - AccountMgr::GetName(plr->GetSession()->GetAccountId(), accountName); - sBan->BanAccount(accountName, "0s", "Tele hack", "Server"); - return true; - } - - return false; - } -}; - void AddSC_boss_vezax() { new boss_vezax(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.h new file mode 100644 index 00000000000000..a3495ef648c45f --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.h @@ -0,0 +1,676 @@ +#ifndef BOSS_GENERAL_VEZAX_H_ +#define BOSS_GENERAL_VEZAX_H_ + +#include "AccountMgr.h" +#include "AchievementCriteriaScript.h" +#include "BanMgr.h" +#include "CreatureScript.h" +#include "GameObjectScript.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "WorldSession.h" +#include "ulduar.h" + +enum VezaxSpellData +{ + SPELL_VEZAX_BERSERK = 26662, + + SPELL_VEZAX_SHADOW_CRASH = 62660, + SPELL_VEZAX_SHADOW_CRASH_DMG = 62659, + SPELL_VEZAX_SHADOW_CRASH_AREA_AURA = 63277, + SPELL_VEZAX_SHADOW_CRASH_AURA = 65269, + + SPELL_SEARING_FLAMES = 62661, + + SPELL_SURGE_OF_DARKNESS = 62662, + + SPELL_MARK_OF_THE_FACELESS_AURA = 63276, + SPELL_MARK_OF_THE_FACELESS_EFFECT = 63278, + + SPELL_AURA_OF_DESPAIR_1 = 62692, + SPELL_AURA_OF_DESPAIR_2 = 64848, + SPELL_CORRUPTED_RAGE = 68415, + SPELL_CORRUPTED_WISDOM = 64646, + SPELL_SHAMANISTIC_RAGE = 30823, + SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 = 31876, + + SPELL_SUMMON_SARONITE_VAPORS = 63081, + NPC_SARONITE_VAPORS = 33488, + SPELL_SARONITE_VAPORS_DMG = 63338, + SPELL_SARONITE_VAPORS_ENERGIZE = 63337, + SPELL_SARONITE_VAPORS_AURA = 63323, + SPELL_SARONITE_VAPORS_DUMMYAURA = 63322, + + SPELL_SARONITE_ANIMUS_FORMATION_VISUAL = 63319, + SPELL_SUMMON_SARONITE_ANIMUS = 63145, + SPELL_SARONITE_BARRIER = 63364, + SPELL_PROFOUND_DARKNESS = 63420, +}; + +enum VezaxNpcs +{ + // NPC_VEZAX = 33271, + // NPC_VEZAX_BUNNY = 33500, + NPC_SARONITE_ANIMUS = 33524, +}; + +enum VezaxGOs +{ + // GO_VEZAX_DOOR = 194750, +}; + +enum VezaxEvents +{ + EVENT_SPELL_VEZAX_SHADOW_CRASH = 1, + EVENT_SPELL_SEARING_FLAMES = 2, + EVENT_SPELL_SURGE_OF_DARKNESS = 3, + EVENT_SPELL_MARK_OF_THE_FACELESS = 4, + EVENT_SPELL_SUMMON_SARONITE_VAPORS = 5, + EVENT_SARONITE_VAPORS_SWIRL = 6, + EVENT_SPELL_SUMMON_SARONITE_ANIMUS = 7, + EVENT_DESPAWN_SARONITE_VAPORS = 8, + EVENT_SPELL_PROFOUND_DARKNESS = 9, + EVENT_BERSERK = 10, + EVENT_RESTORE_TARGET = 11, +}; + +enum VezaxText +{ + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_SURGE_OF_DARKNESS = 2, + SAY_DEATH = 3, + SAY_BERSERK = 4, + SAY_HARDMODE = 5, + SAY_EMOTE_ANIMUS = 6, + SAY_EMOTE_BARRIER = 7, + SAY_EMOTE_SURGE_OF_DARKNESS = 8, +}; + +enum VaporsText +{ + SAY_EMOTE_VAPORS = 0, +}; + +class boss_vezax : public CreatureScript +{ +public: + boss_vezax() : CreatureScript("boss_vezax") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_vezaxAI : public ScriptedAI + { + boss_vezaxAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + { + pInstance = pCreature->GetInstanceScript(); + } + + EventMap events; + SummonList summons; + uint8 vaporsCount; + bool hardmodeAvailable; + bool berserk; + bool bAchievShadowdodger; + + InstanceScript* pInstance; + + void Reset() override + { + vaporsCount = 0; + hardmodeAvailable = true; + berserk = false; + bAchievShadowdodger = true; + events.Reset(); + summons.DespawnAll(); + me->SetLootMode(1); + + if (pInstance) + pInstance->SetData(TYPE_VEZAX, NOT_STARTED); + } + + void JustReachedHome() override + { + me->setActive(false); + } + + void JustEngagedWith(Unit* /*pWho*/) override + { + me->setActive(true); + me->SetInCombatWithZone(); + + events.Reset(); + events.RescheduleEvent(EVENT_SPELL_VEZAX_SHADOW_CRASH, 13s); + events.RescheduleEvent(EVENT_SPELL_SEARING_FLAMES, 10s, 1); + events.RescheduleEvent(EVENT_SPELL_SURGE_OF_DARKNESS, 63s); + events.RescheduleEvent(EVENT_SPELL_MARK_OF_THE_FACELESS, 20s); + events.RescheduleEvent(EVENT_SPELL_SUMMON_SARONITE_VAPORS, 30s); + events.RescheduleEvent(EVENT_BERSERK, 10min); + + Talk(SAY_AGGRO); + + if (pInstance) + pInstance->SetData(TYPE_VEZAX, IN_PROGRESS); + + me->CastSpell(me, SPELL_AURA_OF_DESPAIR_1, true); + } + + void DoAction(int32 param) override + { + switch( param ) + { + case 1: + hardmodeAvailable = false; + break; + case 2: + me->RemoveAura(SPELL_SARONITE_BARRIER); + me->SetLootMode(3); + break; + } + } + + uint32 GetData(uint32 id) const override + { + switch (id) + { + case 1: + return (me->GetLootMode() == 3 ? 1 : 0); + case 2: + return (bAchievShadowdodger ? 1 : 0); + } + return 0; + } + + void SpellHitTarget(Unit* target, SpellInfo const* spell) override + { + if (target && spell && target->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_VEZAX_SHADOW_CRASH_DMG) + bAchievShadowdodger = false; + } + + void UpdateAI(uint32 diff) override + { + if( !UpdateVictim() ) + return; + + if( !berserk && (me->GetPositionX() < 1720.0f || me->GetPositionX() > 1940.0f || me->GetPositionY() < 20.0f || me->GetPositionY() > 210.0f) ) + events.RescheduleEvent(EVENT_BERSERK, 1ms); + + events.Update(diff); + + if( me->HasUnitState(UNIT_STATE_CASTING) ) + return; + + switch( events.ExecuteEvent() ) + { + case 0: + break; + case EVENT_BERSERK: + berserk = true; + me->CastSpell(me, SPELL_VEZAX_BERSERK, true); + Talk(SAY_BERSERK); + break; + case EVENT_SPELL_VEZAX_SHADOW_CRASH: + { + events.Repeat(10s); + + std::vector players; + Map::PlayerList const& pl = me->GetMap()->GetPlayers(); + for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) + { + Player* temp = itr->GetSource(); + if( temp->IsAlive() && temp->GetDistance(me) > 15.0f ) + players.push_back(temp); + } + if (!players.empty()) + { + me->setAttackTimer(BASE_ATTACK, 2000); + Player* target = players.at(urand(0, players.size() - 1)); + me->SetGuidValue(UNIT_FIELD_TARGET, target->GetGUID()); + me->CastSpell(target, SPELL_VEZAX_SHADOW_CRASH, false); + events.ScheduleEvent(EVENT_RESTORE_TARGET, 750ms); + } + } + break; + case EVENT_RESTORE_TARGET: + if (me->GetVictim()) + me->SetGuidValue(UNIT_FIELD_TARGET, me->GetVictim()->GetGUID()); + break; + case EVENT_SPELL_SEARING_FLAMES: + if(!me->HasAura(SPELL_SARONITE_BARRIER)) + me->CastSpell(me->GetVictim(), SPELL_SEARING_FLAMES, false); + events.Repeat(me->GetMap()->Is25ManRaid() ? 8s : 15s); + break; + case EVENT_SPELL_SURGE_OF_DARKNESS: + Talk(SAY_SURGE_OF_DARKNESS); + Talk(SAY_EMOTE_SURGE_OF_DARKNESS); + me->CastSpell(me, SPELL_SURGE_OF_DARKNESS, false); + events.Repeat(63s); + events.DelayEvents(10000, 1); + break; + case EVENT_SPELL_MARK_OF_THE_FACELESS: + { + std::vector outside; + std::vector inside; + Map::PlayerList const& pl = me->GetMap()->GetPlayers(); + for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) + if( Player* tmp = itr->GetSource() ) + if( tmp->IsAlive() ) + { + if( tmp->GetDistance(me) > 15.0f ) + outside.push_back(tmp); + else + inside.push_back(tmp); + } + + Player* t = nullptr; + if( outside.size() >= uint8(me->GetMap()->Is25ManRaid() ? 9 : 4) ) + t = outside.at(urand(0, outside.size() - 1)); + else if( !inside.empty() ) + t = inside.at(urand(0, inside.size() - 1)); + + if (t) + me->CastSpell(t, SPELL_MARK_OF_THE_FACELESS_AURA, false); + + events.Repeat(40s); + } + break; + case EVENT_SPELL_SUMMON_SARONITE_VAPORS: + { + vaporsCount++; + me->CastSpell(me, SPELL_SUMMON_SARONITE_VAPORS, false); + + if( vaporsCount < 6 || !hardmodeAvailable ) + events.Repeat(30s); + else + { + for (ObjectGuid const& guid : summons) + if (Creature* sv = ObjectAccessor::GetCreature(*me, guid)) + { + sv->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + sv->GetMotionMaster()->MoveIdle(); + sv->GetMotionMaster()->MoveCharge(1852.78f, 81.38f, 342.461f, 28.0f); + } + + events.DelayEvents(12000, 0); + events.DelayEvents(12000, 1); + events.ScheduleEvent(EVENT_SARONITE_VAPORS_SWIRL, 6s); + } + } + break; + case EVENT_SARONITE_VAPORS_SWIRL: + if (summons.size()) + { + Talk(SAY_EMOTE_ANIMUS); + if( Creature* sv = ObjectAccessor::GetCreature(*me, *(summons.begin())) ) + sv->CastSpell(sv, SPELL_SARONITE_ANIMUS_FORMATION_VISUAL, true); + + events.ScheduleEvent(EVENT_SPELL_SUMMON_SARONITE_ANIMUS, 2s); + break; + } + break; + case EVENT_SPELL_SUMMON_SARONITE_ANIMUS: + if (summons.size()) + { + Talk(SAY_HARDMODE); + Talk(SAY_EMOTE_BARRIER); + me->CastSpell(me, SPELL_SARONITE_BARRIER, true); + if( Creature* sv = ObjectAccessor::GetCreature(*me, *(summons.begin())) ) + sv->CastSpell(sv, SPELL_SUMMON_SARONITE_ANIMUS, true); + + events.ScheduleEvent(EVENT_DESPAWN_SARONITE_VAPORS, 2500ms); + break; + } + break; + case EVENT_DESPAWN_SARONITE_VAPORS: + summons.DespawnEntry(NPC_SARONITE_VAPORS); + break; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) override + { + summons.DespawnAll(); + if (pInstance) + pInstance->SetData(TYPE_VEZAX, DONE); + + Talk(SAY_DEATH); + + if( GameObject* door = me->FindNearestGameObject(GO_VEZAX_DOOR, 500.0f) ) + if( door->GetGoState() != GO_STATE_ACTIVE ) + { + door->SetLootState(GO_READY); + door->UseDoorOrButton(0, false); + } + } + + void KilledUnit(Unit* who) override + { + if( who->GetTypeId() == TYPEID_PLAYER ) + Talk(SAY_SLAY); + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + } + + void SummonedCreatureDespawn(Creature* s) override + { + summons.Despawn(s); + } + }; +}; + +class npc_ulduar_saronite_vapors : public CreatureScript +{ +public: + npc_ulduar_saronite_vapors() : CreatureScript("npc_ulduar_saronite_vapors") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_saronite_vaporsAI : public NullCreatureAI + { + npc_ulduar_saronite_vaporsAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + pInstance = pCreature->GetInstanceScript(); + me->GetMotionMaster()->MoveRandom(4.0f); + } + + InstanceScript* pInstance; + + void JustDied(Unit* /*killer*/) override + { + me->CastSpell(me, SPELL_SARONITE_VAPORS_AURA, true); + + // killed saronite vapors, hard mode unavailable + if( pInstance ) + if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) ) + vezax->AI()->DoAction(1); + } + + void IsSummonedBy(WorldObject* /*summoner*/) override + { + Talk(SAY_EMOTE_VAPORS); + } + }; +}; + +class npc_ulduar_saronite_animus : public CreatureScript +{ +public: + npc_ulduar_saronite_animus() : CreatureScript("npc_ulduar_saronite_animus") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_saronite_animusAI : public ScriptedAI + { + npc_ulduar_saronite_animusAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceScript(); + if( pInstance ) + if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) ) + vezax->AI()->JustSummoned(me); + timer = 0; + me->SetInCombatWithZone(); + } + + InstanceScript* pInstance; + uint16 timer; + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(3000); + + if( pInstance ) + if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) ) + vezax->AI()->DoAction(2); + } + + void UpdateAI(uint32 diff) override + { + UpdateVictim(); + + timer += diff; + if (timer >= 2000) + { + me->CastSpell(me, SPELL_PROFOUND_DARKNESS, true); + timer -= 2000; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class spell_aura_of_despair : public SpellScriptLoader +{ +public: + spell_aura_of_despair() : SpellScriptLoader("spell_aura_of_despair") { } + + class spell_aura_of_despair_AuraScript : public AuraScript + { + PrepareAuraScript(spell_aura_of_despair_AuraScript) + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + if (Unit* target = GetTarget()) + { + if (target->GetTypeId() != TYPEID_PLAYER) + return; + + target->CastSpell(target, SPELL_AURA_OF_DESPAIR_2, true); + if( target->HasSpell(SPELL_SHAMANISTIC_RAGE) ) + caster->CastSpell(target, SPELL_CORRUPTED_RAGE, true); + else if( target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1) || target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 + 1) || target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 + 2) ) + caster->CastSpell(target, SPELL_CORRUPTED_WISDOM, true); + } + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* target = GetTarget()) + { + target->RemoveAurasDueToSpell(SPELL_AURA_OF_DESPAIR_2); + target->RemoveAurasDueToSpell(SPELL_CORRUPTED_RAGE); + target->RemoveAurasDueToSpell(SPELL_CORRUPTED_WISDOM); + } + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_aura_of_despair_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PREVENT_REGENERATE_POWER, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_aura_of_despair_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PREVENT_REGENERATE_POWER, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_aura_of_despair_AuraScript(); + } +}; + +class spell_mark_of_the_faceless_periodic : public SpellScriptLoader +{ +public: + spell_mark_of_the_faceless_periodic() : SpellScriptLoader("spell_mark_of_the_faceless_periodic") { } + + class spell_mark_of_the_faceless_periodic_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mark_of_the_faceless_periodic_AuraScript) + + void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) + { + if (Unit* caster = GetCaster()) + if (Unit* target = GetTarget()) + if (target->GetMapId() == 603) + { + int32 dmg = 5000; + caster->CastCustomSpell(target, SPELL_MARK_OF_THE_FACELESS_EFFECT, 0, &dmg, 0, true); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_mark_of_the_faceless_periodic_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_mark_of_the_faceless_periodic_AuraScript(); + } +}; + +class spell_mark_of_the_faceless_drainhealth : public SpellScriptLoader +{ +public: + spell_mark_of_the_faceless_drainhealth() : SpellScriptLoader("spell_mark_of_the_faceless_drainhealth") { } + + class spell_mark_of_the_faceless_drainhealth_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mark_of_the_faceless_drainhealth_SpellScript); + + void FilterTargets(std::list& targets) + { + targets.remove(GetExplTargetUnit()); + if (targets.empty()) + Cancel(); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mark_of_the_faceless_drainhealth_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_DEST_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mark_of_the_faceless_drainhealth_SpellScript(); + } +}; + +class spell_saronite_vapors_dummy : public SpellScriptLoader +{ +public: + spell_saronite_vapors_dummy() : SpellScriptLoader("spell_saronite_vapors_dummy") { } + + class spell_saronite_vapors_dummy_AuraScript : public AuraScript + { + PrepareAuraScript(spell_saronite_vapors_dummy_AuraScript) + + void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + { + int32 damage = 100 * pow(2.0f, (float)GetStackAmount()); + caster->CastCustomSpell(GetTarget(), SPELL_SARONITE_VAPORS_DMG, &damage, nullptr, nullptr, true); + } + } + + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_saronite_vapors_dummy_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_saronite_vapors_dummy_AuraScript(); + } +}; + +class spell_saronite_vapors_damage : public SpellScriptLoader +{ +public: + spell_saronite_vapors_damage() : SpellScriptLoader("spell_saronite_vapors_damage") { } + + class spell_saronite_vapors_damage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_saronite_vapors_damage_SpellScript); + + void HandleAfterHit() + { + if (Unit* caster = GetCaster()) + if (GetHitDamage() > 2) + { + int32 mana = GetHitDamage() / 2; + if (Unit* t = GetHitUnit()) + caster->CastCustomSpell(t, SPELL_SARONITE_VAPORS_ENERGIZE, &mana, nullptr, nullptr, true); + } + } + + void Register() override + { + AfterHit += SpellHitFn(spell_saronite_vapors_damage_SpellScript::HandleAfterHit); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_saronite_vapors_damage_SpellScript(); + } +}; + +class achievement_smell_saronite : public AchievementCriteriaScript +{ +public: + achievement_smell_saronite() : AchievementCriteriaScript("achievement_smell_saronite") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_VEZAX && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1); + } +}; + +class achievement_shadowdodger : public AchievementCriteriaScript +{ +public: + achievement_shadowdodger() : AchievementCriteriaScript("achievement_shadowdodger") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_VEZAX && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(2); + } +}; + +class go_ulduar_pure_saronite_deposit : public GameObjectScript +{ +public: + go_ulduar_pure_saronite_deposit() : GameObjectScript("go_ulduar_pure_saronite_deposit") { } + + bool OnGossipHello(Player* plr, GameObject* go) override + { + if (plr->IsGameMaster()) + return false; + + if (InstanceScript* pInstance = go->GetInstanceScript()) + if (pInstance->GetData(TYPE_XT002) != DONE && pInstance->GetData(TYPE_MIMIRON) != DONE && pInstance->GetData(TYPE_THORIM) != DONE && pInstance->GetData(TYPE_FREYA) != DONE && pInstance->GetData(TYPE_HODIR) != DONE) + { + std::string accountName; + AccountMgr::GetName(plr->GetSession()->GetAccountId(), accountName); + sBan->BanAccount(accountName, "0s", "Tele hack", "Server"); + return true; + } + + return false; + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp index d3f8de2ebfd397..b55bf7d2e62860 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_hodir.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "PassiveAI.h" @@ -26,1585 +27,6 @@ #include "SpellScriptLoader.h" #include "ulduar.h" -enum HodirSpellData -{ - SPELL_BERSERK = 26662, - - SPELL_BITING_COLD_BOSS_AURA = 62038, - SPELL_BITING_COLD_PLAYER_AURA = 62039, - SPELL_BITING_COLD_DAMAGE = 62188, - - SPELL_FREEZE = 62469, - - SPELL_FLASH_FREEZE_CAST = 61968, - SPELL_FLASH_FREEZE_INSTAKILL = 62226, - SPELL_FLASH_FREEZE_TRAPPED_PLAYER = 61969, - SPELL_FLASH_FREEZE_TRAPPED_NPC = 61990, - SPELL_FLASH_FREEZE_VISUAL = 62148, - SPELL_SAFE_AREA = 65705, - SPELL_SAFE_AREA_TRIGGERED = 62464, - SPELL_SHATTER_CHEST = 62501, - - SPELL_ICICLE_BOSS_AURA = 62227, - SPELL_ICICLE_TBBA = 63545, - - SPELL_ICICLE_VISUAL_UNPACKED = 62234, - SPELL_ICICLE_VISUAL_PACKED = 62462, - SPELL_ICICLE_VISUAL_FALLING = 62453, - SPELL_ICICLE_FALL_EFFECT_UNPACKED = 62236, - SPELL_ICICLE_FALL_EFFECT_PACKED = 62460, - SPELL_ICE_SHARDS_SMALL = 62457, - SPELL_ICE_SHARDS_BIG = 65370, - SPELL_SNOWDRIFT = 62463, - - SPELL_FROZEN_BLOWS_10 = 62478, - SPELL_FROZEN_BLOWS_25 = 63512, - - // Helpers: - SPELL_PRIEST_DISPELL_MAGIC = 63499, - SPELL_PRIEST_GREAT_HEAL = 62809, - SPELL_PRIEST_SMITE = 61923, - - SPELL_DRUID_WRATH = 62793, - SPELL_DRUID_STARLIGHT_AREA_AURA = 62807, - - SPELL_SHAMAN_LAVA_BURST = 61924, - SPELL_SHAMAN_STORM_CLOUD_10 = 65123, - SPELL_SHAMAN_STORM_CLOUD_25 = 65133, - SPELL_SHAMAN_STORM_POWER_10 = 63711, - SPELL_SHAMAN_STORM_POWER_25 = 65134, - - SPELL_MAGE_FIREBALL = 61909, - SPELL_MAGE_MELT_ICE = 64528, - SPELL_MAGE_CONJURE_TOASTY_FIRE = 62823, - SPELL_MAGE_SUMMON_TOASTY_FIRE = 62819, - SPELL_MAGE_TOASTY_FIRE_AURA = 62821, - SPELL_SINGED = 65280, -}; - -enum HodirNPCs -{ - //NPC_HODIR = 32845, - - NPC_PAN_FIELD_MEDIC_PENNY = 32897, - NPC_DAN_ELLIE_NIGHTFEATHER = 32901, - NPC_SAN_ELEMENTALIST_AVUUN = 32900, - NPC_MAN_MISSY_FLAMECUFFS = 32893, - - NPC_PAH_FIELD_MEDIC_JESSI = 33326, - NPC_DAH_EIVI_NIGHTFEATHER = 33325, - NPC_SAH_ELEMENTALIST_MAHFUUN = 33328, - NPC_MAH_SISSY_FLAMECUFFS = 33327, - - NPC_PHN_BATTLEPRIEST_ELIZA = 32948, - NPC_DHN_TOR_GREYCLOUD = 32941, - NPC_SHN_SPIRITWALKER_YONA = 32950, - NPC_MHN_VEESHA_BLAZEWEAVER = 32946, - - NPC_PHH_BATTLEPRIEST_GINA = 33330, - NPC_DHH_KAR_GREYCLOUD = 33333, - NPC_SHH_SPIRITWALKER_TARA = 33332, - NPC_MHH_AMIRA_BLAZEWEAVER = 33331, - - NPC_FLASH_FREEZE_PLR = 32926, - NPC_FLASH_FREEZE_NPC = 32938, - NPC_ICICLE_UNPACKED = 33169, - NPC_ICICLE_PACKED = 33173, - NPC_TOASTY_FIRE = 33342, - NPC_RARE_WINTER_CACHE_TRIGGER = 88101, -}; - -enum HodirEvents -{ - // Hodir: - EVENT_FLASH_FREEZE = 1, - EVENT_FROZEN_BLOWS = 2, - EVENT_BERSERK = 3, - EVENT_FREEZE = 4, - EVENT_SMALL_ICICLES_ENABLE = 5, - EVENT_HARD_MODE_MISSED = 6, - EVENT_DESPAWN_CHEST = 7, - EVENT_FAIL_HM = 8, - - EVENT_TRY_FREE_HELPER = 10, - EVENT_PRIEST_DISPELL_MAGIC = 11, - EVENT_PRIEST_GREAT_HEAL = 12, - EVENT_PRIEST_SMITE = 13, - EVENT_DRUID_WRATH = 14, - EVENT_DRUID_STARLIGHT = 15, - EVENT_SHAMAN_LAVA_BURST = 16, - EVENT_SHAMAN_STORM_CLOUD = 17, - EVENT_MAGE_TOASTY_FIRE = 18, - EVENT_MAGE_FIREBALL = 19, - EVENT_MAGE_MELT_ICE = 20, -}; - -enum HodirText -{ - TEXT_AGGRO = 0, - TEXT_SLAY = 1, - TEXT_FLASH_FREEZE = 2, - TEXT_STALACTITE = 3, - TEXT_DEATH = 4, - TEXT_BERSERK = 5, - TEXT_HM_MISS = 6, - TEXT_EMOTE_FREEZE = 7, - TEXT_EMOTE_BLOW = 8, -}; - -#define SPELL_FROZEN_BLOWS RAID_MODE(SPELL_FROZEN_BLOWS_10, SPELL_FROZEN_BLOWS_25) -#define SPELL_SHAMAN_STORM_CLOUD RAID_MODE(SPELL_SHAMAN_STORM_CLOUD_10, SPELL_SHAMAN_STORM_CLOUD_25) - -enum HodirSounds -{ - SOUND_HODIR_AGGRO = 15552, - SOUND_HODIR_SLAIN_1 = 15553, - SOUND_HODIR_SLAIN_2 = 15554, - SOUND_HODIR_FLASH_FREEZE = 15555, - SOUND_HODIR_FROZEN_BLOWS = 15556, - SOUND_HODIR_DEFEATED = 15557, - SOUND_HODIR_BERSERK = 15558, -}; - -struct HodirHelperData -{ - uint32 id; - float x, y; -}; -HodirHelperData hhd[4][4] = -{ - // Alliance: - { - {NPC_PAN_FIELD_MEDIC_PENNY, 2020.46f, -236.74f}, - {NPC_DAN_ELLIE_NIGHTFEATHER, 2007.21f, -241.57f}, - {NPC_SAN_ELEMENTALIST_AVUUN, 1999.14f, -230.69f}, - {NPC_MAN_MISSY_FLAMECUFFS, 1984.38f, -242.57f} - }, - { - {NPC_PAH_FIELD_MEDIC_JESSI, 2012.29f, -233.70f}, - {NPC_DAH_EIVI_NIGHTFEATHER, 1995.75f, -241.32f}, - {NPC_SAH_ELEMENTALIST_MAHFUUN, 1989.31f, -234.26f}, - {NPC_MAH_SISSY_FLAMECUFFS, 1977.87f, -233.99f} - }, - // Horde: - { - {NPC_PHN_BATTLEPRIEST_ELIZA, 2020.46f, -236.74f}, - {NPC_DHN_TOR_GREYCLOUD, 2007.21f, -241.57f}, - {NPC_SHN_SPIRITWALKER_YONA, 1999.14f, -230.69f}, - {NPC_MHN_VEESHA_BLAZEWEAVER, 1984.38f, -242.57f} - }, - { - {NPC_PHH_BATTLEPRIEST_GINA, 2012.29f, -233.70f}, - {NPC_DHH_KAR_GREYCLOUD, 1995.75f, -241.32f}, - {NPC_SHH_SPIRITWALKER_TARA, 1989.31f, -234.6f}, - {NPC_MHH_AMIRA_BLAZEWEAVER, 1977.87f, -233.99f} - } -}; - -class boss_hodir : public CreatureScript -{ -public: - boss_hodir() : CreatureScript("boss_hodir") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_hodirAI : public ScriptedAI - { - boss_hodirAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) - { - pInstance = pCreature->GetInstanceScript(); - if (!me->IsAlive()) - if (pInstance) - pInstance->SetData(TYPE_HODIR, DONE); - } - - InstanceScript* pInstance; - EventMap events; - SummonList summons; - ObjectGuid Helpers[8]; - bool berserk{ false }; - bool bAchievCheese{ true }; - bool bAchievGettingCold{ true }; - bool bAchievCacheRare{ true }; - bool bAchievCoolestFriends{ true }; - uint16 addSpawnTimer{ 0 }; - - // Used to make Hodir disengage whenever he leaves his room - const Position ENTRANCE_DOOR{ 1999.160034f, -297.792999f, 431.960999f, 0 }; - const Position EXIT_DOOR{ 1999.709961f, -166.259003f, 432.822998f, 0 }; - - void Reset() override - { - events.Reset(); - summons.DespawnAll(); - berserk = false; - bAchievCheese = true; - bAchievGettingCold = true; - bAchievCacheRare = true; - bAchievCoolestFriends = true; - me->SetSheath(SHEATH_STATE_MELEE); - - // Reset the spells cast after wipe - me->RemoveAllAuras(); - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA); - - if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE) - { - pInstance->SetData(TYPE_HODIR, NOT_STARTED); - } - - if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 900.0f)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - - // Reset helpers - if (!summons.size()) - SpawnHelpers(); - } - - void JustEngagedWith(Unit* /*pWho*/) override - { - me->CastSpell(me, SPELL_BITING_COLD_BOSS_AURA, true); - SmallIcicles(true); - events.Reset(); - events.ScheduleEvent(EVENT_FLASH_FREEZE, 48s, 49s); - events.ScheduleEvent(EVENT_FREEZE, 17s, 20s); - events.ScheduleEvent(EVENT_BERSERK, 8min); - events.ScheduleEvent(EVENT_HARD_MODE_MISSED, 3min); - Talk(TEXT_AGGRO); - - if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE) - { - pInstance->SetData(TYPE_HODIR, IN_PROGRESS); - } - - if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 300.0f)) - { - go->SetGoState(GO_STATE_READY); - } - } - - void DoAction(int action) override - { - if (action) - { - switch (action) - { - case EVENT_FAIL_HM: - if (pInstance) - { - if (GameObject* go = pInstance->instance->GetGameObject(pInstance->GetGuidData(GO_HODIR_CHEST_HARD))) - { - go->SetGoState(GO_STATE_ACTIVE); - events.ScheduleEvent(EVENT_DESPAWN_CHEST, 3s); - } - } - break; - } - } - } - - void SmallIcicles(bool enable) - { - if( enable ) - me->CastSpell(me, SPELL_ICICLE_BOSS_AURA, true); - else - me->RemoveAura(SPELL_ICICLE_BOSS_AURA); - } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) override - { - switch( spell->Id ) - { - case SPELL_ICICLE_TBBA: - me->CastSpell(target, SPELL_ICICLE_VISUAL_UNPACKED, true); - break; - case SPELL_FLASH_FREEZE_VISUAL: - { - std::list fires; - me->GetCreaturesWithEntryInRange(fires, 200.0f, NPC_TOASTY_FIRE); - for (std::list::iterator itr = fires.begin(); itr != fires.end(); ++itr) - (*itr)->AI()->DoAction(1); // remove it - } - break; - } - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (damage >= me->GetHealth() || me->GetHealth() < 150000) - { - damage = 0; - me->SetReactState(REACT_PASSIVE); - if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - { - if (pInstance) - { - pInstance->SetData(TYPE_HODIR, DONE); - me->CastSpell(me, 64899, true); // credit - } - - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetFaction(FACTION_FRIENDLY); - me->GetMotionMaster()->Clear(); - me->AttackStop(); - me->CombatStop(); - me->InterruptNonMeleeSpells(true); - me->RemoveAllAuras(); - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA); - - events.Reset(); - summons.DespawnAll(); - - if( GameObject* d = me->FindNearestGameObject(GO_HODIR_FROZEN_DOOR, 250.0f)) - { - if( d->GetGoState() != GO_STATE_ACTIVE ) - { - d->SetLootState(GO_READY); - d->UseDoorOrButton(0, false); - } - } - if (GameObject* d = me->FindNearestGameObject(GO_HODIR_DOOR, 250.0f)) - { - if( d->GetGoState() != GO_STATE_ACTIVE ) - { - d->SetLootState(GO_READY); - d->UseDoorOrButton(0, false); - } - } - - if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 300.0f)) - { - go->SetGoState(GO_STATE_ACTIVE); - } - - Talk(TEXT_DEATH); - me->DespawnOrUnsummon(10000); - } - } - } - - void UpdateAI(uint32 diff) override - { - if (me->GetPositionY() <= ENTRANCE_DOOR.GetPositionY() || me->GetPositionY() >= EXIT_DOOR.GetPositionY()) - { - boss_hodirAI::EnterEvadeMode(); - return; - } - - if (!UpdateVictim()) - { - if (me->IsInCombat()) - { - Map::PlayerList const& pl = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - itr->GetSource()->CastSpell(itr->GetSource(), SPELL_FLASH_FREEZE_INSTAKILL, true); - EnterEvadeMode(); - } - return; - } - - events.Update(diff); - - if( me->HasUnitState(UNIT_STATE_CASTING) ) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_BERSERK: - { - berserk = true; - me->CastSpell(me, SPELL_BERSERK, true); - Talk(TEXT_BERSERK); - } - break; - case EVENT_HARD_MODE_MISSED: - { - Talk(TEXT_HM_MISS); - bAchievCacheRare = false; - if (pInstance) - { - if (GameObject* go = pInstance->instance->GetGameObject(pInstance->GetGuidData(GO_HODIR_CHEST_HARD))) - { - me->CastSpell(go, SPELL_SHATTER_CHEST, false); - } - } - } - break; - case EVENT_DESPAWN_CHEST: - if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE) - pInstance->SetData(TYPE_HODIR_HM_FAIL, 0); - break; - case EVENT_FLASH_FREEZE: - { - std::list targets; - Map::PlayerList const& pl = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) - targets.push_back(itr->GetSource()); - targets.remove_if(Acore::ObjectTypeIdCheck(TYPEID_PLAYER, false)); - targets.remove_if(Acore::UnitAuraCheck(true, SPELL_FLASH_FREEZE_TRAPPED_PLAYER)); - Acore::Containers::RandomResize(targets, (RAID_MODE(2,3))); - for (std::list::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) - { - float prevZ = (*itr)->GetPositionZ(); - (*itr)->m_positionZ = 432.7f; - (*itr)->CastSpell((*itr), SPELL_ICICLE_VISUAL_PACKED, true); - (*itr)->m_positionZ = prevZ; - } - - me->CastSpell((Unit*)nullptr, SPELL_FLASH_FREEZE_CAST, false); - me->PlayDirectSound(SOUND_HODIR_FLASH_FREEZE, 0); - Talk(TEXT_FLASH_FREEZE); - Talk(TEXT_EMOTE_FREEZE); - SmallIcicles(false); - events.ScheduleEvent(EVENT_FLASH_FREEZE, 48s, 49s); - events.ScheduleEvent(EVENT_SMALL_ICICLES_ENABLE, Is25ManRaid() ? 12s : 24s); - events.ScheduleEvent(EVENT_FROZEN_BLOWS, 15s); - events.RescheduleEvent(EVENT_FREEZE, 17s, 20s); - } - break; - case EVENT_SMALL_ICICLES_ENABLE: - { - SmallIcicles(true); - } - break; - case EVENT_FROZEN_BLOWS: - { - Talk(TEXT_EMOTE_BLOW); - Talk(TEXT_STALACTITE); - me->CastSpell(me, Is25ManRaid()? SPELL_FROZEN_BLOWS_25 : SPELL_FROZEN_BLOWS_10, true); - } - break; - case EVENT_FREEZE: - if (Player* plr = SelectTargetFromPlayerList(50.0f, SPELL_FLASH_FREEZE_TRAPPED_PLAYER)) - { - me->CastSpell(plr, SPELL_FREEZE, false); - } - else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true)) - { - me->CastSpell(target, SPELL_FREEZE, false); - } - events.RescheduleEvent(EVENT_FREEZE, 17s, 20s); - break; - } - - DoMeleeAttackIfReady(); - } - - Creature* GetHelper(uint8 index) - { - return Helpers[index] ? ObjectAccessor::GetCreature(*me, Helpers[index]) : nullptr; - } - - void SpawnHelpers() - { - char faction = 'A'; - if( hhd[0][0].id ) - { - Map::PlayerList const& cl = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = cl.begin(); itr != cl.end(); ++itr) - if (!itr->GetSource()->IsGameMaster()) - { - faction = (itr->GetSource()->GetTeamId() == TEAM_ALLIANCE ? 'A' : 'H'); - break; - } - } - - uint8 cnt = 0; - if( faction ) - for( uint8 k = 0; k < 4; ++k ) - { - if( (faction == 'A' && ( k > 1 || (k == 1 && RAID_MODE(1, 0)) )) || - (faction == 'H' && ( k < 2 || (k == 3 && RAID_MODE(1, 0)) )) ) - continue; - - for( uint8 i = 0; i < 4; ++i ) - { - if( !hhd[k][i].id ) - continue; - - if( Creature* h_p = me->SummonCreature(hhd[k][i].id, hhd[k][i].x, hhd[k][i].y, 432.69f, M_PI / 2) ) - { - h_p->SetFaction(1665); - if( cnt < 8 ) - Helpers[cnt++] = h_p->GetGUID(); - - if( Creature* c = h_p->SummonCreature(NPC_FLASH_FREEZE_NPC, h_p->GetPositionX(), h_p->GetPositionY(), h_p->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000) ) - { - c->CastSpell(h_p, SPELL_FLASH_FREEZE_TRAPPED_NPC, true); - JustSummoned(c); - } - } - } - } - } - - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() == TYPEID_PLAYER) - Talk(TEXT_SLAY); - } - - void JustSummoned(Creature* s) override - { - summons.Summon(s); - } - - void SummonedCreatureDespawn(Creature* s) override - { - summons.Despawn(s); - } - - bool CanAIAttack(Unit const* t) const override - { - if (t->GetTypeId() == TYPEID_PLAYER) - return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER); - else if (t->GetTypeId() == TYPEID_UNIT) - return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC); - - return true; - } - - void SetData(uint32 id, uint32 value) override - { - if (value) - switch (id) - { - case 1: - bAchievCheese = false; - break; - case 2: - bAchievGettingCold = false; - break; - case 4: - bAchievCoolestFriends = false; - break; - } - } - - uint32 GetData(uint32 id) const override - { - switch (id) - { - case 1: - return (bAchievCheese ? 1 : 0); - case 2: - return (bAchievGettingCold ? 1 : 0); - case 3: - return (bAchievCacheRare ? 1 : 0); - case 4: - return (bAchievCoolestFriends ? 1 : 0); - } - return 0; - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - }; -}; - -class npc_ulduar_icicle : public CreatureScript -{ -public: - npc_ulduar_icicle() : CreatureScript("npc_ulduar_icicle") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_icicleAI : public NullCreatureAI - { - npc_ulduar_icicleAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - timer1 = 2000; - timer2 = 5000; - } - - uint16 timer1; - uint16 timer2; - - void UpdateAI(uint32 diff) override - { - if( timer1 <= diff ) - { - me->CastSpell(me, (me->GetEntry() == 33169 ? SPELL_ICICLE_FALL_EFFECT_UNPACKED : SPELL_ICICLE_FALL_EFFECT_PACKED), true); - me->CastSpell(me, SPELL_ICICLE_VISUAL_FALLING, false); - timer1 = 60000; - } - else - timer1 -= diff; - - if (timer2 <= diff) - { - me->SetDisplayId(11686); - timer2 = 60000; - } - else - timer2 -= diff; - } - }; -}; - -class npc_ulduar_flash_freeze : public CreatureScript -{ -public: - npc_ulduar_flash_freeze() : CreatureScript("npc_ulduar_flash_freeze") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_flash_freezeAI : public NullCreatureAI - { - npc_ulduar_flash_freezeAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - timer = 2500; - pInstance = me->GetInstanceScript(); - } - - InstanceScript* pInstance; - uint16 timer; - - void DamageTaken(Unit* doneBy, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override - { - if (pInstance && doneBy) - if (pInstance->GetData(TYPE_HODIR) == NOT_STARTED) - if (Creature* hodir = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_HODIR))) - hodir->AI()->AttackStart(doneBy); - } - - void UpdateAI(uint32 diff) override - { - if (timer <= diff) - { - timer = 2500; - if (me->IsSummon()) - { - if (Unit* s = me->ToTempSummon()->GetSummonerUnit()) - { - if ((s->GetTypeId() == TYPEID_PLAYER && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER)) || (s->GetTypeId() == TYPEID_UNIT && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC))) - me->DespawnOrUnsummon(2000); - else if (s->GetTypeId() == TYPEID_PLAYER) - if (InstanceScript* instanceScript = me->GetInstanceScript()) - if (instanceScript->GetData(TYPE_HODIR) == NOT_STARTED) - { - s->CastSpell(s, SPELL_FLASH_FREEZE_INSTAKILL, true); - me->DespawnOrUnsummon(2000); - } - } - else - { - me->DespawnOrUnsummon(2000); - } - } - } - else - timer -= diff; - } - }; -}; - -class npc_ulduar_toasty_fire : public CreatureScript -{ -public: - npc_ulduar_toasty_fire() : CreatureScript("npc_ulduar_toasty_fire") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_toasty_fireAI : public NullCreatureAI - { - npc_ulduar_toasty_fireAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - me->CastSpell(me, SPELL_MAGE_TOASTY_FIRE_AURA, true); - } - - void DoAction(int32 a) override - { - if (a == 1) - { - if( GameObject* fire = me->FindNearestGameObject(194300, 1.0f) ) - { - fire->SetOwnerGUID(ObjectGuid::Empty); - fire->Delete(); - } - me->DespawnOrUnsummon(); // this will remove DynObjects - } - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - switch( spell->Id ) - { - case SPELL_ICE_SHARDS_SMALL: - case SPELL_ICE_SHARDS_BIG: - DoAction(1); - break; - } - } - }; -}; - -class npc_ulduar_hodir_priest : public CreatureScript -{ -public: - npc_ulduar_hodir_priest() : CreatureScript("npc_ulduar_hodir_priest") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_hodir_priestAI : public ScriptedAI - { - npc_ulduar_hodir_priestAI(Creature* pCreature) : ScriptedAI(pCreature) - { - pInstance = me->GetInstanceScript(); - events.Reset(); - me->SetReactState(REACT_PASSIVE); - } - - EventMap events; - InstanceScript* pInstance; - - void AttackStart(Unit* who) override - { - AttackStartCaster(who, 17.0f); - } - - void ScheduleAbilities() - { - events.ScheduleEvent(EVENT_PRIEST_DISPELL_MAGIC, 7s); - events.ScheduleEvent(EVENT_PRIEST_GREAT_HEAL, 6s, 7s); - events.ScheduleEvent(EVENT_PRIEST_SMITE, 2100ms); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC) - { - events.Reset(); - events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s); - } - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - - if( me->HasUnitState(UNIT_STATE_CASTING) ) - return; - - switch( events.ExecuteEvent() ) - { - case 0: - break; - case EVENT_TRY_FREE_HELPER: - { - if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) ) - if( pInstance ) - if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) ) - if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) ) - { - AttackStart(hodir); - ScheduleAbilities(); - break; - } - events.Repeat(2s); - } - break; - case EVENT_PRIEST_DISPELL_MAGIC: - me->CastCustomSpell(SPELL_PRIEST_DISPELL_MAGIC, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false); - events.Repeat(7s); - break; - case EVENT_PRIEST_GREAT_HEAL: - me->CastSpell(me, SPELL_PRIEST_GREAT_HEAL, false); - events.Repeat(6s, 7s); - break; - case EVENT_PRIEST_SMITE: - if (Unit* victim = me->GetVictim()) - me->CastSpell(victim, SPELL_PRIEST_SMITE, false); - events.Repeat(2100ms); - break; - } - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - - void EnterEvadeMode(EvadeReason /*why*/) override {} - bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; } - - void JustDied(Unit* /*killer*/) override - { - if (pInstance) - if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR))) - hodir->AI()->SetData(4, 1); - } - }; -}; - -class npc_ulduar_hodir_druid : public CreatureScript -{ -public: - npc_ulduar_hodir_druid() : CreatureScript("npc_ulduar_hodir_druid") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_hodir_druidAI : public ScriptedAI - { - npc_ulduar_hodir_druidAI(Creature* pCreature) : ScriptedAI(pCreature) - { - pInstance = me->GetInstanceScript(); - events.Reset(); - me->SetReactState(REACT_PASSIVE); - } - - EventMap events; - InstanceScript* pInstance; - - void AttackStart(Unit* who) override - { - AttackStartCaster(who, 22.0f); - } - - void ScheduleAbilities() - { - events.ScheduleEvent(EVENT_DRUID_WRATH, 1600ms); - events.ScheduleEvent(EVENT_DRUID_STARLIGHT, 10s); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC) - { - events.Reset(); - events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s); - } - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - - if( me->HasUnitState(UNIT_STATE_CASTING) ) - return; - - switch( events.ExecuteEvent() ) - { - case 0: - break; - case EVENT_TRY_FREE_HELPER: - { - if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) ) - if( pInstance ) - if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) ) - if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) ) - { - AttackStart(hodir); - ScheduleAbilities(); - break; - } - events.Repeat(2s); - } - break; - case EVENT_DRUID_WRATH: - if (Unit* victim = me->GetVictim()) - me->CastSpell(victim, SPELL_DRUID_WRATH, false); - events.Repeat(1600ms); - break; - case EVENT_DRUID_STARLIGHT: - if (me->GetPositionZ() < 433.0f) // ensure npc is on the ground - { - me->CastSpell(me, SPELL_DRUID_STARLIGHT_AREA_AURA, false); - events.Repeat(15s); - break; - } - events.Repeat(3s); - break; - } - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - - void EnterEvadeMode(EvadeReason /*why*/) override {} - bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; } - - void JustDied(Unit* /*killer*/) override - { - if (pInstance) - if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR))) - hodir->AI()->SetData(4, 1); - } - }; -}; - -class npc_ulduar_hodir_shaman : public CreatureScript -{ -public: - npc_ulduar_hodir_shaman() : CreatureScript("npc_ulduar_hodir_shaman") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_hodir_shamanAI : public ScriptedAI - { - npc_ulduar_hodir_shamanAI(Creature* pCreature) : ScriptedAI(pCreature) - { - pInstance = me->GetInstanceScript(); - events.Reset(); - me->SetReactState(REACT_PASSIVE); - } - - EventMap events; - InstanceScript* pInstance; - - void AttackStart(Unit* who) override - { - AttackStartCaster(who, 25.0f); - } - - void ScheduleAbilities() - { - events.ScheduleEvent(EVENT_SHAMAN_LAVA_BURST, 2600ms); - events.ScheduleEvent(EVENT_SHAMAN_STORM_CLOUD, 10s); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC) - { - events.Reset(); - events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s); - } - } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) override - { - if (target && spell->Id == SPELL_SHAMAN_STORM_CLOUD) - if (Aura* a = target->GetAura(SPELL_SHAMAN_STORM_CLOUD, me->GetGUID())) - a->SetStackAmount(spell->StackAmount); - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - - if( me->HasUnitState(UNIT_STATE_CASTING) ) - return; - - switch( events.ExecuteEvent() ) - { - case 0: - break; - case EVENT_TRY_FREE_HELPER: - { - if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) ) - if( pInstance ) - if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) ) - if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) ) - { - AttackStart(hodir); - ScheduleAbilities(); - break; - } - events.Repeat(2s); - } - break; - case EVENT_SHAMAN_LAVA_BURST: - if (Unit* victim = me->GetVictim()) - me->CastSpell(victim, SPELL_SHAMAN_LAVA_BURST, false); - events.Repeat(2600ms); - break; - case EVENT_SHAMAN_STORM_CLOUD: - if (Player* target = ScriptedAI::SelectTargetFromPlayerList(35.0f, SPELL_SHAMAN_STORM_CLOUD)) - me->CastSpell(target, SPELL_SHAMAN_STORM_CLOUD, false); - events.Repeat(30s); - break; - } - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - - void EnterEvadeMode(EvadeReason /*why*/) override {} - bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; } - - void JustDied(Unit* /*killer*/) override - { - if (pInstance) - if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR))) - hodir->AI()->SetData(4, 1); - } - }; -}; - -class npc_ulduar_hodir_mage : public CreatureScript -{ -public: - npc_ulduar_hodir_mage() : CreatureScript("npc_ulduar_hodir_mage") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_hodir_mageAI : public ScriptedAI - { - npc_ulduar_hodir_mageAI(Creature* pCreature) : ScriptedAI(pCreature) - { - pInstance = me->GetInstanceScript(); - events.Reset(); - me->SetReactState(REACT_PASSIVE); - } - - EventMap events; - InstanceScript* pInstance; - - void AttackStart(Unit* who) override - { - AttackStartCaster(who, 30.0f); - } - - void ScheduleAbilities() - { - events.ScheduleEvent(EVENT_MAGE_FIREBALL, 3100ms); - events.ScheduleEvent(EVENT_MAGE_TOASTY_FIRE, 6s); - events.ScheduleEvent(EVENT_MAGE_MELT_ICE, 1s); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC) - { - events.Reset(); - events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s); - } - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - - if( me->HasUnitState(UNIT_STATE_CASTING) ) - return; - - switch( events.ExecuteEvent() ) - { - case 0: - break; - case EVENT_TRY_FREE_HELPER: - { - if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) ) - if( pInstance ) - if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) ) - if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) ) - { - AttackStart(hodir); - ScheduleAbilities(); - break; - } - events.Repeat(2s); - } - break; - case EVENT_MAGE_FIREBALL: - if (Unit* victim = me->GetVictim()) - me->CastSpell(victim, SPELL_MAGE_FIREBALL, false); - events.Repeat(3100ms); - break; - case EVENT_MAGE_TOASTY_FIRE: - me->CastSpell(me, SPELL_MAGE_CONJURE_TOASTY_FIRE, false); - events.Repeat(10s); - break; - case EVENT_MAGE_MELT_ICE: - { - std::list FB; - bool found = false; - me->GetCreaturesWithEntryInRange(FB, 150.0f, NPC_FLASH_FREEZE_NPC); - for( std::list::const_iterator itr = FB.begin(); itr != FB.end(); ++itr ) - if( !((*itr)->HasAura(SPELL_MAGE_MELT_ICE)) ) - { - me->CastSpell((*itr), SPELL_MAGE_MELT_ICE, false); - found = true; - break; - } - - if( found ) - { - events.DelayEvents(2s); - events.Repeat(2s); - break; - } - events.Repeat(5s); - } - break; - } - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - - void EnterEvadeMode(EvadeReason /*why*/) override {} - bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; } - - void JustDied(Unit* /*killer*/) override - { - if (pInstance) - if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR))) - hodir->AI()->SetData(4, 1); - } - }; -}; - -class spell_hodir_shatter_chest : public SpellScriptLoader -{ -public: - spell_hodir_shatter_chest() : SpellScriptLoader("spell_hodir_shatter_chest") { } - - class spell_hodir_shatter_chestSpellScript : public SpellScript - { - PrepareSpellScript(spell_hodir_shatter_chestSpellScript) - - void destroyWinterCache(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - - if (Unit* hodir = GetCaster()) - hodir->GetAI()->DoAction(EVENT_FAIL_HM); - } - - void Register() override - { - OnEffectHit += SpellEffectFn(spell_hodir_shatter_chestSpellScript::destroyWinterCache, EFFECT_0, SPELL_EFFECT_TRIGGER_MISSILE); - }; - }; - - SpellScript* GetSpellScript() const override - { - return new spell_hodir_shatter_chestSpellScript(); - } -}; - -class spell_hodir_biting_cold_main_aura : public SpellScriptLoader -{ -public: - spell_hodir_biting_cold_main_aura() : SpellScriptLoader("spell_hodir_biting_cold_main_aura") { } - - class spell_hodir_biting_cold_main_aura_AuraScript : public AuraScript - { - PrepareAuraScript(spell_hodir_biting_cold_main_aura_AuraScript) - - void HandleEffectPeriodic(AuraEffect const* aurEff) - { - if ((aurEff->GetTickNumber() % 4) == 0) - if (Unit* target = GetTarget()) - if (target->GetTypeId() == TYPEID_PLAYER - && !target->isMoving() - && !target->HasAura(SPELL_BITING_COLD_PLAYER_AURA) - && !target->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA)) - target->CastSpell(target, SPELL_BITING_COLD_PLAYER_AURA, true); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_biting_cold_main_aura_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_hodir_biting_cold_main_aura_AuraScript(); - } -}; - -class spell_hodir_biting_cold_player_aura : public SpellScriptLoader -{ -public: - spell_hodir_biting_cold_player_aura() : SpellScriptLoader("spell_hodir_biting_cold_player_aura") { } - - class spell_hodir_biting_cold_player_aura_AuraScript : public AuraScript - { - PrepareAuraScript(spell_hodir_biting_cold_player_aura_AuraScript) - - uint8 counter {0}; - bool prev {false}; - - void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) - { - if (Unit* target = GetTarget()) - { - if (target->GetMapId() == 603) - SetDuration(GetMaxDuration()); - if (target->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER)) - return; - if (target->isMoving() || target->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA)) - { - if (prev) - { - ModStackAmount(-1); - prev = false; - } - else - prev = true; - - if (counter >= 2) - counter -= 2; - else if (counter) - --counter; - } - else - { - prev = false; - ++counter; - if (counter >= 4) - { - if (GetStackAmount() == 2) // increasing from 2 to 3 (not checking >= to improve performance) - if (InstanceScript* pInstance = target->GetInstanceScript()) - if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR))) - hodir->AI()->SetData(2, 1); - ModStackAmount(1); - counter = 0; - } - } - - const int32 dmg = 200 * pow(2.0f, GetStackAmount()); - target->CastCustomSpell(target, SPELL_BITING_COLD_DAMAGE, &dmg, 0, 0, true); - } - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_biting_cold_player_aura_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_hodir_biting_cold_player_aura_AuraScript(); - } -}; - -class spell_hodir_periodic_icicle : public SpellScriptLoader -{ -public: - spell_hodir_periodic_icicle() : SpellScriptLoader("spell_hodir_periodic_icicle") { } - - class spell_hodir_periodic_icicle_SpellScript : public SpellScript - { - PrepareSpellScript(spell_hodir_periodic_icicle_SpellScript); - - void FilterTargets(std::list& targets) - { - targets.remove_if(Acore::ObjectTypeIdCheck(TYPEID_PLAYER, false)); - targets.remove_if(Acore::UnitAuraCheck(true, SPELL_FLASH_FREEZE_TRAPPED_PLAYER)); - Acore::Containers::RandomResize(targets, 1); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_periodic_icicle_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_hodir_periodic_icicle_SpellScript(); - } -}; - -class FlashFreezeCheck -{ -public: - FlashFreezeCheck() { } - - bool operator()(WorldObject* target) const - { - if (Unit* unit = target->ToUnit()) - return unit->HasAura(SPELL_SAFE_AREA_TRIGGERED) || unit->IsPet(); - return true; - } -}; - -class spell_hodir_flash_freeze : public SpellScriptLoader -{ -public: - spell_hodir_flash_freeze() : SpellScriptLoader("spell_hodir_flash_freeze") { } - - class spell_hodir_flash_freeze_SpellScript : public SpellScript - { - PrepareSpellScript(spell_hodir_flash_freeze_SpellScript); - - void FilterTargets(std::list& targets) - { - targets.remove_if(FlashFreezeCheck()); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_flash_freeze_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_flash_freeze_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - class spell_hodir_flash_freeze_AuraScript : public AuraScript - { - PrepareAuraScript(spell_hodir_flash_freeze_AuraScript) - - void HandleEffectPeriodic(AuraEffect const* aurEff) - { - if (aurEff->GetTotalTicks() > 0 && aurEff->GetTickNumber() == uint32(aurEff->GetTotalTicks()) - 1) - { - Unit* target = GetTarget(); - Unit* caster = GetCaster(); - if (!target || !caster || caster->GetTypeId() != TYPEID_UNIT) - return; - - if (Aura* aur = target->GetAura(target->GetTypeId() == TYPEID_PLAYER ? SPELL_FLASH_FREEZE_TRAPPED_PLAYER : SPELL_FLASH_FREEZE_TRAPPED_NPC)) - { - if (Unit* caster2 = aur->GetCaster()) - { - if (caster2->GetTypeId() == TYPEID_UNIT) - { - caster2->ToCreature()->DespawnOrUnsummon(); - } - } - target->CastSpell(target, SPELL_FLASH_FREEZE_INSTAKILL, true); - return; - } - if (target->GetTypeId() == TYPEID_PLAYER) - { - caster->ToCreature()->AI()->SetData(1, 1); - if( Creature* c = target->SummonCreature(NPC_FLASH_FREEZE_PLR, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 5 * 60 * 1000) ) - { - c->CastSpell(target, SPELL_FLASH_FREEZE_TRAPPED_PLAYER, true); - caster->ToCreature()->AI()->JustSummoned(c); - } - } - else if (target->GetTypeId() == TYPEID_UNIT) - { - if( Creature* c = target->SummonCreature(NPC_FLASH_FREEZE_NPC, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000) ) - { - c->CastSpell(target, SPELL_FLASH_FREEZE_TRAPPED_NPC, true); - caster->ToCreature()->AI()->JustSummoned(c); - } - } - } - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_flash_freeze_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_hodir_flash_freeze_SpellScript(); - } - - AuraScript* GetAuraScript() const override - { - return new spell_hodir_flash_freeze_AuraScript(); - } -}; - -class spell_hodir_storm_power : public SpellScriptLoader -{ -public: - spell_hodir_storm_power() : SpellScriptLoader("spell_hodir_storm_power") { } - - class spell_hodir_storm_power_AuraScript : public AuraScript - { - PrepareAuraScript(spell_hodir_storm_power_AuraScript) - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* caster = GetCaster()) - if (Aura* a = caster->GetAura(GetId() == SPELL_SHAMAN_STORM_POWER_10 ? SPELL_SHAMAN_STORM_CLOUD_10 : SPELL_SHAMAN_STORM_CLOUD_25)) - a->ModStackAmount(-1); - } - - void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* target = GetTarget()) - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, GetId(), 0, GetCaster()); - } - - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_hodir_storm_power_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, AURA_EFFECT_HANDLE_REAL); - AfterEffectApply += AuraEffectApplyFn(spell_hodir_storm_power_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_hodir_storm_power_AuraScript(); - } -}; - -class spell_hodir_storm_cloud : public SpellScriptLoader -{ -public: - spell_hodir_storm_cloud() : SpellScriptLoader("spell_hodir_storm_cloud") { } - - class spell_hodir_storm_cloud_AuraScript : public AuraScript - { - PrepareAuraScript(spell_hodir_storm_cloud_AuraScript) - - void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - if (Unit* target = GetTarget()) - target->CastSpell((Unit*)nullptr, (GetId() == SPELL_SHAMAN_STORM_CLOUD_10 ? SPELL_SHAMAN_STORM_POWER_10 : SPELL_SHAMAN_STORM_POWER_25), true); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_storm_cloud_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_hodir_storm_cloud_AuraScript(); - } -}; - -class achievement_cheese_the_freeze : public AchievementCriteriaScript -{ -public: - achievement_cheese_the_freeze() : AchievementCriteriaScript("achievement_cheese_the_freeze") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1); - } -}; - -class achievement_getting_cold_in_here : public AchievementCriteriaScript -{ -public: - achievement_getting_cold_in_here() : AchievementCriteriaScript("achievement_getting_cold_in_here") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(2); - } -}; - -class achievement_i_could_say_that_this_cache_was_rare : public AchievementCriteriaScript -{ -public: - achievement_i_could_say_that_this_cache_was_rare() : AchievementCriteriaScript("achievement_i_could_say_that_this_cache_was_rare") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(3); - } -}; - -class achievement_i_have_the_coolest_friends : public AchievementCriteriaScript -{ -public: - achievement_i_have_the_coolest_friends() : AchievementCriteriaScript("achievement_i_have_the_coolest_friends") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(4); - } -}; - -class achievement_staying_buffed_all_winter_10 : public AchievementCriteriaScript -{ -public: - achievement_staying_buffed_all_winter_10() : AchievementCriteriaScript("achievement_staying_buffed_all_winter_10") {} - - bool OnCheck(Player* player, Unit* /*target*/, uint32 /*criteria_id*/) override - { - return player && player->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA) && player->HasAura(SPELL_DRUID_STARLIGHT_AREA_AURA) && player->HasAura(SPELL_SHAMAN_STORM_POWER_10); - } -}; - -class achievement_staying_buffed_all_winter_25 : public AchievementCriteriaScript -{ -public: - achievement_staying_buffed_all_winter_25() : AchievementCriteriaScript("achievement_staying_buffed_all_winter_25") {} - - bool OnCheck(Player* player, Unit* /*target*/, uint32 /*criteria_id*/) override - { - return player && player->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA) && player->HasAura(SPELL_DRUID_STARLIGHT_AREA_AURA) && player->HasAura(SPELL_SHAMAN_STORM_POWER_25); - } -}; - -class spell_hodir_toasty_fire : public SpellScriptLoader -{ -public: - spell_hodir_toasty_fire() : SpellScriptLoader("spell_hodir_toasty_fire") { } - - class spell_hodir_toasty_fire_AuraScript : public AuraScript - { - PrepareAuraScript(spell_hodir_toasty_fire_AuraScript); - - void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* target = GetTarget()) - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, SPELL_MAGE_TOASTY_FIRE_AURA, 0, GetCaster()); - } - - void Register() override - { - AfterEffectApply += AuraEffectApplyFn(spell_hodir_toasty_fire_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MOD_STAT, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_hodir_toasty_fire_AuraScript(); - } -}; - -class spell_hodir_starlight : public SpellScriptLoader -{ -public: - spell_hodir_starlight() : SpellScriptLoader("spell_hodir_starlight") { } - - class spell_hodir_starlight_AuraScript : public AuraScript - { - PrepareAuraScript(spell_hodir_starlight_AuraScript); - - void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* target = GetTarget()) - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, SPELL_DRUID_STARLIGHT_AREA_AURA, 0, GetCaster()); - } - - void Register() override - { - AfterEffectApply += AuraEffectApplyFn(spell_hodir_starlight_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MELEE_SLOW, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_hodir_starlight_AuraScript(); - } -}; - void AddSC_boss_hodir() { new boss_hodir(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.h new file mode 100644 index 00000000000000..db4b87011c8253 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.h @@ -0,0 +1,1594 @@ +#ifndef BOSS_HODIR_H_ +#define BOSS_HODIR_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "SpellAuras.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "ulduar.h" + +enum HodirSpellData +{ + SPELL_BERSERK = 26662, + + SPELL_BITING_COLD_BOSS_AURA = 62038, + SPELL_BITING_COLD_PLAYER_AURA = 62039, + SPELL_BITING_COLD_DAMAGE = 62188, + + SPELL_FREEZE = 62469, + + SPELL_FLASH_FREEZE_CAST = 61968, + SPELL_FLASH_FREEZE_INSTAKILL = 62226, + SPELL_FLASH_FREEZE_TRAPPED_PLAYER = 61969, + SPELL_FLASH_FREEZE_TRAPPED_NPC = 61990, + SPELL_FLASH_FREEZE_VISUAL = 62148, + SPELL_SAFE_AREA = 65705, + SPELL_SAFE_AREA_TRIGGERED = 62464, + SPELL_SHATTER_CHEST = 62501, + + SPELL_ICICLE_BOSS_AURA = 62227, + SPELL_ICICLE_TBBA = 63545, + + SPELL_ICICLE_VISUAL_UNPACKED = 62234, + SPELL_ICICLE_VISUAL_PACKED = 62462, + SPELL_ICICLE_VISUAL_FALLING = 62453, + SPELL_ICICLE_FALL_EFFECT_UNPACKED = 62236, + SPELL_ICICLE_FALL_EFFECT_PACKED = 62460, + SPELL_ICE_SHARDS_SMALL = 62457, + SPELL_ICE_SHARDS_BIG = 65370, + SPELL_SNOWDRIFT = 62463, + + SPELL_FROZEN_BLOWS_10 = 62478, + SPELL_FROZEN_BLOWS_25 = 63512, + + // Helpers: + SPELL_PRIEST_DISPELL_MAGIC = 63499, + SPELL_PRIEST_GREAT_HEAL = 62809, + SPELL_PRIEST_SMITE = 61923, + + SPELL_DRUID_WRATH = 62793, + SPELL_DRUID_STARLIGHT_AREA_AURA = 62807, + + SPELL_SHAMAN_LAVA_BURST = 61924, + SPELL_SHAMAN_STORM_CLOUD_10 = 65123, + SPELL_SHAMAN_STORM_CLOUD_25 = 65133, + SPELL_SHAMAN_STORM_POWER_10 = 63711, + SPELL_SHAMAN_STORM_POWER_25 = 65134, + + SPELL_MAGE_FIREBALL = 61909, + SPELL_MAGE_MELT_ICE = 64528, + SPELL_MAGE_CONJURE_TOASTY_FIRE = 62823, + SPELL_MAGE_SUMMON_TOASTY_FIRE = 62819, + SPELL_MAGE_TOASTY_FIRE_AURA = 62821, + SPELL_SINGED = 65280, +}; + +enum HodirNPCs +{ + //NPC_HODIR = 32845, + + NPC_PAN_FIELD_MEDIC_PENNY = 32897, + NPC_DAN_ELLIE_NIGHTFEATHER = 32901, + NPC_SAN_ELEMENTALIST_AVUUN = 32900, + NPC_MAN_MISSY_FLAMECUFFS = 32893, + + NPC_PAH_FIELD_MEDIC_JESSI = 33326, + NPC_DAH_EIVI_NIGHTFEATHER = 33325, + NPC_SAH_ELEMENTALIST_MAHFUUN = 33328, + NPC_MAH_SISSY_FLAMECUFFS = 33327, + + NPC_PHN_BATTLEPRIEST_ELIZA = 32948, + NPC_DHN_TOR_GREYCLOUD = 32941, + NPC_SHN_SPIRITWALKER_YONA = 32950, + NPC_MHN_VEESHA_BLAZEWEAVER = 32946, + + NPC_PHH_BATTLEPRIEST_GINA = 33330, + NPC_DHH_KAR_GREYCLOUD = 33333, + NPC_SHH_SPIRITWALKER_TARA = 33332, + NPC_MHH_AMIRA_BLAZEWEAVER = 33331, + + NPC_FLASH_FREEZE_PLR = 32926, + NPC_FLASH_FREEZE_NPC = 32938, + NPC_ICICLE_UNPACKED = 33169, + NPC_ICICLE_PACKED = 33173, + NPC_TOASTY_FIRE = 33342, + NPC_RARE_WINTER_CACHE_TRIGGER = 88101, +}; + +enum HodirEvents +{ + // Hodir: + EVENT_FLASH_FREEZE = 1, + EVENT_FROZEN_BLOWS = 2, + EVENT_BERSERK = 3, + EVENT_FREEZE = 4, + EVENT_SMALL_ICICLES_ENABLE = 5, + EVENT_HARD_MODE_MISSED = 6, + EVENT_DESPAWN_CHEST = 7, + EVENT_FAIL_HM = 8, + + EVENT_TRY_FREE_HELPER = 10, + EVENT_PRIEST_DISPELL_MAGIC = 11, + EVENT_PRIEST_GREAT_HEAL = 12, + EVENT_PRIEST_SMITE = 13, + EVENT_DRUID_WRATH = 14, + EVENT_DRUID_STARLIGHT = 15, + EVENT_SHAMAN_LAVA_BURST = 16, + EVENT_SHAMAN_STORM_CLOUD = 17, + EVENT_MAGE_TOASTY_FIRE = 18, + EVENT_MAGE_FIREBALL = 19, + EVENT_MAGE_MELT_ICE = 20, +}; + +enum HodirText +{ + TEXT_AGGRO = 0, + TEXT_SLAY = 1, + TEXT_FLASH_FREEZE = 2, + TEXT_STALACTITE = 3, + TEXT_DEATH = 4, + TEXT_BERSERK = 5, + TEXT_HM_MISS = 6, + TEXT_EMOTE_FREEZE = 7, + TEXT_EMOTE_BLOW = 8, +}; + +#define SPELL_FROZEN_BLOWS RAID_MODE(SPELL_FROZEN_BLOWS_10, SPELL_FROZEN_BLOWS_25) +#define SPELL_SHAMAN_STORM_CLOUD RAID_MODE(SPELL_SHAMAN_STORM_CLOUD_10, SPELL_SHAMAN_STORM_CLOUD_25) + +enum HodirSounds +{ + SOUND_HODIR_AGGRO = 15552, + SOUND_HODIR_SLAIN_1 = 15553, + SOUND_HODIR_SLAIN_2 = 15554, + SOUND_HODIR_FLASH_FREEZE = 15555, + SOUND_HODIR_FROZEN_BLOWS = 15556, + SOUND_HODIR_DEFEATED = 15557, + SOUND_HODIR_BERSERK = 15558, +}; + +struct HodirHelperData +{ + uint32 id; + float x, y; +}; +HodirHelperData hhd[4][4] = +{ + // Alliance: + { + {NPC_PAN_FIELD_MEDIC_PENNY, 2020.46f, -236.74f}, + {NPC_DAN_ELLIE_NIGHTFEATHER, 2007.21f, -241.57f}, + {NPC_SAN_ELEMENTALIST_AVUUN, 1999.14f, -230.69f}, + {NPC_MAN_MISSY_FLAMECUFFS, 1984.38f, -242.57f} + }, + { + {NPC_PAH_FIELD_MEDIC_JESSI, 2012.29f, -233.70f}, + {NPC_DAH_EIVI_NIGHTFEATHER, 1995.75f, -241.32f}, + {NPC_SAH_ELEMENTALIST_MAHFUUN, 1989.31f, -234.26f}, + {NPC_MAH_SISSY_FLAMECUFFS, 1977.87f, -233.99f} + }, + // Horde: + { + {NPC_PHN_BATTLEPRIEST_ELIZA, 2020.46f, -236.74f}, + {NPC_DHN_TOR_GREYCLOUD, 2007.21f, -241.57f}, + {NPC_SHN_SPIRITWALKER_YONA, 1999.14f, -230.69f}, + {NPC_MHN_VEESHA_BLAZEWEAVER, 1984.38f, -242.57f} + }, + { + {NPC_PHH_BATTLEPRIEST_GINA, 2012.29f, -233.70f}, + {NPC_DHH_KAR_GREYCLOUD, 1995.75f, -241.32f}, + {NPC_SHH_SPIRITWALKER_TARA, 1989.31f, -234.6f}, + {NPC_MHH_AMIRA_BLAZEWEAVER, 1977.87f, -233.99f} + } +}; + +class boss_hodir : public CreatureScript +{ +public: + boss_hodir() : CreatureScript("boss_hodir") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_hodirAI : public ScriptedAI + { + boss_hodirAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + { + pInstance = pCreature->GetInstanceScript(); + if (!me->IsAlive()) + if (pInstance) + pInstance->SetData(TYPE_HODIR, DONE); + } + + InstanceScript* pInstance; + EventMap events; + SummonList summons; + ObjectGuid Helpers[8]; + bool berserk{ false }; + bool bAchievCheese{ true }; + bool bAchievGettingCold{ true }; + bool bAchievCacheRare{ true }; + bool bAchievCoolestFriends{ true }; + uint16 addSpawnTimer{ 0 }; + + // Used to make Hodir disengage whenever he leaves his room + const Position ENTRANCE_DOOR{ 1999.160034f, -297.792999f, 431.960999f, 0 }; + const Position EXIT_DOOR{ 1999.709961f, -166.259003f, 432.822998f, 0 }; + + void Reset() override + { + events.Reset(); + summons.DespawnAll(); + berserk = false; + bAchievCheese = true; + bAchievGettingCold = true; + bAchievCacheRare = true; + bAchievCoolestFriends = true; + me->SetSheath(SHEATH_STATE_MELEE); + + // Reset the spells cast after wipe + me->RemoveAllAuras(); + pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA); + + if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE) + { + pInstance->SetData(TYPE_HODIR, NOT_STARTED); + } + + if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 900.0f)) + { + go->SetGoState(GO_STATE_ACTIVE); + } + + // Reset helpers + if (!summons.size()) + SpawnHelpers(); + } + + void JustEngagedWith(Unit* /*pWho*/) override + { + me->CastSpell(me, SPELL_BITING_COLD_BOSS_AURA, true); + SmallIcicles(true); + events.Reset(); + events.ScheduleEvent(EVENT_FLASH_FREEZE, 48s, 49s); + events.ScheduleEvent(EVENT_FREEZE, 17s, 20s); + events.ScheduleEvent(EVENT_BERSERK, 8min); + events.ScheduleEvent(EVENT_HARD_MODE_MISSED, 3min); + Talk(TEXT_AGGRO); + + if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE) + { + pInstance->SetData(TYPE_HODIR, IN_PROGRESS); + } + + if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 300.0f)) + { + go->SetGoState(GO_STATE_READY); + } + } + + void DoAction(int action) override + { + if (action) + { + switch (action) + { + case EVENT_FAIL_HM: + if (pInstance) + { + if (GameObject* go = pInstance->instance->GetGameObject(pInstance->GetGuidData(GO_HODIR_CHEST_HARD))) + { + go->SetGoState(GO_STATE_ACTIVE); + events.ScheduleEvent(EVENT_DESPAWN_CHEST, 3s); + } + } + break; + } + } + } + + void SmallIcicles(bool enable) + { + if( enable ) + me->CastSpell(me, SPELL_ICICLE_BOSS_AURA, true); + else + me->RemoveAura(SPELL_ICICLE_BOSS_AURA); + } + + void SpellHitTarget(Unit* target, SpellInfo const* spell) override + { + switch( spell->Id ) + { + case SPELL_ICICLE_TBBA: + me->CastSpell(target, SPELL_ICICLE_VISUAL_UNPACKED, true); + break; + case SPELL_FLASH_FREEZE_VISUAL: + { + std::list fires; + me->GetCreaturesWithEntryInRange(fires, 200.0f, NPC_TOASTY_FIRE); + for (std::list::iterator itr = fires.begin(); itr != fires.end(); ++itr) + (*itr)->AI()->DoAction(1); // remove it + } + break; + } + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage >= me->GetHealth() || me->GetHealth() < 150000) + { + damage = 0; + me->SetReactState(REACT_PASSIVE); + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + { + if (pInstance) + { + pInstance->SetData(TYPE_HODIR, DONE); + me->CastSpell(me, 64899, true); // credit + } + + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetFaction(FACTION_FRIENDLY); + me->GetMotionMaster()->Clear(); + me->AttackStop(); + me->CombatStop(); + me->InterruptNonMeleeSpells(true); + me->RemoveAllAuras(); + pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA); + + events.Reset(); + summons.DespawnAll(); + + if( GameObject* d = me->FindNearestGameObject(GO_HODIR_FROZEN_DOOR, 250.0f)) + { + if( d->GetGoState() != GO_STATE_ACTIVE ) + { + d->SetLootState(GO_READY); + d->UseDoorOrButton(0, false); + } + } + if (GameObject* d = me->FindNearestGameObject(GO_HODIR_DOOR, 250.0f)) + { + if( d->GetGoState() != GO_STATE_ACTIVE ) + { + d->SetLootState(GO_READY); + d->UseDoorOrButton(0, false); + } + } + + if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 300.0f)) + { + go->SetGoState(GO_STATE_ACTIVE); + } + + Talk(TEXT_DEATH); + me->DespawnOrUnsummon(10000); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (me->GetPositionY() <= ENTRANCE_DOOR.GetPositionY() || me->GetPositionY() >= EXIT_DOOR.GetPositionY()) + { + boss_hodirAI::EnterEvadeMode(); + return; + } + + if (!UpdateVictim()) + { + if (me->IsInCombat()) + { + Map::PlayerList const& pl = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) + itr->GetSource()->CastSpell(itr->GetSource(), SPELL_FLASH_FREEZE_INSTAKILL, true); + EnterEvadeMode(); + } + return; + } + + events.Update(diff); + + if( me->HasUnitState(UNIT_STATE_CASTING) ) + return; + + switch (events.ExecuteEvent()) + { + case 0: + break; + case EVENT_BERSERK: + { + berserk = true; + me->CastSpell(me, SPELL_BERSERK, true); + Talk(TEXT_BERSERK); + } + break; + case EVENT_HARD_MODE_MISSED: + { + Talk(TEXT_HM_MISS); + bAchievCacheRare = false; + if (pInstance) + { + if (GameObject* go = pInstance->instance->GetGameObject(pInstance->GetGuidData(GO_HODIR_CHEST_HARD))) + { + me->CastSpell(go, SPELL_SHATTER_CHEST, false); + } + } + } + break; + case EVENT_DESPAWN_CHEST: + if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE) + pInstance->SetData(TYPE_HODIR_HM_FAIL, 0); + break; + case EVENT_FLASH_FREEZE: + { + std::list targets; + Map::PlayerList const& pl = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr) + targets.push_back(itr->GetSource()); + targets.remove_if(Acore::ObjectTypeIdCheck(TYPEID_PLAYER, false)); + targets.remove_if(Acore::UnitAuraCheck(true, SPELL_FLASH_FREEZE_TRAPPED_PLAYER)); + Acore::Containers::RandomResize(targets, (RAID_MODE(2,3))); + for (std::list::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) + { + float prevZ = (*itr)->GetPositionZ(); + (*itr)->m_positionZ = 432.7f; + (*itr)->CastSpell((*itr), SPELL_ICICLE_VISUAL_PACKED, true); + (*itr)->m_positionZ = prevZ; + } + + me->CastSpell((Unit*)nullptr, SPELL_FLASH_FREEZE_CAST, false); + me->PlayDirectSound(SOUND_HODIR_FLASH_FREEZE, 0); + Talk(TEXT_FLASH_FREEZE); + Talk(TEXT_EMOTE_FREEZE); + SmallIcicles(false); + events.ScheduleEvent(EVENT_FLASH_FREEZE, 48s, 49s); + events.ScheduleEvent(EVENT_SMALL_ICICLES_ENABLE, Is25ManRaid() ? 12s : 24s); + events.ScheduleEvent(EVENT_FROZEN_BLOWS, 15s); + events.RescheduleEvent(EVENT_FREEZE, 17s, 20s); + } + break; + case EVENT_SMALL_ICICLES_ENABLE: + { + SmallIcicles(true); + } + break; + case EVENT_FROZEN_BLOWS: + { + Talk(TEXT_EMOTE_BLOW); + Talk(TEXT_STALACTITE); + me->CastSpell(me, Is25ManRaid()? SPELL_FROZEN_BLOWS_25 : SPELL_FROZEN_BLOWS_10, true); + } + break; + case EVENT_FREEZE: + if (Player* plr = SelectTargetFromPlayerList(50.0f, SPELL_FLASH_FREEZE_TRAPPED_PLAYER)) + { + me->CastSpell(plr, SPELL_FREEZE, false); + } + else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true)) + { + me->CastSpell(target, SPELL_FREEZE, false); + } + events.RescheduleEvent(EVENT_FREEZE, 17s, 20s); + break; + } + + DoMeleeAttackIfReady(); + } + + Creature* GetHelper(uint8 index) + { + return Helpers[index] ? ObjectAccessor::GetCreature(*me, Helpers[index]) : nullptr; + } + + void SpawnHelpers() + { + char faction = 'A'; + if( hhd[0][0].id ) + { + Map::PlayerList const& cl = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = cl.begin(); itr != cl.end(); ++itr) + if (!itr->GetSource()->IsGameMaster()) + { + faction = (itr->GetSource()->GetTeamId() == TEAM_ALLIANCE ? 'A' : 'H'); + break; + } + } + + uint8 cnt = 0; + if( faction ) + for( uint8 k = 0; k < 4; ++k ) + { + if( (faction == 'A' && ( k > 1 || (k == 1 && RAID_MODE(1, 0)) )) || + (faction == 'H' && ( k < 2 || (k == 3 && RAID_MODE(1, 0)) )) ) + continue; + + for( uint8 i = 0; i < 4; ++i ) + { + if( !hhd[k][i].id ) + continue; + + if( Creature* h_p = me->SummonCreature(hhd[k][i].id, hhd[k][i].x, hhd[k][i].y, 432.69f, M_PI / 2) ) + { + h_p->SetFaction(1665); + if( cnt < 8 ) + Helpers[cnt++] = h_p->GetGUID(); + + if( Creature* c = h_p->SummonCreature(NPC_FLASH_FREEZE_NPC, h_p->GetPositionX(), h_p->GetPositionY(), h_p->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000) ) + { + c->CastSpell(h_p, SPELL_FLASH_FREEZE_TRAPPED_NPC, true); + JustSummoned(c); + } + } + } + } + } + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER) + Talk(TEXT_SLAY); + } + + void JustSummoned(Creature* s) override + { + summons.Summon(s); + } + + void SummonedCreatureDespawn(Creature* s) override + { + summons.Despawn(s); + } + + bool CanAIAttack(Unit const* t) const override + { + if (t->GetTypeId() == TYPEID_PLAYER) + return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER); + else if (t->GetTypeId() == TYPEID_UNIT) + return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC); + + return true; + } + + void SetData(uint32 id, uint32 value) override + { + if (value) + switch (id) + { + case 1: + bAchievCheese = false; + break; + case 2: + bAchievGettingCold = false; + break; + case 4: + bAchievCoolestFriends = false; + break; + } + } + + uint32 GetData(uint32 id) const override + { + switch (id) + { + case 1: + return (bAchievCheese ? 1 : 0); + case 2: + return (bAchievGettingCold ? 1 : 0); + case 3: + return (bAchievCacheRare ? 1 : 0); + case 4: + return (bAchievCoolestFriends ? 1 : 0); + } + return 0; + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + }; +}; + +class npc_ulduar_icicle : public CreatureScript +{ +public: + npc_ulduar_icicle() : CreatureScript("npc_ulduar_icicle") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_icicleAI : public NullCreatureAI + { + npc_ulduar_icicleAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + timer1 = 2000; + timer2 = 5000; + } + + uint16 timer1; + uint16 timer2; + + void UpdateAI(uint32 diff) override + { + if( timer1 <= diff ) + { + me->CastSpell(me, (me->GetEntry() == 33169 ? SPELL_ICICLE_FALL_EFFECT_UNPACKED : SPELL_ICICLE_FALL_EFFECT_PACKED), true); + me->CastSpell(me, SPELL_ICICLE_VISUAL_FALLING, false); + timer1 = 60000; + } + else + timer1 -= diff; + + if (timer2 <= diff) + { + me->SetDisplayId(11686); + timer2 = 60000; + } + else + timer2 -= diff; + } + }; +}; + +class npc_ulduar_flash_freeze : public CreatureScript +{ +public: + npc_ulduar_flash_freeze() : CreatureScript("npc_ulduar_flash_freeze") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_flash_freezeAI : public NullCreatureAI + { + npc_ulduar_flash_freezeAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + timer = 2500; + pInstance = me->GetInstanceScript(); + } + + InstanceScript* pInstance; + uint16 timer; + + void DamageTaken(Unit* doneBy, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override + { + if (pInstance && doneBy) + if (pInstance->GetData(TYPE_HODIR) == NOT_STARTED) + if (Creature* hodir = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_HODIR))) + hodir->AI()->AttackStart(doneBy); + } + + void UpdateAI(uint32 diff) override + { + if (timer <= diff) + { + timer = 2500; + if (me->IsSummon()) + { + if (Unit* s = me->ToTempSummon()->GetSummonerUnit()) + { + if ((s->GetTypeId() == TYPEID_PLAYER && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER)) || (s->GetTypeId() == TYPEID_UNIT && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC))) + me->DespawnOrUnsummon(2000); + else if (s->GetTypeId() == TYPEID_PLAYER) + if (InstanceScript* instanceScript = me->GetInstanceScript()) + if (instanceScript->GetData(TYPE_HODIR) == NOT_STARTED) + { + s->CastSpell(s, SPELL_FLASH_FREEZE_INSTAKILL, true); + me->DespawnOrUnsummon(2000); + } + } + else + { + me->DespawnOrUnsummon(2000); + } + } + } + else + timer -= diff; + } + }; +}; + +class npc_ulduar_toasty_fire : public CreatureScript +{ +public: + npc_ulduar_toasty_fire() : CreatureScript("npc_ulduar_toasty_fire") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_toasty_fireAI : public NullCreatureAI + { + npc_ulduar_toasty_fireAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + me->CastSpell(me, SPELL_MAGE_TOASTY_FIRE_AURA, true); + } + + void DoAction(int32 a) override + { + if (a == 1) + { + if( GameObject* fire = me->FindNearestGameObject(194300, 1.0f) ) + { + fire->SetOwnerGUID(ObjectGuid::Empty); + fire->Delete(); + } + me->DespawnOrUnsummon(); // this will remove DynObjects + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + switch( spell->Id ) + { + case SPELL_ICE_SHARDS_SMALL: + case SPELL_ICE_SHARDS_BIG: + DoAction(1); + break; + } + } + }; +}; + +class npc_ulduar_hodir_priest : public CreatureScript +{ +public: + npc_ulduar_hodir_priest() : CreatureScript("npc_ulduar_hodir_priest") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_hodir_priestAI : public ScriptedAI + { + npc_ulduar_hodir_priestAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = me->GetInstanceScript(); + events.Reset(); + me->SetReactState(REACT_PASSIVE); + } + + EventMap events; + InstanceScript* pInstance; + + void AttackStart(Unit* who) override + { + AttackStartCaster(who, 17.0f); + } + + void ScheduleAbilities() + { + events.ScheduleEvent(EVENT_PRIEST_DISPELL_MAGIC, 7s); + events.ScheduleEvent(EVENT_PRIEST_GREAT_HEAL, 6s, 7s); + events.ScheduleEvent(EVENT_PRIEST_SMITE, 2100ms); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC) + { + events.Reset(); + events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s); + } + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + if( me->HasUnitState(UNIT_STATE_CASTING) ) + return; + + switch( events.ExecuteEvent() ) + { + case 0: + break; + case EVENT_TRY_FREE_HELPER: + { + if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) ) + if( pInstance ) + if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) ) + if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) ) + { + AttackStart(hodir); + ScheduleAbilities(); + break; + } + events.Repeat(2s); + } + break; + case EVENT_PRIEST_DISPELL_MAGIC: + me->CastCustomSpell(SPELL_PRIEST_DISPELL_MAGIC, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false); + events.Repeat(7s); + break; + case EVENT_PRIEST_GREAT_HEAL: + me->CastSpell(me, SPELL_PRIEST_GREAT_HEAL, false); + events.Repeat(6s, 7s); + break; + case EVENT_PRIEST_SMITE: + if (Unit* victim = me->GetVictim()) + me->CastSpell(victim, SPELL_PRIEST_SMITE, false); + events.Repeat(2100ms); + break; + } + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + + void EnterEvadeMode(EvadeReason /*why*/) override {} + bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; } + + void JustDied(Unit* /*killer*/) override + { + if (pInstance) + if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR))) + hodir->AI()->SetData(4, 1); + } + }; +}; + +class npc_ulduar_hodir_druid : public CreatureScript +{ +public: + npc_ulduar_hodir_druid() : CreatureScript("npc_ulduar_hodir_druid") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_hodir_druidAI : public ScriptedAI + { + npc_ulduar_hodir_druidAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = me->GetInstanceScript(); + events.Reset(); + me->SetReactState(REACT_PASSIVE); + } + + EventMap events; + InstanceScript* pInstance; + + void AttackStart(Unit* who) override + { + AttackStartCaster(who, 22.0f); + } + + void ScheduleAbilities() + { + events.ScheduleEvent(EVENT_DRUID_WRATH, 1600ms); + events.ScheduleEvent(EVENT_DRUID_STARLIGHT, 10s); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC) + { + events.Reset(); + events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s); + } + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + if( me->HasUnitState(UNIT_STATE_CASTING) ) + return; + + switch( events.ExecuteEvent() ) + { + case 0: + break; + case EVENT_TRY_FREE_HELPER: + { + if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) ) + if( pInstance ) + if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) ) + if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) ) + { + AttackStart(hodir); + ScheduleAbilities(); + break; + } + events.Repeat(2s); + } + break; + case EVENT_DRUID_WRATH: + if (Unit* victim = me->GetVictim()) + me->CastSpell(victim, SPELL_DRUID_WRATH, false); + events.Repeat(1600ms); + break; + case EVENT_DRUID_STARLIGHT: + if (me->GetPositionZ() < 433.0f) // ensure npc is on the ground + { + me->CastSpell(me, SPELL_DRUID_STARLIGHT_AREA_AURA, false); + events.Repeat(15s); + break; + } + events.Repeat(3s); + break; + } + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + + void EnterEvadeMode(EvadeReason /*why*/) override {} + bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; } + + void JustDied(Unit* /*killer*/) override + { + if (pInstance) + if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR))) + hodir->AI()->SetData(4, 1); + } + }; +}; + +class npc_ulduar_hodir_shaman : public CreatureScript +{ +public: + npc_ulduar_hodir_shaman() : CreatureScript("npc_ulduar_hodir_shaman") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_hodir_shamanAI : public ScriptedAI + { + npc_ulduar_hodir_shamanAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = me->GetInstanceScript(); + events.Reset(); + me->SetReactState(REACT_PASSIVE); + } + + EventMap events; + InstanceScript* pInstance; + + void AttackStart(Unit* who) override + { + AttackStartCaster(who, 25.0f); + } + + void ScheduleAbilities() + { + events.ScheduleEvent(EVENT_SHAMAN_LAVA_BURST, 2600ms); + events.ScheduleEvent(EVENT_SHAMAN_STORM_CLOUD, 10s); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC) + { + events.Reset(); + events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s); + } + } + + void SpellHitTarget(Unit* target, SpellInfo const* spell) override + { + if (target && spell->Id == SPELL_SHAMAN_STORM_CLOUD) + if (Aura* a = target->GetAura(SPELL_SHAMAN_STORM_CLOUD, me->GetGUID())) + a->SetStackAmount(spell->StackAmount); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + if( me->HasUnitState(UNIT_STATE_CASTING) ) + return; + + switch( events.ExecuteEvent() ) + { + case 0: + break; + case EVENT_TRY_FREE_HELPER: + { + if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) ) + if( pInstance ) + if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) ) + if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) ) + { + AttackStart(hodir); + ScheduleAbilities(); + break; + } + events.Repeat(2s); + } + break; + case EVENT_SHAMAN_LAVA_BURST: + if (Unit* victim = me->GetVictim()) + me->CastSpell(victim, SPELL_SHAMAN_LAVA_BURST, false); + events.Repeat(2600ms); + break; + case EVENT_SHAMAN_STORM_CLOUD: + if (Player* target = ScriptedAI::SelectTargetFromPlayerList(35.0f, SPELL_SHAMAN_STORM_CLOUD)) + me->CastSpell(target, SPELL_SHAMAN_STORM_CLOUD, false); + events.Repeat(30s); + break; + } + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + + void EnterEvadeMode(EvadeReason /*why*/) override {} + bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; } + + void JustDied(Unit* /*killer*/) override + { + if (pInstance) + if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR))) + hodir->AI()->SetData(4, 1); + } + }; +}; + +class npc_ulduar_hodir_mage : public CreatureScript +{ +public: + npc_ulduar_hodir_mage() : CreatureScript("npc_ulduar_hodir_mage") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_hodir_mageAI : public ScriptedAI + { + npc_ulduar_hodir_mageAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = me->GetInstanceScript(); + events.Reset(); + me->SetReactState(REACT_PASSIVE); + } + + EventMap events; + InstanceScript* pInstance; + + void AttackStart(Unit* who) override + { + AttackStartCaster(who, 30.0f); + } + + void ScheduleAbilities() + { + events.ScheduleEvent(EVENT_MAGE_FIREBALL, 3100ms); + events.ScheduleEvent(EVENT_MAGE_TOASTY_FIRE, 6s); + events.ScheduleEvent(EVENT_MAGE_MELT_ICE, 1s); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC) + { + events.Reset(); + events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s); + } + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + if( me->HasUnitState(UNIT_STATE_CASTING) ) + return; + + switch( events.ExecuteEvent() ) + { + case 0: + break; + case EVENT_TRY_FREE_HELPER: + { + if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) ) + if( pInstance ) + if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) ) + if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) ) + { + AttackStart(hodir); + ScheduleAbilities(); + break; + } + events.Repeat(2s); + } + break; + case EVENT_MAGE_FIREBALL: + if (Unit* victim = me->GetVictim()) + me->CastSpell(victim, SPELL_MAGE_FIREBALL, false); + events.Repeat(3100ms); + break; + case EVENT_MAGE_TOASTY_FIRE: + me->CastSpell(me, SPELL_MAGE_CONJURE_TOASTY_FIRE, false); + events.Repeat(10s); + break; + case EVENT_MAGE_MELT_ICE: + { + std::list FB; + bool found = false; + me->GetCreaturesWithEntryInRange(FB, 150.0f, NPC_FLASH_FREEZE_NPC); + for( std::list::const_iterator itr = FB.begin(); itr != FB.end(); ++itr ) + if( !((*itr)->HasAura(SPELL_MAGE_MELT_ICE)) ) + { + me->CastSpell((*itr), SPELL_MAGE_MELT_ICE, false); + found = true; + break; + } + + if( found ) + { + events.DelayEvents(2s); + events.Repeat(2s); + break; + } + events.Repeat(5s); + } + break; + } + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + + void EnterEvadeMode(EvadeReason /*why*/) override {} + bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; } + + void JustDied(Unit* /*killer*/) override + { + if (pInstance) + if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR))) + hodir->AI()->SetData(4, 1); + } + }; +}; + +class spell_hodir_shatter_chest : public SpellScriptLoader +{ +public: + spell_hodir_shatter_chest() : SpellScriptLoader("spell_hodir_shatter_chest") { } + + class spell_hodir_shatter_chestSpellScript : public SpellScript + { + PrepareSpellScript(spell_hodir_shatter_chestSpellScript) + + void destroyWinterCache(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + if (Unit* hodir = GetCaster()) + hodir->GetAI()->DoAction(EVENT_FAIL_HM); + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_hodir_shatter_chestSpellScript::destroyWinterCache, EFFECT_0, SPELL_EFFECT_TRIGGER_MISSILE); + }; + }; + + SpellScript* GetSpellScript() const override + { + return new spell_hodir_shatter_chestSpellScript(); + } +}; + +class spell_hodir_biting_cold_main_aura : public SpellScriptLoader +{ +public: + spell_hodir_biting_cold_main_aura() : SpellScriptLoader("spell_hodir_biting_cold_main_aura") { } + + class spell_hodir_biting_cold_main_aura_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hodir_biting_cold_main_aura_AuraScript) + + void HandleEffectPeriodic(AuraEffect const* aurEff) + { + if ((aurEff->GetTickNumber() % 4) == 0) + if (Unit* target = GetTarget()) + if (target->GetTypeId() == TYPEID_PLAYER + && !target->isMoving() + && !target->HasAura(SPELL_BITING_COLD_PLAYER_AURA) + && !target->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA)) + target->CastSpell(target, SPELL_BITING_COLD_PLAYER_AURA, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_biting_cold_main_aura_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_hodir_biting_cold_main_aura_AuraScript(); + } +}; + +class spell_hodir_biting_cold_player_aura : public SpellScriptLoader +{ +public: + spell_hodir_biting_cold_player_aura() : SpellScriptLoader("spell_hodir_biting_cold_player_aura") { } + + class spell_hodir_biting_cold_player_aura_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hodir_biting_cold_player_aura_AuraScript) + + uint8 counter {0}; + bool prev {false}; + + void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) + { + if (Unit* target = GetTarget()) + { + if (target->GetMapId() == 603) + SetDuration(GetMaxDuration()); + if (target->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER)) + return; + if (target->isMoving() || target->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA)) + { + if (prev) + { + ModStackAmount(-1); + prev = false; + } + else + prev = true; + + if (counter >= 2) + counter -= 2; + else if (counter) + --counter; + } + else + { + prev = false; + ++counter; + if (counter >= 4) + { + if (GetStackAmount() == 2) // increasing from 2 to 3 (not checking >= to improve performance) + if (InstanceScript* pInstance = target->GetInstanceScript()) + if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR))) + hodir->AI()->SetData(2, 1); + ModStackAmount(1); + counter = 0; + } + } + + const int32 dmg = 200 * pow(2.0f, GetStackAmount()); + target->CastCustomSpell(target, SPELL_BITING_COLD_DAMAGE, &dmg, 0, 0, true); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_biting_cold_player_aura_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_hodir_biting_cold_player_aura_AuraScript(); + } +}; + +class spell_hodir_periodic_icicle : public SpellScriptLoader +{ +public: + spell_hodir_periodic_icicle() : SpellScriptLoader("spell_hodir_periodic_icicle") { } + + class spell_hodir_periodic_icicle_SpellScript : public SpellScript + { + PrepareSpellScript(spell_hodir_periodic_icicle_SpellScript); + + void FilterTargets(std::list& targets) + { + targets.remove_if(Acore::ObjectTypeIdCheck(TYPEID_PLAYER, false)); + targets.remove_if(Acore::UnitAuraCheck(true, SPELL_FLASH_FREEZE_TRAPPED_PLAYER)); + Acore::Containers::RandomResize(targets, 1); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_periodic_icicle_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_hodir_periodic_icicle_SpellScript(); + } +}; + +class FlashFreezeCheck +{ +public: + FlashFreezeCheck() { } + + bool operator()(WorldObject* target) const + { + if (Unit* unit = target->ToUnit()) + return unit->HasAura(SPELL_SAFE_AREA_TRIGGERED) || unit->IsPet(); + return true; + } +}; + +class spell_hodir_flash_freeze : public SpellScriptLoader +{ +public: + spell_hodir_flash_freeze() : SpellScriptLoader("spell_hodir_flash_freeze") { } + + class spell_hodir_flash_freeze_SpellScript : public SpellScript + { + PrepareSpellScript(spell_hodir_flash_freeze_SpellScript); + + void FilterTargets(std::list& targets) + { + targets.remove_if(FlashFreezeCheck()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_flash_freeze_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_flash_freeze_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + class spell_hodir_flash_freeze_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hodir_flash_freeze_AuraScript) + + void HandleEffectPeriodic(AuraEffect const* aurEff) + { + if (aurEff->GetTotalTicks() > 0 && aurEff->GetTickNumber() == uint32(aurEff->GetTotalTicks()) - 1) + { + Unit* target = GetTarget(); + Unit* caster = GetCaster(); + if (!target || !caster || caster->GetTypeId() != TYPEID_UNIT) + return; + + if (Aura* aur = target->GetAura(target->GetTypeId() == TYPEID_PLAYER ? SPELL_FLASH_FREEZE_TRAPPED_PLAYER : SPELL_FLASH_FREEZE_TRAPPED_NPC)) + { + if (Unit* caster2 = aur->GetCaster()) + { + if (caster2->GetTypeId() == TYPEID_UNIT) + { + caster2->ToCreature()->DespawnOrUnsummon(); + } + } + target->CastSpell(target, SPELL_FLASH_FREEZE_INSTAKILL, true); + return; + } + if (target->GetTypeId() == TYPEID_PLAYER) + { + caster->ToCreature()->AI()->SetData(1, 1); + if( Creature* c = target->SummonCreature(NPC_FLASH_FREEZE_PLR, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 5 * 60 * 1000) ) + { + c->CastSpell(target, SPELL_FLASH_FREEZE_TRAPPED_PLAYER, true); + caster->ToCreature()->AI()->JustSummoned(c); + } + } + else if (target->GetTypeId() == TYPEID_UNIT) + { + if( Creature* c = target->SummonCreature(NPC_FLASH_FREEZE_NPC, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000) ) + { + c->CastSpell(target, SPELL_FLASH_FREEZE_TRAPPED_NPC, true); + caster->ToCreature()->AI()->JustSummoned(c); + } + } + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_flash_freeze_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_hodir_flash_freeze_SpellScript(); + } + + AuraScript* GetAuraScript() const override + { + return new spell_hodir_flash_freeze_AuraScript(); + } +}; + +class spell_hodir_storm_power : public SpellScriptLoader +{ +public: + spell_hodir_storm_power() : SpellScriptLoader("spell_hodir_storm_power") { } + + class spell_hodir_storm_power_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hodir_storm_power_AuraScript) + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + if (Aura* a = caster->GetAura(GetId() == SPELL_SHAMAN_STORM_POWER_10 ? SPELL_SHAMAN_STORM_CLOUD_10 : SPELL_SHAMAN_STORM_CLOUD_25)) + a->ModStackAmount(-1); + } + + void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* target = GetTarget()) + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, GetId(), 0, GetCaster()); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_hodir_storm_power_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, AURA_EFFECT_HANDLE_REAL); + AfterEffectApply += AuraEffectApplyFn(spell_hodir_storm_power_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_hodir_storm_power_AuraScript(); + } +}; + +class spell_hodir_storm_cloud : public SpellScriptLoader +{ +public: + spell_hodir_storm_cloud() : SpellScriptLoader("spell_hodir_storm_cloud") { } + + class spell_hodir_storm_cloud_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hodir_storm_cloud_AuraScript) + + void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + if (Unit* target = GetTarget()) + target->CastSpell((Unit*)nullptr, (GetId() == SPELL_SHAMAN_STORM_CLOUD_10 ? SPELL_SHAMAN_STORM_POWER_10 : SPELL_SHAMAN_STORM_POWER_25), true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_storm_cloud_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_hodir_storm_cloud_AuraScript(); + } +}; + +class achievement_cheese_the_freeze : public AchievementCriteriaScript +{ +public: + achievement_cheese_the_freeze() : AchievementCriteriaScript("achievement_cheese_the_freeze") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1); + } +}; + +class achievement_getting_cold_in_here : public AchievementCriteriaScript +{ +public: + achievement_getting_cold_in_here() : AchievementCriteriaScript("achievement_getting_cold_in_here") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(2); + } +}; + +class achievement_i_could_say_that_this_cache_was_rare : public AchievementCriteriaScript +{ +public: + achievement_i_could_say_that_this_cache_was_rare() : AchievementCriteriaScript("achievement_i_could_say_that_this_cache_was_rare") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(3); + } +}; + +class achievement_i_have_the_coolest_friends : public AchievementCriteriaScript +{ +public: + achievement_i_have_the_coolest_friends() : AchievementCriteriaScript("achievement_i_have_the_coolest_friends") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(4); + } +}; + +class achievement_staying_buffed_all_winter_10 : public AchievementCriteriaScript +{ +public: + achievement_staying_buffed_all_winter_10() : AchievementCriteriaScript("achievement_staying_buffed_all_winter_10") {} + + bool OnCheck(Player* player, Unit* /*target*/, uint32 /*criteria_id*/) override + { + return player && player->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA) && player->HasAura(SPELL_DRUID_STARLIGHT_AREA_AURA) && player->HasAura(SPELL_SHAMAN_STORM_POWER_10); + } +}; + +class achievement_staying_buffed_all_winter_25 : public AchievementCriteriaScript +{ +public: + achievement_staying_buffed_all_winter_25() : AchievementCriteriaScript("achievement_staying_buffed_all_winter_25") {} + + bool OnCheck(Player* player, Unit* /*target*/, uint32 /*criteria_id*/) override + { + return player && player->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA) && player->HasAura(SPELL_DRUID_STARLIGHT_AREA_AURA) && player->HasAura(SPELL_SHAMAN_STORM_POWER_25); + } +}; + +class spell_hodir_toasty_fire : public SpellScriptLoader +{ +public: + spell_hodir_toasty_fire() : SpellScriptLoader("spell_hodir_toasty_fire") { } + + class spell_hodir_toasty_fire_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hodir_toasty_fire_AuraScript); + + void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* target = GetTarget()) + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, SPELL_MAGE_TOASTY_FIRE_AURA, 0, GetCaster()); + } + + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_hodir_toasty_fire_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MOD_STAT, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_hodir_toasty_fire_AuraScript(); + } +}; + +class spell_hodir_starlight : public SpellScriptLoader +{ +public: + spell_hodir_starlight() : SpellScriptLoader("spell_hodir_starlight") { } + + class spell_hodir_starlight_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hodir_starlight_AuraScript); + + void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* target = GetTarget()) + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, SPELL_DRUID_STARLIGHT_AREA_AURA, 0, GetCaster()); + } + + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_hodir_starlight_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MELEE_SLOW, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_hodir_starlight_AuraScript(); + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp index e7e21fa99ec91a..cf2d90a09cba15 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_ignis.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "GameTime.h" @@ -27,527 +28,6 @@ #include "Vehicle.h" #include "ulduar.h" -#define SPELL_FLAME_JETS_10 62680 -#define SPELL_FLAME_JETS_25 63472 -#define S_FLAME_JETS RAID_MODE(SPELL_FLAME_JETS_10, SPELL_FLAME_JETS_25) -#define SPELL_SCORCH_10 62546 -#define SPELL_SCORCH_25 63474 -#define S_SCORCH RAID_MODE(SPELL_SCORCH_10, SPELL_SCORCH_25) -#define SPELL_ACTIVATE_CONSTRUCT 62488 -#define SPELL_STRENGTH_OF_THE_CREATOR 64473 -#define SPELL_SLAG_POT_10 62717 -#define SPELL_SLAG_POT_25 63477 -#define S_SLAG_POT RAID_MODE(SPELL_SLAG_POT_10, SPELL_SLAG_POT_25) -#define SPELL_BERSERK 64238 -#define SPELL_GRAB 62707 -#define SPELL_GRAB_TRIGGERED 62708 -#define SPELL_GRAB_CONTROL_2 62711 - -#define SPELL_SCORCHED_GROUND_10 62548 -#define SPELL_SCORCHED_GROUND_25 63476 -#define S_SCORCHED_GROUND RAID_MODE(SPELL_SCORCHED_GROUND_10, SPELL_SCORCHED_GROUND_25) -#define SPELL_HEAT_AREA 62343 -#define SPELL_HEAT_BUFF 65667 -#define SPELL_MOLTEN 62373 -#define SPELL_BRITTLE_10 62382 -#define SPELL_BRITTLE_25 67114 -#define S_BRITTLE RAID_MODE(SPELL_BRITTLE_10, SPELL_BRITTLE_25) -#define SPELL_SHATTER 62383 - -#define BOSS_IGNIS 33118 -#define NPC_IRON_CONSTRUCT 33121 -#define NPC_SCORCHED_GROUND 33123 -#define NPC_WATER_TRIGGER 22515 - -enum Texts -{ - SAY_AGGRO = 0, - SAY_SUMMON = 1, - SAY_SLAG_POT = 2, - SAY_SCORCH = 3, - SAY_SLAY = 4, - SAY_BERSERK = 5, - SAY_DEATH = 6, - EMOTE_JETS = 7, -}; - -#define ACHIEV_STOKIN_THE_FURNACE_EVENT 20951 - -enum eEvents -{ - EVENT_NONE = 0, - EVENT_ACTIVATE_CONSTRUCT, - EVENT_SPELL_SCORCH, - EVENT_ENABLE_ROTATE, - EVENT_SPELL_FLAME_JETS, - EVENT_GRAB, -}; - -class npc_ulduar_iron_construct : public CreatureScript -{ -public: - npc_ulduar_iron_construct() : CreatureScript("npc_ulduar_iron_construct") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_iron_constructAI : public ScriptedAI - { - npc_ulduar_iron_constructAI(Creature* pCreature) : ScriptedAI(pCreature) - { - me->CastSpell(me, 38757, true); - } - - uint16 timer; - - void Reset() override - { - timer = 1000; - me->SetReactState(REACT_PASSIVE); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - } - - void JustReachedHome() override - { - me->CastSpell(me, 38757, true); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if (spell->Id == SPELL_ACTIVATE_CONSTRUCT) - { - me->RemoveAura(38757); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - if (InstanceScript* instance = me->GetInstanceScript()) - if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS))) - { - ignis->CastSpell(ignis, SPELL_STRENGTH_OF_THE_CREATOR, true); - AttackStart(ignis->GetVictim()); - DoZoneInCombat(); - } - } - else if (spell->Id == SPELL_HEAT_BUFF) - { - if (Aura* heat = me->GetAura(SPELL_HEAT_BUFF)) - { - if (heat->GetStackAmount() >= 10) - { - if (heat->GetStackAmount() > 10) - { - heat->ModStackAmount(-1); - } - me->CastSpell(me, SPELL_MOLTEN, true); - me->GetThreatMgr().ResetAllThreat(); - } - } - } - } - - void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if( damage >= RAID_MODE(3000U, 5000U) && me->GetAura(S_BRITTLE) ) - { - me->CastSpell(me, SPELL_SHATTER, true); - Unit::Kill(attacker, me); - - if (InstanceScript* instance = me->GetInstanceScript()) - if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS))) - ignis->AI()->SetData(1337, 0); - } - } - - void JustDied(Unit* /*killer*/) override - { - if (InstanceScript* instance = me->GetInstanceScript()) - if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS))) - ignis->RemoveAuraFromStack(SPELL_STRENGTH_OF_THE_CREATOR); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (timer <= diff) - { - timer = 1000; - if (Aura* a = me->GetAura(SPELL_MOLTEN)) - if (me->FindNearestCreature(NPC_WATER_TRIGGER, 18.0f, true)) - { - me->RemoveAura(a); - me->CastSpell(me, S_BRITTLE, true); - } - } - else - timer -= diff; - - DoMeleeAttackIfReady(); - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - }; -}; - -class boss_ignis : public CreatureScript -{ -public: - boss_ignis() : CreatureScript("boss_ignis") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_ignisAI : public ScriptedAI - { - boss_ignisAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - EventMap events; - uint8 counter; - bool bShattered; - uint32 lastShatterMSTime; - - void Reset() override - { - events.Reset(); - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - counter = 0; - bShattered = false; - lastShatterMSTime = 0; - - if( InstanceScript* m_pInstance = me->GetInstanceScript() ) - { - m_pInstance->SetData(TYPE_IGNIS, NOT_STARTED); - m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT); - } - } - - void JustEngagedWith(Unit* /*who*/) override - { - me->setActive(true); - - std::list icl; - me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT); - for( std::list::iterator itr = icl.begin(); itr != icl.end(); ++itr ) - { - if (!(*itr)->IsAlive()) - { - (*itr)->Respawn(); - (*itr)->UpdatePosition((*itr)->GetHomePosition(), true); - (*itr)->StopMovingOnCurrentPos(); - } - (*itr)->AI()->Reset(); - if (!(*itr)->HasAura(38757)) - (*itr)->CastSpell((*itr), 38757, true); - } - - bShattered = false; - lastShatterMSTime = 0; - events.Reset(); - events.ScheduleEvent(EVENT_ACTIVATE_CONSTRUCT, RAID_MODE(40000, 30000)); - events.ScheduleEvent(EVENT_SPELL_SCORCH, 10s); - events.ScheduleEvent(EVENT_SPELL_FLAME_JETS, 32s); - events.ScheduleEvent(EVENT_GRAB, 25s); - - Talk(SAY_AGGRO); - DoZoneInCombat(); - - if( InstanceScript* m_pInstance = me->GetInstanceScript() ) - { - m_pInstance->SetData(TYPE_IGNIS, IN_PROGRESS); - m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT); - m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT); - } - } - - void SetData(uint32 id, uint32 /*value*/) override - { - if (id == 1337) - { - if (lastShatterMSTime) - if (getMSTimeDiff(lastShatterMSTime, GameTime::GetGameTimeMS().count()) <= 5000) - bShattered = true; - - lastShatterMSTime = GameTime::GetGameTimeMS().count(); - } - } - - uint32 GetData(uint32 id) const override - { - if (id == 1337) - return (bShattered ? 1 : 0); - return 0; - } - - void JustReachedHome() override - { - me->setActive(false); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - - if( me->GetInstanceScript() ) - me->GetInstanceScript()->SetData(TYPE_IGNIS, DONE); - - std::list icl; - me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT); - for( std::list::iterator itr = icl.begin(); itr != icl.end(); ++itr ) - if ((*itr)->IsAlive() && (*itr)->IsInCombat()) - Unit::Kill(*itr, *itr); - } - - void SpellHit(Unit* caster, SpellInfo const* spell) override - { - if (caster && spell->Id == SPELL_GRAB_CONTROL_2) - { - //caster->ClearUnitState(UNIT_STATE_ONVEHICLE); - me->CastSpell(caster, S_SLAG_POT, true); - } - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if( me->GetPositionX() < 490.0f || me->GetPositionX() > 690.0f || me->GetPositionY() < 130.0f || me->GetPositionY() > 410.0f ) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_ACTIVATE_CONSTRUCT: - Talk(SAY_SUMMON); - me->CastCustomSpell(SPELL_ACTIVATE_CONSTRUCT, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false); - if (++counter >= 20) - { - Talk(SAY_BERSERK); - me->CastSpell(me, SPELL_BERSERK, true); - break; - } - events.RepeatEvent(RAID_MODE(40000, 30000)); - break; - case EVENT_SPELL_SCORCH: - Talk(SAY_SCORCH); - me->SetControlled(true, UNIT_STATE_ROOT); - me->DisableRotate(true); - me->SendMovementFlagUpdate(); - me->CastSpell(me->GetVictim(), S_SCORCH, false); - events.Repeat(20s); - events.RescheduleEvent(EVENT_ENABLE_ROTATE, 3s); - break; - case EVENT_ENABLE_ROTATE: - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - break; - case EVENT_SPELL_FLAME_JETS: - Talk(EMOTE_JETS); - me->CastSpell(me->GetVictim(), S_FLAME_JETS, false); - events.Repeat(25s); - break; - case EVENT_GRAB: - { - std::list icl; - me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT); - - GuidVector playerGUIDs; - Map::PlayerList const& pl = me->GetMap()->GetPlayers(); - Player* temp = nullptr; - - for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) - { - temp = itr->GetSource(); - if( !temp->IsAlive() || temp->GetExactDist2d(me) > 90.0f ) - continue; - if( me->GetVictim() && temp->GetGUID() == me->GetVictim()->GetGUID() ) - continue; - bool found = false; - for (std::list::iterator iterator = icl.begin(); iterator != icl.end(); ++iterator) - { - if ((*iterator)->GetVictim() && (*iterator)->GetVictim()->GetGUID() == temp->GetGUID()) - { - found = true; - break; - } - } - - if( !found ) - playerGUIDs.push_back(temp->GetGUID()); - } - - if( !playerGUIDs.empty() ) - { - int8 pos = urand(0, playerGUIDs.size() - 1); - if( Player* pTarget = ObjectAccessor::GetPlayer(*me, playerGUIDs.at(pos)) ) - { - Talk(SAY_SLAG_POT); - me->CastSpell(pTarget, SPELL_GRAB, false); - } - } - - events.Repeat(24s); - events.DelayEvents(6s); - } - break; - } - - DoMeleeAttackIfReady(); - } - - void EnterEvadeMode(EvadeReason why) override - { - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - ScriptedAI::EnterEvadeMode(why); - } - }; -}; - -class spell_ignis_scorch : public SpellScriptLoader -{ -public: - spell_ignis_scorch() : SpellScriptLoader("spell_ignis_scorch") { } - - class spell_ignis_scorch_AuraScript : public AuraScript - { - PrepareAuraScript(spell_ignis_scorch_AuraScript) - - void HandleEffectPeriodic(AuraEffect const* aurEff) - { - if (aurEff->GetTotalTicks() >= 0 && aurEff->GetTickNumber() == uint32(aurEff->GetTotalTicks())) - if (Unit* c = GetCaster()) - if (Creature* s = c->SummonCreature(NPC_SCORCHED_GROUND, c->GetPositionX() + 20.0f * cos(c->GetOrientation()), c->GetPositionY() + 20.0f * std::sin(c->GetOrientation()), 361.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000)) - { - if (!s->FindNearestCreature(NPC_WATER_TRIGGER, 25.0f, true)) // must be away from the water - s->CastSpell(s, (aurEff->GetId() == 62546 ? SPELL_SCORCHED_GROUND_10 : SPELL_SCORCHED_GROUND_25), true); - } - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_ignis_scorch_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_ignis_scorch_AuraScript(); - } -}; - -class spell_ignis_grab_initial : public SpellScriptLoader -{ -public: - spell_ignis_grab_initial() : SpellScriptLoader("spell_ignis_grab_initial") { } - - class spell_ignis_grab_initial_SpellScript : public SpellScript - { - PrepareSpellScript(spell_ignis_grab_initial_SpellScript); - - void HandleScript(SpellEffIndex /*effIndex*/) - { - if (Unit* t = GetHitUnit()) - t->CastSpell(t, SPELL_GRAB_TRIGGERED, true); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_ignis_grab_initial_SpellScript::HandleScript, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_ignis_grab_initial_SpellScript(); - } -}; - -class spell_ignis_slag_pot : public SpellScriptLoader -{ -public: - spell_ignis_slag_pot() : SpellScriptLoader("spell_ignis_slag_pot") { } - - class spell_ignis_slag_pot_AuraScript : public AuraScript - { - PrepareAuraScript(spell_ignis_slag_pot_AuraScript) - - void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) - { - if (Unit* c = GetCaster()) - if (Unit* t = GetTarget()) - c->CastSpell(t, (GetId() == 62717 ? 65722 : 65723), true); - } - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* t = GetTarget()) - { - t->ApplySpellImmune(GetId(), IMMUNITY_ID, 62549, true); - t->ApplySpellImmune(GetId(), IMMUNITY_ID, 63475, true); - } - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* t = GetTarget()) - { - t->ApplySpellImmune(GetId(), IMMUNITY_ID, 62549, false); - t->ApplySpellImmune(GetId(), IMMUNITY_ID, 63475, false); - if (t->IsAlive()) - t->CastSpell(t, (GetId() == 62717 ? 62836 : 63536), true); - } - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_ignis_slag_pot_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - OnEffectApply += AuraEffectApplyFn(spell_ignis_slag_pot_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_ignis_slag_pot_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_ignis_slag_pot_AuraScript(); - } -}; - -class achievement_ignis_shattered : public AchievementCriteriaScript -{ -public: - achievement_ignis_shattered() : AchievementCriteriaScript("achievement_ignis_shattered") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - if (!target || target->GetTypeId() != TYPEID_UNIT) - return false; - return !!target->ToCreature()->AI()->GetData(1337); - } -}; - void AddSC_boss_ignis() { new boss_ignis(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.h new file mode 100644 index 00000000000000..23aca7f8102efa --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.h @@ -0,0 +1,537 @@ +#ifndef BOSS_IGNIS_H_ +#define BOSS_IGNIS_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "GameTime.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "SpellAuras.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "Vehicle.h" +#include "ulduar.h" + +#define SPELL_FLAME_JETS_10 62680 +#define SPELL_FLAME_JETS_25 63472 +#define S_FLAME_JETS RAID_MODE(SPELL_FLAME_JETS_10, SPELL_FLAME_JETS_25) +#define SPELL_SCORCH_10 62546 +#define SPELL_SCORCH_25 63474 +#define S_SCORCH RAID_MODE(SPELL_SCORCH_10, SPELL_SCORCH_25) +#define SPELL_ACTIVATE_CONSTRUCT 62488 +#define SPELL_STRENGTH_OF_THE_CREATOR 64473 +#define SPELL_SLAG_POT_10 62717 +#define SPELL_SLAG_POT_25 63477 +#define S_SLAG_POT RAID_MODE(SPELL_SLAG_POT_10, SPELL_SLAG_POT_25) +#define SPELL_BERSERK 64238 +#define SPELL_GRAB 62707 +#define SPELL_GRAB_TRIGGERED 62708 +#define SPELL_GRAB_CONTROL_2 62711 + +#define SPELL_SCORCHED_GROUND_10 62548 +#define SPELL_SCORCHED_GROUND_25 63476 +#define S_SCORCHED_GROUND RAID_MODE(SPELL_SCORCHED_GROUND_10, SPELL_SCORCHED_GROUND_25) +#define SPELL_HEAT_AREA 62343 +#define SPELL_HEAT_BUFF 65667 +#define SPELL_MOLTEN 62373 +#define SPELL_BRITTLE_10 62382 +#define SPELL_BRITTLE_25 67114 +#define S_BRITTLE RAID_MODE(SPELL_BRITTLE_10, SPELL_BRITTLE_25) +#define SPELL_SHATTER 62383 + +#define BOSS_IGNIS 33118 +#define NPC_IRON_CONSTRUCT 33121 +#define NPC_SCORCHED_GROUND 33123 +#define NPC_WATER_TRIGGER 22515 + +enum Texts +{ + SAY_AGGRO = 0, + SAY_SUMMON = 1, + SAY_SLAG_POT = 2, + SAY_SCORCH = 3, + SAY_SLAY = 4, + SAY_BERSERK = 5, + SAY_DEATH = 6, + EMOTE_JETS = 7, +}; + +#define ACHIEV_STOKIN_THE_FURNACE_EVENT 20951 + +enum eEvents +{ + EVENT_NONE = 0, + EVENT_ACTIVATE_CONSTRUCT, + EVENT_SPELL_SCORCH, + EVENT_ENABLE_ROTATE, + EVENT_SPELL_FLAME_JETS, + EVENT_GRAB, +}; + +class npc_ulduar_iron_construct : public CreatureScript +{ +public: + npc_ulduar_iron_construct() : CreatureScript("npc_ulduar_iron_construct") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_iron_constructAI : public ScriptedAI + { + npc_ulduar_iron_constructAI(Creature* pCreature) : ScriptedAI(pCreature) + { + me->CastSpell(me, 38757, true); + } + + uint16 timer; + + void Reset() override + { + timer = 1000; + me->SetReactState(REACT_PASSIVE); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + } + + void JustReachedHome() override + { + me->CastSpell(me, 38757, true); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_ACTIVATE_CONSTRUCT) + { + me->RemoveAura(38757); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS))) + { + ignis->CastSpell(ignis, SPELL_STRENGTH_OF_THE_CREATOR, true); + AttackStart(ignis->GetVictim()); + DoZoneInCombat(); + } + } + else if (spell->Id == SPELL_HEAT_BUFF) + { + if (Aura* heat = me->GetAura(SPELL_HEAT_BUFF)) + { + if (heat->GetStackAmount() >= 10) + { + if (heat->GetStackAmount() > 10) + { + heat->ModStackAmount(-1); + } + me->CastSpell(me, SPELL_MOLTEN, true); + me->GetThreatMgr().ResetAllThreat(); + } + } + } + } + + void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if( damage >= RAID_MODE(3000U, 5000U) && me->GetAura(S_BRITTLE) ) + { + me->CastSpell(me, SPELL_SHATTER, true); + Unit::Kill(attacker, me); + + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS))) + ignis->AI()->SetData(1337, 0); + } + } + + void JustDied(Unit* /*killer*/) override + { + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS))) + ignis->RemoveAuraFromStack(SPELL_STRENGTH_OF_THE_CREATOR); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (timer <= diff) + { + timer = 1000; + if (Aura* a = me->GetAura(SPELL_MOLTEN)) + if (me->FindNearestCreature(NPC_WATER_TRIGGER, 18.0f, true)) + { + me->RemoveAura(a); + me->CastSpell(me, S_BRITTLE, true); + } + } + else + timer -= diff; + + DoMeleeAttackIfReady(); + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + }; +}; + +class boss_ignis : public CreatureScript +{ +public: + boss_ignis() : CreatureScript("boss_ignis") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_ignisAI : public ScriptedAI + { + boss_ignisAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + EventMap events; + uint8 counter; + bool bShattered; + uint32 lastShatterMSTime; + + void Reset() override + { + events.Reset(); + me->SetControlled(false, UNIT_STATE_ROOT); + me->DisableRotate(false); + counter = 0; + bShattered = false; + lastShatterMSTime = 0; + + if( InstanceScript* m_pInstance = me->GetInstanceScript() ) + { + m_pInstance->SetData(TYPE_IGNIS, NOT_STARTED); + m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT); + } + } + + void JustEngagedWith(Unit* /*who*/) override + { + me->setActive(true); + + std::list icl; + me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT); + for( std::list::iterator itr = icl.begin(); itr != icl.end(); ++itr ) + { + if (!(*itr)->IsAlive()) + { + (*itr)->Respawn(); + (*itr)->UpdatePosition((*itr)->GetHomePosition(), true); + (*itr)->StopMovingOnCurrentPos(); + } + (*itr)->AI()->Reset(); + if (!(*itr)->HasAura(38757)) + (*itr)->CastSpell((*itr), 38757, true); + } + + bShattered = false; + lastShatterMSTime = 0; + events.Reset(); + events.ScheduleEvent(EVENT_ACTIVATE_CONSTRUCT, RAID_MODE(40000, 30000)); + events.ScheduleEvent(EVENT_SPELL_SCORCH, 10s); + events.ScheduleEvent(EVENT_SPELL_FLAME_JETS, 32s); + events.ScheduleEvent(EVENT_GRAB, 25s); + + Talk(SAY_AGGRO); + DoZoneInCombat(); + + if( InstanceScript* m_pInstance = me->GetInstanceScript() ) + { + m_pInstance->SetData(TYPE_IGNIS, IN_PROGRESS); + m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT); + m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT); + } + } + + void SetData(uint32 id, uint32 /*value*/) override + { + if (id == 1337) + { + if (lastShatterMSTime) + if (getMSTimeDiff(lastShatterMSTime, GameTime::GetGameTimeMS().count()) <= 5000) + bShattered = true; + + lastShatterMSTime = GameTime::GetGameTimeMS().count(); + } + } + + uint32 GetData(uint32 id) const override + { + if (id == 1337) + return (bShattered ? 1 : 0); + return 0; + } + + void JustReachedHome() override + { + me->setActive(false); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + + if( me->GetInstanceScript() ) + me->GetInstanceScript()->SetData(TYPE_IGNIS, DONE); + + std::list icl; + me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT); + for( std::list::iterator itr = icl.begin(); itr != icl.end(); ++itr ) + if ((*itr)->IsAlive() && (*itr)->IsInCombat()) + Unit::Kill(*itr, *itr); + } + + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + if (caster && spell->Id == SPELL_GRAB_CONTROL_2) + { + //caster->ClearUnitState(UNIT_STATE_ONVEHICLE); + me->CastSpell(caster, S_SLAG_POT, true); + } + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if( me->GetPositionX() < 490.0f || me->GetPositionX() > 690.0f || me->GetPositionY() < 130.0f || me->GetPositionY() > 410.0f ) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case 0: + break; + case EVENT_ACTIVATE_CONSTRUCT: + Talk(SAY_SUMMON); + me->CastCustomSpell(SPELL_ACTIVATE_CONSTRUCT, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false); + if (++counter >= 20) + { + Talk(SAY_BERSERK); + me->CastSpell(me, SPELL_BERSERK, true); + break; + } + events.RepeatEvent(RAID_MODE(40000, 30000)); + break; + case EVENT_SPELL_SCORCH: + Talk(SAY_SCORCH); + me->SetControlled(true, UNIT_STATE_ROOT); + me->DisableRotate(true); + me->SendMovementFlagUpdate(); + me->CastSpell(me->GetVictim(), S_SCORCH, false); + events.Repeat(20s); + events.RescheduleEvent(EVENT_ENABLE_ROTATE, 3s); + break; + case EVENT_ENABLE_ROTATE: + me->SetControlled(false, UNIT_STATE_ROOT); + me->DisableRotate(false); + break; + case EVENT_SPELL_FLAME_JETS: + Talk(EMOTE_JETS); + me->CastSpell(me->GetVictim(), S_FLAME_JETS, false); + events.Repeat(25s); + break; + case EVENT_GRAB: + { + std::list icl; + me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT); + + GuidVector playerGUIDs; + Map::PlayerList const& pl = me->GetMap()->GetPlayers(); + Player* temp = nullptr; + + for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) + { + temp = itr->GetSource(); + if( !temp->IsAlive() || temp->GetExactDist2d(me) > 90.0f ) + continue; + if( me->GetVictim() && temp->GetGUID() == me->GetVictim()->GetGUID() ) + continue; + bool found = false; + for (std::list::iterator iterator = icl.begin(); iterator != icl.end(); ++iterator) + { + if ((*iterator)->GetVictim() && (*iterator)->GetVictim()->GetGUID() == temp->GetGUID()) + { + found = true; + break; + } + } + + if( !found ) + playerGUIDs.push_back(temp->GetGUID()); + } + + if( !playerGUIDs.empty() ) + { + int8 pos = urand(0, playerGUIDs.size() - 1); + if( Player* pTarget = ObjectAccessor::GetPlayer(*me, playerGUIDs.at(pos)) ) + { + Talk(SAY_SLAG_POT); + me->CastSpell(pTarget, SPELL_GRAB, false); + } + } + + events.Repeat(24s); + events.DelayEvents(6s); + } + break; + } + + DoMeleeAttackIfReady(); + } + + void EnterEvadeMode(EvadeReason why) override + { + me->SetControlled(false, UNIT_STATE_ROOT); + me->DisableRotate(false); + ScriptedAI::EnterEvadeMode(why); + } + }; +}; + +class spell_ignis_scorch : public SpellScriptLoader +{ +public: + spell_ignis_scorch() : SpellScriptLoader("spell_ignis_scorch") { } + + class spell_ignis_scorch_AuraScript : public AuraScript + { + PrepareAuraScript(spell_ignis_scorch_AuraScript) + + void HandleEffectPeriodic(AuraEffect const* aurEff) + { + if (aurEff->GetTotalTicks() >= 0 && aurEff->GetTickNumber() == uint32(aurEff->GetTotalTicks())) + if (Unit* c = GetCaster()) + if (Creature* s = c->SummonCreature(NPC_SCORCHED_GROUND, c->GetPositionX() + 20.0f * cos(c->GetOrientation()), c->GetPositionY() + 20.0f * std::sin(c->GetOrientation()), 361.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000)) + { + if (!s->FindNearestCreature(NPC_WATER_TRIGGER, 25.0f, true)) // must be away from the water + s->CastSpell(s, (aurEff->GetId() == 62546 ? SPELL_SCORCHED_GROUND_10 : SPELL_SCORCHED_GROUND_25), true); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_ignis_scorch_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_ignis_scorch_AuraScript(); + } +}; + +class spell_ignis_grab_initial : public SpellScriptLoader +{ +public: + spell_ignis_grab_initial() : SpellScriptLoader("spell_ignis_grab_initial") { } + + class spell_ignis_grab_initial_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ignis_grab_initial_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* t = GetHitUnit()) + t->CastSpell(t, SPELL_GRAB_TRIGGERED, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_ignis_grab_initial_SpellScript::HandleScript, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ignis_grab_initial_SpellScript(); + } +}; + +class spell_ignis_slag_pot : public SpellScriptLoader +{ +public: + spell_ignis_slag_pot() : SpellScriptLoader("spell_ignis_slag_pot") { } + + class spell_ignis_slag_pot_AuraScript : public AuraScript + { + PrepareAuraScript(spell_ignis_slag_pot_AuraScript) + + void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) + { + if (Unit* c = GetCaster()) + if (Unit* t = GetTarget()) + c->CastSpell(t, (GetId() == 62717 ? 65722 : 65723), true); + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* t = GetTarget()) + { + t->ApplySpellImmune(GetId(), IMMUNITY_ID, 62549, true); + t->ApplySpellImmune(GetId(), IMMUNITY_ID, 63475, true); + } + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* t = GetTarget()) + { + t->ApplySpellImmune(GetId(), IMMUNITY_ID, 62549, false); + t->ApplySpellImmune(GetId(), IMMUNITY_ID, 63475, false); + if (t->IsAlive()) + t->CastSpell(t, (GetId() == 62717 ? 62836 : 63536), true); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_ignis_slag_pot_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + OnEffectApply += AuraEffectApplyFn(spell_ignis_slag_pot_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_ignis_slag_pot_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_ignis_slag_pot_AuraScript(); + } +}; + +class achievement_ignis_shattered : public AchievementCriteriaScript +{ +public: + achievement_ignis_shattered() : AchievementCriteriaScript("achievement_ignis_shattered") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + if (!target || target->GetTypeId() != TYPEID_UNIT) + return false; + return !!target->ToCreature()->AI()->GetData(1337); + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp index 6af801f5439721..7a4354e307e449 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_kologarn.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "PassiveAI.h" @@ -26,867 +27,6 @@ #include "Vehicle.h" #include "ulduar.h" -enum KologarnSays -{ - SAY_AGGRO = 0, - SAY_SLAY = 1, - SAY_LEFT_ARM_GONE = 2, - SAY_RIGHT_ARM_GONE = 3, - SAY_SHOCKWAVE = 4, - SAY_GRAB_PLAYER = 5, - SAY_DEATH = 6, - SAY_BERSERK = 7, - EMOTE_STONE_GRIP = 8, - EMOTE_EYES = 9 -}; - -enum KologarnSpells -{ - SPELL_KOLOGARN_REDUCE_PARRY = 64651, - - // BASIC - SPELL_OVERHEAD_SMASH_10 = 63356, - SPELL_OVERHEAD_SMASH_25 = 64003, - SPELL_ONEARMED_OVERHEAD_SMASH_10 = 63573, - SPELL_ONEARMED_OVERHEAD_SMASH_25 = 64006, - SPELL_PETRIFYING_BREATH_10 = 62030, - SPELL_PETRIFYING_BREATH_25 = 63980, - SPELL_STONE_SHOUT_10 = 63716, - SPELL_STONE_SHOUT_25 = 64005, - - // EYEBEAM - SPELL_FOCUSED_EYEBEAM_SUMMON = 63342, - SPELL_FOCUSED_EYEBEAM_10 = 63347, - SPELL_FOCUSED_EYEBEAM_25 = 63977, - SPELL_FOCUSED_EYEBEAM_RIGHT = 63702, - SPELL_FOCUSED_EYEBEAM_LEFT = 63676, - - // ARMS - SPELL_ARM_DEAD_10 = 63629, - SPELL_ARM_DEAD_25 = 63979, - SPELL_RUBBLE_FALL_10 = 63821, - SPELL_RUBBLE_FALL_25 = 64001, - SPELL_ARM_RESPAWN_VISUAL = 64753, - - // LEFT ARM - SPELL_ARM_SWEEP_10 = 63766, - SPELL_ARM_SWEEP_25 = 63983, - - // RIGHT ARM - SPELL_STONE_GRIP_10 = 62166, - SPELL_STONE_GRIP_25 = 63981, - SPELL_RIDE_RIGHT_ARM_10 = 62056, - SPELL_RIDE_RIGHT_ARM_25 = 63985, - - // RUBBLE TRASH - SPELL_RUBBLE_ATTACK_10 = 63818, - SPELL_RUBBLE_ATTACK_25 = 63978, -}; - -#define SPELL_PETRIFYING_BREATH RAID_MODE(SPELL_PETRIFYING_BREATH_10, SPELL_PETRIFYING_BREATH_25) -#define SPELL_OVERHEAD_SMASH RAID_MODE(SPELL_OVERHEAD_SMASH_10, SPELL_OVERHEAD_SMASH_25) -#define SPELL_ONEARMED_OVERHEAD_SMASH RAID_MODE(SPELL_ONEARMED_OVERHEAD_SMASH_10, SPELL_ONEARMED_OVERHEAD_SMASH_25) -#define SPELL_ARM_DEAD RAID_MODE(SPELL_ARM_DEAD_10, SPELL_ARM_DEAD_25) -#define SPELL_ARM_SWEEP RAID_MODE(SPELL_ARM_SWEEP_10, SPELL_ARM_SWEEP_25) -#define SPELL_STONE_GRIP RAID_MODE(SPELL_STONE_GRIP_10, SPELL_STONE_GRIP_25) -#define SPELL_FOCUSED_EYEBEAM RAID_MODE(SPELL_FOCUSED_EYEBEAM_10, SPELL_FOCUSED_EYEBEAM_25) -#define SPELL_RUBBLE_FALL RAID_MODE(SPELL_RUBBLE_FALL_10, SPELL_RUBBLE_FALL_25) -#define SPELL_RUBBLE_ATTACK RAID_MODE(SPELL_RUBBLE_ATTACK_10, SPELL_RUBBLE_ATTACK_25) -#define SPELL_RIDE_RIGHT_ARM RAID_MODE(SPELL_RIDE_RIGHT_ARM_10, SPELL_RIDE_RIGHT_ARM_25) -#define SPELL_STONE_SHOUT RAID_MODE(SPELL_STONE_SHOUT_10, SPELL_STONE_SHOUT_25) - -enum KologarnEvents -{ - EVENT_SMASH = 1, - EVENT_GRIP = 2, - EVENT_SWEEP = 3, - EVENT_RESTORE_ARM_LEFT = 4, - EVENT_RESTORE_ARM_RIGHT = 5, - EVENT_FOCUSED_EYEBEAM = 6, - EVENT_STONE_SHOUT = 7, - EVENT_PREPARE_BREATH = 8, // Kologarn can't cast breath on pull -}; - -enum KologarnNPCs -{ - NPC_LEFT_ARM = 32933, - NPC_RIGHT_ARM = 32934, - NPC_SWEEP_TRIGGER = 33661, - NPC_EYE_LEFT = 33632, - NPC_EYE_RIGHT = 33802, - NPC_RUBBLE_TRIGGER = 33809, - NPC_RUBBLE_SUMMON = 33768, -}; - -enum KologarnSounds -{ - SOUND_AGGRO = 15586, - SOUND_SLAY1 = 15587, - SOUND_SLAY2 = 15588, - SOUND_LARM_GONE = 15589, - SOUND_RARM_GONE = 15590, - SOUND_SHOCKWAVE = 15591, - SOUND_GRIP = 15592, - SOUND_DEATH = 15593, - SOUND_BERSERK = 15594, -}; - -enum Misc -{ - ACHIEVEMENT_DISARMED_CRITERIA = 21687, - - DATA_KOLOGARN_LOOKS_ACHIEV = 55, - DATA_KOLOGARN_RUBBLE_ACHIEV = 56, - DATA_KOLOGARN_ARMS_ACHIEV = 57, -}; - -class boss_kologarn : public CreatureScript -{ -public: - boss_kologarn() : CreatureScript("boss_kologarn") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_kologarnAI : public ScriptedAI - { - boss_kologarnAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me), breathReady(false) - { - m_pInstance = me->GetInstanceScript(); - eyebeamTarget = nullptr; - assert(vehicle); - me->SetStandState(UNIT_STAND_STATE_SUBMERGED); - } - - InstanceScript* m_pInstance; - - Vehicle* vehicle; - ObjectGuid _left, _right; - EventMap events; - SummonList summons; - - Unit* eyebeamTarget; - - bool _looksAchievement, breathReady; - uint8 _rubbleAchievement; - - void MoveInLineOfSight(Unit* who) override - { - if (who->GetTypeId() == TYPEID_PLAYER && me->GetExactDist2d(who) < 45.0f && me->getStandState() == UNIT_STAND_STATE_SUBMERGED) - { - me->SetStandState(UNIT_STAND_STATE_STAND); - if (Unit* arm = ObjectAccessor::GetCreature(*me, _left)) - arm->CastSpell(arm, SPELL_ARM_RESPAWN_VISUAL, true); - if (Unit* arm = ObjectAccessor::GetCreature(*me, _right)) - arm->CastSpell(arm, SPELL_ARM_RESPAWN_VISUAL, true); - } - - if (me->GetExactDist2d(who) < 30.0f) - ScriptedAI::MoveInLineOfSight(who); - } - - void EnterEvadeMode(EvadeReason why) override - { - if (!_EnterEvadeMode(why)) - return; - Reset(); - me->setActive(false); - } - - void AttachLeftArm() - { - if (Unit* arm = ObjectAccessor::GetCreature(*me, _left)) - arm->SetHealth(arm->GetMaxHealth()); - else if (Creature* accessory = me->SummonCreature(NPC_LEFT_ARM, *me, TEMPSUMMON_MANUAL_DESPAWN)) - { - accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY); - if (!me->HandleSpellClick(accessory, 0)) - accessory->DespawnOrUnsummon(); - else - { - _left = accessory->GetGUID(); - accessory->SetOrientation(M_PI); - accessory->CastSpell(accessory, SPELL_ARM_RESPAWN_VISUAL, true); - } - } - } - - void AttachRightArm() - { - if (Unit* arm = ObjectAccessor::GetCreature(*me, _right)) - arm->SetHealth(arm->GetMaxHealth()); - else if (Creature* accessory = me->SummonCreature(NPC_RIGHT_ARM, *me, TEMPSUMMON_MANUAL_DESPAWN)) - { - accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY); - if (!me->HandleSpellClick(accessory, 1)) - accessory->DespawnOrUnsummon(); - else - { - _right = accessory->GetGUID(); - accessory->SetOrientation(M_PI); - accessory->CastSpell(accessory, SPELL_ARM_RESPAWN_VISUAL, true); - } - } - } - - void Reset() override - { - _rubbleAchievement = 0; - _looksAchievement = true; - - me->SetDisableGravity(true); - me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); - me->DisableRotate(true); - - events.Reset(); - summons.DespawnAll(); - - if (m_pInstance) - { - m_pInstance->SetData(TYPE_KOLOGARN, NOT_STARTED); - - // Open the door inside Kologarn chamber - if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS))) - door->SetGoState(GO_STATE_ACTIVE); - } - - AttachLeftArm(); - AttachRightArm(); - - // Reset breath on pull - breathReady = false; - } - - void DoAction(int32 param) override - { - if (param == DATA_KOLOGARN_LOOKS_ACHIEV) - _looksAchievement = false; - if (param == DATA_KOLOGARN_RUBBLE_ACHIEV) - { - // Means arm died - if (m_pInstance && (!_left || !_right)) - m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_DISARMED_CRITERIA); - - ++_rubbleAchievement; - } - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_KOLOGARN_LOOKS_ACHIEV) - return _looksAchievement; - else if (param == DATA_KOLOGARN_RUBBLE_ACHIEV) - return (_rubbleAchievement >= 5); - else if (param == DATA_KOLOGARN_ARMS_ACHIEV) - return !_rubbleAchievement; - - return 0; - } - - void AttackStart(Unit* who) override - { - me->Attack(who, true); - } - - void JustSummoned(Creature* cr) override - { - if (cr->GetEntry() != NPC_LEFT_ARM && cr->GetEntry() != NPC_RIGHT_ARM) - summons.Summon(cr); - } - - void JustDied(Unit*) override - { - summons.DespawnAll(); - me->StopMoving(); - if (m_pInstance) - m_pInstance->SetData(TYPE_KOLOGARN, DONE); - - Talk(SAY_DEATH); - - if (m_pInstance) - { - // Open the door inside Kologarn chamber - if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS))) - door->SetGoState(GO_STATE_ACTIVE); - } - - if (GameObject* bridge = me->FindNearestGameObject(GO_KOLOGARN_BRIDGE, 100)) - bridge->SetGoState(GO_STATE_READY); - - // Summon Chest - if (GameObject* go = me->SummonGameObject(RAID_MODE(GO_KOLOGARN_CHEST, GO_KOLOGARN_CHEST_HERO), 1839.62f, -35.98f, 448.81f, 3.6f, 0, 0, 0, 0, 7 * 86400)) - { - me->RemoveGameObject(go, false); - go->SetSpellId(1); // hack to make it despawn - go->ReplaceAllGameObjectFlags((GameObjectFlags)0); - go->SetLootRecipient(me); - } - if (Creature* arm = ObjectAccessor::GetCreature(*me, _left)) - arm->DespawnOrUnsummon(3000); // visual - if (Creature* arm = ObjectAccessor::GetCreature(*me, _right)) - arm->DespawnOrUnsummon(3000); // visual - } - - void KilledUnit(Unit*) override - { - if (!urand(0, 2)) - return; - - Talk(SAY_SLAY); - } - - void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override - { - if (!me->IsAlive()) - return; - - if (!apply) - { - // left arm - if (who->GetGUID() == _left) - { - _left.Clear(); - if (me->IsInCombat()) - { - Talk(SAY_LEFT_ARM_GONE); - events.ScheduleEvent(EVENT_RESTORE_ARM_LEFT, 50s); - } - } - else - { - _right.Clear(); - if (me->IsInCombat()) - { - Talk(SAY_RIGHT_ARM_GONE); - events.ScheduleEvent(EVENT_RESTORE_ARM_RIGHT, 50s); - } - } - - me->CastSpell(me, SPELL_ARM_DEAD, true); - if (!_right && !_left) - events.ScheduleEvent(EVENT_STONE_SHOUT, 5s); - } - } - - void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (who && who->GetEntry() == me->GetEntry() && me->GetHealth()) - { - damage = std::min(damage, me->GetHealth() - 1); - me->LowerPlayerDamageReq(damage); - } - } - - void JustEngagedWith(Unit* /*who*/) override - { - if (m_pInstance) - m_pInstance->SetData(TYPE_KOLOGARN, IN_PROGRESS); - - events.ScheduleEvent(EVENT_SMASH, 8s); - events.ScheduleEvent(EVENT_SWEEP, 17s); - events.ScheduleEvent(EVENT_GRIP, 15s); - events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 10s); - events.ScheduleEvent(EVENT_PREPARE_BREATH, 3s); - //events.ScheduleEvent(EVENT_ENRAGE, x); no info - - Talk(SAY_AGGRO); - me->setActive(true); - - // Close the door inside Kologarn chamber - if (m_pInstance) - { - if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS))) - { - door->SetGoState(GO_STATE_READY); - } - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_PREPARE_BREATH: - breathReady = true; - break; - case EVENT_STONE_SHOUT: - if (_left || _right) - { - return; - } - - me->CastSpell(me->GetVictim(), SPELL_STONE_SHOUT, false); - events.ScheduleEvent(EVENT_STONE_SHOUT, 2s); - break; - case EVENT_SMASH: - if (_left && _right) - me->CastSpell(me->GetVictim(), SPELL_OVERHEAD_SMASH, false); - else if (_left || _right) - me->CastSpell(me->GetVictim(), SPELL_ONEARMED_OVERHEAD_SMASH, false); - - events.DelayEvents(1s); - events.ScheduleEvent(EVENT_SMASH, 14s); - return; - case EVENT_SWEEP: - if (_left) - { - if (Creature* cr = me->FindNearestCreature(NPC_SWEEP_TRIGGER, 300)) - cr->CastSpell(cr, SPELL_ARM_SWEEP, false); - - if (urand(0, 1)) - Talk(SAY_SHOCKWAVE); - } - - events.DelayEvents(1s); - events.ScheduleEvent(EVENT_SWEEP, 17s); - return; - case EVENT_GRIP: - events.ScheduleEvent(EVENT_GRIP, 25s); - if (!_right) - break; - - me->CastSpell(me, SPELL_STONE_GRIP, false); - Talk(SAY_GRAB_PLAYER); - Talk(EMOTE_STONE_GRIP); - return; - case EVENT_FOCUSED_EYEBEAM: - { - events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 20s); - - if ((eyebeamTarget = SelectTarget(SelectTargetMethod::MinDistance, 0, 0, true))) - { - me->CastSpell(eyebeamTarget, SPELL_FOCUSED_EYEBEAM_SUMMON, false); - } - - Talk(EMOTE_EYES); - return; - } - case EVENT_RESTORE_ARM_LEFT: - // shouldn't happen - AttachLeftArm(); - return; - case EVENT_RESTORE_ARM_RIGHT: - // shouldn't happen - AttachRightArm(); - return; - } - - //Make sure our attack is ready and we aren't currently casting before checking distance - if (me->isAttackReady() && me->GetVictim()) // victim could die by a spell (IMPORTANT!!!) and kologarn entered evade mode - { - //If we are within range melee the target - if (me->IsWithinMeleeRange(me->GetVictim())) - { - me->AttackerStateUpdate(me->GetVictim()); - me->resetAttackTimer(); - return; - } - else if (Unit* tgt = me->SelectNearbyTarget()) - { - me->AttackerStateUpdate(tgt); - me->resetAttackTimer(); - return; - } - - if (breathReady) - me->CastSpell(me->GetVictim(), SPELL_PETRIFYING_BREATH, false); - me->resetAttackTimer(); - } - } - }; -}; - -// also used for left arm, all functions except JustDied wont be used by left arm -class boss_kologarn_arms : public CreatureScript -{ -public: - boss_kologarn_arms() : CreatureScript("boss_kologarn_arms") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_kologarn_armsAI : public ScriptedAI - { - boss_kologarn_armsAI(Creature* c) : ScriptedAI(c) { } - - int32 _damageDone; - bool _combatStarted; - - void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override {} - void MoveInLineOfSight(Unit*) override {} - void AttackStart(Unit*) override {} - void UpdateAI(uint32 /*diff*/) override {} - - void Reset() override - { - _combatStarted = false; - _damageDone = 0; - } - - void PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool apply) override - { - if (!apply) - _damageDone = 0; - else - { - //who->ClearUnitState(UNIT_STATE_ONVEHICLE); - if (!_damageDone) - _damageDone = RAID_MODE(80000, 380000); - } - } - - void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (!_combatStarted) - if (InstanceScript* instance = me->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_KOLOGARN))) - { - _combatStarted = true; - if (!cr->IsInCombat() && who) - cr->AI()->AttackStart(who); - } - - if (_damageDone > 0) - { - _damageDone -= damage; - if (_damageDone <= 0 || damage >= me->GetHealth()) - me->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE); - } - } - - void JustDied(Unit*) override - { - float x, y, z; - // left arm - if( me->GetEntry() == NPC_LEFT_ARM ) - { - x = 1776.97f; - y = -44.8396f; - z = 448.888f; - } - else - { - x = 1777.82f; - y = -3.50803f; - z = 448.888f; - } - - if (Creature* cr = me->SummonTrigger(x, y, z, 0, 5000)) - { - cr->CastSpell(cr, SPELL_RUBBLE_FALL, true); - - if (me->GetInstanceScript()) - if (Creature* kologarn = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN))) - for (uint8 i = 0; i < 5; ++i) - if (Creature* cr2 = kologarn->SummonCreature(NPC_RUBBLE_SUMMON, cr->GetPositionX() + irand(-5, 5), cr->GetPositionY() + irand(-5, 5), cr->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000)) - { - cr2->SetInCombatWithZone(); - if (Unit* target = SelectTargetFromPlayerList(100)) - cr2->AI()->AttackStart(target); - } - } - - if (me->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN))) - cr->AI()->DoAction(DATA_KOLOGARN_RUBBLE_ACHIEV); - - me->ExitVehicle(); - } - }; -}; - -class boss_kologarn_eyebeam : public CreatureScript -{ -public: - boss_kologarn_eyebeam() : CreatureScript("boss_kologarn_eyebeam") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - struct boss_kologarn_eyebeamAI : public ScriptedAI - { - boss_kologarn_eyebeamAI(Creature* c) : ScriptedAI(c), _timer(1), _damaged(false), justSpawned(true) - { - m_pInstance = (InstanceScript*)c->GetInstanceScript(); - } - - InstanceScript* m_pInstance; - uint32 _timer; - bool _damaged, justSpawned; - - void DamageDealt(Unit* /*victim*/, uint32& damage, DamageEffectType /*damageType*/) override - { - if (damage > 0 && !_damaged && me->GetInstanceScript()) - { - _damaged = true; - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN))) - cr->AI()->DoAction(DATA_KOLOGARN_LOOKS_ACHIEV); - } - } - - void UpdateAI(uint32 diff) override - { - if (justSpawned) - { - me->DespawnOrUnsummon(10000); - if (Creature* cr = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(TYPE_KOLOGARN))) - { - me->CastSpell(cr, me->GetEntry() == NPC_EYE_LEFT ? SPELL_FOCUSED_EYEBEAM_LEFT : SPELL_FOCUSED_EYEBEAM_RIGHT, true); - } - me->CastSpell(me, SPELL_FOCUSED_EYEBEAM, true); - justSpawned = false; - } - if (_timer) - { - _timer += diff; - if (_timer >= 2000) - { - me->CastSpell(me, (me->GetMap()->Is25ManRaid() ? SPELL_FOCUSED_EYEBEAM_25 : SPELL_FOCUSED_EYEBEAM_10), true); - _timer = 0; - } - } - } - }; -}; - -// predicate function to select non main tank target -class StoneGripTargetSelector -{ -public: - StoneGripTargetSelector(Creature* me, Unit const* victim) : _me(me), _victim(victim) {} - - bool operator() (WorldObject* target) const - { - if (target == _victim && _me->GetThreatMgr().GetThreatListSize() > 1) - return true; - - if (target->GetTypeId() != TYPEID_PLAYER) - return true; - - return false; - } - -private: - Creature* _me; - Unit const* _victim; -}; - -class spell_ulduar_stone_grip_cast_target : public SpellScriptLoader -{ -public: - spell_ulduar_stone_grip_cast_target() : SpellScriptLoader("spell_ulduar_stone_grip_cast_target") { } - - class spell_ulduar_stone_grip_cast_target_SpellScript : public SpellScript - { - PrepareSpellScript(spell_ulduar_stone_grip_cast_target_SpellScript); - - bool Load() override - { - if (GetCaster()->GetTypeId() != TYPEID_UNIT) - return false; - return true; - } - - void FilterTargetsInitial(std::list& targets) - { - // Remove "main tank" and non-player targets - targets.remove_if (StoneGripTargetSelector(GetCaster()->ToCreature(), GetCaster()->GetVictim())); - // Maximum affected targets per difficulty mode - uint32 maxTargets = 1; - if (GetSpellInfo()->Id == 63981) - maxTargets = 3; - - // Return a random amount of targets based on maxTargets - while (maxTargets < targets.size()) - { - std::list::iterator itr = targets.begin(); - advance(itr, urand(0, targets.size() - 1)); - targets.erase(itr); - } - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ulduar_stone_grip_cast_target_SpellScript::FilterTargetsInitial, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_ulduar_stone_grip_cast_target_SpellScript(); - } -}; - -class spell_ulduar_stone_grip : public SpellScriptLoader -{ -public: - spell_ulduar_stone_grip() : SpellScriptLoader("spell_ulduar_stone_grip") { } - - class spell_ulduar_stone_grip_AuraScript : public AuraScript - { - PrepareAuraScript(spell_ulduar_stone_grip_AuraScript); - - void OnRemoveStun(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - if (Player* owner = GetOwner()->ToPlayer()) - owner->RemoveAurasDueToSpell(aurEff->GetAmount()); - } - - void Register() override - { - OnEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_AuraScript::OnRemoveStun, EFFECT_2, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_ulduar_stone_grip_AuraScript(); - } -}; - -class spell_ulduar_squeezed_lifeless : public SpellScriptLoader -{ -public: - spell_ulduar_squeezed_lifeless() : SpellScriptLoader("spell_ulduar_squeezed_lifeless") { } - - class spell_ulduar_squeezed_lifeless_SpellScript : public SpellScript - { - PrepareSpellScript(spell_ulduar_squeezed_lifeless_SpellScript); - - void HandleInstaKill(SpellEffIndex /*effIndex*/) - { - if (!GetHitPlayer() || !GetHitPlayer()->GetVehicle()) - return; - - // Hack to set correct position is in _ExitVehicle() - GetHitPlayer()->ExitVehicle(); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_ulduar_squeezed_lifeless_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_ulduar_squeezed_lifeless_SpellScript(); - } -}; - -class spell_kologarn_stone_shout : public SpellScriptLoader -{ -public: - spell_kologarn_stone_shout() : SpellScriptLoader("spell_kologarn_stone_shout") { } - - class spell_kologarn_stone_shout_AuraScript : public AuraScript - { - PrepareAuraScript(spell_kologarn_stone_shout_AuraScript); - - void OnPeriodic(AuraEffect const* /*aurEff*/) - { - uint32 triggerSpellId = GetSpellInfo()->Effects[EFFECT_0].TriggerSpell; - if (Unit* caster = GetCaster()) - caster->CastSpell(caster, triggerSpellId, false); - } - - void Register() override - { - if (m_scriptSpellId == SPELL_STONE_SHOUT_10 || m_scriptSpellId == SPELL_STONE_SHOUT_25) - OnEffectPeriodic += AuraEffectPeriodicFn(spell_kologarn_stone_shout_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_kologarn_stone_shout_AuraScript(); - } - - class spell_kologarn_stone_shout_SpellScript : public SpellScript - { - PrepareSpellScript(spell_kologarn_stone_shout_SpellScript); - - void FilterTargets(std::list& targets) - { - targets.remove_if (PlayerOrPetCheck()); - } - - void Register() override - { - if (m_scriptSpellId != SPELL_STONE_SHOUT_10 && m_scriptSpellId != SPELL_STONE_SHOUT_25) - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kologarn_stone_shout_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_kologarn_stone_shout_SpellScript(); - } -}; - -class achievement_kologarn_looks_could_kill : public AchievementCriteriaScript -{ -public: - achievement_kologarn_looks_could_kill() : AchievementCriteriaScript("achievement_kologarn_looks_could_kill") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - if (target) - if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN))) - return cr->AI()->GetData(DATA_KOLOGARN_LOOKS_ACHIEV); - - return false; - } -}; - -class achievement_kologarn_rubble_and_roll : public AchievementCriteriaScript -{ -public: - achievement_kologarn_rubble_and_roll() : AchievementCriteriaScript("achievement_kologarn_rubble_and_roll") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - if (target) - if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN))) - return cr->AI()->GetData(DATA_KOLOGARN_RUBBLE_ACHIEV); - - return false; - } -}; - -class achievement_kologarn_with_open_arms : public AchievementCriteriaScript -{ -public: - achievement_kologarn_with_open_arms() : AchievementCriteriaScript("achievement_kologarn_with_open_arms") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - if (target) - if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN))) - return cr->AI()->GetData(DATA_KOLOGARN_ARMS_ACHIEV); - - return false; - } -}; - void AddSC_boss_kologarn() { // Npcs diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.h new file mode 100644 index 00000000000000..1b52988a9678e0 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.h @@ -0,0 +1,876 @@ +#ifndef BOSS_KOLOGARN_H_ +#define BOSS_KOLOGARN_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "Vehicle.h" +#include "ulduar.h" + +enum KologarnSays +{ + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_LEFT_ARM_GONE = 2, + SAY_RIGHT_ARM_GONE = 3, + SAY_SHOCKWAVE = 4, + SAY_GRAB_PLAYER = 5, + SAY_DEATH = 6, + SAY_BERSERK = 7, + EMOTE_STONE_GRIP = 8, + EMOTE_EYES = 9 +}; + +enum KologarnSpells +{ + SPELL_KOLOGARN_REDUCE_PARRY = 64651, + + // BASIC + SPELL_OVERHEAD_SMASH_10 = 63356, + SPELL_OVERHEAD_SMASH_25 = 64003, + SPELL_ONEARMED_OVERHEAD_SMASH_10 = 63573, + SPELL_ONEARMED_OVERHEAD_SMASH_25 = 64006, + SPELL_PETRIFYING_BREATH_10 = 62030, + SPELL_PETRIFYING_BREATH_25 = 63980, + SPELL_STONE_SHOUT_10 = 63716, + SPELL_STONE_SHOUT_25 = 64005, + + // EYEBEAM + SPELL_FOCUSED_EYEBEAM_SUMMON = 63342, + SPELL_FOCUSED_EYEBEAM_10 = 63347, + SPELL_FOCUSED_EYEBEAM_25 = 63977, + SPELL_FOCUSED_EYEBEAM_RIGHT = 63702, + SPELL_FOCUSED_EYEBEAM_LEFT = 63676, + + // ARMS + SPELL_ARM_DEAD_10 = 63629, + SPELL_ARM_DEAD_25 = 63979, + SPELL_RUBBLE_FALL_10 = 63821, + SPELL_RUBBLE_FALL_25 = 64001, + SPELL_ARM_RESPAWN_VISUAL = 64753, + + // LEFT ARM + SPELL_ARM_SWEEP_10 = 63766, + SPELL_ARM_SWEEP_25 = 63983, + + // RIGHT ARM + SPELL_STONE_GRIP_10 = 62166, + SPELL_STONE_GRIP_25 = 63981, + SPELL_RIDE_RIGHT_ARM_10 = 62056, + SPELL_RIDE_RIGHT_ARM_25 = 63985, + + // RUBBLE TRASH + SPELL_RUBBLE_ATTACK_10 = 63818, + SPELL_RUBBLE_ATTACK_25 = 63978, +}; + +#define SPELL_PETRIFYING_BREATH RAID_MODE(SPELL_PETRIFYING_BREATH_10, SPELL_PETRIFYING_BREATH_25) +#define SPELL_OVERHEAD_SMASH RAID_MODE(SPELL_OVERHEAD_SMASH_10, SPELL_OVERHEAD_SMASH_25) +#define SPELL_ONEARMED_OVERHEAD_SMASH RAID_MODE(SPELL_ONEARMED_OVERHEAD_SMASH_10, SPELL_ONEARMED_OVERHEAD_SMASH_25) +#define SPELL_ARM_DEAD RAID_MODE(SPELL_ARM_DEAD_10, SPELL_ARM_DEAD_25) +#define SPELL_ARM_SWEEP RAID_MODE(SPELL_ARM_SWEEP_10, SPELL_ARM_SWEEP_25) +#define SPELL_STONE_GRIP RAID_MODE(SPELL_STONE_GRIP_10, SPELL_STONE_GRIP_25) +#define SPELL_FOCUSED_EYEBEAM RAID_MODE(SPELL_FOCUSED_EYEBEAM_10, SPELL_FOCUSED_EYEBEAM_25) +#define SPELL_RUBBLE_FALL RAID_MODE(SPELL_RUBBLE_FALL_10, SPELL_RUBBLE_FALL_25) +#define SPELL_RUBBLE_ATTACK RAID_MODE(SPELL_RUBBLE_ATTACK_10, SPELL_RUBBLE_ATTACK_25) +#define SPELL_RIDE_RIGHT_ARM RAID_MODE(SPELL_RIDE_RIGHT_ARM_10, SPELL_RIDE_RIGHT_ARM_25) +#define SPELL_STONE_SHOUT RAID_MODE(SPELL_STONE_SHOUT_10, SPELL_STONE_SHOUT_25) + +enum KologarnEvents +{ + EVENT_SMASH = 1, + EVENT_GRIP = 2, + EVENT_SWEEP = 3, + EVENT_RESTORE_ARM_LEFT = 4, + EVENT_RESTORE_ARM_RIGHT = 5, + EVENT_FOCUSED_EYEBEAM = 6, + EVENT_STONE_SHOUT = 7, + EVENT_PREPARE_BREATH = 8, // Kologarn can't cast breath on pull +}; + +enum KologarnNPCs +{ + NPC_LEFT_ARM = 32933, + NPC_RIGHT_ARM = 32934, + NPC_SWEEP_TRIGGER = 33661, + NPC_EYE_LEFT = 33632, + NPC_EYE_RIGHT = 33802, + NPC_RUBBLE_TRIGGER = 33809, + NPC_RUBBLE_SUMMON = 33768, +}; + +enum KologarnSounds +{ + SOUND_AGGRO = 15586, + SOUND_SLAY1 = 15587, + SOUND_SLAY2 = 15588, + SOUND_LARM_GONE = 15589, + SOUND_RARM_GONE = 15590, + SOUND_SHOCKWAVE = 15591, + SOUND_GRIP = 15592, + SOUND_DEATH = 15593, + SOUND_BERSERK = 15594, +}; + +enum Misc +{ + ACHIEVEMENT_DISARMED_CRITERIA = 21687, + + DATA_KOLOGARN_LOOKS_ACHIEV = 55, + DATA_KOLOGARN_RUBBLE_ACHIEV = 56, + DATA_KOLOGARN_ARMS_ACHIEV = 57, +}; + +class boss_kologarn : public CreatureScript +{ +public: + boss_kologarn() : CreatureScript("boss_kologarn") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_kologarnAI : public ScriptedAI + { + boss_kologarnAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me), breathReady(false) + { + m_pInstance = me->GetInstanceScript(); + eyebeamTarget = nullptr; + assert(vehicle); + me->SetStandState(UNIT_STAND_STATE_SUBMERGED); + } + + InstanceScript* m_pInstance; + + Vehicle* vehicle; + ObjectGuid _left, _right; + EventMap events; + SummonList summons; + + Unit* eyebeamTarget; + + bool _looksAchievement, breathReady; + uint8 _rubbleAchievement; + + void MoveInLineOfSight(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER && me->GetExactDist2d(who) < 45.0f && me->getStandState() == UNIT_STAND_STATE_SUBMERGED) + { + me->SetStandState(UNIT_STAND_STATE_STAND); + if (Unit* arm = ObjectAccessor::GetCreature(*me, _left)) + arm->CastSpell(arm, SPELL_ARM_RESPAWN_VISUAL, true); + if (Unit* arm = ObjectAccessor::GetCreature(*me, _right)) + arm->CastSpell(arm, SPELL_ARM_RESPAWN_VISUAL, true); + } + + if (me->GetExactDist2d(who) < 30.0f) + ScriptedAI::MoveInLineOfSight(who); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (!_EnterEvadeMode(why)) + return; + Reset(); + me->setActive(false); + } + + void AttachLeftArm() + { + if (Unit* arm = ObjectAccessor::GetCreature(*me, _left)) + arm->SetHealth(arm->GetMaxHealth()); + else if (Creature* accessory = me->SummonCreature(NPC_LEFT_ARM, *me, TEMPSUMMON_MANUAL_DESPAWN)) + { + accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY); + if (!me->HandleSpellClick(accessory, 0)) + accessory->DespawnOrUnsummon(); + else + { + _left = accessory->GetGUID(); + accessory->SetOrientation(M_PI); + accessory->CastSpell(accessory, SPELL_ARM_RESPAWN_VISUAL, true); + } + } + } + + void AttachRightArm() + { + if (Unit* arm = ObjectAccessor::GetCreature(*me, _right)) + arm->SetHealth(arm->GetMaxHealth()); + else if (Creature* accessory = me->SummonCreature(NPC_RIGHT_ARM, *me, TEMPSUMMON_MANUAL_DESPAWN)) + { + accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY); + if (!me->HandleSpellClick(accessory, 1)) + accessory->DespawnOrUnsummon(); + else + { + _right = accessory->GetGUID(); + accessory->SetOrientation(M_PI); + accessory->CastSpell(accessory, SPELL_ARM_RESPAWN_VISUAL, true); + } + } + } + + void Reset() override + { + _rubbleAchievement = 0; + _looksAchievement = true; + + me->SetDisableGravity(true); + me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); + me->DisableRotate(true); + + events.Reset(); + summons.DespawnAll(); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_KOLOGARN, NOT_STARTED); + + // Open the door inside Kologarn chamber + if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS))) + door->SetGoState(GO_STATE_ACTIVE); + } + + AttachLeftArm(); + AttachRightArm(); + + // Reset breath on pull + breathReady = false; + } + + void DoAction(int32 param) override + { + if (param == DATA_KOLOGARN_LOOKS_ACHIEV) + _looksAchievement = false; + if (param == DATA_KOLOGARN_RUBBLE_ACHIEV) + { + // Means arm died + if (m_pInstance && (!_left || !_right)) + m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_DISARMED_CRITERIA); + + ++_rubbleAchievement; + } + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_KOLOGARN_LOOKS_ACHIEV) + return _looksAchievement; + else if (param == DATA_KOLOGARN_RUBBLE_ACHIEV) + return (_rubbleAchievement >= 5); + else if (param == DATA_KOLOGARN_ARMS_ACHIEV) + return !_rubbleAchievement; + + return 0; + } + + void AttackStart(Unit* who) override + { + me->Attack(who, true); + } + + void JustSummoned(Creature* cr) override + { + if (cr->GetEntry() != NPC_LEFT_ARM && cr->GetEntry() != NPC_RIGHT_ARM) + summons.Summon(cr); + } + + void JustDied(Unit*) override + { + summons.DespawnAll(); + me->StopMoving(); + if (m_pInstance) + m_pInstance->SetData(TYPE_KOLOGARN, DONE); + + Talk(SAY_DEATH); + + if (m_pInstance) + { + // Open the door inside Kologarn chamber + if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS))) + door->SetGoState(GO_STATE_ACTIVE); + } + + if (GameObject* bridge = me->FindNearestGameObject(GO_KOLOGARN_BRIDGE, 100)) + bridge->SetGoState(GO_STATE_READY); + + // Summon Chest + if (GameObject* go = me->SummonGameObject(RAID_MODE(GO_KOLOGARN_CHEST, GO_KOLOGARN_CHEST_HERO), 1839.62f, -35.98f, 448.81f, 3.6f, 0, 0, 0, 0, 7 * 86400)) + { + me->RemoveGameObject(go, false); + go->SetSpellId(1); // hack to make it despawn + go->ReplaceAllGameObjectFlags((GameObjectFlags)0); + go->SetLootRecipient(me); + } + if (Creature* arm = ObjectAccessor::GetCreature(*me, _left)) + arm->DespawnOrUnsummon(3000); // visual + if (Creature* arm = ObjectAccessor::GetCreature(*me, _right)) + arm->DespawnOrUnsummon(3000); // visual + } + + void KilledUnit(Unit*) override + { + if (!urand(0, 2)) + return; + + Talk(SAY_SLAY); + } + + void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override + { + if (!me->IsAlive()) + return; + + if (!apply) + { + // left arm + if (who->GetGUID() == _left) + { + _left.Clear(); + if (me->IsInCombat()) + { + Talk(SAY_LEFT_ARM_GONE); + events.ScheduleEvent(EVENT_RESTORE_ARM_LEFT, 50s); + } + } + else + { + _right.Clear(); + if (me->IsInCombat()) + { + Talk(SAY_RIGHT_ARM_GONE); + events.ScheduleEvent(EVENT_RESTORE_ARM_RIGHT, 50s); + } + } + + me->CastSpell(me, SPELL_ARM_DEAD, true); + if (!_right && !_left) + events.ScheduleEvent(EVENT_STONE_SHOUT, 5s); + } + } + + void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (who && who->GetEntry() == me->GetEntry() && me->GetHealth()) + { + damage = std::min(damage, me->GetHealth() - 1); + me->LowerPlayerDamageReq(damage); + } + } + + void JustEngagedWith(Unit* /*who*/) override + { + if (m_pInstance) + m_pInstance->SetData(TYPE_KOLOGARN, IN_PROGRESS); + + events.ScheduleEvent(EVENT_SMASH, 8s); + events.ScheduleEvent(EVENT_SWEEP, 17s); + events.ScheduleEvent(EVENT_GRIP, 15s); + events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 10s); + events.ScheduleEvent(EVENT_PREPARE_BREATH, 3s); + //events.ScheduleEvent(EVENT_ENRAGE, x); no info + + Talk(SAY_AGGRO); + me->setActive(true); + + // Close the door inside Kologarn chamber + if (m_pInstance) + { + if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS))) + { + door->SetGoState(GO_STATE_READY); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_PREPARE_BREATH: + breathReady = true; + break; + case EVENT_STONE_SHOUT: + if (_left || _right) + { + return; + } + + me->CastSpell(me->GetVictim(), SPELL_STONE_SHOUT, false); + events.ScheduleEvent(EVENT_STONE_SHOUT, 2s); + break; + case EVENT_SMASH: + if (_left && _right) + me->CastSpell(me->GetVictim(), SPELL_OVERHEAD_SMASH, false); + else if (_left || _right) + me->CastSpell(me->GetVictim(), SPELL_ONEARMED_OVERHEAD_SMASH, false); + + events.DelayEvents(1s); + events.ScheduleEvent(EVENT_SMASH, 14s); + return; + case EVENT_SWEEP: + if (_left) + { + if (Creature* cr = me->FindNearestCreature(NPC_SWEEP_TRIGGER, 300)) + cr->CastSpell(cr, SPELL_ARM_SWEEP, false); + + if (urand(0, 1)) + Talk(SAY_SHOCKWAVE); + } + + events.DelayEvents(1s); + events.ScheduleEvent(EVENT_SWEEP, 17s); + return; + case EVENT_GRIP: + events.ScheduleEvent(EVENT_GRIP, 25s); + if (!_right) + break; + + me->CastSpell(me, SPELL_STONE_GRIP, false); + Talk(SAY_GRAB_PLAYER); + Talk(EMOTE_STONE_GRIP); + return; + case EVENT_FOCUSED_EYEBEAM: + { + events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 20s); + + if ((eyebeamTarget = SelectTarget(SelectTargetMethod::MinDistance, 0, 0, true))) + { + me->CastSpell(eyebeamTarget, SPELL_FOCUSED_EYEBEAM_SUMMON, false); + } + + Talk(EMOTE_EYES); + return; + } + case EVENT_RESTORE_ARM_LEFT: + // shouldn't happen + AttachLeftArm(); + return; + case EVENT_RESTORE_ARM_RIGHT: + // shouldn't happen + AttachRightArm(); + return; + } + + //Make sure our attack is ready and we aren't currently casting before checking distance + if (me->isAttackReady() && me->GetVictim()) // victim could die by a spell (IMPORTANT!!!) and kologarn entered evade mode + { + //If we are within range melee the target + if (me->IsWithinMeleeRange(me->GetVictim())) + { + me->AttackerStateUpdate(me->GetVictim()); + me->resetAttackTimer(); + return; + } + else if (Unit* tgt = me->SelectNearbyTarget()) + { + me->AttackerStateUpdate(tgt); + me->resetAttackTimer(); + return; + } + + if (breathReady) + me->CastSpell(me->GetVictim(), SPELL_PETRIFYING_BREATH, false); + me->resetAttackTimer(); + } + } + }; +}; + +// also used for left arm, all functions except JustDied wont be used by left arm +class boss_kologarn_arms : public CreatureScript +{ +public: + boss_kologarn_arms() : CreatureScript("boss_kologarn_arms") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_kologarn_armsAI : public ScriptedAI + { + boss_kologarn_armsAI(Creature* c) : ScriptedAI(c) { } + + int32 _damageDone; + bool _combatStarted; + + void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override {} + void MoveInLineOfSight(Unit*) override {} + void AttackStart(Unit*) override {} + void UpdateAI(uint32 /*diff*/) override {} + + void Reset() override + { + _combatStarted = false; + _damageDone = 0; + } + + void PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool apply) override + { + if (!apply) + _damageDone = 0; + else + { + //who->ClearUnitState(UNIT_STATE_ONVEHICLE); + if (!_damageDone) + _damageDone = RAID_MODE(80000, 380000); + } + } + + void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (!_combatStarted) + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_KOLOGARN))) + { + _combatStarted = true; + if (!cr->IsInCombat() && who) + cr->AI()->AttackStart(who); + } + + if (_damageDone > 0) + { + _damageDone -= damage; + if (_damageDone <= 0 || damage >= me->GetHealth()) + me->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE); + } + } + + void JustDied(Unit*) override + { + float x, y, z; + // left arm + if( me->GetEntry() == NPC_LEFT_ARM ) + { + x = 1776.97f; + y = -44.8396f; + z = 448.888f; + } + else + { + x = 1777.82f; + y = -3.50803f; + z = 448.888f; + } + + if (Creature* cr = me->SummonTrigger(x, y, z, 0, 5000)) + { + cr->CastSpell(cr, SPELL_RUBBLE_FALL, true); + + if (me->GetInstanceScript()) + if (Creature* kologarn = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN))) + for (uint8 i = 0; i < 5; ++i) + if (Creature* cr2 = kologarn->SummonCreature(NPC_RUBBLE_SUMMON, cr->GetPositionX() + irand(-5, 5), cr->GetPositionY() + irand(-5, 5), cr->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000)) + { + cr2->SetInCombatWithZone(); + if (Unit* target = SelectTargetFromPlayerList(100)) + cr2->AI()->AttackStart(target); + } + } + + if (me->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN))) + cr->AI()->DoAction(DATA_KOLOGARN_RUBBLE_ACHIEV); + + me->ExitVehicle(); + } + }; +}; + +class boss_kologarn_eyebeam : public CreatureScript +{ +public: + boss_kologarn_eyebeam() : CreatureScript("boss_kologarn_eyebeam") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + struct boss_kologarn_eyebeamAI : public ScriptedAI + { + boss_kologarn_eyebeamAI(Creature* c) : ScriptedAI(c), _timer(1), _damaged(false), justSpawned(true) + { + m_pInstance = (InstanceScript*)c->GetInstanceScript(); + } + + InstanceScript* m_pInstance; + uint32 _timer; + bool _damaged, justSpawned; + + void DamageDealt(Unit* /*victim*/, uint32& damage, DamageEffectType /*damageType*/) override + { + if (damage > 0 && !_damaged && me->GetInstanceScript()) + { + _damaged = true; + if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN))) + cr->AI()->DoAction(DATA_KOLOGARN_LOOKS_ACHIEV); + } + } + + void UpdateAI(uint32 diff) override + { + if (justSpawned) + { + me->DespawnOrUnsummon(10000); + if (Creature* cr = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(TYPE_KOLOGARN))) + { + me->CastSpell(cr, me->GetEntry() == NPC_EYE_LEFT ? SPELL_FOCUSED_EYEBEAM_LEFT : SPELL_FOCUSED_EYEBEAM_RIGHT, true); + } + me->CastSpell(me, SPELL_FOCUSED_EYEBEAM, true); + justSpawned = false; + } + if (_timer) + { + _timer += diff; + if (_timer >= 2000) + { + me->CastSpell(me, (me->GetMap()->Is25ManRaid() ? SPELL_FOCUSED_EYEBEAM_25 : SPELL_FOCUSED_EYEBEAM_10), true); + _timer = 0; + } + } + } + }; +}; + +// predicate function to select non main tank target +class StoneGripTargetSelector +{ +public: + StoneGripTargetSelector(Creature* me, Unit const* victim) : _me(me), _victim(victim) {} + + bool operator() (WorldObject* target) const + { + if (target == _victim && _me->GetThreatMgr().GetThreatListSize() > 1) + return true; + + if (target->GetTypeId() != TYPEID_PLAYER) + return true; + + return false; + } + +private: + Creature* _me; + Unit const* _victim; +}; + +class spell_ulduar_stone_grip_cast_target : public SpellScriptLoader +{ +public: + spell_ulduar_stone_grip_cast_target() : SpellScriptLoader("spell_ulduar_stone_grip_cast_target") { } + + class spell_ulduar_stone_grip_cast_target_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_stone_grip_cast_target_SpellScript); + + bool Load() override + { + if (GetCaster()->GetTypeId() != TYPEID_UNIT) + return false; + return true; + } + + void FilterTargetsInitial(std::list& targets) + { + // Remove "main tank" and non-player targets + targets.remove_if (StoneGripTargetSelector(GetCaster()->ToCreature(), GetCaster()->GetVictim())); + // Maximum affected targets per difficulty mode + uint32 maxTargets = 1; + if (GetSpellInfo()->Id == 63981) + maxTargets = 3; + + // Return a random amount of targets based on maxTargets + while (maxTargets < targets.size()) + { + std::list::iterator itr = targets.begin(); + advance(itr, urand(0, targets.size() - 1)); + targets.erase(itr); + } + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ulduar_stone_grip_cast_target_SpellScript::FilterTargetsInitial, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ulduar_stone_grip_cast_target_SpellScript(); + } +}; + +class spell_ulduar_stone_grip : public SpellScriptLoader +{ +public: + spell_ulduar_stone_grip() : SpellScriptLoader("spell_ulduar_stone_grip") { } + + class spell_ulduar_stone_grip_AuraScript : public AuraScript + { + PrepareAuraScript(spell_ulduar_stone_grip_AuraScript); + + void OnRemoveStun(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Player* owner = GetOwner()->ToPlayer()) + owner->RemoveAurasDueToSpell(aurEff->GetAmount()); + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_AuraScript::OnRemoveStun, EFFECT_2, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_ulduar_stone_grip_AuraScript(); + } +}; + +class spell_ulduar_squeezed_lifeless : public SpellScriptLoader +{ +public: + spell_ulduar_squeezed_lifeless() : SpellScriptLoader("spell_ulduar_squeezed_lifeless") { } + + class spell_ulduar_squeezed_lifeless_SpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_squeezed_lifeless_SpellScript); + + void HandleInstaKill(SpellEffIndex /*effIndex*/) + { + if (!GetHitPlayer() || !GetHitPlayer()->GetVehicle()) + return; + + // Hack to set correct position is in _ExitVehicle() + GetHitPlayer()->ExitVehicle(); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_ulduar_squeezed_lifeless_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_ulduar_squeezed_lifeless_SpellScript(); + } +}; + +class spell_kologarn_stone_shout : public SpellScriptLoader +{ +public: + spell_kologarn_stone_shout() : SpellScriptLoader("spell_kologarn_stone_shout") { } + + class spell_kologarn_stone_shout_AuraScript : public AuraScript + { + PrepareAuraScript(spell_kologarn_stone_shout_AuraScript); + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + uint32 triggerSpellId = GetSpellInfo()->Effects[EFFECT_0].TriggerSpell; + if (Unit* caster = GetCaster()) + caster->CastSpell(caster, triggerSpellId, false); + } + + void Register() override + { + if (m_scriptSpellId == SPELL_STONE_SHOUT_10 || m_scriptSpellId == SPELL_STONE_SHOUT_25) + OnEffectPeriodic += AuraEffectPeriodicFn(spell_kologarn_stone_shout_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_kologarn_stone_shout_AuraScript(); + } + + class spell_kologarn_stone_shout_SpellScript : public SpellScript + { + PrepareSpellScript(spell_kologarn_stone_shout_SpellScript); + + void FilterTargets(std::list& targets) + { + targets.remove_if (PlayerOrPetCheck()); + } + + void Register() override + { + if (m_scriptSpellId != SPELL_STONE_SHOUT_10 && m_scriptSpellId != SPELL_STONE_SHOUT_25) + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kologarn_stone_shout_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_kologarn_stone_shout_SpellScript(); + } +}; + +class achievement_kologarn_looks_could_kill : public AchievementCriteriaScript +{ +public: + achievement_kologarn_looks_could_kill() : AchievementCriteriaScript("achievement_kologarn_looks_could_kill") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + if (target) + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN))) + return cr->AI()->GetData(DATA_KOLOGARN_LOOKS_ACHIEV); + + return false; + } +}; + +class achievement_kologarn_rubble_and_roll : public AchievementCriteriaScript +{ +public: + achievement_kologarn_rubble_and_roll() : AchievementCriteriaScript("achievement_kologarn_rubble_and_roll") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + if (target) + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN))) + return cr->AI()->GetData(DATA_KOLOGARN_RUBBLE_ACHIEV); + + return false; + } +}; + +class achievement_kologarn_with_open_arms : public AchievementCriteriaScript +{ +public: + achievement_kologarn_with_open_arms() : AchievementCriteriaScript("achievement_kologarn_with_open_arms") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + if (target) + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN))) + return cr->AI()->GetData(DATA_KOLOGARN_ARMS_ACHIEV); + + return false; + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index 00ba652b45403a..c38896286e45e5 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_mimiron.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "GameObjectScript.h" @@ -30,2462 +31,6 @@ #include "Vehicle.h" #include "ulduar.h" -enum SpellData -{ - SPELL_BERSERK = 64238, - - // PHASE 1: - SPELL_NAPALM_SHELL_25 = 65026, - SPELL_NAPALM_SHELL_10 = 63666, - - SPELL_PLASMA_BLAST_25 = 64529, - SPELL_PLASMA_BLAST_10 = 62997, - - SPELL_SHOCK_BLAST = 63631, - - SPELL_PROXIMITY_MINES = 63027, - NPC_PROXIMITY_MINE = 34362, - SPELL_MINE_EXPLOSION_25 = 63009, - SPELL_MINE_EXPLOSION_10 = 66351, - SPELL_SUMMON_PROXIMITY_MINE = 65347, - - // PHASE 2: - SPELL_HEAT_WAVE = 64533, - - SPELL_ROCKET_STRIKE_AURA = 64064, - NPC_ROCKET_VISUAL = 34050, - NPC_ROCKET_STRIKE_N = 34047, - - SPELL_RAPID_BURST = 63382, - SPELL_RAPID_BURST_DAMAGE_25_1 = 64531, - SPELL_RAPID_BURST_DAMAGE_25_2 = 64532, - SPELL_RAPID_BURST_DAMAGE_10_1 = 63387, - SPELL_RAPID_BURST_DAMAGE_10_2 = 64019, - SPELL_SUMMON_BURST_TARGET = 64840, - - SPELL_SPINNING_UP = 63414, - - // PHASE 3: - SPELL_PLASMA_BALL_25 = 64535, - SPELL_PLASMA_BALL_10 = 63689, - - SPELL_MAGNETIC_CORE = 64436, - SPELL_SPINNING = 64438, - - SPELL_SUMMON_BOMB_BOT = 63811, - SPELL_BB_EXPLODE = 63801, - - SPELL_BEAM_GREEN = 63295, - SPELL_BEAM_YELLOW = 63292, - SPELL_BEAM_BLUE = 63294, - - // PHASE 4: - SPELL_HAND_PULSE_10_R = 64352, - SPELL_HAND_PULSE_25_R = 64537, - SPELL_HAND_PULSE_10_L = 64348, - SPELL_HAND_PULSE_25_L = 64536, - - SPELL_SELF_REPAIR = 64383, - SPELL_SLEEP = 64394, -}; - -enum NPCs -{ - //NPC_MIMIRON = 33350, - NPC_LEVIATHAN_MKII = 33432, - NPC_LEVIATHAN_MKII_CANNON = 34071, - NPC_VX001 = 33651, - NPC_AERIAL_COMMAND_UNIT = 33670, - NPC_COMPUTER = 34143, - NPC_BOMB_BOT = 33836, - NPC_BOT_SUMMON_TRIGGER = 33856, - NPC_ASSAULT_BOT = 34057, - NPC_JUNK_BOT = 33855, - NPC_MAGNETIC_CORE = 34068, -}; - -enum GOs -{ - //GO_MIMIRON_ELEVATOR = 194749, - GO_DOOR_1 = 194776, - GO_DOOR_2 = 194774, - GO_DOOR_3 = 194775, - GO_BUTTON = 194739, - // pads: 194740-48 -}; - -enum HardMode -{ - SPELL_EMERGENCY_MODE = 64582, - SPELL_SELF_DESTRUCT = 64610, - - SPELL_SUMMON_FLAMES_INITIAL = 64563, - NPC_FLAMES_INITIAL = 34363, - SPELL_SUMMON_FLAMES_SPREAD = 64564, - NPC_FLAMES_SPREAD = 34121, - SPELL_FLAMES_AURA = 64561, - - SPELL_VX001_FROST_BOMB = 64623, - SPELL_FROST_BOMB_VISUAL_AURA = 64624, - SPELL_SUMMON_FROST_BOMB = 64627, - NPC_FROST_BOMB = 34149, - SPELL_FROST_BOMB_EXPLOSION_10 = 64626, - SPELL_FROST_BOMB_EXPLOSION_25 = 65333, - - SPELL_FLAME_SUPPRESSANT_10yd = 65192, - SPELL_FLAME_SUPPRESSANT_50000yd = 64570, - - SPELL_WATER_SPRAY = 64619, - SPELL_DEAFENING_SIREN = 64616, - NPC_EMERGENCY_FIRE_BOT = 34147, - - SPELL_ENTER_VEHICLE_0 = 63112, - SPELL_ENTER_VEHICLE_1 = 63313, - SPELL_ENTER_VEHICLE_2 = 63314, - SPELL_ENTER_VEHICLE_4 = 63316, -}; - -enum EVENTS -{ - // Mimiron: - EVENT_SIT_LMK2 = 1, - EVENT_SIT_LMK2_INTERVAL = 2, - EVENT_LMK2_RETREAT_INTERVAL = 7, - EVENT_ELEVATOR_INTERVAL_1 = 8, - EVENT_ELEVATOR_INTERVAL_2 = 9, - EVENT_SITTING_ON_VX001 = 10, - EVENT_ENTER_VX001 = 11, - EVENT_EMOTE_VX001 = 12, - EVENT_VX001_START_FIGHT = 13, - EVENT_ELEVATOR_INTERVAL_0 = 14, - EVENT_GET_OUT_VX001 = 21, - EVENT_SAY_VX001_DEAD = 22, - EVENT_ENTER_ACU = 23, - EVENT_SAY_ACU_ACTIVATE = 24, - EVENT_ACU_START_ATTACK = 25, - EVENT_VX001_EMOTESTATE_DEATH = 26, - EVENT_SAY_ACU_DEAD = 31, - EVENT_LEVIATHAN_COME_CLOSER = 32, - EVENT_VX001_EMOTE_JUMP = 33, - EVENT_LEVIATHAN_RIDE_MIDDLE = 34, - EVENT_JOIN_TOGETHER = 342, - EVENT_JOIN_ACU = 35, - EVENT_START_PHASE4 = 36, - EVENT_FINISH = 50, - EVENT_SAY_VOLTRON_DEAD = 51, - EVENT_DISAPPEAR = 52, - EVENT_BERSERK = 53, - EVENT_BERSERK_2 = 54, - - // Leviathan: - EVENT_SPELL_NAPALM_SHELL = 3, - EVENT_SPELL_PLASMA_BLAST = 4, - EVENT_SPELL_SHOCK_BLAST = 5, - EVENT_PROXIMITY_MINES_1 = 6, - - // VX001: - EVENT_SPELL_HEAT_WAVE = 15, - EVENT_SPELL_ROCKET_STRIKE = 16, - EVENT_REINSTALL_ROCKETS = 17, - EVENT_SPELL_RAPID_BURST = 18, - EVENT_SPELL_RAPID_BURST_INTERVAL = 19, - EVENT_SPELL_SPINNING_UP = 20, - EVENT_HAND_PULSE = 37, - - // ACU: - EVENT_SPELL_PLASMA_BALL = 27, - EVENT_SUMMON_BOMB_BOT = 28, - EVENT_BOMB_BOT_CHASE = 29, - EVENT_BOMB_BOT_RELOCATE = 30, - EVENT_SUMMON_ASSAULT_BOT = 40, - EVENT_SUMMON_JUNK_BOT = 41, - EVENT_MAGNETIC_CORE_PULL_DOWN = 42, - EVENT_MAGNETIC_CORE_FREE = 43, - EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE = 44, - - // Hard mode: - EVENT_COMPUTER_SAY_INITIATED = 60, - EVENT_COMPUTER_SAY_MINUTES = 61, - EVENT_MIMIRON_SAY_HARDMODE = 62, - EVENT_SPAWN_FLAMES_INITIAL = 63, - EVENT_FLAMES_SPREAD = 64, - EVENT_FLAME_SUPPRESSION_50000 = 65, - EVENT_FLAME_SUPPRESSION_10 = 66, - EVENT_FROST_BOMB = 67, - EVENT_SUMMON_EMERGENCY_FIRE_BOTS = 68, - EVENT_EMERGENCY_BOT_CHECK = 69, - EVENT_EMERGENCY_BOT_ATTACK = 70, -}; - -#define SPELL_NAPALM_SHELL RAID_MODE(SPELL_NAPALM_SHELL_10, SPELL_NAPALM_SHELL_25) -#define SPELL_PLASMA_BLAST RAID_MODE(SPELL_PLASMA_BLAST_10, SPELL_PLASMA_BLAST_25) -#define SPELL_MINE_EXPLOSION RAID_MODE(SPELL_MINE_EXPLOSION_10, SPELL_MINE_EXPLOSION_25) -#define SPELL_PLASMA_BALL RAID_MODE(SPELL_PLASMA_BALL_10, SPELL_PLASMA_BALL_25) -#define SPELL_HAND_PULSE_R RAID_MODE(SPELL_HAND_PULSE_10_R, SPELL_HAND_PULSE_25_R) -#define SPELL_HAND_PULSE_L RAID_MODE(SPELL_HAND_PULSE_10_L, SPELL_HAND_PULSE_25_L) -#define SPELL_FROST_BOMB_EXPLOSION RAID_MODE(SPELL_FROST_BOMB_EXPLOSION_10, SPELL_FROST_BOMB_EXPLOSION_25) - -enum Texts -{ - // Mimiron - SAY_AGGRO = 0, // Unused - SAY_HARDMODE_ON = 1, - SAY_MKII_ACTIVATE = 2, - SAY_MKII_SLAY = 3, - SAY_MKII_DEATH = 4, - SAY_VX001_ACTIVATE = 5, - SAY_VX001_SLAY = 6, - SAY_VX001_DEATH = 7, - SAY_AERIAL_ACTIVATE = 8, - SAY_AERIAL_SLAY = 9, - SAY_AERIAL_DEATH = 10, - SAY_V07TRON_ACTIVATE = 11, - SAY_V07TRON_SLAY = 12, - SAY_V07TRON_DEATH = 13, - SAY_BERSERK = 14, - - // MK II - EMOTE_PLASMA_BLAST = 0, - - // Computer (Hardmode countdown) - TALK_COMPUTER_INITIATED = 0, - TALK_COMPUTER_TERMINATED = 1, - TALK_COMPUTER_TEN = 2, - TALK_COMPUTER_NINE = 3, - TALK_COMPUTER_EIGHT = 4, - TALK_COMPUTER_SEVEN = 5, - TALK_COMPUTER_SIX = 6, - TALK_COMPUTER_FIVE = 7, - TALK_COMPUTER_FOUR = 8, - TALK_COMPUTER_THREE = 9, - TALK_COMPUTER_TWO = 10, - TALK_COMPUTER_ONE = 11, - TALK_COMPUTER_ZERO = 12, -}; - -#define GetMimiron() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_MIMIRON)) -#define GetLMK2() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_LEVIATHAN_MKII)) -#define GetVX001() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_VX001)) -#define GetACU() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_ACU)) - -class boss_mimiron : public CreatureScript -{ -public: - boss_mimiron() : CreatureScript("boss_mimiron") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_mimironAI : public ScriptedAI - { - boss_mimironAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) - { - pInstance = me->GetInstanceScript(); - if (!me->IsAlive()) - if (pInstance) - pInstance->SetData(TYPE_MIMIRON, DONE); - bIsEvading = false; - } - - InstanceScript* pInstance; - EventMap events; - SummonList summons; - bool bIsEvading; - bool hardmode; - bool berserk; - bool bAchievProximityMine; - bool bAchievBombBot; - bool bAchievRocketStrike; - uint32 allowedFlameSpreadTime; - bool changeAllowedFlameSpreadTime; - uint8 minutesTalkNum; - uint32 outofCombatTimer; - - void Reset() override - { - hardmode = false; - berserk = false; - bAchievProximityMine = false; - bAchievBombBot = false; - bAchievRocketStrike = false; - allowedFlameSpreadTime = 0; - outofCombatTimer = 0; - changeAllowedFlameSpreadTime = false; - ResetGameObjects(); - events.Reset(); - summons.DespawnAll(); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - - if (pInstance && pInstance->GetData(TYPE_MIMIRON) != DONE) - pInstance->SetData(TYPE_MIMIRON, NOT_STARTED); - } - - void AttackStart(Unit* who) override - { - if (who) - me->Attack(who, true); // skip following - } - - void JustReachedHome() override - { - me->setActive(false); - ScriptedAI::JustReachedHome(); - } - - void JustEngagedWith(Unit* /*who*/) override - { - me->setActive(true); - DoZoneInCombat(); - me->RemoveAllAuras(); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - events.Reset(); - - if (Creature* c = GetLMK2()) - { - if (c->IsInEvadeMode()) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - if (!c->IsAlive()) - c->Respawn(); - - me->EnterVehicle(c, 1); - } - else - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - CloseDoorAndButton(); - - if (!hardmode) - { - Talk(SAY_MKII_ACTIVATE); - events.ScheduleEvent(EVENT_SIT_LMK2, 6s); - events.ScheduleEvent(EVENT_BERSERK, 15min); - } - else - { - events.ScheduleEvent(EVENT_MIMIRON_SAY_HARDMODE, 7s); - events.ScheduleEvent(EVENT_BERSERK, Is25ManRaid() ? 10min : 8min); - - events.ScheduleEvent(EVENT_COMPUTER_SAY_INITIATED, 0ms); - events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, 3s); - minutesTalkNum = Is25ManRaid() ? TALK_COMPUTER_TEN : TALK_COMPUTER_EIGHT; - for (uint32 i = 0; i < uint32(TALK_COMPUTER_ZERO - minutesTalkNum - 1); ++i) - events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, (i + 1)*MINUTE * IN_MILLISECONDS); - events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, (TALK_COMPUTER_ZERO - minutesTalkNum)*MINUTE * IN_MILLISECONDS + 6000); - } - - // ensure LMK2 is at proper position - if (pInstance) - if (Creature* LMK2 = GetLMK2()) - { - LMK2->UpdatePosition(LMK2->GetHomePosition(), true); - LMK2->StopMovingOnCurrentPos(); - } - - if (pInstance && pInstance->GetData(TYPE_MIMIRON) != DONE) - pInstance->SetData(TYPE_MIMIRON, IN_PROGRESS); - } - - void UpdateAI(uint32 diff) override - { - if (!me->IsInCombat()) - { - outofCombatTimer += diff; - if (outofCombatTimer >= 10000) - { - outofCombatTimer = 0; - if (Creature* c = GetLMK2()) - me->CastSpell(c, RAND(SPELL_ENTER_VEHICLE_0, SPELL_ENTER_VEHICLE_1, SPELL_ENTER_VEHICLE_2, SPELL_ENTER_VEHICLE_4), true); - } - return; - } - - Position p = me->GetHomePosition(); - if (me->GetExactDist(&p) > 80.0f || !SelectTargetFromPlayerList(150.0f)) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - events.Update(diff); - - switch( events.ExecuteEvent() ) - { - case 0: - break; - case EVENT_COMPUTER_SAY_INITIATED: - if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) ) - computer->AI()->Talk(TALK_COMPUTER_INITIATED); - break; - case EVENT_COMPUTER_SAY_MINUTES: - if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) ) - computer->AI()->Talk(minutesTalkNum++); - break; - case EVENT_MIMIRON_SAY_HARDMODE: - Talk(SAY_HARDMODE_ON); - events.ScheduleEvent(EVENT_SPAWN_FLAMES_INITIAL, 0ms); - events.ScheduleEvent(EVENT_SIT_LMK2, 4s); - break; - case EVENT_SPAWN_FLAMES_INITIAL: - { - if (changeAllowedFlameSpreadTime) - allowedFlameSpreadTime = GameTime::GetGameTime().count(); - - std::vector pg; - Map::PlayerList const& pl = me->GetMap()->GetPlayers(); - for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) - if( Player* plr = itr->GetSource() ) - if( plr->IsAlive() && plr->GetExactDist2d(me) < 150.0f && !plr->IsGameMaster() ) - pg.push_back(plr); - - for( uint8 i = 0; i < 3; ++i ) - if( !pg.empty() ) - { - uint8 index = urand(0, pg.size() - 1); - Player* player = pg[index]; - float angle = rand_norm() * 2 * M_PI; - float z = 364.35f; - if (!player->IsWithinLOS(player->GetPositionX() + cos(angle) * 5.0f, player->GetPositionY() + std::sin(angle) * 5.0f, z)) - { - angle = player->GetAngle(2744.65f, 2569.46f); - } - me->CastSpell(player->GetPositionX() + cos(angle) * 5.0f, player->GetPositionY() + std::sin(angle) * 5.0f, z, SPELL_SUMMON_FLAMES_INITIAL, true); - pg.erase(pg.begin() + index); - } - - events.Repeat(30s); - } - break; - case EVENT_BERSERK: - berserk = true; - Talk(SAY_BERSERK); - if( hardmode ) - me->SummonCreature(33576, 2744.78f, 2569.47f, 364.32f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 120000); - events.ScheduleEvent(EVENT_BERSERK_2, 0ms); - break; - case EVENT_BERSERK_2: - { - Creature* VX001 = nullptr; - Creature* LMK2 = nullptr; - Creature* ACU = nullptr; - if ((VX001 = GetVX001())) - VX001->CastSpell(VX001, SPELL_BERSERK, true); - if ((LMK2 = GetLMK2())) - LMK2->CastSpell(LMK2, SPELL_BERSERK, true); - if ((ACU = GetACU())) - ACU->CastSpell(ACU, SPELL_BERSERK, true); - events.Repeat(30s); - } - break; - case EVENT_SIT_LMK2: - if(Creature* LMK2 = GetLMK2()) - { - me->EnterVehicle(LMK2, 6); - events.ScheduleEvent(EVENT_SIT_LMK2_INTERVAL, 2s); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_SIT_LMK2_INTERVAL: - if (Creature* LMK2 = GetLMK2()) - { - if (hardmode) - { - LMK2->CastSpell(LMK2, SPELL_EMERGENCY_MODE, true); - if( Vehicle* veh = LMK2->GetVehicleKit() ) - if( Unit* cannon = veh->GetPassenger(3) ) - cannon->CastSpell(cannon, SPELL_EMERGENCY_MODE, true); - } - LMK2->AI()->SetData(1, 1); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_LMK2_RETREAT_INTERVAL: - if (Creature* LMK2 = GetLMK2()) - { - me->EnterVehicle(LMK2, 1); - Talk(SAY_MKII_DEATH); - LMK2->SetFacingTo(3.58f); - events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_0, 6s); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_ELEVATOR_INTERVAL_0: - if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 100.0f) ) - { - elevator->SetLootState(GO_READY); - elevator->UseDoorOrButton(0, false); - elevator->EnableCollision(false); - } - events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_1, 6s); - break; - case EVENT_ELEVATOR_INTERVAL_1: - if(me->SummonCreature(NPC_VX001, 2744.65f, 2569.46f, 364.40f, 3.14f, TEMPSUMMON_MANUAL_DESPAWN)) - { - if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 100.0f) ) - { - elevator->SetLootState(GO_READY); - elevator->UseDoorOrButton(0, true); - elevator->EnableCollision(false); - } - events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_2, 18s); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_ELEVATOR_INTERVAL_2: - if (Creature* VX001 = GetVX001()) - { - me->EnterVehicle(VX001, 0); - events.ScheduleEvent(EVENT_SITTING_ON_VX001, 4s); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_SITTING_ON_VX001: - Talk(SAY_VX001_ACTIVATE); - events.ScheduleEvent(EVENT_ENTER_VX001, 5s); - break; - case EVENT_ENTER_VX001: - if( Creature* VX001 = GetVX001() ) - { - me->EnterVehicle(VX001, 1); - events.ScheduleEvent(EVENT_EMOTE_VX001, 2s); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_EMOTE_VX001: - if( Creature* VX001 = GetVX001() ) - { - VX001->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); - events.ScheduleEvent(EVENT_VX001_START_FIGHT, 1750ms); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_VX001_START_FIGHT: - if( Creature* VX001 = GetVX001() ) - { - if( hardmode ) - VX001->CastSpell(VX001, SPELL_EMERGENCY_MODE, true); - VX001->AI()->SetData(1, 2); - me->SetInCombatWithZone(); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_VX001_EMOTESTATE_DEATH: - if( Creature* VX001 = GetVX001() ) - { - VX001->HandleEmoteCommand(EMOTE_STATE_DROWNED); - VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DROWNED); - events.ScheduleEvent(EVENT_GET_OUT_VX001, 2500ms); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_GET_OUT_VX001: - if( Creature* VX001 = GetVX001() ) - if( Creature* ACU = me->SummonCreature(NPC_AERIAL_COMMAND_UNIT, 2743.91f, 2568.78f, 391.34f, M_PI, TEMPSUMMON_MANUAL_DESPAWN) ) - { - me->EnterVehicle(VX001, 4); - float speed = ACU->GetDistance(2737.75f, 2574.22f, 381.34f) / 2.0f; - ACU->MonsterMoveWithSpeed(2737.75f, 2574.22f, 381.34f, speed); - ACU->SetPosition(2737.75f, 2574.22f, 381.34f, M_PI); - events.ScheduleEvent(EVENT_SAY_VX001_DEAD, 2s); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_SAY_VX001_DEAD: - changeAllowedFlameSpreadTime = true; - Talk(SAY_VX001_DEATH); - events.ScheduleEvent(EVENT_ENTER_ACU, 7s); - break; - case EVENT_ENTER_ACU: - if( Creature* ACU = GetACU() ) - { - me->EnterVehicle(ACU, 0); - events.ScheduleEvent(EVENT_SAY_ACU_ACTIVATE, 6s); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_SAY_ACU_ACTIVATE: - Talk(SAY_AERIAL_ACTIVATE); - events.ScheduleEvent(EVENT_ACU_START_ATTACK, 4s); - break; - case EVENT_ACU_START_ATTACK: - if( Creature* ACU = GetACU() ) - { - if( hardmode ) - ACU->CastSpell(ACU, SPELL_EMERGENCY_MODE, true); - ACU->AI()->SetData(1, 3); - me->SetInCombatWithZone(); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_SAY_ACU_DEAD: - Talk(SAY_AERIAL_DEATH); - events.ScheduleEvent(EVENT_LEVIATHAN_COME_CLOSER, 5s); - break; - case EVENT_LEVIATHAN_COME_CLOSER: - if (Creature* LMK2 = GetLMK2()) - { - LMK2->GetMotionMaster()->MoveCharge(2755.77f, 2574.95f, 364.31f, 21.0f); - events.ScheduleEvent(EVENT_VX001_EMOTE_JUMP, 4s); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); - break; - case EVENT_VX001_EMOTE_JUMP: - { - Creature* LMK2 = GetLMK2(); - Creature* VX001 = GetVX001(); - if( !VX001 || !LMK2 ) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - VX001->SendMeleeAttackStop(); - VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_02); - VX001->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_02); - events.ScheduleEvent(EVENT_LEVIATHAN_RIDE_MIDDLE, 4800ms); - } - break; - case EVENT_LEVIATHAN_RIDE_MIDDLE: - { - Creature* VX001 = GetVX001(); - Creature* LMK2 = GetLMK2(); - if( !VX001 || !LMK2 ) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - LMK2->GetMotionMaster()->MoveCharge(2744.65f, 2569.46f, 364.31f, 21.0f); - VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_CUSTOM_SPELL_01); - VX001->HandleEmoteCommand(EMOTE_STATE_CUSTOM_SPELL_01); - VX001->EnterVehicle(LMK2, 3); - events.ScheduleEvent(EVENT_JOIN_TOGETHER, 3s); - } - break; - case EVENT_JOIN_TOGETHER: - { - Creature* ACU = GetACU(); - Creature* VX001 = GetVX001(); - if( !VX001 || !ACU ) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - ACU->SetDisableGravity(false); - ACU->EnterVehicle(VX001, 3); - me->EnterVehicle(VX001, 1); - Talk(SAY_V07TRON_ACTIVATE); - events.ScheduleEvent(EVENT_START_PHASE4, 10s); - } - break; - case EVENT_START_PHASE4: - { - Creature* VX001 = GetVX001(); - Creature* LMK2 = GetLMK2(); - Creature* ACU = GetACU(); - if( !VX001 || !LMK2 || !ACU ) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - LMK2->AI()->SetData(1, 4); - VX001->AI()->SetData(1, 4); - ACU->AI()->SetData(1, 4); - LMK2->CastSpell(LMK2, SPELL_SELF_REPAIR, true); //LMK2->SetHealth( LMK2->GetMaxHealth()/2 ); - VX001->CastSpell(VX001, SPELL_SELF_REPAIR, true); //VX001->SetHealth( VX001->GetMaxHealth()/2 ); - ACU->CastSpell(ACU, SPELL_SELF_REPAIR, true); //ACU->SetHealth( ACU->GetMaxHealth()/2 ); - if( hardmode ) - { - LMK2->CastSpell(LMK2, SPELL_EMERGENCY_MODE, true); - VX001->CastSpell(VX001, SPELL_EMERGENCY_MODE, true); - ACU->CastSpell(ACU, SPELL_EMERGENCY_MODE, true); - } - me->SetInCombatWithZone(); - } - break; - case EVENT_FINISH: - { - Creature* LMK2 = GetLMK2(); - Creature* VX001 = GetVX001(); - Creature* ACU = GetACU(); - - if (!VX001 || !LMK2 || !ACU) - return; - - LMK2->GetMotionMaster()->Clear(); - LMK2->StopMoving(); - LMK2->InterruptNonMeleeSpells(false); - LMK2->AttackStop(); - LMK2->AI()->SetData(1, 0); - LMK2->DespawnOrUnsummon(7000); - LMK2->SetReactState(REACT_PASSIVE); - VX001->InterruptNonMeleeSpells(false); - VX001->AttackStop(); - VX001->AI()->SetData(1, 0); - VX001->DespawnOrUnsummon(7000); - VX001->SetReactState(REACT_PASSIVE); - ACU->InterruptNonMeleeSpells(false); - ACU->AttackStop(); - ACU->AI()->SetData(1, 0); - ACU->DespawnOrUnsummon(7000); - ACU->SetReactState(REACT_PASSIVE); - - Position exitPos = me->GetPosition(); - me->_ExitVehicle(&exitPos); - me->AttackStop(); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); - me->GetMotionMaster()->Clear(); - summons.DoAction(1337); // despawn summons of summons - summons.DespawnEntry(NPC_FLAMES_INITIAL); - summons.DespawnEntry(33576); - - float angle = VX001->GetOrientation(); - float v_x = me->GetPositionX() + cos(angle) * 10.0f; - float v_y = me->GetPositionY() + std::sin(angle) * 10.0f; - me->GetMotionMaster()->MoveJump(v_x, v_y, 364.32f, 7.0f, 7.0f); - - if( pInstance ) - for( uint16 i = 0; i < 3; ++i ) - if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) ) - if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) ) - if( door->GetGoState() != GO_STATE_ACTIVE ) - { - door->SetLootState(GO_READY); - door->UseDoorOrButton(0, false); - } - - if (pInstance) - pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_LEVIATHAN_MKII, 1, me); - - if (hardmode) - if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) ) - computer->AI()->Talk(TALK_COMPUTER_TERMINATED); - - events.Reset(); - events.ScheduleEvent(EVENT_SAY_VOLTRON_DEAD, 6s); - } - break; - case EVENT_SAY_VOLTRON_DEAD: - Talk(SAY_V07TRON_DEATH); - // spawn chest - if (uint32 chestId = (hardmode ? RAID_MODE(GO_MIMIRON_CHEST_HARD, GO_MIMIRON_CHEST_HERO_HARD) : RAID_MODE(GO_MIMIRON_CHEST, GO_MIMIRON_CHEST_HERO))) - { - if (GameObject* go = me->SummonGameObject(chestId, 2744.65f, 2569.46f, 364.397f, 0, 0, 0, 0, 0, 0)) - { - go->ReplaceAllGameObjectFlags((GameObjectFlags)0); - go->SetLootRecipient(me->GetMap()); - } - } - events.ScheduleEvent(EVENT_DISAPPEAR, 15s); - break; - case EVENT_DISAPPEAR: - if( pInstance ) - pInstance->SetData(TYPE_MIMIRON, DONE); - summons.DespawnAll(); - me->DespawnOrUnsummon(); - break; - } - } - - void MoveInLineOfSight(Unit* /*mover*/) override {} - - void EnterEvadeMode(EvadeReason why) override - { - if (bIsEvading) - return; - bIsEvading = true; - - if (Creature* c = GetLMK2()) - { - c->AI()->EnterEvadeMode(why); - } - if (Creature* c = GetVX001()) - { - c->AI()->EnterEvadeMode(why); - c->DespawnOrUnsummon(); - } - if (Creature* c = GetACU()) - { - c->AI()->EnterEvadeMode(why); - c->DespawnOrUnsummon(); - } - - summons.DoAction(1337); // despawn summons of summons - - me->RemoveAllAuras(); - me->ExitVehicle(); - ScriptedAI::EnterEvadeMode(why); - - bIsEvading = false; - } - - void JustSummoned(Creature* s) override - { - summons.Summon(s); - } - - void SummonedCreatureDespawn(Creature* s) override - { - summons.Despawn(s); - } - - void ResetGameObjects() - { - if( pInstance ) - for( uint16 i = 0; i < 3; ++i ) - if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) ) - if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) ) - if( door->GetGoState() != GO_STATE_ACTIVE ) - { - door->SetLootState(GO_READY); - door->UseDoorOrButton(0, false); - } - - if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 200.0f) ) - { - if( elevator->GetGoState() != GO_STATE_ACTIVE ) - { - elevator->SetLootState(GO_READY); - elevator->SetByteValue(GAMEOBJECT_BYTES_1, 0, GO_STATE_ACTIVE); - } - elevator->EnableCollision(false); - } - - if( GameObject* button = me->FindNearestGameObject(GO_BUTTON, 200.0f) ) - if( button->GetGoState() != GO_STATE_READY ) - { - button->SetLootState(GO_READY); - button->UseDoorOrButton(0, false); - button->RemoveGameObjectFlag(GO_FLAG_IN_USE); - } - } - - void CloseDoorAndButton() - { - if( pInstance ) - for( uint16 i = 0; i < 3; ++i ) - if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) ) - if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) ) - if( door->GetGoState() != GO_STATE_READY ) - { - door->SetLootState(GO_READY); - door->UseDoorOrButton(0, false); - } - - if( GameObject* button = me->FindNearestGameObject(GO_BUTTON, 200.0f) ) - if( button->GetGoState() != GO_STATE_ACTIVE ) - { - button->SetLootState(GO_READY); - button->UseDoorOrButton(0, false); - } - } - - void SetData(uint32 /*id*/, uint32 value) override - { - switch (value) // end of phase 1-3, 4-6 for voltron - { - case 1: - events.ScheduleEvent(EVENT_LMK2_RETREAT_INTERVAL, 5s); - break; - case 2: - events.ScheduleEvent(EVENT_VX001_EMOTESTATE_DEATH, 2500ms); - break; - case 3: - events.ScheduleEvent(EVENT_SAY_ACU_DEAD, 5s); - break; - case 4: - case 5: - case 6: - { - Creature* LMK2 = GetLMK2(); - Creature* VX001 = GetVX001(); - Creature* ACU = GetACU(); - if (!LMK2 || !VX001 || !ACU) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - Spell* s1 = LMK2->GetCurrentSpell(CURRENT_GENERIC_SPELL); - Spell* s2 = VX001->GetCurrentSpell(CURRENT_GENERIC_SPELL); - Spell* s3 = ACU->GetCurrentSpell(CURRENT_GENERIC_SPELL); - if (s1 && s2 && s3 && s1->GetSpellInfo()->Id == SPELL_SELF_REPAIR && s2->GetSpellInfo()->Id == SPELL_SELF_REPAIR && s3->GetSpellInfo()->Id == SPELL_SELF_REPAIR) - events.ScheduleEvent(EVENT_FINISH, 0ms); - } - break; - case 7: - hardmode = true; - break; - case 11: - bAchievProximityMine = true; - break; - case 12: - bAchievBombBot = true; - break; - case 13: - bAchievRocketStrike = true; - break; - } - } - - uint32 GetData(uint32 id) const override - { - switch (id) - { - case 1: - return (hardmode ? 1 : 0); - case 2: - return (berserk ? 1 : 0); - case 10: - return allowedFlameSpreadTime; - case 11: - return (bAchievProximityMine ? 1 : 0); - case 12: - return (bAchievBombBot ? 1 : 0); - case 13: - return (bAchievRocketStrike ? 1 : 0); - } - return 0; - } - }; -}; - -class npc_ulduar_leviathan_mkii : public CreatureScript -{ -public: - npc_ulduar_leviathan_mkii() : CreatureScript("npc_ulduar_leviathan_mkii") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_leviathan_mkiiAI : public ScriptedAI - { - npc_ulduar_leviathan_mkiiAI(Creature* pCreature) : ScriptedAI(pCreature) - { - pInstance = me->GetInstanceScript(); - bIsEvading = false; - } - - InstanceScript* pInstance; - EventMap events; - bool bIsEvading; - uint8 Phase; - - void Reset() override - { - Phase = 0; - if (Unit* c = GetS3()) - c->ExitVehicle(); // this should never happen! - if (Creature* c = me->SummonCreature(NPC_LEVIATHAN_MKII_CANNON, *me, TEMPSUMMON_MANUAL_DESPAWN)) - c->EnterVehicle(me, 3); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_AGGRESSIVE); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - - events.Reset(); - } - - void SetData(uint32 id, uint32 value) override - { - if (id == 1) // setting phase to start fighting - { - switch (value) - { - case 0: - Phase = 0; - events.Reset(); - break; - case 1: - Phase = 1; - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - if (Unit* target = SelectTargetFromPlayerList(75.0f)) - AttackStart(target); - DoZoneInCombat(); - events.Reset(); - events.ScheduleEvent(EVENT_SPELL_NAPALM_SHELL, 3s); - events.ScheduleEvent(EVENT_SPELL_PLASMA_BLAST, 10s); - events.ScheduleEvent(EVENT_SPELL_SHOCK_BLAST, 20s); - events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 6s); - if (Creature* c = GetMimiron()) - if (c->AI()->GetData(1)) - events.ScheduleEvent(EVENT_FLAME_SUPPRESSION_50000, 60s); - break; - case 4: - me->SetReactState(REACT_AGGRESSIVE); - DoResetThreatList(); - Phase = 4; - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - if (Unit* target = SelectTargetFromPlayerList(75.0f)) - AttackStart(target); - DoZoneInCombat(); - events.Reset(); - events.ScheduleEvent(EVENT_SPELL_SHOCK_BLAST, 20s); - events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 6s); - break; - } - } - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (damage >= me->GetHealth() || me->GetHealth() < 15000) - { - damage = 0; - if (me->GetReactState() == REACT_PASSIVE) - return; - me->SetReactState(REACT_PASSIVE); - if (Phase == 1) - { - if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - { - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->GetMotionMaster()->Clear(); - me->AttackStop(); - me->SetReactState(REACT_PASSIVE); - SetData(1, 0); - me->InterruptNonMeleeSpells(false); - me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); - if (Unit* cannon = GetS3()) - cannon->ExitVehicle(); - me->GetMotionMaster()->MoveCharge(2795.076f, 2598.616f, 364.32f, 21.0f); - if (Creature* c = GetMimiron()) - c->AI()->SetData(0, 1); - } - } - else if (Phase == 4) - { - if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - { - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->InterruptNonMeleeSpells(false); - me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); - me->CastSpell(me, SPELL_SELF_REPAIR, false); - if (Creature* c = GetMimiron()) - { - if (c->AI()->GetData(1)) - me->CastSpell(me, SPELL_EMERGENCY_MODE, true); - if (c->AI()->GetData(2)) - me->CastSpell(me, SPELL_BERSERK, true); - c->AI()->SetData(0, 4); - } - } - } - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (!me->HasUnitState(UNIT_STATE_CASTING)) - DoMeleeAttackIfReady(); - - Unit* cannon = GetS3(); - if (!cannon || cannon->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CASTING) || me->HasAuraType(SPELL_AURA_MOD_SILENCE)) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_SPELL_NAPALM_SHELL: - { - Player* pTarget = nullptr; - std::vector pList; - Map::PlayerList const& pl = me->GetMap()->GetPlayers(); - for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) - if (Player* plr = itr->GetSource()) - if( plr->IsAlive() && plr->GetDistance2d(me) > 15.0f ) - pList.push_back(plr); - - if (!pList.empty()) - pTarget = pList[urand(0, pList.size() - 1)]; - else - pTarget = (Player*)SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true); - - if( pTarget ) - cannon->CastSpell(pTarget, SPELL_NAPALM_SHELL, false); - - events.Repeat(14s); - } - break; - case EVENT_SPELL_PLASMA_BLAST: - if (Unit* victim = me->GetVictim()) - { - Talk(EMOTE_PLASMA_BLAST); - cannon->CastSpell(victim, SPELL_PLASMA_BLAST, false); - } - events.Repeat(22s); - break; - case EVENT_SPELL_SHOCK_BLAST: - me->CastSpell(me->GetVictim(), SPELL_SHOCK_BLAST, false); - events.Repeat(30s); - events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 8s); - break; - case EVENT_PROXIMITY_MINES_1: - for (uint8 i = 0; i < 10; ++i) - { - me->CastSpell(me, SPELL_SUMMON_PROXIMITY_MINE, true); - } - break; - case EVENT_FLAME_SUPPRESSION_50000: - me->CastSpell(me, SPELL_FLAME_SUPPRESSANT_50000yd, false); - break; - } - } - - void MoveInLineOfSight(Unit* /*mover*/) override {} - - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() == TYPEID_PLAYER) - if (Creature* c = GetMimiron()) - { - if (Phase == 1) - { - c->AI()->Talk(SAY_MKII_SLAY); - } - else - { - c->AI()->Talk(SAY_V07TRON_SLAY); - } - } - } - - void EnterEvadeMode(EvadeReason why) override - { - if (bIsEvading) - return; - bIsEvading = true; - - me->RemoveAllAuras(); - me->ExitVehicle(); - ScriptedAI::EnterEvadeMode(); - - if (Creature* mimiron = GetMimiron()) - mimiron->AI()->EnterEvadeMode(why); - - bIsEvading = false; - } - - void PassengerBoarded(Unit* p, int8 /*seat*/, bool apply) override - { - if (p->GetEntry() == NPC_LEVIATHAN_MKII_CANNON && !apply) - { - Unit::Kill(p, p); - p->ToCreature()->DespawnOrUnsummon(6000); - } - } - - Unit* GetS3() - { - if (Vehicle* vk = me->GetVehicleKit()) - if (Unit* cannon = vk->GetPassenger(3)) - return cannon; - - return 0; - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if( spell->Id == SPELL_SELF_REPAIR ) - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_AGGRESSIVE); - } - } - }; -}; - -class npc_ulduar_vx001 : public CreatureScript -{ -public: - npc_ulduar_vx001() : CreatureScript("npc_ulduar_vx001") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_vx001AI : public ScriptedAI - { - npc_ulduar_vx001AI(Creature* pCreature) : ScriptedAI(pCreature) - { - pInstance = me->GetInstanceScript(); - bIsEvading = false; - } - - InstanceScript* pInstance; - EventMap events; - bool bIsEvading; - uint8 Phase; - bool fighting; - bool leftarm; - uint32 spinningUpOrientation; - uint16 spinningUpTimer; - - void Reset() override - { - Phase = 0; - fighting = false; - leftarm = false; - spinningUpTimer = 0; - me->SetRegeneratingHealth(false); - events.Reset(); - } - - void AttackStart(Unit* /*who*/) override {} - - void SetData(uint32 id, uint32 value) override - { - if (id == 1) // setting phase to start fighting - { - switch (value) - { - case 0: - Phase = 0; - fighting = false; - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - events.Reset(); - break; - case 2: - Phase = 2; - fighting = true; - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_SPELL_CAST_OMNI); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - events.Reset(); - events.ScheduleEvent(EVENT_SPELL_HEAT_WAVE, 10s); - events.ScheduleEvent(EVENT_SPELL_ROCKET_STRIKE, 16s); - events.ScheduleEvent(EVENT_SPELL_RAPID_BURST, 0ms); - events.ScheduleEvent(EVENT_SPELL_SPINNING_UP, 30s); - events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 3s); - if (Creature* c = GetMimiron()) - if (c->AI()->GetData(1)) - { - events.ScheduleEvent(EVENT_FLAME_SUPPRESSION_10, 7s); - events.ScheduleEvent(EVENT_FROST_BOMB, 1s); - } - break; - case 4: - Phase = 4; - fighting = true; - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - events.Reset(); - events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 3s); - events.ScheduleEvent(EVENT_SPELL_ROCKET_STRIKE, 16s); - events.ScheduleEvent(EVENT_HAND_PULSE, 1ms); - events.ScheduleEvent(EVENT_SPELL_SPINNING_UP, 30s); - if (Creature* c = GetMimiron()) - if (c->AI()->GetData(1)) - events.ScheduleEvent(EVENT_FROST_BOMB, 1s); - break; - } - } - } - - uint32 GetData(uint32 /*id*/) const override - { - return spinningUpOrientation; - } - - void DoAction(int32 action) override - { - if (action == 1337) - if( Vehicle* vk = me->GetVehicleKit() ) - for (uint8 i = 0; i < 2; ++i) - if (Unit* r = vk->GetPassenger(5 + i)) - if (r->GetTypeId() == TYPEID_UNIT) - r->ToCreature()->DespawnOrUnsummon(1); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (damage >= me->GetHealth() || me->GetHealth() < 15000) - { - damage = 0; - if (me->GetReactState() == REACT_PASSIVE) - return; - me->SetReactState(REACT_PASSIVE); - if (Phase == 2) - { - if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - { - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - SetData(1, 0); - me->InterruptNonMeleeSpells(false); - me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); - me->SendMeleeAttackStop(); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_06); - me->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_06); - if (Creature* c = GetMimiron()) - c->AI()->SetData(0, 2); - } - } - else if (Phase == 4) - { - if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - { - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->InterruptNonMeleeSpells(false); - me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); - me->CastSpell(me, SPELL_SELF_REPAIR, false); - if (Creature* c = GetMimiron()) - { - if (c->AI()->GetData(1)) - me->CastSpell(me, SPELL_EMERGENCY_MODE, true); - if (c->AI()->GetData(2)) - me->CastSpell(me, SPELL_BERSERK, true); - c->AI()->SetData(0, 5); - } - } - } - } - } - - void UpdateAI(uint32 diff) override - { - if (!fighting) - return; - - events.Update(diff); - - if (spinningUpTimer) // executed about a second after starting casting to ensure players can see the correct direction - { - if (spinningUpTimer <= diff) - { - float angle = (spinningUpOrientation * 2 * M_PI) / 100.0f; - me->SetFacingTo(angle); - - spinningUpTimer = 0; - } - else - spinningUpTimer -= diff; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_SPELL_HEAT_WAVE: - me->CastSpell(me, SPELL_HEAT_WAVE, true); - events.Repeat(10s); - break; - case EVENT_SPELL_ROCKET_STRIKE: - if( Vehicle* vk = me->GetVehicleKit() ) - { - for( int i = 0; i < (Phase / 2); ++i ) - { - uint8 index = (Phase == 2 ? rand() % 2 : i); - if( Unit* r = vk->GetPassenger(5 + index) ) - if (Player* temp = SelectTargetFromPlayerList(100.0f)) - { - if( Creature* trigger = me->SummonCreature(NPC_ROCKET_STRIKE_N, temp->GetPositionX(), temp->GetPositionY(), temp->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 6000) ) - trigger->CastSpell(trigger, SPELL_ROCKET_STRIKE_AURA, true); - Position exitPos = r->GetPosition(); - exitPos.m_positionX += cos(me->GetOrientation()) * 2.35f; - exitPos.m_positionY += std::sin(me->GetOrientation()) * 2.35f; - exitPos.m_positionZ += 2.0f * Phase; - r->_ExitVehicle(&exitPos); - me->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE, r->GetGUID()); - if (r->GetTypeId() == TYPEID_UNIT) - r->ToCreature()->AI()->SetData(0, 0); - } - } - events.Repeat(20s); - events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 10s); - } - break; - case EVENT_REINSTALL_ROCKETS: - if (Vehicle* vk = me->GetVehicleKit()) - { - for (uint8 i = 5; i <= 6; ++i) - if (!vk->GetPassenger(i)) - if (TempSummon* accessory = me->SummonCreature(NPC_ROCKET_VISUAL, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 4.0f, me->GetOrientation(), TEMPSUMMON_MANUAL_DESPAWN)) - if (!me->HandleSpellClick(accessory, i)) - accessory->UnSummon(); - } - break; - case EVENT_SPELL_RAPID_BURST: - if (Player* p = SelectTargetFromPlayerList(80.0f)) - { - me->CastSpell(p, SPELL_RAPID_BURST, true); - me->SetFacingToObject(p); - } - events.Repeat(3200ms); - break; - case EVENT_HAND_PULSE: - if (Player* p = SelectTargetFromPlayerList(80.0f)) - { - me->SetFacingToObject(p); - if (Unit* vb = me->GetVehicleBase()) - { - vb->SendMeleeAttackStop(); - vb->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - - if( !leftarm ) - { - vb->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_03); - me->CastSpell(p, SPELL_HAND_PULSE_R, false); - } - else - { - vb->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_04); - me->CastSpell(p, SPELL_HAND_PULSE_L, false); - } - } - - leftarm = !leftarm; - } - events.Repeat(1750ms); - break; - case EVENT_SPELL_SPINNING_UP: - events.Repeat(45s); - if (Player* p = SelectTargetFromPlayerList(80.0f)) - { - float angle = me->GetAngle(p); - - spinningUpOrientation = (uint32)((angle * 100.0f) / (2 * M_PI)); - spinningUpTimer = 1500; - me->SetFacingTo(angle); - me->CastSpell(p, SPELL_SPINNING_UP, true); - if (Unit* vehicle = me->GetVehicleBase()) - { - vehicle->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_CUSTOM_SPELL_01); - vehicle->HandleEmoteCommand(EMOTE_STATE_CUSTOM_SPELL_01); - } - events.RescheduleEvent((Phase == 2 ? EVENT_SPELL_RAPID_BURST : EVENT_HAND_PULSE), 14s + 500ms); - } - break; - case EVENT_FLAME_SUPPRESSION_10: - me->CastSpell(me, SPELL_FLAME_SUPPRESSANT_10yd, false); - events.Repeat(10s); - break; - case EVENT_FROST_BOMB: - me->CastCustomSpell(SPELL_VX001_FROST_BOMB, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false); - events.Repeat(45s); - break; - } - } - - void MoveInLineOfSight(Unit* /*mover*/) override {} - - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() == TYPEID_PLAYER) - if (Creature* c = GetMimiron()) - { - if (Phase == 2) - { - c->AI()->Talk(SAY_VX001_SLAY); - } - else - { - c->AI()->Talk(SAY_V07TRON_SLAY); - } - } - } - - void EnterEvadeMode(EvadeReason why) override - { - if (bIsEvading) - return; - bIsEvading = true; - - me->RemoveAllAuras(); - me->ExitVehicle(); - _EnterEvadeMode(); - Reset(); - if (Creature* mimiron = GetMimiron()) - mimiron->AI()->EnterEvadeMode(why); - - bIsEvading = false; - } - - void PassengerBoarded(Unit* p, int8 /*seat*/, bool apply) override - { - if (p->GetEntry() == NPC_ROCKET_VISUAL && !apply) - p->ToCreature()->DespawnOrUnsummon(8000); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if( spell->Id == SPELL_SELF_REPAIR ) - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_AGGRESSIVE); - } - } - }; -}; - -class npc_ulduar_aerial_command_unit : public CreatureScript -{ -public: - npc_ulduar_aerial_command_unit() : CreatureScript("npc_ulduar_aerial_command_unit") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_aerial_command_unitAI : public ScriptedAI - { - npc_ulduar_aerial_command_unitAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) - { - pInstance = me->GetInstanceScript(); - bIsEvading = false; - immobilized = false; - me->SetDisableGravity(true); - } - - InstanceScript* pInstance; - EventMap events; - SummonList summons; - bool bIsEvading; - uint8 Phase; - bool immobilized; - - void Reset() override - { - Phase = 0; - events.Reset(); - summons.DespawnAll(); - } - - void AttackStart(Unit* who) override - { - if (who) - me->Attack(who, true); // skip following - } - - void SetData(uint32 id, uint32 value) override - { - if (id == 1) // setting phase to start fighting - { - switch (value) - { - case 0: - Phase = 0; - events.Reset(); - immobilized = false; - break; - case 3: - Phase = 3; - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - if (Unit* target = SelectTargetFromPlayerList(75.0f)) - AttackStart(target); - DoZoneInCombat(); - events.Reset(); - events.ScheduleEvent(EVENT_SPELL_PLASMA_BALL, 0ms); - events.ScheduleEvent(EVENT_SUMMON_BOMB_BOT, 15s); - events.ScheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 1s); - events.ScheduleEvent(EVENT_SUMMON_JUNK_BOT, 10s); - if (Creature* c = GetMimiron()) - if (c->AI()->GetData(1)) - events.ScheduleEvent(EVENT_SUMMON_EMERGENCY_FIRE_BOTS, 0ms); - break; - case 4: - me->SetReactState(REACT_AGGRESSIVE); - DoResetThreatList(); - Phase = 4; - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - if (Unit* target = SelectTargetFromPlayerList(75.0f)) - AttackStart(target); - DoZoneInCombat(); - events.Reset(); - events.ScheduleEvent(EVENT_SPELL_PLASMA_BALL, 0ms); - } - } - else if (id == 2 && !immobilized && Phase == 3) // magnetic core - { - immobilized = true; - events.ScheduleEvent(EVENT_MAGNETIC_CORE_PULL_DOWN, 2s); - } - } - - void DoAction(int32 param) override - { - if (param == 1337) - summons.DespawnAll(); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (damage >= me->GetHealth() || me->GetHealth() < 15000) - { - damage = 0; - if (me->GetReactState() == REACT_PASSIVE) - return; - me->SetReactState(REACT_PASSIVE); - if (Phase == 3) - { - if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) - { - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->GetMotionMaster()->Clear(); - me->StopMoving(); - me->AttackStop(); - me->SetReactState(REACT_PASSIVE); - SetData(1, 0); - me->InterruptNonMeleeSpells(false); - me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); - - me->MonsterMoveWithSpeed(2744.65f, 2569.46f, 381.34f, me->GetDistance(2744.65f, 2569.46f, 381.34f)); - me->UpdatePosition(2744.65f, 2569.46f, 381.34f, M_PI, false); - - if (Creature* c = GetMimiron()) - c->AI()->SetData(0, 3); - } - } - else if (Phase == 4) - { - if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) - { - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->InterruptNonMeleeSpells(false); - me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); - me->CastSpell(me, SPELL_SELF_REPAIR, false); - if (Creature* c = GetMimiron()) - { - if (c->AI()->GetData(1)) - me->CastSpell(me, SPELL_EMERGENCY_MODE, true); - if (c->AI()->GetData(2)) - me->CastSpell(me, SPELL_BERSERK, true); - c->AI()->SetData(0, 6); - } - } - } - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - // following :D - if( Phase == 3 && !immobilized ) - if( Unit* victim = me->GetVictim() ) - if( me->GetExactDist2d(victim) > 25.0f ) - { - float angle = victim->GetAngle(me->GetPositionX(), me->GetPositionY()); - me->SetOrientation( me->GetAngle(victim->GetPositionX(), victim->GetPositionY()) ); - float x = victim->GetPositionX() + 15.0f * cos(angle); - float y = victim->GetPositionY() + 15.0f * std::sin(angle); - - // check if there's magnetic core in line of movement - Creature* mc = nullptr; - std::list cl; - me->GetCreaturesWithEntryInRange(cl, me->GetExactDist2d(victim), NPC_MAGNETIC_CORE); - for( std::list::iterator itr = cl.begin(); itr != cl.end(); ++itr ) - { - if ((*itr)->IsInBetween(me, victim, 4.0f) && (*itr)->GetExactDist2d(victim) >= 10.0f) // don't come very close just because there's a magnetic core - { - x = (*itr)->GetPositionX(); - y = (*itr)->GetPositionY(); - mc = (*itr); - break; - } - } - - float speed = me->GetExactDist(x, y, 381.34f); - me->MonsterMoveWithSpeed(x, y, 381.34f, speed); - me->UpdatePosition(x, y, 381.34f, me->GetAngle(victim), false); - if (mc) - { - mc->AI()->SetData(0, 0); - SetData(2, 1); - } - } - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_SPELL_PLASMA_BALL: - if( !immobilized ) - { - if (Phase == 3) - { - if( Unit* victim = me->GetVictim() ) - me->CastSpell(victim, SPELL_PLASMA_BALL, false); - } - else - { - if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 27.5f, true)) - { - me->SetFacingToObject(victim); - me->CastSpell(victim, SPELL_PLASMA_BALL, false); - } - } - } - events.Repeat(3s); - break; - case EVENT_SUMMON_BOMB_BOT: - if( !immobilized ) - me->CastSpell(me, SPELL_SUMMON_BOMB_BOT, false); - events.Repeat(15s); - break; - case EVENT_SUMMON_ASSAULT_BOT: - if( GameObject* pad = me->FindNearestGameObject(RAND(194742, 194746, 194745), 200.0f) ) - if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_TIMED_DESPAWN, 15000)) - trigger->AI()->DoAction(2); - events.Repeat(30s); - break; - case EVENT_SUMMON_JUNK_BOT: - if( GameObject* pad = me->FindNearestGameObject(RAND(194741, 194744, 194747), 200.0f) ) - if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_TIMED_DESPAWN, 15000)) - trigger->AI()->DoAction(1); - events.Repeat(10s); - break; - case EVENT_SUMMON_EMERGENCY_FIRE_BOTS: - { - uint32 ids[3] = {194740, 194743, 194748}; - for( uint8 i = 0; i < 3; ++i ) - if( GameObject* pad = me->FindNearestGameObject(ids[i], 200.0f) ) - if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_MANUAL_DESPAWN)) - trigger->AI()->DoAction(3); - events.Repeat(45s); - } - break; - case EVENT_MAGNETIC_CORE_PULL_DOWN: - me->CastSpell(me, SPELL_MAGNETIC_CORE, true); - me->CastSpell(me, SPELL_SPINNING, true); - me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 365.34f, me->GetExactDist(me->GetPositionX(), me->GetPositionY(), 365.34f)); - me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), 365.34f, me->GetOrientation(), false); - events.ScheduleEvent(EVENT_MAGNETIC_CORE_FREE, 20s); - break; - case EVENT_MAGNETIC_CORE_FREE: - me->RemoveAura(SPELL_SPINNING); - me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 381.34f, me->GetDistance(me->GetPositionX(), me->GetPositionY(), 381.34f)); - me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), 381.34f, me->GetOrientation(), false); - events.ScheduleEvent(EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE, 1s); - break; - case EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE: - immobilized = false; - break; - } - } - - void MoveInLineOfSight(Unit* /*mover*/) override {} - - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() == TYPEID_PLAYER) - if (Creature* c = GetMimiron()) - { - if (Phase == 3) - { - c->AI()->Talk(SAY_AERIAL_SLAY); - } - else - { - c->AI()->Talk(SAY_V07TRON_SLAY); - } - } - } - - void EnterEvadeMode(EvadeReason why) override - { - if (bIsEvading) - return; - bIsEvading = true; - - me->RemoveAllAuras(); - me->ExitVehicle(); - _EnterEvadeMode(); - Reset(); - if (Creature* mimiron = GetMimiron()) - mimiron->AI()->EnterEvadeMode(why); - - bIsEvading = false; - } - - void JustSummoned(Creature* s) override - { - summons.Summon(s); - if (s->GetEntry() == NPC_BOMB_BOT) - s->m_positionZ = 364.34f; - } - - void SummonedCreatureDespawn(Creature* s) override - { - summons.Despawn(s); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if( spell->Id == SPELL_SELF_REPAIR ) - { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetReactState(REACT_AGGRESSIVE); - } - } - }; -}; - -class npc_ulduar_proximity_mine : public CreatureScript -{ -public: - npc_ulduar_proximity_mine() : CreatureScript("npc_ulduar_proximity_mine") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_proximity_mineAI : public ScriptedAI - { - npc_ulduar_proximity_mineAI(Creature* pCreature) : ScriptedAI(pCreature) - { - exploded = false; - timer = 2500; - timer2 = 35000; - } - - bool exploded; - uint16 timer; - uint16 timer2; - - void AttackStart(Unit* /*who*/) override {} - void MoveInLineOfSight(Unit* /*who*/) override {} - bool CanAIAttack(Unit const* /*target*/) const override { return false; } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) override - { - if (target && spell && target->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_MINE_EXPLOSION) - if (InstanceScript* pInstance = me->GetInstanceScript()) - if (Creature* c = GetMimiron()) - c->AI()->SetData(0, 11); - } - - // MoveInLineOfSight is checked every few yards, can't use it - void UpdateAI(uint32 diff) override - { - if (timer2 <= diff) - { - timer2 = 35000; - if (!exploded) - { - exploded = true; - me->CastSpell(me, SPELL_MINE_EXPLOSION, false); - } - } - else - timer2 -= diff; - - if (timer <= diff) - { - timer = 500; - if (!exploded && SelectTargetFromPlayerList(1.9f)) - { - exploded = true; - me->CastSpell(me, SPELL_MINE_EXPLOSION, false); - } - } - else - timer -= diff; - } - }; -}; - -class npc_ulduar_mimiron_rocket : public CreatureScript -{ -public: - npc_ulduar_mimiron_rocket() : CreatureScript("npc_ulduar_mimiron_rocket") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_mimiron_rocketAI : public NullCreatureAI - { - npc_ulduar_mimiron_rocketAI(Creature* pCreature) : NullCreatureAI(pCreature) {} - - void InitializeAI() override - { - if (!me->isDead()) - Reset(); - } - - void Reset() override - { - me->SetCanFly(true); - me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING); - me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); - } - - void SetData(uint32 /*id*/, uint32 /*value*/) override - { - me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 100.0f, false, true); - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!me->GetVehicle()) - { - me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN) + 0.4f, false); - me->SetSpeed(MOVE_FLIGHT, me->GetSpeedRate(MOVE_RUN), false); - } - } - }; -}; - -class npc_ulduar_magnetic_core : public CreatureScript -{ -public: - npc_ulduar_magnetic_core() : CreatureScript("npc_ulduar_magnetic_core") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_magnetic_coreAI : public NullCreatureAI - { - npc_ulduar_magnetic_coreAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - pInstance = me->GetInstanceScript(); - if (Creature* c = GetACU()) - if (c->GetExactDist2d(me) <= 10.0f) - { - me->SendMonsterMove(c->GetPositionX(), c->GetPositionY(), 364.313f, 1); - me->UpdatePosition(c->GetPositionX(), c->GetPositionY(), 364.313f, me->GetOrientation(), true); - me->StopMovingOnCurrentPos(); - c->AI()->SetData(2, 1); - despawnTimer = 20000; - return; - } - despawnTimer = 60000; - } - - InstanceScript* pInstance; - uint16 despawnTimer; - - void SetData(uint32 /*id*/, uint32 /*value*/) override - { - despawnTimer = 20000; - } - - void UpdateAI(uint32 diff) override - { - if (despawnTimer <= diff) - { - despawnTimer = 60000; - me->DespawnOrUnsummon(1); - } - else - despawnTimer -= diff; - } - }; -}; - -class npc_ulduar_bot_summon_trigger : public CreatureScript -{ -public: - npc_ulduar_bot_summon_trigger() : CreatureScript("npc_ulduar_bot_summon_trigger") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_bot_summon_triggerAI : public NullCreatureAI - { - npc_ulduar_bot_summon_triggerAI(Creature* pCreature) : NullCreatureAI(pCreature) { } - - uint32 timer; - uint8 option; - - void Reset() override - { - timer = 8000; - option = 0; - } - - void DoAction(int32 param) override - { - switch( param ) - { - case 1: - me->CastSpell(me, SPELL_BEAM_GREEN, true); - option = 1; - break; - case 2: - me->CastSpell(me, SPELL_BEAM_YELLOW, true); - option = 2; - break; - case 3: - me->CastSpell(me, SPELL_BEAM_BLUE, true); - option = 3; - break; - } - } - - void UpdateAI(uint32 diff) override - { - if( timer <= diff ) - { - uint32 option_npcid[3] = {NPC_JUNK_BOT, NPC_ASSAULT_BOT, NPC_EMERGENCY_FIRE_BOT}; - InstanceScript* pInstance = me->GetInstanceScript(); - if (Creature* ACU = GetACU()) // ACU summons for easy removing - if( Creature* bot = ACU->SummonCreature( option_npcid[option - 1], *me, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 25000 ) ) - { - if( option < 3 ) - bot->SetInCombatWithZone(); - if (Creature* m = GetMimiron()) - if (m->AI()->GetData(1)) // hardmode - bot->CastSpell(bot, SPELL_EMERGENCY_MODE, true); - } - - me->DespawnOrUnsummon(500); - timer = 99999; - } - else - timer -= diff; - } - }; -}; - -class spell_mimiron_rapid_burst : public SpellScriptLoader -{ -public: - spell_mimiron_rapid_burst() : SpellScriptLoader("spell_mimiron_rapid_burst") { } - - class spell_mimiron_rapid_burst_AuraScript : public AuraScript - { - PrepareAuraScript(spell_mimiron_rapid_burst_AuraScript) - - void HandleEffectPeriodic(AuraEffect const* aurEff) - { - if (Unit* c = GetCaster()) - { - uint32 id = ( c->GetMap()->Is25ManRaid() ? ((aurEff->GetTickNumber() % 2) ? SPELL_RAPID_BURST_DAMAGE_25_2 : SPELL_RAPID_BURST_DAMAGE_25_1) : ((aurEff->GetTickNumber() % 2) ? SPELL_RAPID_BURST_DAMAGE_10_2 : SPELL_RAPID_BURST_DAMAGE_10_1) ); - c->CastSpell((Unit*)nullptr, id, true); - } - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_rapid_burst_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_mimiron_rapid_burst_AuraScript(); - } -}; - -class spell_mimiron_p3wx2_laser_barrage : public SpellScriptLoader -{ -public: - spell_mimiron_p3wx2_laser_barrage() : SpellScriptLoader("spell_mimiron_p3wx2_laser_barrage") { } - - class spell_mimiron_p3wx2_laser_barrage_AuraScript : public AuraScript - { - PrepareAuraScript(spell_mimiron_p3wx2_laser_barrage_AuraScript) - - uint32 lastMSTime; - float lastOrientation; - - bool Load() override - { - lastMSTime = GameTime::GetGameTimeMS().count(); - lastOrientation = -1.0f; - return true; - } - - void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) - { - if (Unit* c = GetCaster()) - { - if (c->GetTypeId() != TYPEID_UNIT) - return; - uint32 diff = getMSTimeDiff(lastMSTime, GameTime::GetGameTimeMS().count()); - if (lastOrientation == -1.0f) - { - lastOrientation = (c->ToCreature()->AI()->GetData(0) * 2 * M_PI) / 100.0f; - diff = 0; - } - float new_o = Position::NormalizeOrientation(lastOrientation - (M_PI / 60) * (diff / 250.0f)); - lastMSTime = GameTime::GetGameTimeMS().count(); - lastOrientation = new_o; - c->SetFacingTo(new_o); - - c->CastSpell((Unit*)nullptr, 63297, true); - c->CastSpell((Unit*)nullptr, 64042, true); - } - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_p3wx2_laser_barrage_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_mimiron_p3wx2_laser_barrage_AuraScript(); - } -}; - -class go_ulduar_do_not_push_this_button : public GameObjectScript -{ -public: - go_ulduar_do_not_push_this_button() : GameObjectScript("go_ulduar_do_not_push_this_button") { } - - bool OnGossipHello(Player* player, GameObject* go) override - { - if(!player || !go) - return true; - - if (InstanceScript* instance = go->GetInstanceScript()) - { - if(instance->GetData(TYPE_MIMIRON) != NOT_STARTED) - return false; - - if (Creature* c = ObjectAccessor::GetCreature(*go, instance->GetGuidData(TYPE_MIMIRON))) - { - c->AI()->SetData(0, 7); - c->AI()->AttackStart(player); - } - } - - return false; - } -}; - -class npc_ulduar_flames_initial : public CreatureScript -{ -public: - npc_ulduar_flames_initial() : CreatureScript("npc_ulduar_flames_initial") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_flames_initialAI : public NullCreatureAI - { - npc_ulduar_flames_initialAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - CreateTime = GameTime::GetGameTime().count(); - events.Reset(); - events.ScheduleEvent(EVENT_FLAMES_SPREAD, 5750ms); - if( Creature* flame = me->SummonCreature(NPC_FLAMES_SPREAD, me->GetPositionX(), me->GetPositionY(), 364.32f, 0.0f) ) - { - FlameList.push_back(flame->GetGUID()); - flame->CastSpell(flame, SPELL_FLAMES_AURA, true); - } - } - - GuidList FlameList; - EventMap events; - uint32 CreateTime; - - void DoAction(int32 action) override - { - if (action == 1337) - RemoveAll(); - } - - void SpreadFlame(float x, float y) - { - if( Creature* flame = me->SummonCreature(NPC_FLAMES_SPREAD, x, y, 364.32f, 0.0f) ) - { - FlameList.push_back(flame->GetGUID()); - if (Creature* c = me->FindNearestCreature(NPC_FLAMES_SPREAD, 10.0f)) - if (c->GetExactDist2d(flame->GetPositionX(), flame->GetPositionY()) <= 4.0f) - return; - flame->CastSpell(flame, SPELL_FLAMES_AURA, true); - } - } - - void RemoveFlame(ObjectGuid guid) - { - FlameList.remove(guid); - } - - void RemoveAll() - { - for (ObjectGuid const& guid : FlameList) - if (Creature* c = ObjectAccessor::GetCreature(*me, guid)) - c->DespawnOrUnsummon(); - FlameList.clear(); - me->DespawnOrUnsummon(); - } - - void UpdateAI(uint32 diff) override - { - if (InstanceScript* pInstance = me->GetInstanceScript()) - if (pInstance->GetData(TYPE_MIMIRON) != IN_PROGRESS) - { - RemoveAll(); - return; - } - - events.Update(diff); - - switch( events.ExecuteEvent() ) - { - case 0: - break; - case EVENT_FLAMES_SPREAD: - { - if( FlameList.empty() ) - { - me->DespawnOrUnsummon(); - return; - } - - if (InstanceScript* pInstance = me->GetInstanceScript()) - if (Creature* mimiron = GetMimiron()) - if (CreateTime < mimiron->AI()->GetData(10)) - { - break; - } - - Creature* last = ObjectAccessor::GetCreature(*me, FlameList.back()); - if( last ) - { - float prevdist = 100.0f; - Player* target = nullptr; - - Map::PlayerList const& pl = me->GetMap()->GetPlayers(); - for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) - if( Player* plr = itr->GetSource() ) - if( plr->IsAlive() && plr->GetExactDist2d(last) < prevdist && !plr->IsGameMaster() ) - { - target = plr; - prevdist = plr->GetExactDist2d(last); - } - - if (target && prevdist >= 4.0f) // no need to spread when player is standing in fire, check distance - { - float angle = last->GetAngle(target->GetPositionX(), target->GetPositionY()) - M_PI / 8 + rand_norm() * 2 * M_PI / 8; - SpreadFlame(last->GetPositionX() + 7.0f * cos(angle), last->GetPositionY() + 7.0f * std::sin(angle)); - } - } - - events.Repeat(5750ms); - } - break; - } - } - }; -}; - -class npc_ulduar_flames_spread : public CreatureScript -{ -public: - npc_ulduar_flames_spread() : CreatureScript("npc_ulduar_flames_spread") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_flames_spreadAI : public NullCreatureAI - { - npc_ulduar_flames_spreadAI(Creature* pCreature) : NullCreatureAI(pCreature) {} - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - switch( spell->Id ) - { - case SPELL_FROST_BOMB_EXPLOSION_10: - case SPELL_FROST_BOMB_EXPLOSION_25: - case SPELL_FLAME_SUPPRESSANT_10yd: - case SPELL_FLAME_SUPPRESSANT_50000yd: - case SPELL_WATER_SPRAY: - { - if (me->IsSummon()) - if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit()) - if (Creature* c = summoner->ToCreature()) - if (c->AI()) - CAST_AI(npc_ulduar_flames_initial::npc_ulduar_flames_initialAI, c->AI())->RemoveFlame(me->GetGUID()); - - me->RemoveAllAuras(); - me->DespawnOrUnsummon(2500); - } - break; - case SPELL_VX001_FROST_BOMB: - me->CastSpell(me, SPELL_SUMMON_FROST_BOMB, true); - break; - } - } - }; -}; - -class npc_ulduar_emergency_fire_bot : public CreatureScript -{ -public: - npc_ulduar_emergency_fire_bot() : CreatureScript("npc_ulduar_emergency_fire_bot") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_emergency_fire_botAI : public ScriptedAI - { - npc_ulduar_emergency_fire_botAI(Creature* pCreature) : ScriptedAI(pCreature) - { - events.Reset(); - events.ScheduleEvent(EVENT_EMERGENCY_BOT_CHECK, 1s); - } - - EventMap events; - - void MoveInLineOfSight(Unit*) override {} - void AttackStart(Unit*) override {} - - void MovementInform(uint32 type, uint32 id) override - { - if (type == POINT_MOTION_TYPE && id == 1) - events.ScheduleEvent(EVENT_EMERGENCY_BOT_ATTACK, 0ms); - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - switch( events.ExecuteEvent() ) - { - case 0: - break; - case EVENT_EMERGENCY_BOT_CHECK: - events.Repeat(15s); - if (Creature* flame = me->FindNearestCreature(NPC_FLAMES_SPREAD, 150.0f, true)) - { - me->SetOrientation(me->GetAngle(flame->GetPositionX(), flame->GetPositionY())); - float dist = me->GetExactDist2d(flame); - if (dist <= 5.0f) - events.ScheduleEvent(EVENT_EMERGENCY_BOT_ATTACK, 0ms); - else - me->GetMotionMaster()->MovePoint(1, me->GetPositionX() + (dist - 5.0f)*cos(me->GetOrientation()), me->GetPositionY() + (dist - 5.0f)*sin(me->GetOrientation()), 364.32f); - } - break; - case EVENT_EMERGENCY_BOT_ATTACK: - me->CastSpell((Unit*)nullptr, SPELL_WATER_SPRAY, false); - events.RescheduleEvent(EVENT_EMERGENCY_BOT_CHECK, 5s); - break; - } - } - }; -}; - -class npc_ulduar_rocket_strike_trigger : public CreatureScript -{ -public: - npc_ulduar_rocket_strike_trigger() : CreatureScript("npc_ulduar_rocket_strike_trigger") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_rocket_strike_triggerAI : public NullCreatureAI - { - npc_ulduar_rocket_strike_triggerAI(Creature* pCreature) : NullCreatureAI(pCreature) {} - - void SpellHitTarget(Unit* target, SpellInfo const* spell) override - { - if (!target || !spell) - return; - if (spell->Id == 63041) - { - if (target->GetEntry() == NPC_ASSAULT_BOT) - me->CastSpell(me, 65040, true); // achievement Not-So-Friendly Fire - else if (target->GetTypeId() == TYPEID_PLAYER) - if (InstanceScript* pInstance = me->GetInstanceScript()) - if (Creature* c = GetMimiron()) - c->AI()->SetData(0, 13); - } - } - }; -}; - -class achievement_mimiron_firefighter : public AchievementCriteriaScript -{ -public: - achievement_mimiron_firefighter() : AchievementCriteriaScript("achievement_mimiron_firefighter") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1); - } -}; - -class achievement_mimiron_set_up_us_the_bomb_11 : public AchievementCriteriaScript -{ -public: - achievement_mimiron_set_up_us_the_bomb_11() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_11") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(11); - } -}; - -class achievement_mimiron_set_up_us_the_bomb_12 : public AchievementCriteriaScript -{ -public: - achievement_mimiron_set_up_us_the_bomb_12() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_12") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(12); - } -}; - -class achievement_mimiron_set_up_us_the_bomb_13 : public AchievementCriteriaScript -{ -public: - achievement_mimiron_set_up_us_the_bomb_13() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_13") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(13); - } -}; - void AddSC_boss_mimiron() { new boss_mimiron(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.h new file mode 100644 index 00000000000000..55f9bf4c4f66d1 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.h @@ -0,0 +1,2475 @@ +#ifndef BOSS_MIMIRON_H_ +#define BOSS_MIMIRON_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "GameObjectScript.h" +#include "GameTime.h" +#include "MapMgr.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "Spell.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "Vehicle.h" +#include "ulduar.h" + +enum SpellData +{ + SPELL_BERSERK = 64238, + + // PHASE 1: + SPELL_NAPALM_SHELL_25 = 65026, + SPELL_NAPALM_SHELL_10 = 63666, + + SPELL_PLASMA_BLAST_25 = 64529, + SPELL_PLASMA_BLAST_10 = 62997, + + SPELL_SHOCK_BLAST = 63631, + + SPELL_PROXIMITY_MINES = 63027, + NPC_PROXIMITY_MINE = 34362, + SPELL_MINE_EXPLOSION_25 = 63009, + SPELL_MINE_EXPLOSION_10 = 66351, + SPELL_SUMMON_PROXIMITY_MINE = 65347, + + // PHASE 2: + SPELL_HEAT_WAVE = 64533, + + SPELL_ROCKET_STRIKE_AURA = 64064, + NPC_ROCKET_VISUAL = 34050, + NPC_ROCKET_STRIKE_N = 34047, + + SPELL_RAPID_BURST = 63382, + SPELL_RAPID_BURST_DAMAGE_25_1 = 64531, + SPELL_RAPID_BURST_DAMAGE_25_2 = 64532, + SPELL_RAPID_BURST_DAMAGE_10_1 = 63387, + SPELL_RAPID_BURST_DAMAGE_10_2 = 64019, + SPELL_SUMMON_BURST_TARGET = 64840, + + SPELL_SPINNING_UP = 63414, + + // PHASE 3: + SPELL_PLASMA_BALL_25 = 64535, + SPELL_PLASMA_BALL_10 = 63689, + + SPELL_MAGNETIC_CORE = 64436, + SPELL_SPINNING = 64438, + + SPELL_SUMMON_BOMB_BOT = 63811, + SPELL_BB_EXPLODE = 63801, + + SPELL_BEAM_GREEN = 63295, + SPELL_BEAM_YELLOW = 63292, + SPELL_BEAM_BLUE = 63294, + + // PHASE 4: + SPELL_HAND_PULSE_10_R = 64352, + SPELL_HAND_PULSE_25_R = 64537, + SPELL_HAND_PULSE_10_L = 64348, + SPELL_HAND_PULSE_25_L = 64536, + + SPELL_SELF_REPAIR = 64383, + SPELL_SLEEP = 64394, +}; + +enum NPCs +{ + //NPC_MIMIRON = 33350, + NPC_LEVIATHAN_MKII = 33432, + NPC_LEVIATHAN_MKII_CANNON = 34071, + NPC_VX001 = 33651, + NPC_AERIAL_COMMAND_UNIT = 33670, + NPC_COMPUTER = 34143, + NPC_BOMB_BOT = 33836, + NPC_BOT_SUMMON_TRIGGER = 33856, + NPC_ASSAULT_BOT = 34057, + NPC_JUNK_BOT = 33855, + NPC_MAGNETIC_CORE = 34068, +}; + +enum GOs +{ + //GO_MIMIRON_ELEVATOR = 194749, + GO_DOOR_1 = 194776, + GO_DOOR_2 = 194774, + GO_DOOR_3 = 194775, + GO_BUTTON = 194739, + // pads: 194740-48 +}; + +enum HardMode +{ + SPELL_EMERGENCY_MODE = 64582, + SPELL_SELF_DESTRUCT = 64610, + + SPELL_SUMMON_FLAMES_INITIAL = 64563, + NPC_FLAMES_INITIAL = 34363, + SPELL_SUMMON_FLAMES_SPREAD = 64564, + NPC_FLAMES_SPREAD = 34121, + SPELL_FLAMES_AURA = 64561, + + SPELL_VX001_FROST_BOMB = 64623, + SPELL_FROST_BOMB_VISUAL_AURA = 64624, + SPELL_SUMMON_FROST_BOMB = 64627, + NPC_FROST_BOMB = 34149, + SPELL_FROST_BOMB_EXPLOSION_10 = 64626, + SPELL_FROST_BOMB_EXPLOSION_25 = 65333, + + SPELL_FLAME_SUPPRESSANT_10yd = 65192, + SPELL_FLAME_SUPPRESSANT_50000yd = 64570, + + SPELL_WATER_SPRAY = 64619, + SPELL_DEAFENING_SIREN = 64616, + NPC_EMERGENCY_FIRE_BOT = 34147, + + SPELL_ENTER_VEHICLE_0 = 63112, + SPELL_ENTER_VEHICLE_1 = 63313, + SPELL_ENTER_VEHICLE_2 = 63314, + SPELL_ENTER_VEHICLE_4 = 63316, +}; + +enum EVENTS +{ + // Mimiron: + EVENT_SIT_LMK2 = 1, + EVENT_SIT_LMK2_INTERVAL = 2, + EVENT_LMK2_RETREAT_INTERVAL = 7, + EVENT_ELEVATOR_INTERVAL_1 = 8, + EVENT_ELEVATOR_INTERVAL_2 = 9, + EVENT_SITTING_ON_VX001 = 10, + EVENT_ENTER_VX001 = 11, + EVENT_EMOTE_VX001 = 12, + EVENT_VX001_START_FIGHT = 13, + EVENT_ELEVATOR_INTERVAL_0 = 14, + EVENT_GET_OUT_VX001 = 21, + EVENT_SAY_VX001_DEAD = 22, + EVENT_ENTER_ACU = 23, + EVENT_SAY_ACU_ACTIVATE = 24, + EVENT_ACU_START_ATTACK = 25, + EVENT_VX001_EMOTESTATE_DEATH = 26, + EVENT_SAY_ACU_DEAD = 31, + EVENT_LEVIATHAN_COME_CLOSER = 32, + EVENT_VX001_EMOTE_JUMP = 33, + EVENT_LEVIATHAN_RIDE_MIDDLE = 34, + EVENT_JOIN_TOGETHER = 342, + EVENT_JOIN_ACU = 35, + EVENT_START_PHASE4 = 36, + EVENT_FINISH = 50, + EVENT_SAY_VOLTRON_DEAD = 51, + EVENT_DISAPPEAR = 52, + EVENT_BERSERK = 53, + EVENT_BERSERK_2 = 54, + + // Leviathan: + EVENT_SPELL_NAPALM_SHELL = 3, + EVENT_SPELL_PLASMA_BLAST = 4, + EVENT_SPELL_SHOCK_BLAST = 5, + EVENT_PROXIMITY_MINES_1 = 6, + + // VX001: + EVENT_SPELL_HEAT_WAVE = 15, + EVENT_SPELL_ROCKET_STRIKE = 16, + EVENT_REINSTALL_ROCKETS = 17, + EVENT_SPELL_RAPID_BURST = 18, + EVENT_SPELL_RAPID_BURST_INTERVAL = 19, + EVENT_SPELL_SPINNING_UP = 20, + EVENT_HAND_PULSE = 37, + + // ACU: + EVENT_SPELL_PLASMA_BALL = 27, + EVENT_SUMMON_BOMB_BOT = 28, + EVENT_BOMB_BOT_CHASE = 29, + EVENT_BOMB_BOT_RELOCATE = 30, + EVENT_SUMMON_ASSAULT_BOT = 40, + EVENT_SUMMON_JUNK_BOT = 41, + EVENT_MAGNETIC_CORE_PULL_DOWN = 42, + EVENT_MAGNETIC_CORE_FREE = 43, + EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE = 44, + + // Hard mode: + EVENT_COMPUTER_SAY_INITIATED = 60, + EVENT_COMPUTER_SAY_MINUTES = 61, + EVENT_MIMIRON_SAY_HARDMODE = 62, + EVENT_SPAWN_FLAMES_INITIAL = 63, + EVENT_FLAMES_SPREAD = 64, + EVENT_FLAME_SUPPRESSION_50000 = 65, + EVENT_FLAME_SUPPRESSION_10 = 66, + EVENT_FROST_BOMB = 67, + EVENT_SUMMON_EMERGENCY_FIRE_BOTS = 68, + EVENT_EMERGENCY_BOT_CHECK = 69, + EVENT_EMERGENCY_BOT_ATTACK = 70, +}; + +#define SPELL_NAPALM_SHELL RAID_MODE(SPELL_NAPALM_SHELL_10, SPELL_NAPALM_SHELL_25) +#define SPELL_PLASMA_BLAST RAID_MODE(SPELL_PLASMA_BLAST_10, SPELL_PLASMA_BLAST_25) +#define SPELL_MINE_EXPLOSION RAID_MODE(SPELL_MINE_EXPLOSION_10, SPELL_MINE_EXPLOSION_25) +#define SPELL_PLASMA_BALL RAID_MODE(SPELL_PLASMA_BALL_10, SPELL_PLASMA_BALL_25) +#define SPELL_HAND_PULSE_R RAID_MODE(SPELL_HAND_PULSE_10_R, SPELL_HAND_PULSE_25_R) +#define SPELL_HAND_PULSE_L RAID_MODE(SPELL_HAND_PULSE_10_L, SPELL_HAND_PULSE_25_L) +#define SPELL_FROST_BOMB_EXPLOSION RAID_MODE(SPELL_FROST_BOMB_EXPLOSION_10, SPELL_FROST_BOMB_EXPLOSION_25) + +enum Texts +{ + // Mimiron + SAY_AGGRO = 0, // Unused + SAY_HARDMODE_ON = 1, + SAY_MKII_ACTIVATE = 2, + SAY_MKII_SLAY = 3, + SAY_MKII_DEATH = 4, + SAY_VX001_ACTIVATE = 5, + SAY_VX001_SLAY = 6, + SAY_VX001_DEATH = 7, + SAY_AERIAL_ACTIVATE = 8, + SAY_AERIAL_SLAY = 9, + SAY_AERIAL_DEATH = 10, + SAY_V07TRON_ACTIVATE = 11, + SAY_V07TRON_SLAY = 12, + SAY_V07TRON_DEATH = 13, + SAY_BERSERK = 14, + + // MK II + EMOTE_PLASMA_BLAST = 0, + + // Computer (Hardmode countdown) + TALK_COMPUTER_INITIATED = 0, + TALK_COMPUTER_TERMINATED = 1, + TALK_COMPUTER_TEN = 2, + TALK_COMPUTER_NINE = 3, + TALK_COMPUTER_EIGHT = 4, + TALK_COMPUTER_SEVEN = 5, + TALK_COMPUTER_SIX = 6, + TALK_COMPUTER_FIVE = 7, + TALK_COMPUTER_FOUR = 8, + TALK_COMPUTER_THREE = 9, + TALK_COMPUTER_TWO = 10, + TALK_COMPUTER_ONE = 11, + TALK_COMPUTER_ZERO = 12, +}; + +#define GetMimiron() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_MIMIRON)) +#define GetLMK2() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_LEVIATHAN_MKII)) +#define GetVX001() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_VX001)) +#define GetACU() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_ACU)) + +class boss_mimiron : public CreatureScript +{ +public: + boss_mimiron() : CreatureScript("boss_mimiron") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_mimironAI : public ScriptedAI + { + boss_mimironAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + { + pInstance = me->GetInstanceScript(); + if (!me->IsAlive()) + if (pInstance) + pInstance->SetData(TYPE_MIMIRON, DONE); + bIsEvading = false; + } + + InstanceScript* pInstance; + EventMap events; + SummonList summons; + bool bIsEvading; + bool hardmode; + bool berserk; + bool bAchievProximityMine; + bool bAchievBombBot; + bool bAchievRocketStrike; + uint32 allowedFlameSpreadTime; + bool changeAllowedFlameSpreadTime; + uint8 minutesTalkNum; + uint32 outofCombatTimer; + + void Reset() override + { + hardmode = false; + berserk = false; + bAchievProximityMine = false; + bAchievBombBot = false; + bAchievRocketStrike = false; + allowedFlameSpreadTime = 0; + outofCombatTimer = 0; + changeAllowedFlameSpreadTime = false; + ResetGameObjects(); + events.Reset(); + summons.DespawnAll(); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + + if (pInstance && pInstance->GetData(TYPE_MIMIRON) != DONE) + pInstance->SetData(TYPE_MIMIRON, NOT_STARTED); + } + + void AttackStart(Unit* who) override + { + if (who) + me->Attack(who, true); // skip following + } + + void JustReachedHome() override + { + me->setActive(false); + ScriptedAI::JustReachedHome(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + me->setActive(true); + DoZoneInCombat(); + me->RemoveAllAuras(); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + events.Reset(); + + if (Creature* c = GetLMK2()) + { + if (c->IsInEvadeMode()) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + if (!c->IsAlive()) + c->Respawn(); + + me->EnterVehicle(c, 1); + } + else + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + CloseDoorAndButton(); + + if (!hardmode) + { + Talk(SAY_MKII_ACTIVATE); + events.ScheduleEvent(EVENT_SIT_LMK2, 6s); + events.ScheduleEvent(EVENT_BERSERK, 15min); + } + else + { + events.ScheduleEvent(EVENT_MIMIRON_SAY_HARDMODE, 7s); + events.ScheduleEvent(EVENT_BERSERK, Is25ManRaid() ? 10min : 8min); + + events.ScheduleEvent(EVENT_COMPUTER_SAY_INITIATED, 0ms); + events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, 3s); + minutesTalkNum = Is25ManRaid() ? TALK_COMPUTER_TEN : TALK_COMPUTER_EIGHT; + for (uint32 i = 0; i < uint32(TALK_COMPUTER_ZERO - minutesTalkNum - 1); ++i) + events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, (i + 1)*MINUTE * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, (TALK_COMPUTER_ZERO - minutesTalkNum)*MINUTE * IN_MILLISECONDS + 6000); + } + + // ensure LMK2 is at proper position + if (pInstance) + if (Creature* LMK2 = GetLMK2()) + { + LMK2->UpdatePosition(LMK2->GetHomePosition(), true); + LMK2->StopMovingOnCurrentPos(); + } + + if (pInstance && pInstance->GetData(TYPE_MIMIRON) != DONE) + pInstance->SetData(TYPE_MIMIRON, IN_PROGRESS); + } + + void UpdateAI(uint32 diff) override + { + if (!me->IsInCombat()) + { + outofCombatTimer += diff; + if (outofCombatTimer >= 10000) + { + outofCombatTimer = 0; + if (Creature* c = GetLMK2()) + me->CastSpell(c, RAND(SPELL_ENTER_VEHICLE_0, SPELL_ENTER_VEHICLE_1, SPELL_ENTER_VEHICLE_2, SPELL_ENTER_VEHICLE_4), true); + } + return; + } + + Position p = me->GetHomePosition(); + if (me->GetExactDist(&p) > 80.0f || !SelectTargetFromPlayerList(150.0f)) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + events.Update(diff); + + switch( events.ExecuteEvent() ) + { + case 0: + break; + case EVENT_COMPUTER_SAY_INITIATED: + if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) ) + computer->AI()->Talk(TALK_COMPUTER_INITIATED); + break; + case EVENT_COMPUTER_SAY_MINUTES: + if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) ) + computer->AI()->Talk(minutesTalkNum++); + break; + case EVENT_MIMIRON_SAY_HARDMODE: + Talk(SAY_HARDMODE_ON); + events.ScheduleEvent(EVENT_SPAWN_FLAMES_INITIAL, 0ms); + events.ScheduleEvent(EVENT_SIT_LMK2, 4s); + break; + case EVENT_SPAWN_FLAMES_INITIAL: + { + if (changeAllowedFlameSpreadTime) + allowedFlameSpreadTime = GameTime::GetGameTime().count(); + + std::vector pg; + Map::PlayerList const& pl = me->GetMap()->GetPlayers(); + for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) + if( Player* plr = itr->GetSource() ) + if( plr->IsAlive() && plr->GetExactDist2d(me) < 150.0f && !plr->IsGameMaster() ) + pg.push_back(plr); + + for( uint8 i = 0; i < 3; ++i ) + if( !pg.empty() ) + { + uint8 index = urand(0, pg.size() - 1); + Player* player = pg[index]; + float angle = rand_norm() * 2 * M_PI; + float z = 364.35f; + if (!player->IsWithinLOS(player->GetPositionX() + cos(angle) * 5.0f, player->GetPositionY() + std::sin(angle) * 5.0f, z)) + { + angle = player->GetAngle(2744.65f, 2569.46f); + } + me->CastSpell(player->GetPositionX() + cos(angle) * 5.0f, player->GetPositionY() + std::sin(angle) * 5.0f, z, SPELL_SUMMON_FLAMES_INITIAL, true); + pg.erase(pg.begin() + index); + } + + events.Repeat(30s); + } + break; + case EVENT_BERSERK: + berserk = true; + Talk(SAY_BERSERK); + if( hardmode ) + me->SummonCreature(33576, 2744.78f, 2569.47f, 364.32f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 120000); + events.ScheduleEvent(EVENT_BERSERK_2, 0ms); + break; + case EVENT_BERSERK_2: + { + Creature* VX001 = nullptr; + Creature* LMK2 = nullptr; + Creature* ACU = nullptr; + if ((VX001 = GetVX001())) + VX001->CastSpell(VX001, SPELL_BERSERK, true); + if ((LMK2 = GetLMK2())) + LMK2->CastSpell(LMK2, SPELL_BERSERK, true); + if ((ACU = GetACU())) + ACU->CastSpell(ACU, SPELL_BERSERK, true); + events.Repeat(30s); + } + break; + case EVENT_SIT_LMK2: + if(Creature* LMK2 = GetLMK2()) + { + me->EnterVehicle(LMK2, 6); + events.ScheduleEvent(EVENT_SIT_LMK2_INTERVAL, 2s); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_SIT_LMK2_INTERVAL: + if (Creature* LMK2 = GetLMK2()) + { + if (hardmode) + { + LMK2->CastSpell(LMK2, SPELL_EMERGENCY_MODE, true); + if( Vehicle* veh = LMK2->GetVehicleKit() ) + if( Unit* cannon = veh->GetPassenger(3) ) + cannon->CastSpell(cannon, SPELL_EMERGENCY_MODE, true); + } + LMK2->AI()->SetData(1, 1); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_LMK2_RETREAT_INTERVAL: + if (Creature* LMK2 = GetLMK2()) + { + me->EnterVehicle(LMK2, 1); + Talk(SAY_MKII_DEATH); + LMK2->SetFacingTo(3.58f); + events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_0, 6s); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_ELEVATOR_INTERVAL_0: + if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 100.0f) ) + { + elevator->SetLootState(GO_READY); + elevator->UseDoorOrButton(0, false); + elevator->EnableCollision(false); + } + events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_1, 6s); + break; + case EVENT_ELEVATOR_INTERVAL_1: + if(me->SummonCreature(NPC_VX001, 2744.65f, 2569.46f, 364.40f, 3.14f, TEMPSUMMON_MANUAL_DESPAWN)) + { + if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 100.0f) ) + { + elevator->SetLootState(GO_READY); + elevator->UseDoorOrButton(0, true); + elevator->EnableCollision(false); + } + events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_2, 18s); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_ELEVATOR_INTERVAL_2: + if (Creature* VX001 = GetVX001()) + { + me->EnterVehicle(VX001, 0); + events.ScheduleEvent(EVENT_SITTING_ON_VX001, 4s); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_SITTING_ON_VX001: + Talk(SAY_VX001_ACTIVATE); + events.ScheduleEvent(EVENT_ENTER_VX001, 5s); + break; + case EVENT_ENTER_VX001: + if( Creature* VX001 = GetVX001() ) + { + me->EnterVehicle(VX001, 1); + events.ScheduleEvent(EVENT_EMOTE_VX001, 2s); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_EMOTE_VX001: + if( Creature* VX001 = GetVX001() ) + { + VX001->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + events.ScheduleEvent(EVENT_VX001_START_FIGHT, 1750ms); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_VX001_START_FIGHT: + if( Creature* VX001 = GetVX001() ) + { + if( hardmode ) + VX001->CastSpell(VX001, SPELL_EMERGENCY_MODE, true); + VX001->AI()->SetData(1, 2); + me->SetInCombatWithZone(); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_VX001_EMOTESTATE_DEATH: + if( Creature* VX001 = GetVX001() ) + { + VX001->HandleEmoteCommand(EMOTE_STATE_DROWNED); + VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DROWNED); + events.ScheduleEvent(EVENT_GET_OUT_VX001, 2500ms); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_GET_OUT_VX001: + if( Creature* VX001 = GetVX001() ) + if( Creature* ACU = me->SummonCreature(NPC_AERIAL_COMMAND_UNIT, 2743.91f, 2568.78f, 391.34f, M_PI, TEMPSUMMON_MANUAL_DESPAWN) ) + { + me->EnterVehicle(VX001, 4); + float speed = ACU->GetDistance(2737.75f, 2574.22f, 381.34f) / 2.0f; + ACU->MonsterMoveWithSpeed(2737.75f, 2574.22f, 381.34f, speed); + ACU->SetPosition(2737.75f, 2574.22f, 381.34f, M_PI); + events.ScheduleEvent(EVENT_SAY_VX001_DEAD, 2s); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_SAY_VX001_DEAD: + changeAllowedFlameSpreadTime = true; + Talk(SAY_VX001_DEATH); + events.ScheduleEvent(EVENT_ENTER_ACU, 7s); + break; + case EVENT_ENTER_ACU: + if( Creature* ACU = GetACU() ) + { + me->EnterVehicle(ACU, 0); + events.ScheduleEvent(EVENT_SAY_ACU_ACTIVATE, 6s); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_SAY_ACU_ACTIVATE: + Talk(SAY_AERIAL_ACTIVATE); + events.ScheduleEvent(EVENT_ACU_START_ATTACK, 4s); + break; + case EVENT_ACU_START_ATTACK: + if( Creature* ACU = GetACU() ) + { + if( hardmode ) + ACU->CastSpell(ACU, SPELL_EMERGENCY_MODE, true); + ACU->AI()->SetData(1, 3); + me->SetInCombatWithZone(); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_SAY_ACU_DEAD: + Talk(SAY_AERIAL_DEATH); + events.ScheduleEvent(EVENT_LEVIATHAN_COME_CLOSER, 5s); + break; + case EVENT_LEVIATHAN_COME_CLOSER: + if (Creature* LMK2 = GetLMK2()) + { + LMK2->GetMotionMaster()->MoveCharge(2755.77f, 2574.95f, 364.31f, 21.0f); + events.ScheduleEvent(EVENT_VX001_EMOTE_JUMP, 4s); + break; + } + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_VX001_EMOTE_JUMP: + { + Creature* LMK2 = GetLMK2(); + Creature* VX001 = GetVX001(); + if( !VX001 || !LMK2 ) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + VX001->SendMeleeAttackStop(); + VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_02); + VX001->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_02); + events.ScheduleEvent(EVENT_LEVIATHAN_RIDE_MIDDLE, 4800ms); + } + break; + case EVENT_LEVIATHAN_RIDE_MIDDLE: + { + Creature* VX001 = GetVX001(); + Creature* LMK2 = GetLMK2(); + if( !VX001 || !LMK2 ) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + LMK2->GetMotionMaster()->MoveCharge(2744.65f, 2569.46f, 364.31f, 21.0f); + VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_CUSTOM_SPELL_01); + VX001->HandleEmoteCommand(EMOTE_STATE_CUSTOM_SPELL_01); + VX001->EnterVehicle(LMK2, 3); + events.ScheduleEvent(EVENT_JOIN_TOGETHER, 3s); + } + break; + case EVENT_JOIN_TOGETHER: + { + Creature* ACU = GetACU(); + Creature* VX001 = GetVX001(); + if( !VX001 || !ACU ) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + ACU->SetDisableGravity(false); + ACU->EnterVehicle(VX001, 3); + me->EnterVehicle(VX001, 1); + Talk(SAY_V07TRON_ACTIVATE); + events.ScheduleEvent(EVENT_START_PHASE4, 10s); + } + break; + case EVENT_START_PHASE4: + { + Creature* VX001 = GetVX001(); + Creature* LMK2 = GetLMK2(); + Creature* ACU = GetACU(); + if( !VX001 || !LMK2 || !ACU ) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + LMK2->AI()->SetData(1, 4); + VX001->AI()->SetData(1, 4); + ACU->AI()->SetData(1, 4); + LMK2->CastSpell(LMK2, SPELL_SELF_REPAIR, true); //LMK2->SetHealth( LMK2->GetMaxHealth()/2 ); + VX001->CastSpell(VX001, SPELL_SELF_REPAIR, true); //VX001->SetHealth( VX001->GetMaxHealth()/2 ); + ACU->CastSpell(ACU, SPELL_SELF_REPAIR, true); //ACU->SetHealth( ACU->GetMaxHealth()/2 ); + if( hardmode ) + { + LMK2->CastSpell(LMK2, SPELL_EMERGENCY_MODE, true); + VX001->CastSpell(VX001, SPELL_EMERGENCY_MODE, true); + ACU->CastSpell(ACU, SPELL_EMERGENCY_MODE, true); + } + me->SetInCombatWithZone(); + } + break; + case EVENT_FINISH: + { + Creature* LMK2 = GetLMK2(); + Creature* VX001 = GetVX001(); + Creature* ACU = GetACU(); + + if (!VX001 || !LMK2 || !ACU) + return; + + LMK2->GetMotionMaster()->Clear(); + LMK2->StopMoving(); + LMK2->InterruptNonMeleeSpells(false); + LMK2->AttackStop(); + LMK2->AI()->SetData(1, 0); + LMK2->DespawnOrUnsummon(7000); + LMK2->SetReactState(REACT_PASSIVE); + VX001->InterruptNonMeleeSpells(false); + VX001->AttackStop(); + VX001->AI()->SetData(1, 0); + VX001->DespawnOrUnsummon(7000); + VX001->SetReactState(REACT_PASSIVE); + ACU->InterruptNonMeleeSpells(false); + ACU->AttackStop(); + ACU->AI()->SetData(1, 0); + ACU->DespawnOrUnsummon(7000); + ACU->SetReactState(REACT_PASSIVE); + + Position exitPos = me->GetPosition(); + me->_ExitVehicle(&exitPos); + me->AttackStop(); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); + me->GetMotionMaster()->Clear(); + summons.DoAction(1337); // despawn summons of summons + summons.DespawnEntry(NPC_FLAMES_INITIAL); + summons.DespawnEntry(33576); + + float angle = VX001->GetOrientation(); + float v_x = me->GetPositionX() + cos(angle) * 10.0f; + float v_y = me->GetPositionY() + std::sin(angle) * 10.0f; + me->GetMotionMaster()->MoveJump(v_x, v_y, 364.32f, 7.0f, 7.0f); + + if( pInstance ) + for( uint16 i = 0; i < 3; ++i ) + if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) ) + if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) ) + if( door->GetGoState() != GO_STATE_ACTIVE ) + { + door->SetLootState(GO_READY); + door->UseDoorOrButton(0, false); + } + + if (pInstance) + pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_LEVIATHAN_MKII, 1, me); + + if (hardmode) + if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) ) + computer->AI()->Talk(TALK_COMPUTER_TERMINATED); + + events.Reset(); + events.ScheduleEvent(EVENT_SAY_VOLTRON_DEAD, 6s); + } + break; + case EVENT_SAY_VOLTRON_DEAD: + Talk(SAY_V07TRON_DEATH); + // spawn chest + if (uint32 chestId = (hardmode ? RAID_MODE(GO_MIMIRON_CHEST_HARD, GO_MIMIRON_CHEST_HERO_HARD) : RAID_MODE(GO_MIMIRON_CHEST, GO_MIMIRON_CHEST_HERO))) + { + if (GameObject* go = me->SummonGameObject(chestId, 2744.65f, 2569.46f, 364.397f, 0, 0, 0, 0, 0, 0)) + { + go->ReplaceAllGameObjectFlags((GameObjectFlags)0); + go->SetLootRecipient(me->GetMap()); + } + } + events.ScheduleEvent(EVENT_DISAPPEAR, 15s); + break; + case EVENT_DISAPPEAR: + if( pInstance ) + pInstance->SetData(TYPE_MIMIRON, DONE); + summons.DespawnAll(); + me->DespawnOrUnsummon(); + break; + } + } + + void MoveInLineOfSight(Unit* /*mover*/) override {} + + void EnterEvadeMode(EvadeReason why) override + { + if (bIsEvading) + return; + bIsEvading = true; + + if (Creature* c = GetLMK2()) + { + c->AI()->EnterEvadeMode(why); + } + if (Creature* c = GetVX001()) + { + c->AI()->EnterEvadeMode(why); + c->DespawnOrUnsummon(); + } + if (Creature* c = GetACU()) + { + c->AI()->EnterEvadeMode(why); + c->DespawnOrUnsummon(); + } + + summons.DoAction(1337); // despawn summons of summons + + me->RemoveAllAuras(); + me->ExitVehicle(); + ScriptedAI::EnterEvadeMode(why); + + bIsEvading = false; + } + + void JustSummoned(Creature* s) override + { + summons.Summon(s); + } + + void SummonedCreatureDespawn(Creature* s) override + { + summons.Despawn(s); + } + + void ResetGameObjects() + { + if( pInstance ) + for( uint16 i = 0; i < 3; ++i ) + if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) ) + if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) ) + if( door->GetGoState() != GO_STATE_ACTIVE ) + { + door->SetLootState(GO_READY); + door->UseDoorOrButton(0, false); + } + + if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 200.0f) ) + { + if( elevator->GetGoState() != GO_STATE_ACTIVE ) + { + elevator->SetLootState(GO_READY); + elevator->SetByteValue(GAMEOBJECT_BYTES_1, 0, GO_STATE_ACTIVE); + } + elevator->EnableCollision(false); + } + + if( GameObject* button = me->FindNearestGameObject(GO_BUTTON, 200.0f) ) + if( button->GetGoState() != GO_STATE_READY ) + { + button->SetLootState(GO_READY); + button->UseDoorOrButton(0, false); + button->RemoveGameObjectFlag(GO_FLAG_IN_USE); + } + } + + void CloseDoorAndButton() + { + if( pInstance ) + for( uint16 i = 0; i < 3; ++i ) + if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) ) + if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) ) + if( door->GetGoState() != GO_STATE_READY ) + { + door->SetLootState(GO_READY); + door->UseDoorOrButton(0, false); + } + + if( GameObject* button = me->FindNearestGameObject(GO_BUTTON, 200.0f) ) + if( button->GetGoState() != GO_STATE_ACTIVE ) + { + button->SetLootState(GO_READY); + button->UseDoorOrButton(0, false); + } + } + + void SetData(uint32 /*id*/, uint32 value) override + { + switch (value) // end of phase 1-3, 4-6 for voltron + { + case 1: + events.ScheduleEvent(EVENT_LMK2_RETREAT_INTERVAL, 5s); + break; + case 2: + events.ScheduleEvent(EVENT_VX001_EMOTESTATE_DEATH, 2500ms); + break; + case 3: + events.ScheduleEvent(EVENT_SAY_ACU_DEAD, 5s); + break; + case 4: + case 5: + case 6: + { + Creature* LMK2 = GetLMK2(); + Creature* VX001 = GetVX001(); + Creature* ACU = GetACU(); + if (!LMK2 || !VX001 || !ACU) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + Spell* s1 = LMK2->GetCurrentSpell(CURRENT_GENERIC_SPELL); + Spell* s2 = VX001->GetCurrentSpell(CURRENT_GENERIC_SPELL); + Spell* s3 = ACU->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (s1 && s2 && s3 && s1->GetSpellInfo()->Id == SPELL_SELF_REPAIR && s2->GetSpellInfo()->Id == SPELL_SELF_REPAIR && s3->GetSpellInfo()->Id == SPELL_SELF_REPAIR) + events.ScheduleEvent(EVENT_FINISH, 0ms); + } + break; + case 7: + hardmode = true; + break; + case 11: + bAchievProximityMine = true; + break; + case 12: + bAchievBombBot = true; + break; + case 13: + bAchievRocketStrike = true; + break; + } + } + + uint32 GetData(uint32 id) const override + { + switch (id) + { + case 1: + return (hardmode ? 1 : 0); + case 2: + return (berserk ? 1 : 0); + case 10: + return allowedFlameSpreadTime; + case 11: + return (bAchievProximityMine ? 1 : 0); + case 12: + return (bAchievBombBot ? 1 : 0); + case 13: + return (bAchievRocketStrike ? 1 : 0); + } + return 0; + } + }; +}; + +class npc_ulduar_leviathan_mkii : public CreatureScript +{ +public: + npc_ulduar_leviathan_mkii() : CreatureScript("npc_ulduar_leviathan_mkii") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_leviathan_mkiiAI : public ScriptedAI + { + npc_ulduar_leviathan_mkiiAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = me->GetInstanceScript(); + bIsEvading = false; + } + + InstanceScript* pInstance; + EventMap events; + bool bIsEvading; + uint8 Phase; + + void Reset() override + { + Phase = 0; + if (Unit* c = GetS3()) + c->ExitVehicle(); // this should never happen! + if (Creature* c = me->SummonCreature(NPC_LEVIATHAN_MKII_CANNON, *me, TEMPSUMMON_MANUAL_DESPAWN)) + c->EnterVehicle(me, 3); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + + events.Reset(); + } + + void SetData(uint32 id, uint32 value) override + { + if (id == 1) // setting phase to start fighting + { + switch (value) + { + case 0: + Phase = 0; + events.Reset(); + break; + case 1: + Phase = 1; + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + if (Unit* target = SelectTargetFromPlayerList(75.0f)) + AttackStart(target); + DoZoneInCombat(); + events.Reset(); + events.ScheduleEvent(EVENT_SPELL_NAPALM_SHELL, 3s); + events.ScheduleEvent(EVENT_SPELL_PLASMA_BLAST, 10s); + events.ScheduleEvent(EVENT_SPELL_SHOCK_BLAST, 20s); + events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 6s); + if (Creature* c = GetMimiron()) + if (c->AI()->GetData(1)) + events.ScheduleEvent(EVENT_FLAME_SUPPRESSION_50000, 60s); + break; + case 4: + me->SetReactState(REACT_AGGRESSIVE); + DoResetThreatList(); + Phase = 4; + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + if (Unit* target = SelectTargetFromPlayerList(75.0f)) + AttackStart(target); + DoZoneInCombat(); + events.Reset(); + events.ScheduleEvent(EVENT_SPELL_SHOCK_BLAST, 20s); + events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 6s); + break; + } + } + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage >= me->GetHealth() || me->GetHealth() < 15000) + { + damage = 0; + if (me->GetReactState() == REACT_PASSIVE) + return; + me->SetReactState(REACT_PASSIVE); + if (Phase == 1) + { + if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + { + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->GetMotionMaster()->Clear(); + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + SetData(1, 0); + me->InterruptNonMeleeSpells(false); + me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); + if (Unit* cannon = GetS3()) + cannon->ExitVehicle(); + me->GetMotionMaster()->MoveCharge(2795.076f, 2598.616f, 364.32f, 21.0f); + if (Creature* c = GetMimiron()) + c->AI()->SetData(0, 1); + } + } + else if (Phase == 4) + { + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + { + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->InterruptNonMeleeSpells(false); + me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); + me->CastSpell(me, SPELL_SELF_REPAIR, false); + if (Creature* c = GetMimiron()) + { + if (c->AI()->GetData(1)) + me->CastSpell(me, SPELL_EMERGENCY_MODE, true); + if (c->AI()->GetData(2)) + me->CastSpell(me, SPELL_BERSERK, true); + c->AI()->SetData(0, 4); + } + } + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (!me->HasUnitState(UNIT_STATE_CASTING)) + DoMeleeAttackIfReady(); + + Unit* cannon = GetS3(); + if (!cannon || cannon->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CASTING) || me->HasAuraType(SPELL_AURA_MOD_SILENCE)) + return; + + switch (events.ExecuteEvent()) + { + case 0: + break; + case EVENT_SPELL_NAPALM_SHELL: + { + Player* pTarget = nullptr; + std::vector pList; + Map::PlayerList const& pl = me->GetMap()->GetPlayers(); + for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) + if (Player* plr = itr->GetSource()) + if( plr->IsAlive() && plr->GetDistance2d(me) > 15.0f ) + pList.push_back(plr); + + if (!pList.empty()) + pTarget = pList[urand(0, pList.size() - 1)]; + else + pTarget = (Player*)SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true); + + if( pTarget ) + cannon->CastSpell(pTarget, SPELL_NAPALM_SHELL, false); + + events.Repeat(14s); + } + break; + case EVENT_SPELL_PLASMA_BLAST: + if (Unit* victim = me->GetVictim()) + { + Talk(EMOTE_PLASMA_BLAST); + cannon->CastSpell(victim, SPELL_PLASMA_BLAST, false); + } + events.Repeat(22s); + break; + case EVENT_SPELL_SHOCK_BLAST: + me->CastSpell(me->GetVictim(), SPELL_SHOCK_BLAST, false); + events.Repeat(30s); + events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 8s); + break; + case EVENT_PROXIMITY_MINES_1: + for (uint8 i = 0; i < 10; ++i) + { + me->CastSpell(me, SPELL_SUMMON_PROXIMITY_MINE, true); + } + break; + case EVENT_FLAME_SUPPRESSION_50000: + me->CastSpell(me, SPELL_FLAME_SUPPRESSANT_50000yd, false); + break; + } + } + + void MoveInLineOfSight(Unit* /*mover*/) override {} + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER) + if (Creature* c = GetMimiron()) + { + if (Phase == 1) + { + c->AI()->Talk(SAY_MKII_SLAY); + } + else + { + c->AI()->Talk(SAY_V07TRON_SLAY); + } + } + } + + void EnterEvadeMode(EvadeReason why) override + { + if (bIsEvading) + return; + bIsEvading = true; + + me->RemoveAllAuras(); + me->ExitVehicle(); + ScriptedAI::EnterEvadeMode(); + + if (Creature* mimiron = GetMimiron()) + mimiron->AI()->EnterEvadeMode(why); + + bIsEvading = false; + } + + void PassengerBoarded(Unit* p, int8 /*seat*/, bool apply) override + { + if (p->GetEntry() == NPC_LEVIATHAN_MKII_CANNON && !apply) + { + Unit::Kill(p, p); + p->ToCreature()->DespawnOrUnsummon(6000); + } + } + + Unit* GetS3() + { + if (Vehicle* vk = me->GetVehicleKit()) + if (Unit* cannon = vk->GetPassenger(3)) + return cannon; + + return 0; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if( spell->Id == SPELL_SELF_REPAIR ) + { + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + } + } + }; +}; + +class npc_ulduar_vx001 : public CreatureScript +{ +public: + npc_ulduar_vx001() : CreatureScript("npc_ulduar_vx001") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_vx001AI : public ScriptedAI + { + npc_ulduar_vx001AI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = me->GetInstanceScript(); + bIsEvading = false; + } + + InstanceScript* pInstance; + EventMap events; + bool bIsEvading; + uint8 Phase; + bool fighting; + bool leftarm; + uint32 spinningUpOrientation; + uint16 spinningUpTimer; + + void Reset() override + { + Phase = 0; + fighting = false; + leftarm = false; + spinningUpTimer = 0; + me->SetRegeneratingHealth(false); + events.Reset(); + } + + void AttackStart(Unit* /*who*/) override {} + + void SetData(uint32 id, uint32 value) override + { + if (id == 1) // setting phase to start fighting + { + switch (value) + { + case 0: + Phase = 0; + fighting = false; + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + events.Reset(); + break; + case 2: + Phase = 2; + fighting = true; + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_SPELL_CAST_OMNI); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + events.Reset(); + events.ScheduleEvent(EVENT_SPELL_HEAT_WAVE, 10s); + events.ScheduleEvent(EVENT_SPELL_ROCKET_STRIKE, 16s); + events.ScheduleEvent(EVENT_SPELL_RAPID_BURST, 0ms); + events.ScheduleEvent(EVENT_SPELL_SPINNING_UP, 30s); + events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 3s); + if (Creature* c = GetMimiron()) + if (c->AI()->GetData(1)) + { + events.ScheduleEvent(EVENT_FLAME_SUPPRESSION_10, 7s); + events.ScheduleEvent(EVENT_FROST_BOMB, 1s); + } + break; + case 4: + Phase = 4; + fighting = true; + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + events.Reset(); + events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 3s); + events.ScheduleEvent(EVENT_SPELL_ROCKET_STRIKE, 16s); + events.ScheduleEvent(EVENT_HAND_PULSE, 1ms); + events.ScheduleEvent(EVENT_SPELL_SPINNING_UP, 30s); + if (Creature* c = GetMimiron()) + if (c->AI()->GetData(1)) + events.ScheduleEvent(EVENT_FROST_BOMB, 1s); + break; + } + } + } + + uint32 GetData(uint32 /*id*/) const override + { + return spinningUpOrientation; + } + + void DoAction(int32 action) override + { + if (action == 1337) + if( Vehicle* vk = me->GetVehicleKit() ) + for (uint8 i = 0; i < 2; ++i) + if (Unit* r = vk->GetPassenger(5 + i)) + if (r->GetTypeId() == TYPEID_UNIT) + r->ToCreature()->DespawnOrUnsummon(1); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage >= me->GetHealth() || me->GetHealth() < 15000) + { + damage = 0; + if (me->GetReactState() == REACT_PASSIVE) + return; + me->SetReactState(REACT_PASSIVE); + if (Phase == 2) + { + if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + { + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + SetData(1, 0); + me->InterruptNonMeleeSpells(false); + me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); + me->SendMeleeAttackStop(); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_06); + me->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_06); + if (Creature* c = GetMimiron()) + c->AI()->SetData(0, 2); + } + } + else if (Phase == 4) + { + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + { + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->InterruptNonMeleeSpells(false); + me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); + me->CastSpell(me, SPELL_SELF_REPAIR, false); + if (Creature* c = GetMimiron()) + { + if (c->AI()->GetData(1)) + me->CastSpell(me, SPELL_EMERGENCY_MODE, true); + if (c->AI()->GetData(2)) + me->CastSpell(me, SPELL_BERSERK, true); + c->AI()->SetData(0, 5); + } + } + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!fighting) + return; + + events.Update(diff); + + if (spinningUpTimer) // executed about a second after starting casting to ensure players can see the correct direction + { + if (spinningUpTimer <= diff) + { + float angle = (spinningUpOrientation * 2 * M_PI) / 100.0f; + me->SetFacingTo(angle); + + spinningUpTimer = 0; + } + else + spinningUpTimer -= diff; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case 0: + break; + case EVENT_SPELL_HEAT_WAVE: + me->CastSpell(me, SPELL_HEAT_WAVE, true); + events.Repeat(10s); + break; + case EVENT_SPELL_ROCKET_STRIKE: + if( Vehicle* vk = me->GetVehicleKit() ) + { + for( int i = 0; i < (Phase / 2); ++i ) + { + uint8 index = (Phase == 2 ? rand() % 2 : i); + if( Unit* r = vk->GetPassenger(5 + index) ) + if (Player* temp = SelectTargetFromPlayerList(100.0f)) + { + if( Creature* trigger = me->SummonCreature(NPC_ROCKET_STRIKE_N, temp->GetPositionX(), temp->GetPositionY(), temp->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 6000) ) + trigger->CastSpell(trigger, SPELL_ROCKET_STRIKE_AURA, true); + Position exitPos = r->GetPosition(); + exitPos.m_positionX += cos(me->GetOrientation()) * 2.35f; + exitPos.m_positionY += std::sin(me->GetOrientation()) * 2.35f; + exitPos.m_positionZ += 2.0f * Phase; + r->_ExitVehicle(&exitPos); + me->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE, r->GetGUID()); + if (r->GetTypeId() == TYPEID_UNIT) + r->ToCreature()->AI()->SetData(0, 0); + } + } + events.Repeat(20s); + events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 10s); + } + break; + case EVENT_REINSTALL_ROCKETS: + if (Vehicle* vk = me->GetVehicleKit()) + { + for (uint8 i = 5; i <= 6; ++i) + if (!vk->GetPassenger(i)) + if (TempSummon* accessory = me->SummonCreature(NPC_ROCKET_VISUAL, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 4.0f, me->GetOrientation(), TEMPSUMMON_MANUAL_DESPAWN)) + if (!me->HandleSpellClick(accessory, i)) + accessory->UnSummon(); + } + break; + case EVENT_SPELL_RAPID_BURST: + if (Player* p = SelectTargetFromPlayerList(80.0f)) + { + me->CastSpell(p, SPELL_RAPID_BURST, true); + me->SetFacingToObject(p); + } + events.Repeat(3200ms); + break; + case EVENT_HAND_PULSE: + if (Player* p = SelectTargetFromPlayerList(80.0f)) + { + me->SetFacingToObject(p); + if (Unit* vb = me->GetVehicleBase()) + { + vb->SendMeleeAttackStop(); + vb->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + + if( !leftarm ) + { + vb->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_03); + me->CastSpell(p, SPELL_HAND_PULSE_R, false); + } + else + { + vb->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_04); + me->CastSpell(p, SPELL_HAND_PULSE_L, false); + } + } + + leftarm = !leftarm; + } + events.Repeat(1750ms); + break; + case EVENT_SPELL_SPINNING_UP: + events.Repeat(45s); + if (Player* p = SelectTargetFromPlayerList(80.0f)) + { + float angle = me->GetAngle(p); + + spinningUpOrientation = (uint32)((angle * 100.0f) / (2 * M_PI)); + spinningUpTimer = 1500; + me->SetFacingTo(angle); + me->CastSpell(p, SPELL_SPINNING_UP, true); + if (Unit* vehicle = me->GetVehicleBase()) + { + vehicle->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_CUSTOM_SPELL_01); + vehicle->HandleEmoteCommand(EMOTE_STATE_CUSTOM_SPELL_01); + } + events.RescheduleEvent((Phase == 2 ? EVENT_SPELL_RAPID_BURST : EVENT_HAND_PULSE), 14s + 500ms); + } + break; + case EVENT_FLAME_SUPPRESSION_10: + me->CastSpell(me, SPELL_FLAME_SUPPRESSANT_10yd, false); + events.Repeat(10s); + break; + case EVENT_FROST_BOMB: + me->CastCustomSpell(SPELL_VX001_FROST_BOMB, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false); + events.Repeat(45s); + break; + } + } + + void MoveInLineOfSight(Unit* /*mover*/) override {} + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER) + if (Creature* c = GetMimiron()) + { + if (Phase == 2) + { + c->AI()->Talk(SAY_VX001_SLAY); + } + else + { + c->AI()->Talk(SAY_V07TRON_SLAY); + } + } + } + + void EnterEvadeMode(EvadeReason why) override + { + if (bIsEvading) + return; + bIsEvading = true; + + me->RemoveAllAuras(); + me->ExitVehicle(); + _EnterEvadeMode(); + Reset(); + if (Creature* mimiron = GetMimiron()) + mimiron->AI()->EnterEvadeMode(why); + + bIsEvading = false; + } + + void PassengerBoarded(Unit* p, int8 /*seat*/, bool apply) override + { + if (p->GetEntry() == NPC_ROCKET_VISUAL && !apply) + p->ToCreature()->DespawnOrUnsummon(8000); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if( spell->Id == SPELL_SELF_REPAIR ) + { + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + } + } + }; +}; + +class npc_ulduar_aerial_command_unit : public CreatureScript +{ +public: + npc_ulduar_aerial_command_unit() : CreatureScript("npc_ulduar_aerial_command_unit") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_aerial_command_unitAI : public ScriptedAI + { + npc_ulduar_aerial_command_unitAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + { + pInstance = me->GetInstanceScript(); + bIsEvading = false; + immobilized = false; + me->SetDisableGravity(true); + } + + InstanceScript* pInstance; + EventMap events; + SummonList summons; + bool bIsEvading; + uint8 Phase; + bool immobilized; + + void Reset() override + { + Phase = 0; + events.Reset(); + summons.DespawnAll(); + } + + void AttackStart(Unit* who) override + { + if (who) + me->Attack(who, true); // skip following + } + + void SetData(uint32 id, uint32 value) override + { + if (id == 1) // setting phase to start fighting + { + switch (value) + { + case 0: + Phase = 0; + events.Reset(); + immobilized = false; + break; + case 3: + Phase = 3; + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + if (Unit* target = SelectTargetFromPlayerList(75.0f)) + AttackStart(target); + DoZoneInCombat(); + events.Reset(); + events.ScheduleEvent(EVENT_SPELL_PLASMA_BALL, 0ms); + events.ScheduleEvent(EVENT_SUMMON_BOMB_BOT, 15s); + events.ScheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 1s); + events.ScheduleEvent(EVENT_SUMMON_JUNK_BOT, 10s); + if (Creature* c = GetMimiron()) + if (c->AI()->GetData(1)) + events.ScheduleEvent(EVENT_SUMMON_EMERGENCY_FIRE_BOTS, 0ms); + break; + case 4: + me->SetReactState(REACT_AGGRESSIVE); + DoResetThreatList(); + Phase = 4; + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + if (Unit* target = SelectTargetFromPlayerList(75.0f)) + AttackStart(target); + DoZoneInCombat(); + events.Reset(); + events.ScheduleEvent(EVENT_SPELL_PLASMA_BALL, 0ms); + } + } + else if (id == 2 && !immobilized && Phase == 3) // magnetic core + { + immobilized = true; + events.ScheduleEvent(EVENT_MAGNETIC_CORE_PULL_DOWN, 2s); + } + } + + void DoAction(int32 param) override + { + if (param == 1337) + summons.DespawnAll(); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage >= me->GetHealth() || me->GetHealth() < 15000) + { + damage = 0; + if (me->GetReactState() == REACT_PASSIVE) + return; + me->SetReactState(REACT_PASSIVE); + if (Phase == 3) + { + if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + { + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->GetMotionMaster()->Clear(); + me->StopMoving(); + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + SetData(1, 0); + me->InterruptNonMeleeSpells(false); + me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); + + me->MonsterMoveWithSpeed(2744.65f, 2569.46f, 381.34f, me->GetDistance(2744.65f, 2569.46f, 381.34f)); + me->UpdatePosition(2744.65f, 2569.46f, 381.34f, M_PI, false); + + if (Creature* c = GetMimiron()) + c->AI()->SetData(0, 3); + } + } + else if (Phase == 4) + { + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + { + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->InterruptNonMeleeSpells(false); + me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE); + me->CastSpell(me, SPELL_SELF_REPAIR, false); + if (Creature* c = GetMimiron()) + { + if (c->AI()->GetData(1)) + me->CastSpell(me, SPELL_EMERGENCY_MODE, true); + if (c->AI()->GetData(2)) + me->CastSpell(me, SPELL_BERSERK, true); + c->AI()->SetData(0, 6); + } + } + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + // following :D + if( Phase == 3 && !immobilized ) + if( Unit* victim = me->GetVictim() ) + if( me->GetExactDist2d(victim) > 25.0f ) + { + float angle = victim->GetAngle(me->GetPositionX(), me->GetPositionY()); + me->SetOrientation( me->GetAngle(victim->GetPositionX(), victim->GetPositionY()) ); + float x = victim->GetPositionX() + 15.0f * cos(angle); + float y = victim->GetPositionY() + 15.0f * std::sin(angle); + + // check if there's magnetic core in line of movement + Creature* mc = nullptr; + std::list cl; + me->GetCreaturesWithEntryInRange(cl, me->GetExactDist2d(victim), NPC_MAGNETIC_CORE); + for( std::list::iterator itr = cl.begin(); itr != cl.end(); ++itr ) + { + if ((*itr)->IsInBetween(me, victim, 4.0f) && (*itr)->GetExactDist2d(victim) >= 10.0f) // don't come very close just because there's a magnetic core + { + x = (*itr)->GetPositionX(); + y = (*itr)->GetPositionY(); + mc = (*itr); + break; + } + } + + float speed = me->GetExactDist(x, y, 381.34f); + me->MonsterMoveWithSpeed(x, y, 381.34f, speed); + me->UpdatePosition(x, y, 381.34f, me->GetAngle(victim), false); + if (mc) + { + mc->AI()->SetData(0, 0); + SetData(2, 1); + } + } + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case 0: + break; + case EVENT_SPELL_PLASMA_BALL: + if( !immobilized ) + { + if (Phase == 3) + { + if( Unit* victim = me->GetVictim() ) + me->CastSpell(victim, SPELL_PLASMA_BALL, false); + } + else + { + if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 27.5f, true)) + { + me->SetFacingToObject(victim); + me->CastSpell(victim, SPELL_PLASMA_BALL, false); + } + } + } + events.Repeat(3s); + break; + case EVENT_SUMMON_BOMB_BOT: + if( !immobilized ) + me->CastSpell(me, SPELL_SUMMON_BOMB_BOT, false); + events.Repeat(15s); + break; + case EVENT_SUMMON_ASSAULT_BOT: + if( GameObject* pad = me->FindNearestGameObject(RAND(194742, 194746, 194745), 200.0f) ) + if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_TIMED_DESPAWN, 15000)) + trigger->AI()->DoAction(2); + events.Repeat(30s); + break; + case EVENT_SUMMON_JUNK_BOT: + if( GameObject* pad = me->FindNearestGameObject(RAND(194741, 194744, 194747), 200.0f) ) + if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_TIMED_DESPAWN, 15000)) + trigger->AI()->DoAction(1); + events.Repeat(10s); + break; + case EVENT_SUMMON_EMERGENCY_FIRE_BOTS: + { + uint32 ids[3] = {194740, 194743, 194748}; + for( uint8 i = 0; i < 3; ++i ) + if( GameObject* pad = me->FindNearestGameObject(ids[i], 200.0f) ) + if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_MANUAL_DESPAWN)) + trigger->AI()->DoAction(3); + events.Repeat(45s); + } + break; + case EVENT_MAGNETIC_CORE_PULL_DOWN: + me->CastSpell(me, SPELL_MAGNETIC_CORE, true); + me->CastSpell(me, SPELL_SPINNING, true); + me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 365.34f, me->GetExactDist(me->GetPositionX(), me->GetPositionY(), 365.34f)); + me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), 365.34f, me->GetOrientation(), false); + events.ScheduleEvent(EVENT_MAGNETIC_CORE_FREE, 20s); + break; + case EVENT_MAGNETIC_CORE_FREE: + me->RemoveAura(SPELL_SPINNING); + me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 381.34f, me->GetDistance(me->GetPositionX(), me->GetPositionY(), 381.34f)); + me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), 381.34f, me->GetOrientation(), false); + events.ScheduleEvent(EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE, 1s); + break; + case EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE: + immobilized = false; + break; + } + } + + void MoveInLineOfSight(Unit* /*mover*/) override {} + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER) + if (Creature* c = GetMimiron()) + { + if (Phase == 3) + { + c->AI()->Talk(SAY_AERIAL_SLAY); + } + else + { + c->AI()->Talk(SAY_V07TRON_SLAY); + } + } + } + + void EnterEvadeMode(EvadeReason why) override + { + if (bIsEvading) + return; + bIsEvading = true; + + me->RemoveAllAuras(); + me->ExitVehicle(); + _EnterEvadeMode(); + Reset(); + if (Creature* mimiron = GetMimiron()) + mimiron->AI()->EnterEvadeMode(why); + + bIsEvading = false; + } + + void JustSummoned(Creature* s) override + { + summons.Summon(s); + if (s->GetEntry() == NPC_BOMB_BOT) + s->m_positionZ = 364.34f; + } + + void SummonedCreatureDespawn(Creature* s) override + { + summons.Despawn(s); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if( spell->Id == SPELL_SELF_REPAIR ) + { + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + } + } + }; +}; + +class npc_ulduar_proximity_mine : public CreatureScript +{ +public: + npc_ulduar_proximity_mine() : CreatureScript("npc_ulduar_proximity_mine") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_proximity_mineAI : public ScriptedAI + { + npc_ulduar_proximity_mineAI(Creature* pCreature) : ScriptedAI(pCreature) + { + exploded = false; + timer = 2500; + timer2 = 35000; + } + + bool exploded; + uint16 timer; + uint16 timer2; + + void AttackStart(Unit* /*who*/) override {} + void MoveInLineOfSight(Unit* /*who*/) override {} + bool CanAIAttack(Unit const* /*target*/) const override { return false; } + + void SpellHitTarget(Unit* target, SpellInfo const* spell) override + { + if (target && spell && target->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_MINE_EXPLOSION) + if (InstanceScript* pInstance = me->GetInstanceScript()) + if (Creature* c = GetMimiron()) + c->AI()->SetData(0, 11); + } + + // MoveInLineOfSight is checked every few yards, can't use it + void UpdateAI(uint32 diff) override + { + if (timer2 <= diff) + { + timer2 = 35000; + if (!exploded) + { + exploded = true; + me->CastSpell(me, SPELL_MINE_EXPLOSION, false); + } + } + else + timer2 -= diff; + + if (timer <= diff) + { + timer = 500; + if (!exploded && SelectTargetFromPlayerList(1.9f)) + { + exploded = true; + me->CastSpell(me, SPELL_MINE_EXPLOSION, false); + } + } + else + timer -= diff; + } + }; +}; + +class npc_ulduar_mimiron_rocket : public CreatureScript +{ +public: + npc_ulduar_mimiron_rocket() : CreatureScript("npc_ulduar_mimiron_rocket") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_mimiron_rocketAI : public NullCreatureAI + { + npc_ulduar_mimiron_rocketAI(Creature* pCreature) : NullCreatureAI(pCreature) {} + + void InitializeAI() override + { + if (!me->isDead()) + Reset(); + } + + void Reset() override + { + me->SetCanFly(true); + me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING); + me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); + } + + void SetData(uint32 /*id*/, uint32 /*value*/) override + { + me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 100.0f, false, true); + } + + void UpdateAI(uint32 /*diff*/) override + { + if (!me->GetVehicle()) + { + me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN) + 0.4f, false); + me->SetSpeed(MOVE_FLIGHT, me->GetSpeedRate(MOVE_RUN), false); + } + } + }; +}; + +class npc_ulduar_magnetic_core : public CreatureScript +{ +public: + npc_ulduar_magnetic_core() : CreatureScript("npc_ulduar_magnetic_core") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_magnetic_coreAI : public NullCreatureAI + { + npc_ulduar_magnetic_coreAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + pInstance = me->GetInstanceScript(); + if (Creature* c = GetACU()) + if (c->GetExactDist2d(me) <= 10.0f) + { + me->SendMonsterMove(c->GetPositionX(), c->GetPositionY(), 364.313f, 1); + me->UpdatePosition(c->GetPositionX(), c->GetPositionY(), 364.313f, me->GetOrientation(), true); + me->StopMovingOnCurrentPos(); + c->AI()->SetData(2, 1); + despawnTimer = 20000; + return; + } + despawnTimer = 60000; + } + + InstanceScript* pInstance; + uint16 despawnTimer; + + void SetData(uint32 /*id*/, uint32 /*value*/) override + { + despawnTimer = 20000; + } + + void UpdateAI(uint32 diff) override + { + if (despawnTimer <= diff) + { + despawnTimer = 60000; + me->DespawnOrUnsummon(1); + } + else + despawnTimer -= diff; + } + }; +}; + +class npc_ulduar_bot_summon_trigger : public CreatureScript +{ +public: + npc_ulduar_bot_summon_trigger() : CreatureScript("npc_ulduar_bot_summon_trigger") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_bot_summon_triggerAI : public NullCreatureAI + { + npc_ulduar_bot_summon_triggerAI(Creature* pCreature) : NullCreatureAI(pCreature) { } + + uint32 timer; + uint8 option; + + void Reset() override + { + timer = 8000; + option = 0; + } + + void DoAction(int32 param) override + { + switch( param ) + { + case 1: + me->CastSpell(me, SPELL_BEAM_GREEN, true); + option = 1; + break; + case 2: + me->CastSpell(me, SPELL_BEAM_YELLOW, true); + option = 2; + break; + case 3: + me->CastSpell(me, SPELL_BEAM_BLUE, true); + option = 3; + break; + } + } + + void UpdateAI(uint32 diff) override + { + if( timer <= diff ) + { + uint32 option_npcid[3] = {NPC_JUNK_BOT, NPC_ASSAULT_BOT, NPC_EMERGENCY_FIRE_BOT}; + InstanceScript* pInstance = me->GetInstanceScript(); + if (Creature* ACU = GetACU()) // ACU summons for easy removing + if( Creature* bot = ACU->SummonCreature( option_npcid[option - 1], *me, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 25000 ) ) + { + if( option < 3 ) + bot->SetInCombatWithZone(); + if (Creature* m = GetMimiron()) + if (m->AI()->GetData(1)) // hardmode + bot->CastSpell(bot, SPELL_EMERGENCY_MODE, true); + } + + me->DespawnOrUnsummon(500); + timer = 99999; + } + else + timer -= diff; + } + }; +}; + +class spell_mimiron_rapid_burst : public SpellScriptLoader +{ +public: + spell_mimiron_rapid_burst() : SpellScriptLoader("spell_mimiron_rapid_burst") { } + + class spell_mimiron_rapid_burst_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mimiron_rapid_burst_AuraScript) + + void HandleEffectPeriodic(AuraEffect const* aurEff) + { + if (Unit* c = GetCaster()) + { + uint32 id = ( c->GetMap()->Is25ManRaid() ? ((aurEff->GetTickNumber() % 2) ? SPELL_RAPID_BURST_DAMAGE_25_2 : SPELL_RAPID_BURST_DAMAGE_25_1) : ((aurEff->GetTickNumber() % 2) ? SPELL_RAPID_BURST_DAMAGE_10_2 : SPELL_RAPID_BURST_DAMAGE_10_1) ); + c->CastSpell((Unit*)nullptr, id, true); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_rapid_burst_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_mimiron_rapid_burst_AuraScript(); + } +}; + +class spell_mimiron_p3wx2_laser_barrage : public SpellScriptLoader +{ +public: + spell_mimiron_p3wx2_laser_barrage() : SpellScriptLoader("spell_mimiron_p3wx2_laser_barrage") { } + + class spell_mimiron_p3wx2_laser_barrage_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mimiron_p3wx2_laser_barrage_AuraScript) + + uint32 lastMSTime; + float lastOrientation; + + bool Load() override + { + lastMSTime = GameTime::GetGameTimeMS().count(); + lastOrientation = -1.0f; + return true; + } + + void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) + { + if (Unit* c = GetCaster()) + { + if (c->GetTypeId() != TYPEID_UNIT) + return; + uint32 diff = getMSTimeDiff(lastMSTime, GameTime::GetGameTimeMS().count()); + if (lastOrientation == -1.0f) + { + lastOrientation = (c->ToCreature()->AI()->GetData(0) * 2 * M_PI) / 100.0f; + diff = 0; + } + float new_o = Position::NormalizeOrientation(lastOrientation - (M_PI / 60) * (diff / 250.0f)); + lastMSTime = GameTime::GetGameTimeMS().count(); + lastOrientation = new_o; + c->SetFacingTo(new_o); + + c->CastSpell((Unit*)nullptr, 63297, true); + c->CastSpell((Unit*)nullptr, 64042, true); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_p3wx2_laser_barrage_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_mimiron_p3wx2_laser_barrage_AuraScript(); + } +}; + +class go_ulduar_do_not_push_this_button : public GameObjectScript +{ +public: + go_ulduar_do_not_push_this_button() : GameObjectScript("go_ulduar_do_not_push_this_button") { } + + bool OnGossipHello(Player* player, GameObject* go) override + { + if(!player || !go) + return true; + + if (InstanceScript* instance = go->GetInstanceScript()) + { + if(instance->GetData(TYPE_MIMIRON) != NOT_STARTED) + return false; + + if (Creature* c = ObjectAccessor::GetCreature(*go, instance->GetGuidData(TYPE_MIMIRON))) + { + c->AI()->SetData(0, 7); + c->AI()->AttackStart(player); + } + } + + return false; + } +}; + +class npc_ulduar_flames_initial : public CreatureScript +{ +public: + npc_ulduar_flames_initial() : CreatureScript("npc_ulduar_flames_initial") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_flames_initialAI : public NullCreatureAI + { + npc_ulduar_flames_initialAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + CreateTime = GameTime::GetGameTime().count(); + events.Reset(); + events.ScheduleEvent(EVENT_FLAMES_SPREAD, 5750ms); + if( Creature* flame = me->SummonCreature(NPC_FLAMES_SPREAD, me->GetPositionX(), me->GetPositionY(), 364.32f, 0.0f) ) + { + FlameList.push_back(flame->GetGUID()); + flame->CastSpell(flame, SPELL_FLAMES_AURA, true); + } + } + + GuidList FlameList; + EventMap events; + uint32 CreateTime; + + void DoAction(int32 action) override + { + if (action == 1337) + RemoveAll(); + } + + void SpreadFlame(float x, float y) + { + if( Creature* flame = me->SummonCreature(NPC_FLAMES_SPREAD, x, y, 364.32f, 0.0f) ) + { + FlameList.push_back(flame->GetGUID()); + if (Creature* c = me->FindNearestCreature(NPC_FLAMES_SPREAD, 10.0f)) + if (c->GetExactDist2d(flame->GetPositionX(), flame->GetPositionY()) <= 4.0f) + return; + flame->CastSpell(flame, SPELL_FLAMES_AURA, true); + } + } + + void RemoveFlame(ObjectGuid guid) + { + FlameList.remove(guid); + } + + void RemoveAll() + { + for (ObjectGuid const& guid : FlameList) + if (Creature* c = ObjectAccessor::GetCreature(*me, guid)) + c->DespawnOrUnsummon(); + FlameList.clear(); + me->DespawnOrUnsummon(); + } + + void UpdateAI(uint32 diff) override + { + if (InstanceScript* pInstance = me->GetInstanceScript()) + if (pInstance->GetData(TYPE_MIMIRON) != IN_PROGRESS) + { + RemoveAll(); + return; + } + + events.Update(diff); + + switch( events.ExecuteEvent() ) + { + case 0: + break; + case EVENT_FLAMES_SPREAD: + { + if( FlameList.empty() ) + { + me->DespawnOrUnsummon(); + return; + } + + if (InstanceScript* pInstance = me->GetInstanceScript()) + if (Creature* mimiron = GetMimiron()) + if (CreateTime < mimiron->AI()->GetData(10)) + { + break; + } + + Creature* last = ObjectAccessor::GetCreature(*me, FlameList.back()); + if( last ) + { + float prevdist = 100.0f; + Player* target = nullptr; + + Map::PlayerList const& pl = me->GetMap()->GetPlayers(); + for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr ) + if( Player* plr = itr->GetSource() ) + if( plr->IsAlive() && plr->GetExactDist2d(last) < prevdist && !plr->IsGameMaster() ) + { + target = plr; + prevdist = plr->GetExactDist2d(last); + } + + if (target && prevdist >= 4.0f) // no need to spread when player is standing in fire, check distance + { + float angle = last->GetAngle(target->GetPositionX(), target->GetPositionY()) - M_PI / 8 + rand_norm() * 2 * M_PI / 8; + SpreadFlame(last->GetPositionX() + 7.0f * cos(angle), last->GetPositionY() + 7.0f * std::sin(angle)); + } + } + + events.Repeat(5750ms); + } + break; + } + } + }; +}; + +class npc_ulduar_flames_spread : public CreatureScript +{ +public: + npc_ulduar_flames_spread() : CreatureScript("npc_ulduar_flames_spread") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_flames_spreadAI : public NullCreatureAI + { + npc_ulduar_flames_spreadAI(Creature* pCreature) : NullCreatureAI(pCreature) {} + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + switch( spell->Id ) + { + case SPELL_FROST_BOMB_EXPLOSION_10: + case SPELL_FROST_BOMB_EXPLOSION_25: + case SPELL_FLAME_SUPPRESSANT_10yd: + case SPELL_FLAME_SUPPRESSANT_50000yd: + case SPELL_WATER_SPRAY: + { + if (me->IsSummon()) + if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit()) + if (Creature* c = summoner->ToCreature()) + if (c->AI()) + CAST_AI(npc_ulduar_flames_initial::npc_ulduar_flames_initialAI, c->AI())->RemoveFlame(me->GetGUID()); + + me->RemoveAllAuras(); + me->DespawnOrUnsummon(2500); + } + break; + case SPELL_VX001_FROST_BOMB: + me->CastSpell(me, SPELL_SUMMON_FROST_BOMB, true); + break; + } + } + }; +}; + +class npc_ulduar_emergency_fire_bot : public CreatureScript +{ +public: + npc_ulduar_emergency_fire_bot() : CreatureScript("npc_ulduar_emergency_fire_bot") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_emergency_fire_botAI : public ScriptedAI + { + npc_ulduar_emergency_fire_botAI(Creature* pCreature) : ScriptedAI(pCreature) + { + events.Reset(); + events.ScheduleEvent(EVENT_EMERGENCY_BOT_CHECK, 1s); + } + + EventMap events; + + void MoveInLineOfSight(Unit*) override {} + void AttackStart(Unit*) override {} + + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE && id == 1) + events.ScheduleEvent(EVENT_EMERGENCY_BOT_ATTACK, 0ms); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + switch( events.ExecuteEvent() ) + { + case 0: + break; + case EVENT_EMERGENCY_BOT_CHECK: + events.Repeat(15s); + if (Creature* flame = me->FindNearestCreature(NPC_FLAMES_SPREAD, 150.0f, true)) + { + me->SetOrientation(me->GetAngle(flame->GetPositionX(), flame->GetPositionY())); + float dist = me->GetExactDist2d(flame); + if (dist <= 5.0f) + events.ScheduleEvent(EVENT_EMERGENCY_BOT_ATTACK, 0ms); + else + me->GetMotionMaster()->MovePoint(1, me->GetPositionX() + (dist - 5.0f)*cos(me->GetOrientation()), me->GetPositionY() + (dist - 5.0f)*sin(me->GetOrientation()), 364.32f); + } + break; + case EVENT_EMERGENCY_BOT_ATTACK: + me->CastSpell((Unit*)nullptr, SPELL_WATER_SPRAY, false); + events.RescheduleEvent(EVENT_EMERGENCY_BOT_CHECK, 5s); + break; + } + } + }; +}; + +class npc_ulduar_rocket_strike_trigger : public CreatureScript +{ +public: + npc_ulduar_rocket_strike_trigger() : CreatureScript("npc_ulduar_rocket_strike_trigger") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_rocket_strike_triggerAI : public NullCreatureAI + { + npc_ulduar_rocket_strike_triggerAI(Creature* pCreature) : NullCreatureAI(pCreature) {} + + void SpellHitTarget(Unit* target, SpellInfo const* spell) override + { + if (!target || !spell) + return; + if (spell->Id == 63041) + { + if (target->GetEntry() == NPC_ASSAULT_BOT) + me->CastSpell(me, 65040, true); // achievement Not-So-Friendly Fire + else if (target->GetTypeId() == TYPEID_PLAYER) + if (InstanceScript* pInstance = me->GetInstanceScript()) + if (Creature* c = GetMimiron()) + c->AI()->SetData(0, 13); + } + } + }; +}; + +class achievement_mimiron_firefighter : public AchievementCriteriaScript +{ +public: + achievement_mimiron_firefighter() : AchievementCriteriaScript("achievement_mimiron_firefighter") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1); + } +}; + +class achievement_mimiron_set_up_us_the_bomb_11 : public AchievementCriteriaScript +{ +public: + achievement_mimiron_set_up_us_the_bomb_11() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_11") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(11); + } +}; + +class achievement_mimiron_set_up_us_the_bomb_12 : public AchievementCriteriaScript +{ +public: + achievement_mimiron_set_up_us_the_bomb_12() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_12") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(12); + } +}; + +class achievement_mimiron_set_up_us_the_bomb_13 : public AchievementCriteriaScript +{ +public: + achievement_mimiron_set_up_us_the_bomb_13() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_13") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(13); + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index c92f5db29cf2e3..c4a1d9e7cf5a73 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_razorscale.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "GameObjectScript.h" @@ -27,1147 +28,6 @@ #include "WaypointMgr.h" #include "ulduar.h" -enum Spells -{ - // Razorscale - SPELL_FLAMEBUFFET_10 = 64016, - SPELL_FLAMEBUFFET_25 = 64023, - SPELL_FIREBALL = 63815, - SPELL_WINGBUFFET = 62666, - SPELL_FLAMEBREATH_10 = 63317, - SPELL_FLAMEBREATH_25 = 64021, - SPELL_FUSEARMOR = 64771, - SPELL_FUSED_ARMOR = 64774, // Applied on 5th stack of SPELL_FUSEARMOR - SPELL_DEVOURINGFLAME = 63236, - SPELL_BERSERK = 47008, - - // Haproons - SPELL_CHAIN_1 = 49679, - SPELL_CHAIN_2 = 49682, - SPELL_CHAIN_3 = 49683, - SPELL_CHAIN_4 = 49684, - SPELL_LAUNCH_CHAIN = 62505, - - // Dark Rune Sentinel - SPELL_WHIRLWIND = 63808, - SPELL_BATTLE_SHOUT_10 = 46763, - SPELL_BATTLE_SHOUT_25 = 64062, - - // Dark Rune Guardian - SPELL_STORMSTRIKE_DMG = 65971, - SPELL_STORMSTRIKE_DEBUFF = 64757, - - // Dark Rune Watcher - SPELL_LIGHTINGBOLT_10 = 63809, - SPELL_LIGHTINGBOLT_25 = 64696, - SPELL_CHAINLIGHTNING_10 = 64758, - SPELL_CHAINLIGHTNING_25 = 64759, -}; - -#define SPELL_FLAMEBUFFET RAID_MODE(SPELL_FLAMEBUFFET_10, SPELL_FLAMEBUFFET_25) -#define SPELL_FLAMEBREATH RAID_MODE(SPELL_FLAMEBREATH_10, SPELL_FLAMEBREATH_25) -#define SPELL_BATTLE_SHOUT RAID_MODE(SPELL_BATTLE_SHOUT_10, SPELL_BATTLE_SHOUT_25) -#define SPELL_LIGHTINGBOLT RAID_MODE(SPELL_LIGHTINGBOLT_10, SPELL_LIGHTINGBOLT_25) -#define SPELL_CHAINLIGHTNING RAID_MODE(SPELL_CHAINLIGHTNING_10, SPELL_CHAINLIGHTNING_25) -#define REQ_CHAIN_COUNT RAID_MODE(2, 4) - -enum NPCs -{ - NPC_DARK_RUNE_SENTINEL = 33846, - NPC_DARK_RUNE_GUARDIAN = 33388, - NPC_DARK_RUNE_WATCHER = 33453, - NPC_EXPEDITION_ENGINEER = 33287, - NPC_EXPEDITION_COMMANDER = 33210, - NPC_RAZORSCALE_CONTROLLER = 33233, // Trigger Creature -}; - -enum GOs -{ - GO_DRILL = 195305, - GO_HARPOON_GUN_1 = 194519, - GO_HARPOON_GUN_2 = 194541, - GO_HARPOON_GUN_3 = 194542, - GO_HARPOON_GUN_4 = 194543, - GO_BROKEN_HARPOON = 194565, -}; - -enum eEvents -{ - EVENT_NONE = 0, - EVENT_COMMANDER_SAY_AGGRO, - EVENT_EE_SAY_MOVE_OUT, - EVENT_ENRAGE, - EVENT_SPELL_FIREBALL, - EVENT_SPELL_DEVOURING_FLAME, - EVENT_SUMMON_MOLE_MACHINES, - EVENT_SUMMON_ADDS, - EVENT_WARN_DEEP_BREATH, - EVENT_PHASE2_FLAME_BREATH, - EVENT_FLY_UP, - EVENT_RESUME_FIXING, - EVENT_SPELL_FLAME_BREATH, - EVENT_SPELL_DEVOURING_FLAME_GROUND, - EVENT_SPELL_FUSE_ARMOR, - EVENT_SPELL_FLAME_BUFFET, -}; - -enum Texts -{ - // Razorscale - EMOTE_PERMA_GROUND = 0, - EMOTE_BREATH = 1, - EMOTE_BERSERK = 2, - - // Expedition Commander - SAY_COMMANDER_AGGRO = 0, - SAY_COMMANDER_GROUND_PHASE = 1, - SAY_COMMANDER_ENGINEERS_DEAD = 2, // Should be called when all engineers are dead, currently unused - - // Expedition Engineer - SAY_EE_AGGRO = 0, - SAY_EE_START_REPAIR = 1, - SAY_EE_REBUILD_TURRETS = 2, - - // Harpoon - EMOTE_HARPOON = 0, -}; - -enum Misc -{ - POINT_RAZORSCALE_INIT = 1, - REPAIR_POINTS = 25, - - // Expedition Commander Gossip - GOSSIP_MENU_START_ENCOUNTER = 10314, - NPC_TEXT_COMMANDER = 40100, -}; - -const Position CORDS_GROUND = {588.0f, -166.0f, 391.1f}; -const Position CORDS_AIR = {588.0f, -178.0f, 490.0f}; - -class boss_razorscale : public CreatureScript -{ -public: - boss_razorscale() : CreatureScript("boss_razorscale") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_razorscaleAI : public ScriptedAI - { - boss_razorscaleAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) - { - pInstance = me->GetInstanceScript(); - startPath = true; - } - - InstanceScript* pInstance; - EventMap events; - SummonList summons; - ObjectGuid ExpeditionEngineerGUIDs[3]; - ObjectGuid CommanderGUID; - float cords[4][2]; - bool bGroundPhase; - bool startPath; - uint8 flyTimes; - - void InitializeAI() override - { - me->SetDisableGravity(true); - me->setActive(true); - Reset(); - } - - void Reset() override - { - events.Reset(); - summons.DespawnAll(); - - for (uint8 i = 0; i < 3; ++i) - ExpeditionEngineerGUIDs[i].Clear(); - - // Show gossip icon if previously hidden - if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID)) - if (!commander->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP)) - commander->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); - - CommanderGUID.Clear(); - bGroundPhase = false; - flyTimes = 0; - - if( pInstance ) - pInstance->SetData(TYPE_RAZORSCALE, NOT_STARTED); - } - - void AttackStart(Unit* who) override - { - if (who && me->Attack(who, true) && bGroundPhase) - me->GetMotionMaster()->MoveChase(who); - } - - void JustEngagedWith(Unit* /*who*/) override - { - me->SetInCombatWithZone(); - events.Reset(); - events.ScheduleEvent(EVENT_COMMANDER_SAY_AGGRO, 5s); - events.ScheduleEvent(EVENT_EE_SAY_MOVE_OUT, 10s); - events.ScheduleEvent(EVENT_ENRAGE, 10min); - events.ScheduleEvent(EVENT_SPELL_FIREBALL, 6s); - events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME, 13s); - events.ScheduleEvent(EVENT_SUMMON_MOLE_MACHINES, 11s); - - std::list eeList; - me->GetCreaturesWithEntryInRange(eeList, 300.0f, NPC_EXPEDITION_ENGINEER); - uint8 i = 0; - for( std::list::iterator itr = eeList.begin(); itr != eeList.end(); ++itr ) - { - if( i > 2 ) - break; - ExpeditionEngineerGUIDs[i] = (*itr)->GetGUID(); - if (!i) - (*itr)->AI()->Talk(SAY_EE_AGGRO); - ++i; - } - if (Creature* c = me->FindNearestCreature(NPC_EXPEDITION_COMMANDER, 300.0f, true)) - CommanderGUID = c->GetGUID(); - - if( pInstance ) - pInstance->SetData(TYPE_RAZORSCALE, IN_PROGRESS); - } - - void JustDied(Unit* /*Killer*/) override - { - summons.DespawnAll(); - - if( pInstance ) - pInstance->SetData(TYPE_RAZORSCALE, DONE); - } - - void SpellHit(Unit* caster, SpellInfo const* spell) override - { - if (!caster || !pInstance) - return; - - switch (spell->Id) - { - case SPELL_LAUNCH_CHAIN: - { - uint32 spellId = SPELL_CHAIN_4; - - if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1)) - { - spellId = SPELL_CHAIN_1; - } - else if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_2)) - { - spellId = SPELL_CHAIN_2; - } - else if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_3)) - { - spellId = SPELL_CHAIN_3; - } - - caster->CastSpell(me, spellId, true); - } - break; - case SPELL_CHAIN_1: - case SPELL_CHAIN_2: - case SPELL_CHAIN_3: - case SPELL_CHAIN_4: - { - uint8 count = 0; - if( me->HasAura(SPELL_CHAIN_1) ) - count++; - if( me->HasAura(SPELL_CHAIN_3) ) - count++; - if (RAID_MODE(0, 1)) - { - if( me->HasAura(SPELL_CHAIN_2) ) - count++; - if( me->HasAura(SPELL_CHAIN_4) ) - count++; - } - if( count >= REQ_CHAIN_COUNT ) - { - if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID)) - commander->AI()->Talk(SAY_COMMANDER_GROUND_PHASE); - - me->InterruptNonMeleeSpells(true); - events.CancelEvent(EVENT_SPELL_FIREBALL); - events.CancelEvent(EVENT_SPELL_DEVOURING_FLAME); - events.CancelEvent(EVENT_SUMMON_MOLE_MACHINES); - me->SetTarget(); - me->SendMeleeAttackStop(me->GetVictim()); - me->GetMotionMaster()->MoveLand(0, CORDS_GROUND, 25.0f); - } - } - break; - } - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override - { - if (me->GetPositionZ() > 440.0f) // protection, razorscale is attackable (so harpoons can hit him, etc.), but should not receive dmg while in air - damage = 0; - else if (!bGroundPhase && ((me->GetHealth() * 100) / me->GetMaxHealth() < 50) && me->HasAura(62794)) // already below 50%, but still in chains and stunned - events.RescheduleEvent(EVENT_WARN_DEEP_BREATH, 0ms); - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type == POINT_MOTION_TYPE && id == POINT_RAZORSCALE_INIT) - { - me->SetFacingTo(1.6f); - return; - } - else if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized() && !me->IsInCombat()) - { - startPath = true; - return; - } - - if (type != EFFECT_MOTION_TYPE) - return; - if (id == 0) // landed - { - me->SetControlled(true, UNIT_STATE_ROOT); - me->DisableRotate(true); - me->SetOrientation((float)(M_PI + 0.01) / 2); - me->SetFacingTo(M_PI / 2); - me->SetDisableGravity(false); - me->CastSpell(me, 62794, true); - events.ScheduleEvent(EVENT_WARN_DEEP_BREATH, 30s); - } - else if (id == 1) // flied up - { - events.ScheduleEvent(EVENT_SPELL_FIREBALL, 2s); - events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME, 4s); - events.ScheduleEvent(EVENT_SUMMON_MOLE_MACHINES, 5s); - } - } - - void UpdateAI(uint32 diff) override - { - if (startPath) - { - me->StopMoving(); - startPath = false; - if (WaypointPath const* i_path = sWaypointMgr->GetPath(me->GetWaypointPath())) - { - Movement::PointsArray pathPoints; - pathPoints.push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ())); - for (uint8 i = 0; i < i_path->size(); ++i) - { - WaypointData const* node = i_path->at(i); - pathPoints.push_back(G3D::Vector3(node->x, node->y, node->z)); - } - me->GetMotionMaster()->MoveSplinePath(&pathPoints); - } - } - - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_ENRAGE: - Talk(EMOTE_BERSERK); - me->CastSpell(me, SPELL_BERSERK, true); - break; - case EVENT_COMMANDER_SAY_AGGRO: - if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID)) - commander->AI()->Talk(SAY_COMMANDER_AGGRO); - break; - case EVENT_EE_SAY_MOVE_OUT: - for (uint8 i = 0; i < 3; ++i) - if (Creature* c = ObjectAccessor::GetCreature(*me, ExpeditionEngineerGUIDs[i])) - { - if (!i) - c->AI()->Talk(SAY_EE_START_REPAIR); - c->AI()->SetData(1, 0); // start repairing - } - break; - case EVENT_SPELL_FIREBALL: - if( Unit* pTarget = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, true) ) - me->CastSpell(pTarget, SPELL_FIREBALL, false); - events.Repeat(4s); - break; - case EVENT_SPELL_DEVOURING_FLAME: - if( Unit* pTarget = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, true) ) - me->CastSpell(pTarget, SPELL_DEVOURINGFLAME, false); - events.Repeat(13s); - break; - case EVENT_SUMMON_MOLE_MACHINES: - { - memset(cords, '\0', sizeof(cords)); - uint8 num = RAID_MODE( urand(2, 3), urand(2, 4) ); - for( int i = 0; i < num; ++i ) - { - // X: (550, 625) Y: (-185, -230) - cords[i][0] = urand(550, 625); - cords[i][1] = -230 + rand() % 45; - if( GameObject* drill = me->SummonGameObject(GO_DRILL, cords[i][0], cords[i][1], 391.1f, M_PI / 4, 0.0f, 0.0f, 0.0f, 0.0f, 8) ) - { - //drill->SetGoAnimProgress(0); - //drill->SetLootState(GO_READY); - //drill->UseDoorOrButton(8); - //drill->SetGoState(GO_STATE_READY); - drill->SetGoState(GO_STATE_ACTIVE); - drill->SetGoAnimProgress(0); - } - } - events.Repeat(45s); - events.RescheduleEvent(EVENT_SUMMON_ADDS, 4s); - } - break; - case EVENT_SUMMON_ADDS: - for( int i = 0; i < 4; ++i ) - { - if( !cords[i][0] ) - break; - - uint8 opt; - uint8 r = urand(1, 100); - if( r <= 30 ) opt = 1; - else if( r <= 65 ) opt = 2; - else opt = 3; - - for( int j = 0; j < 4; ++j ) - { - float x = cords[i][0] + 4.0f * cos(j * M_PI / 2); - float y = cords[i][1] + 4.0f * std::sin(j * M_PI / 2); - - uint32 npc_entry = 0; - switch( opt ) - { - case 1: - if( j == 1 ) npc_entry = NPC_DARK_RUNE_SENTINEL; - break; - case 2: - switch( j ) - { - case 1: - npc_entry = NPC_DARK_RUNE_WATCHER; - break; - case 2: - npc_entry = NPC_DARK_RUNE_GUARDIAN; - break; - } - break; - default: // case 3: - switch( j ) - { - case 1: - npc_entry = NPC_DARK_RUNE_WATCHER; - break; - case 2: - npc_entry = NPC_DARK_RUNE_GUARDIAN; - break; - case 3: - npc_entry = NPC_DARK_RUNE_GUARDIAN; - break; - } - break; - } - - if( npc_entry ) - if (Creature* c = me->SummonCreature(npc_entry, x, y, 391.1f, j * M_PI / 2, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000)) - DoZoneInCombat(c); - } - } - break; - case EVENT_WARN_DEEP_BREATH: - Talk(EMOTE_BREATH); - me->RemoveAura(62794); - events.ScheduleEvent(EVENT_PHASE2_FLAME_BREATH, 2500ms); - break; - case EVENT_PHASE2_FLAME_BREATH: - me->CastSpell(me, SPELL_FLAMEBREATH, true); - events.ScheduleEvent(EVENT_FLY_UP, 2s); - break; - case EVENT_FLY_UP: - me->SetInCombatWithZone(); // just in case - if (pInstance) - for( int i = 0; i < 4; ++i ) - if( ObjectGuid guid = pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i) ) - if( Creature* hfs = ObjectAccessor::GetCreature(*me, guid) ) - { - me->SummonCreature(34188, hfs->GetPositionX(), hfs->GetPositionY(), hfs->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 22000); - hfs->AI()->SetData(1, 0); - } - - me->RemoveAura(SPELL_LAUNCH_CHAIN); - me->RemoveAura(SPELL_CHAIN_1); - me->RemoveAura(SPELL_CHAIN_3); - if (RAID_MODE(0, 1)) - { - me->RemoveAura(SPELL_CHAIN_2); - me->RemoveAura(SPELL_CHAIN_4); - } - me->CastSpell(me, SPELL_WINGBUFFET, true); - - if( (me->GetHealth() * 100) / me->GetMaxHealth() < 50 ) // start phase 3 - { - Talk(EMOTE_PERMA_GROUND); - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - DoResetThreatList(); - Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0, true); - if (!target) - target = me->SelectNearestPlayer(200.0f); - if (target) - { - AttackStart(target); - me->GetMotionMaster()->MoveChase(target); - } - bGroundPhase = true; - events.CancelEvent(EVENT_SPELL_FIREBALL); - events.CancelEvent(EVENT_SPELL_DEVOURING_FLAME); - events.CancelEvent(EVENT_SUMMON_MOLE_MACHINES); - - events.ScheduleEvent(EVENT_SPELL_FLAME_BREATH, 20s); - events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME_GROUND, 5s); - events.ScheduleEvent(EVENT_SPELL_FUSE_ARMOR, 10s); - events.ScheduleEvent(EVENT_SPELL_FLAME_BUFFET, 3s); - - break; - } - else - { - ++flyTimes; - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - me->SendMeleeAttackStop(me->GetVictim()); - me->GetMotionMaster()->MoveIdle(); - me->StopMoving(); - me->SetDisableGravity(true); - me->GetMotionMaster()->MoveTakeoff(1, CORDS_AIR, 25.0f); - events.ScheduleEvent(EVENT_RESUME_FIXING, 22s); - } - - break; - case EVENT_RESUME_FIXING: - for (uint8 i = 0; i < 3; ++i) - if (Creature* c = ObjectAccessor::GetCreature(*me, ExpeditionEngineerGUIDs[i])) - { - if (!i) - c->AI()->Talk(SAY_EE_REBUILD_TURRETS); - c->AI()->SetData(1, 0); // start repairing - } - break; - case EVENT_SPELL_FLAME_BREATH: - me->CastSpell(me->GetVictim(), SPELL_FLAMEBREATH, false); - events.Repeat(20s); - break; - case EVENT_SPELL_DEVOURING_FLAME_GROUND: - me->CastSpell(me->GetVictim(), SPELL_DEVOURINGFLAME, false); - events.Repeat(13s); - break; - case EVENT_SPELL_FUSE_ARMOR: - if (Unit* victim = me->GetVictim()) - if (me->IsWithinMeleeRange(victim)) - { - me->CastSpell(victim, SPELL_FUSEARMOR, false); - if (Aura* aur = victim->GetAura(SPELL_FUSEARMOR)) - if (aur->GetStackAmount() == 5) - victim->CastSpell(victim, SPELL_FUSED_ARMOR, true); - events.Repeat(10s); - break; - } - events.Repeat(2s); - break; - case EVENT_SPELL_FLAME_BUFFET: - me->CastSpell(me->GetVictim(), SPELL_FLAMEBUFFET, false); - events.Repeat(7s); - break; - } - - if (bGroundPhase) - DoMeleeAttackIfReady(); - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - - void JustReachedHome() override - { - startPath = true; - } - - void JustSummoned(Creature* s) override - { - summons.Summon(s); - } - - uint32 GetData(uint32 id) const override - { - if (id == 1) - return (flyTimes <= 1 ? 1 : 0); - return 0; - } - - void KilledUnit(Unit* victim) override - { - if (victim && victim->GetEntry() == NPC_DARK_RUNE_GUARDIAN) - if (pInstance) - pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_DARK_RUNE_GUARDIAN, 1, me); - } - - void EnterEvadeMode(EvadeReason why) override - { - me->SetDisableGravity(true); - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - ScriptedAI::EnterEvadeMode(why); - } - }; -}; - -class npc_ulduar_expedition_commander : public CreatureScript -{ -public: - npc_ulduar_expedition_commander() : CreatureScript("npc_ulduar_expedition_commander") { } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (!player || !creature) - return true; - - InstanceScript* instance = creature->GetInstanceScript(); - if (!instance) - return true; - - if (instance->GetData(TYPE_RAZORSCALE) == DONE) - return true; - - Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE)); - if (!razorscale || razorscale->IsInCombat()) - return true; - - AddGossipItemFor(player, GOSSIP_MENU_START_ENCOUNTER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - SendGossipMenuFor(player, NPC_TEXT_COMMANDER, creature); - return true; - } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 uiAction) override - { - if (!player || !creature) - return true; - - if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) - { - InstanceScript* instance = creature->GetInstanceScript(); - if (!instance || instance->GetData(TYPE_RAZORSCALE) == DONE) - return true; - - Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE)); - if (razorscale && !razorscale->IsInCombat()) - { - // Do not show gossip icon if encounter is in progress - creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); - - // reset npcs NPC_HARPOON_FIRE_STATE - for (uint8 i = 0; i < 4; ++i) - if (Creature* hfs = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i))) - hfs->AI()->SetData(1, 0); - - if (razorscale->AI()) - { - razorscale->AI()->AttackStart(player); - razorscale->GetMotionMaster()->MoveIdle(); - razorscale->GetMotionMaster()->MovePoint(POINT_RAZORSCALE_INIT, 588.0f, -178.0f, 490.0f, false, false); - } - } - } - - player->PlayerTalkClass->SendCloseGossip(); - return true; - } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); - } - - struct npc_ulduar_expedition_commanderAI : public NullCreatureAI - { - npc_ulduar_expedition_commanderAI(Creature* creature) : NullCreatureAI(creature) - { - _instance = creature->GetInstanceScript(); - _introSpoken = _instance->GetData(TYPE_RAZORSCALE) == DONE; - me->SetReactState(REACT_AGGRESSIVE); - } - - void MoveInLineOfSight(Unit* who) override - { - if (_introSpoken) - return; - - if (who->GetTypeId() != TYPEID_PLAYER || me->GetExactDist2d(who) > 15.0f) - return; - - _introSpoken = true; - //Talk(SAY_COMMANDER_INTRO); // No source leads to showing any text messages, perhaps only SOUND ID 15647 is played? - } - - private: - InstanceScript* _instance; - bool _introSpoken; - }; -}; - -class npc_ulduar_harpoonfirestate : public CreatureScript -{ -public: - npc_ulduar_harpoonfirestate() : CreatureScript("npc_ulduar_harpoonfirestate") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_harpoonfirestateAI : public NullCreatureAI - { - npc_ulduar_harpoonfirestateAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - pInstance = me->GetInstanceScript(); - } - - InstanceScript* pInstance; - uint8 repairPoints; - - void Reset() override - { - repairPoints = 0; - } - - uint32 GetHarpoonGunIdForThisHFS() - { - if (pInstance) - { - if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1) ) - return GO_HARPOON_GUN_1; - else if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_2) ) - return GO_HARPOON_GUN_2; - else if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_3) ) - return GO_HARPOON_GUN_3; - else - return GO_HARPOON_GUN_4; - } - return 0; - } - - void SetData(uint32 id, uint32 value) override - { - switch (id) - { - case 1: // cleanup at the start of the fight - if (pInstance) - { - uint32 h_entry = GetHarpoonGunIdForThisHFS(); - if( GameObject* wh = me->FindNearestGameObject(h_entry, 5.0f) ) - { - wh->SetRespawnTime(0); - wh->Delete(); - } - if( GameObject* bh = me->FindNearestGameObject(GO_BROKEN_HARPOON, 5.0f) ) - if (bh->GetPhaseMask() != 1) - bh->SetPhaseMask(1, true); - } - Reset(); - break; - case 2: // repairing - if (repairPoints < REPAIR_POINTS) - { - if (++repairPoints >= REPAIR_POINTS) - { - if( GameObject* bh = me->FindNearestGameObject(GO_BROKEN_HARPOON, 4.0f) ) - bh->SetPhaseMask(2, true); - if( GameObject* wh = me->SummonGameObject(GetHarpoonGunIdForThisHFS(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 3 * M_PI / 2, 0.0f, 0.0f, 0.0f, 0.0f, 0) ) - { - me->RemoveGameObject(wh, false); - if (Creature* cr = me->SummonCreature(NPC_RAZORSCALE_CONTROLLER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 5000)) - cr->AI()->Talk(EMOTE_HARPOON); - } - } - } - break; - case 3: // shoot - if (pInstance) - { - Creature* razorscale = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_RAZORSCALE)); - if (!razorscale) - return; - if (!razorscale->HasAura(value)) - me->CastSpell(razorscale, SPELL_LAUNCH_CHAIN, true); - } - break; - } - } - - uint32 GetData(uint32 id) const override - { - switch (id) - { - case 2: - return (repairPoints >= REPAIR_POINTS ? 1 : 0); - } - return 0; - } - }; -}; - -class npc_ulduar_expedition_engineer : public CreatureScript -{ -public: - npc_ulduar_expedition_engineer() : CreatureScript("npc_ulduar_expedition_engineer") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_expedition_engineerAI : public NullCreatureAI - { - npc_ulduar_expedition_engineerAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - pInstance = me->GetInstanceScript(); - } - - InstanceScript* pInstance; - bool working; - uint16 timer; - ObjectGuid fixingGUID; - - void Reset() override - { - working = false; - timer = 0; - fixingGUID.Clear(); - } - - void SetData(uint32 id, uint32 /*value*/) override - { - switch (id) - { - case 1: // start/resume repairing - working = true; - timer = 0; - fixingGUID.Clear(); - break; - case 2: // stop repairing - Reset(); - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND); - me->GetMotionMaster()->MoveTargetedHome(); - break; - } - } - - void UpdateAI(uint32 diff) override - { - if (working) - { - if (timer <= diff) - { - timer = 3000; - - if (fixingGUID) - { - if (Creature* c = ObjectAccessor::GetCreature(*me, fixingGUID)) - if (me->GetExactDist2dSq(c) <= 25.0f) - { - if( me->GetUInt32Value(UNIT_NPC_EMOTESTATE) != EMOTE_STATE_WORK ) - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_WORK); - - if (std::fabs(me->GetOrientation() - me->GetAngle(c)) > M_PI / 4) - me->SetFacingToObject(c); - - c->AI()->SetData(2, 0); - if (c->AI()->GetData(2)) - fixingGUID.Clear(); - } - } - - if (!fixingGUID) - { - Creature* razorscale = nullptr; - if( ObjectGuid rsGUID = pInstance->GetGuidData(TYPE_RAZORSCALE) ) - razorscale = ObjectAccessor::GetCreature(*me, rsGUID); - - if( !razorscale || !razorscale->IsInCombat() ) - { - Reset(); - me->GetMotionMaster()->MoveTargetedHome(); - return; - } - - for( int i = 0; i < 4; ++i ) - if( ObjectGuid fs_GUID = pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i) ) - if( Creature* fs = ObjectAccessor::GetCreature(*me, fs_GUID) ) - if (!fs->AI()->GetData(2)) - { - float a = rand_norm() * M_PI; - me->GetMotionMaster()->MovePoint(0, fs->GetPositionX() + 3.0f * cos(a), fs->GetPositionY() + 3.0f * std::sin(a), fs->GetPositionZ()); - fixingGUID = fs->GetGUID(); - return; - } - - Reset(); // all harpoons repaired - me->GetMotionMaster()->MoveTargetedHome(); - } - } - else - timer -= diff; - } - else if (me->GetUInt32Value(UNIT_NPC_EMOTESTATE) == EMOTE_STATE_WORK) - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND); - } - }; -}; - -class go_ulduar_working_harpoon : public GameObjectScript -{ -public: - go_ulduar_working_harpoon() : GameObjectScript("go_ulduar_working_harpoon") { } - - bool OnGossipHello(Player* user, GameObject* go) override - { - if( !user || !go ) - return true; - - InstanceScript* pInstance = go->GetInstanceScript(); - if( !pInstance ) - return true; - - Creature* rs = nullptr; - if( ObjectGuid rsGUID = pInstance->GetGuidData(TYPE_RAZORSCALE) ) - rs = ObjectAccessor::GetCreature(*go, rsGUID); - - if( !rs || !rs->IsInCombat() ) - { - go->SetRespawnTime(0); - go->Delete(); - return true; - } - - uint32 npc = 0; - uint32 spell = 0; - switch( go->GetEntry() ) - { - case GO_HARPOON_GUN_1: - npc = DATA_HARPOON_FIRE_STATE_1; - spell = SPELL_CHAIN_1; - break; - case GO_HARPOON_GUN_2: - npc = DATA_HARPOON_FIRE_STATE_2; - spell = SPELL_CHAIN_2; - break; - case GO_HARPOON_GUN_3: - npc = DATA_HARPOON_FIRE_STATE_3; - spell = SPELL_CHAIN_3; - break; - case GO_HARPOON_GUN_4: - npc = DATA_HARPOON_FIRE_STATE_4; - spell = SPELL_CHAIN_4; - break; - } - - if( ObjectGuid g = pInstance->GetGuidData(npc) ) - if( Creature* hfs = ObjectAccessor::GetCreature(*go, g) ) - hfs->AI()->SetData(3, spell); - - go->SetLootState(GO_JUST_DEACTIVATED); - return true; - } -}; - -class npc_ulduar_dark_rune_guardian : public CreatureScript -{ -public: - npc_ulduar_dark_rune_guardian() : CreatureScript("npc_ulduar_dark_rune_guardian") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_dark_rune_guardianAI : public ScriptedAI - { - npc_ulduar_dark_rune_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - uint32 timer2; - - void Reset() override - { - timer2 = 6000; - } - - bool CanAIAttack(Unit const* target) const override - { - return target && target->GetEntry() != NPC_RAZORSCALE; - } - - void UpdateAI(uint32 diff) override - { - if( !UpdateVictim() ) - return; - - if (timer2 <= diff) timer2 = 0; - else timer2 -= diff; - if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim())) - { - me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DMG, true); - me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DMG, true); // cast the same twice cus second one requires setting offhand damage - me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DEBUFF, true); - timer2 = urand(8000, 10000); - return; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class npc_ulduar_dark_rune_watcher : public CreatureScript -{ -public: - npc_ulduar_dark_rune_watcher() : CreatureScript("npc_ulduar_dark_rune_watcher") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_dark_rune_watcherAI : public ScriptedAI - { - npc_ulduar_dark_rune_watcherAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - uint32 timer1; - uint32 timer2; - - void Reset() override - { - timer1 = 6000; - timer2 = 2000; - } - - bool CanAIAttack(Unit const* target) const override - { - return target && target->GetEntry() != NPC_RAZORSCALE; - } - - void UpdateAI(uint32 diff) override - { - if( !UpdateVictim() ) - return; - - if( timer1 <= diff ) - { - me->CastSpell(me->GetVictim(), SPELL_CHAINLIGHTNING, false); - timer1 = urand(10000, 12000); - return; - } - else - timer1 -= diff; - - if (timer2 <= diff) - { - me->CastSpell(me->GetVictim(), SPELL_LIGHTINGBOLT, false); - timer2 = 4000; - return; - } - else - timer2 -= diff; - - DoMeleeAttackIfReady(); - } - }; -}; - -class npc_ulduar_dark_rune_sentinel : public CreatureScript -{ -public: - npc_ulduar_dark_rune_sentinel() : CreatureScript("npc_ulduar_dark_rune_sentinel") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_ulduar_dark_rune_sentinelAI : public ScriptedAI - { - npc_ulduar_dark_rune_sentinelAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - uint32 timer1; - uint32 timer2; - - void Reset() override - { - timer1 = urand(1000, 2000); - timer2 = 6000; - } - - bool CanAIAttack(Unit const* target) const override - { - return target && target->GetEntry() != NPC_RAZORSCALE; - } - - void UpdateAI(uint32 diff) override - { - if( !UpdateVictim() ) - return; - - if( timer1 <= diff ) - { - me->CastSpell(me, SPELL_BATTLE_SHOUT, false); - timer1 = urand(15000, 20000); - } - else - timer1 -= diff; - - if (timer2 <= diff) timer2 = 0; - else timer2 -= diff; - if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim())) - { - me->CastSpell(me, SPELL_WHIRLWIND, false); - timer2 = urand(10000, 12000); - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class achievement_quick_shave : public AchievementCriteriaScript -{ -public: - achievement_quick_shave() : AchievementCriteriaScript("achievement_quick_shave") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetTypeId() == TYPEID_UNIT && target->GetEntry() == NPC_RAZORSCALE && target->ToCreature()->AI()->GetData(1); - } -}; - -class achievement_iron_dwarf_medium_rare : public AchievementCriteriaScript -{ -public: - achievement_iron_dwarf_medium_rare() : AchievementCriteriaScript("achievement_iron_dwarf_medium_rare") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_RAZORSCALE; - } -}; - void AddSC_boss_razorscale() { new boss_razorscale(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.h new file mode 100644 index 00000000000000..22360225823474 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.h @@ -0,0 +1,1157 @@ +#ifndef BOSS_RAZORSCALE_H_ +#define BOSS_RAZORSCALE_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "GameObjectScript.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "ScriptedGossip.h" +#include "SpellAuras.h" +#include "SpellScript.h" +#include "WaypointMgr.h" +#include "ulduar.h" + +enum Spells +{ + // Razorscale + SPELL_FLAMEBUFFET_10 = 64016, + SPELL_FLAMEBUFFET_25 = 64023, + SPELL_FIREBALL = 63815, + SPELL_WINGBUFFET = 62666, + SPELL_FLAMEBREATH_10 = 63317, + SPELL_FLAMEBREATH_25 = 64021, + SPELL_FUSEARMOR = 64771, + SPELL_FUSED_ARMOR = 64774, // Applied on 5th stack of SPELL_FUSEARMOR + SPELL_DEVOURINGFLAME = 63236, + SPELL_BERSERK = 47008, + + // Haproons + SPELL_CHAIN_1 = 49679, + SPELL_CHAIN_2 = 49682, + SPELL_CHAIN_3 = 49683, + SPELL_CHAIN_4 = 49684, + SPELL_LAUNCH_CHAIN = 62505, + + // Dark Rune Sentinel + SPELL_WHIRLWIND = 63808, + SPELL_BATTLE_SHOUT_10 = 46763, + SPELL_BATTLE_SHOUT_25 = 64062, + + // Dark Rune Guardian + SPELL_STORMSTRIKE_DMG = 65971, + SPELL_STORMSTRIKE_DEBUFF = 64757, + + // Dark Rune Watcher + SPELL_LIGHTINGBOLT_10 = 63809, + SPELL_LIGHTINGBOLT_25 = 64696, + SPELL_CHAINLIGHTNING_10 = 64758, + SPELL_CHAINLIGHTNING_25 = 64759, +}; + +#define SPELL_FLAMEBUFFET RAID_MODE(SPELL_FLAMEBUFFET_10, SPELL_FLAMEBUFFET_25) +#define SPELL_FLAMEBREATH RAID_MODE(SPELL_FLAMEBREATH_10, SPELL_FLAMEBREATH_25) +#define SPELL_BATTLE_SHOUT RAID_MODE(SPELL_BATTLE_SHOUT_10, SPELL_BATTLE_SHOUT_25) +#define SPELL_LIGHTINGBOLT RAID_MODE(SPELL_LIGHTINGBOLT_10, SPELL_LIGHTINGBOLT_25) +#define SPELL_CHAINLIGHTNING RAID_MODE(SPELL_CHAINLIGHTNING_10, SPELL_CHAINLIGHTNING_25) +#define REQ_CHAIN_COUNT RAID_MODE(2, 4) + +enum NPCs +{ + NPC_DARK_RUNE_SENTINEL = 33846, + NPC_DARK_RUNE_GUARDIAN = 33388, + NPC_DARK_RUNE_WATCHER = 33453, + NPC_EXPEDITION_ENGINEER = 33287, + NPC_EXPEDITION_COMMANDER = 33210, + NPC_RAZORSCALE_CONTROLLER = 33233, // Trigger Creature +}; + +enum GOs +{ + GO_DRILL = 195305, + GO_HARPOON_GUN_1 = 194519, + GO_HARPOON_GUN_2 = 194541, + GO_HARPOON_GUN_3 = 194542, + GO_HARPOON_GUN_4 = 194543, + GO_BROKEN_HARPOON = 194565, +}; + +enum eEvents +{ + EVENT_NONE = 0, + EVENT_COMMANDER_SAY_AGGRO, + EVENT_EE_SAY_MOVE_OUT, + EVENT_ENRAGE, + EVENT_SPELL_FIREBALL, + EVENT_SPELL_DEVOURING_FLAME, + EVENT_SUMMON_MOLE_MACHINES, + EVENT_SUMMON_ADDS, + EVENT_WARN_DEEP_BREATH, + EVENT_PHASE2_FLAME_BREATH, + EVENT_FLY_UP, + EVENT_RESUME_FIXING, + EVENT_SPELL_FLAME_BREATH, + EVENT_SPELL_DEVOURING_FLAME_GROUND, + EVENT_SPELL_FUSE_ARMOR, + EVENT_SPELL_FLAME_BUFFET, +}; + +enum Texts +{ + // Razorscale + EMOTE_PERMA_GROUND = 0, + EMOTE_BREATH = 1, + EMOTE_BERSERK = 2, + + // Expedition Commander + SAY_COMMANDER_AGGRO = 0, + SAY_COMMANDER_GROUND_PHASE = 1, + SAY_COMMANDER_ENGINEERS_DEAD = 2, // Should be called when all engineers are dead, currently unused + + // Expedition Engineer + SAY_EE_AGGRO = 0, + SAY_EE_START_REPAIR = 1, + SAY_EE_REBUILD_TURRETS = 2, + + // Harpoon + EMOTE_HARPOON = 0, +}; + +enum Misc +{ + POINT_RAZORSCALE_INIT = 1, + REPAIR_POINTS = 25, + + // Expedition Commander Gossip + GOSSIP_MENU_START_ENCOUNTER = 10314, + NPC_TEXT_COMMANDER = 40100, +}; + +const Position CORDS_GROUND = {588.0f, -166.0f, 391.1f}; +const Position CORDS_AIR = {588.0f, -178.0f, 490.0f}; + +class boss_razorscale : public CreatureScript +{ +public: + boss_razorscale() : CreatureScript("boss_razorscale") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_razorscaleAI : public ScriptedAI + { + boss_razorscaleAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + { + pInstance = me->GetInstanceScript(); + startPath = true; + } + + InstanceScript* pInstance; + EventMap events; + SummonList summons; + ObjectGuid ExpeditionEngineerGUIDs[3]; + ObjectGuid CommanderGUID; + float cords[4][2]; + bool bGroundPhase; + bool startPath; + uint8 flyTimes; + + void InitializeAI() override + { + me->SetDisableGravity(true); + me->setActive(true); + Reset(); + } + + void Reset() override + { + events.Reset(); + summons.DespawnAll(); + + for (uint8 i = 0; i < 3; ++i) + ExpeditionEngineerGUIDs[i].Clear(); + + // Show gossip icon if previously hidden + if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID)) + if (!commander->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP)) + commander->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); + + CommanderGUID.Clear(); + bGroundPhase = false; + flyTimes = 0; + + if( pInstance ) + pInstance->SetData(TYPE_RAZORSCALE, NOT_STARTED); + } + + void AttackStart(Unit* who) override + { + if (who && me->Attack(who, true) && bGroundPhase) + me->GetMotionMaster()->MoveChase(who); + } + + void JustEngagedWith(Unit* /*who*/) override + { + me->SetInCombatWithZone(); + events.Reset(); + events.ScheduleEvent(EVENT_COMMANDER_SAY_AGGRO, 5s); + events.ScheduleEvent(EVENT_EE_SAY_MOVE_OUT, 10s); + events.ScheduleEvent(EVENT_ENRAGE, 10min); + events.ScheduleEvent(EVENT_SPELL_FIREBALL, 6s); + events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME, 13s); + events.ScheduleEvent(EVENT_SUMMON_MOLE_MACHINES, 11s); + + std::list eeList; + me->GetCreaturesWithEntryInRange(eeList, 300.0f, NPC_EXPEDITION_ENGINEER); + uint8 i = 0; + for( std::list::iterator itr = eeList.begin(); itr != eeList.end(); ++itr ) + { + if( i > 2 ) + break; + ExpeditionEngineerGUIDs[i] = (*itr)->GetGUID(); + if (!i) + (*itr)->AI()->Talk(SAY_EE_AGGRO); + ++i; + } + if (Creature* c = me->FindNearestCreature(NPC_EXPEDITION_COMMANDER, 300.0f, true)) + CommanderGUID = c->GetGUID(); + + if( pInstance ) + pInstance->SetData(TYPE_RAZORSCALE, IN_PROGRESS); + } + + void JustDied(Unit* /*Killer*/) override + { + summons.DespawnAll(); + + if( pInstance ) + pInstance->SetData(TYPE_RAZORSCALE, DONE); + } + + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + if (!caster || !pInstance) + return; + + switch (spell->Id) + { + case SPELL_LAUNCH_CHAIN: + { + uint32 spellId = SPELL_CHAIN_4; + + if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1)) + { + spellId = SPELL_CHAIN_1; + } + else if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_2)) + { + spellId = SPELL_CHAIN_2; + } + else if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_3)) + { + spellId = SPELL_CHAIN_3; + } + + caster->CastSpell(me, spellId, true); + } + break; + case SPELL_CHAIN_1: + case SPELL_CHAIN_2: + case SPELL_CHAIN_3: + case SPELL_CHAIN_4: + { + uint8 count = 0; + if( me->HasAura(SPELL_CHAIN_1) ) + count++; + if( me->HasAura(SPELL_CHAIN_3) ) + count++; + if (RAID_MODE(0, 1)) + { + if( me->HasAura(SPELL_CHAIN_2) ) + count++; + if( me->HasAura(SPELL_CHAIN_4) ) + count++; + } + if( count >= REQ_CHAIN_COUNT ) + { + if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID)) + commander->AI()->Talk(SAY_COMMANDER_GROUND_PHASE); + + me->InterruptNonMeleeSpells(true); + events.CancelEvent(EVENT_SPELL_FIREBALL); + events.CancelEvent(EVENT_SPELL_DEVOURING_FLAME); + events.CancelEvent(EVENT_SUMMON_MOLE_MACHINES); + me->SetTarget(); + me->SendMeleeAttackStop(me->GetVictim()); + me->GetMotionMaster()->MoveLand(0, CORDS_GROUND, 25.0f); + } + } + break; + } + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override + { + if (me->GetPositionZ() > 440.0f) // protection, razorscale is attackable (so harpoons can hit him, etc.), but should not receive dmg while in air + damage = 0; + else if (!bGroundPhase && ((me->GetHealth() * 100) / me->GetMaxHealth() < 50) && me->HasAura(62794)) // already below 50%, but still in chains and stunned + events.RescheduleEvent(EVENT_WARN_DEEP_BREATH, 0ms); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE && id == POINT_RAZORSCALE_INIT) + { + me->SetFacingTo(1.6f); + return; + } + else if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized() && !me->IsInCombat()) + { + startPath = true; + return; + } + + if (type != EFFECT_MOTION_TYPE) + return; + if (id == 0) // landed + { + me->SetControlled(true, UNIT_STATE_ROOT); + me->DisableRotate(true); + me->SetOrientation((float)(M_PI + 0.01) / 2); + me->SetFacingTo(M_PI / 2); + me->SetDisableGravity(false); + me->CastSpell(me, 62794, true); + events.ScheduleEvent(EVENT_WARN_DEEP_BREATH, 30s); + } + else if (id == 1) // flied up + { + events.ScheduleEvent(EVENT_SPELL_FIREBALL, 2s); + events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME, 4s); + events.ScheduleEvent(EVENT_SUMMON_MOLE_MACHINES, 5s); + } + } + + void UpdateAI(uint32 diff) override + { + if (startPath) + { + me->StopMoving(); + startPath = false; + if (WaypointPath const* i_path = sWaypointMgr->GetPath(me->GetWaypointPath())) + { + Movement::PointsArray pathPoints; + pathPoints.push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ())); + for (uint8 i = 0; i < i_path->size(); ++i) + { + WaypointData const* node = i_path->at(i); + pathPoints.push_back(G3D::Vector3(node->x, node->y, node->z)); + } + me->GetMotionMaster()->MoveSplinePath(&pathPoints); + } + } + + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case 0: + break; + case EVENT_ENRAGE: + Talk(EMOTE_BERSERK); + me->CastSpell(me, SPELL_BERSERK, true); + break; + case EVENT_COMMANDER_SAY_AGGRO: + if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID)) + commander->AI()->Talk(SAY_COMMANDER_AGGRO); + break; + case EVENT_EE_SAY_MOVE_OUT: + for (uint8 i = 0; i < 3; ++i) + if (Creature* c = ObjectAccessor::GetCreature(*me, ExpeditionEngineerGUIDs[i])) + { + if (!i) + c->AI()->Talk(SAY_EE_START_REPAIR); + c->AI()->SetData(1, 0); // start repairing + } + break; + case EVENT_SPELL_FIREBALL: + if( Unit* pTarget = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, true) ) + me->CastSpell(pTarget, SPELL_FIREBALL, false); + events.Repeat(4s); + break; + case EVENT_SPELL_DEVOURING_FLAME: + if( Unit* pTarget = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, true) ) + me->CastSpell(pTarget, SPELL_DEVOURINGFLAME, false); + events.Repeat(13s); + break; + case EVENT_SUMMON_MOLE_MACHINES: + { + memset(cords, '\0', sizeof(cords)); + uint8 num = RAID_MODE( urand(2, 3), urand(2, 4) ); + for( int i = 0; i < num; ++i ) + { + // X: (550, 625) Y: (-185, -230) + cords[i][0] = urand(550, 625); + cords[i][1] = -230 + rand() % 45; + if( GameObject* drill = me->SummonGameObject(GO_DRILL, cords[i][0], cords[i][1], 391.1f, M_PI / 4, 0.0f, 0.0f, 0.0f, 0.0f, 8) ) + { + //drill->SetGoAnimProgress(0); + //drill->SetLootState(GO_READY); + //drill->UseDoorOrButton(8); + //drill->SetGoState(GO_STATE_READY); + drill->SetGoState(GO_STATE_ACTIVE); + drill->SetGoAnimProgress(0); + } + } + events.Repeat(45s); + events.RescheduleEvent(EVENT_SUMMON_ADDS, 4s); + } + break; + case EVENT_SUMMON_ADDS: + for( int i = 0; i < 4; ++i ) + { + if( !cords[i][0] ) + break; + + uint8 opt; + uint8 r = urand(1, 100); + if( r <= 30 ) opt = 1; + else if( r <= 65 ) opt = 2; + else opt = 3; + + for( int j = 0; j < 4; ++j ) + { + float x = cords[i][0] + 4.0f * cos(j * M_PI / 2); + float y = cords[i][1] + 4.0f * std::sin(j * M_PI / 2); + + uint32 npc_entry = 0; + switch( opt ) + { + case 1: + if( j == 1 ) npc_entry = NPC_DARK_RUNE_SENTINEL; + break; + case 2: + switch( j ) + { + case 1: + npc_entry = NPC_DARK_RUNE_WATCHER; + break; + case 2: + npc_entry = NPC_DARK_RUNE_GUARDIAN; + break; + } + break; + default: // case 3: + switch( j ) + { + case 1: + npc_entry = NPC_DARK_RUNE_WATCHER; + break; + case 2: + npc_entry = NPC_DARK_RUNE_GUARDIAN; + break; + case 3: + npc_entry = NPC_DARK_RUNE_GUARDIAN; + break; + } + break; + } + + if( npc_entry ) + if (Creature* c = me->SummonCreature(npc_entry, x, y, 391.1f, j * M_PI / 2, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000)) + DoZoneInCombat(c); + } + } + break; + case EVENT_WARN_DEEP_BREATH: + Talk(EMOTE_BREATH); + me->RemoveAura(62794); + events.ScheduleEvent(EVENT_PHASE2_FLAME_BREATH, 2500ms); + break; + case EVENT_PHASE2_FLAME_BREATH: + me->CastSpell(me, SPELL_FLAMEBREATH, true); + events.ScheduleEvent(EVENT_FLY_UP, 2s); + break; + case EVENT_FLY_UP: + me->SetInCombatWithZone(); // just in case + if (pInstance) + for( int i = 0; i < 4; ++i ) + if( ObjectGuid guid = pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i) ) + if( Creature* hfs = ObjectAccessor::GetCreature(*me, guid) ) + { + me->SummonCreature(34188, hfs->GetPositionX(), hfs->GetPositionY(), hfs->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 22000); + hfs->AI()->SetData(1, 0); + } + + me->RemoveAura(SPELL_LAUNCH_CHAIN); + me->RemoveAura(SPELL_CHAIN_1); + me->RemoveAura(SPELL_CHAIN_3); + if (RAID_MODE(0, 1)) + { + me->RemoveAura(SPELL_CHAIN_2); + me->RemoveAura(SPELL_CHAIN_4); + } + me->CastSpell(me, SPELL_WINGBUFFET, true); + + if( (me->GetHealth() * 100) / me->GetMaxHealth() < 50 ) // start phase 3 + { + Talk(EMOTE_PERMA_GROUND); + me->SetControlled(false, UNIT_STATE_ROOT); + me->DisableRotate(false); + DoResetThreatList(); + Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0, true); + if (!target) + target = me->SelectNearestPlayer(200.0f); + if (target) + { + AttackStart(target); + me->GetMotionMaster()->MoveChase(target); + } + bGroundPhase = true; + events.CancelEvent(EVENT_SPELL_FIREBALL); + events.CancelEvent(EVENT_SPELL_DEVOURING_FLAME); + events.CancelEvent(EVENT_SUMMON_MOLE_MACHINES); + + events.ScheduleEvent(EVENT_SPELL_FLAME_BREATH, 20s); + events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME_GROUND, 5s); + events.ScheduleEvent(EVENT_SPELL_FUSE_ARMOR, 10s); + events.ScheduleEvent(EVENT_SPELL_FLAME_BUFFET, 3s); + + break; + } + else + { + ++flyTimes; + me->SetControlled(false, UNIT_STATE_ROOT); + me->DisableRotate(false); + me->SendMeleeAttackStop(me->GetVictim()); + me->GetMotionMaster()->MoveIdle(); + me->StopMoving(); + me->SetDisableGravity(true); + me->GetMotionMaster()->MoveTakeoff(1, CORDS_AIR, 25.0f); + events.ScheduleEvent(EVENT_RESUME_FIXING, 22s); + } + + break; + case EVENT_RESUME_FIXING: + for (uint8 i = 0; i < 3; ++i) + if (Creature* c = ObjectAccessor::GetCreature(*me, ExpeditionEngineerGUIDs[i])) + { + if (!i) + c->AI()->Talk(SAY_EE_REBUILD_TURRETS); + c->AI()->SetData(1, 0); // start repairing + } + break; + case EVENT_SPELL_FLAME_BREATH: + me->CastSpell(me->GetVictim(), SPELL_FLAMEBREATH, false); + events.Repeat(20s); + break; + case EVENT_SPELL_DEVOURING_FLAME_GROUND: + me->CastSpell(me->GetVictim(), SPELL_DEVOURINGFLAME, false); + events.Repeat(13s); + break; + case EVENT_SPELL_FUSE_ARMOR: + if (Unit* victim = me->GetVictim()) + if (me->IsWithinMeleeRange(victim)) + { + me->CastSpell(victim, SPELL_FUSEARMOR, false); + if (Aura* aur = victim->GetAura(SPELL_FUSEARMOR)) + if (aur->GetStackAmount() == 5) + victim->CastSpell(victim, SPELL_FUSED_ARMOR, true); + events.Repeat(10s); + break; + } + events.Repeat(2s); + break; + case EVENT_SPELL_FLAME_BUFFET: + me->CastSpell(me->GetVictim(), SPELL_FLAMEBUFFET, false); + events.Repeat(7s); + break; + } + + if (bGroundPhase) + DoMeleeAttackIfReady(); + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + + void JustReachedHome() override + { + startPath = true; + } + + void JustSummoned(Creature* s) override + { + summons.Summon(s); + } + + uint32 GetData(uint32 id) const override + { + if (id == 1) + return (flyTimes <= 1 ? 1 : 0); + return 0; + } + + void KilledUnit(Unit* victim) override + { + if (victim && victim->GetEntry() == NPC_DARK_RUNE_GUARDIAN) + if (pInstance) + pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_DARK_RUNE_GUARDIAN, 1, me); + } + + void EnterEvadeMode(EvadeReason why) override + { + me->SetDisableGravity(true); + me->SetControlled(false, UNIT_STATE_ROOT); + me->DisableRotate(false); + ScriptedAI::EnterEvadeMode(why); + } + }; +}; + +class npc_ulduar_expedition_commander : public CreatureScript +{ +public: + npc_ulduar_expedition_commander() : CreatureScript("npc_ulduar_expedition_commander") { } + + bool OnGossipHello(Player* player, Creature* creature) override + { + if (!player || !creature) + return true; + + InstanceScript* instance = creature->GetInstanceScript(); + if (!instance) + return true; + + if (instance->GetData(TYPE_RAZORSCALE) == DONE) + return true; + + Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE)); + if (!razorscale || razorscale->IsInCombat()) + return true; + + AddGossipItemFor(player, GOSSIP_MENU_START_ENCOUNTER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + SendGossipMenuFor(player, NPC_TEXT_COMMANDER, creature); + return true; + } + + bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 uiAction) override + { + if (!player || !creature) + return true; + + if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) + { + InstanceScript* instance = creature->GetInstanceScript(); + if (!instance || instance->GetData(TYPE_RAZORSCALE) == DONE) + return true; + + Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE)); + if (razorscale && !razorscale->IsInCombat()) + { + // Do not show gossip icon if encounter is in progress + creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + + // reset npcs NPC_HARPOON_FIRE_STATE + for (uint8 i = 0; i < 4; ++i) + if (Creature* hfs = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i))) + hfs->AI()->SetData(1, 0); + + if (razorscale->AI()) + { + razorscale->AI()->AttackStart(player); + razorscale->GetMotionMaster()->MoveIdle(); + razorscale->GetMotionMaster()->MovePoint(POINT_RAZORSCALE_INIT, 588.0f, -178.0f, 490.0f, false, false); + } + } + } + + player->PlayerTalkClass->SendCloseGossip(); + return true; + } + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI(creature); + } + + struct npc_ulduar_expedition_commanderAI : public NullCreatureAI + { + npc_ulduar_expedition_commanderAI(Creature* creature) : NullCreatureAI(creature) + { + _instance = creature->GetInstanceScript(); + _introSpoken = _instance->GetData(TYPE_RAZORSCALE) == DONE; + me->SetReactState(REACT_AGGRESSIVE); + } + + void MoveInLineOfSight(Unit* who) override + { + if (_introSpoken) + return; + + if (who->GetTypeId() != TYPEID_PLAYER || me->GetExactDist2d(who) > 15.0f) + return; + + _introSpoken = true; + //Talk(SAY_COMMANDER_INTRO); // No source leads to showing any text messages, perhaps only SOUND ID 15647 is played? + } + + private: + InstanceScript* _instance; + bool _introSpoken; + }; +}; + +class npc_ulduar_harpoonfirestate : public CreatureScript +{ +public: + npc_ulduar_harpoonfirestate() : CreatureScript("npc_ulduar_harpoonfirestate") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_harpoonfirestateAI : public NullCreatureAI + { + npc_ulduar_harpoonfirestateAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + pInstance = me->GetInstanceScript(); + } + + InstanceScript* pInstance; + uint8 repairPoints; + + void Reset() override + { + repairPoints = 0; + } + + uint32 GetHarpoonGunIdForThisHFS() + { + if (pInstance) + { + if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1) ) + return GO_HARPOON_GUN_1; + else if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_2) ) + return GO_HARPOON_GUN_2; + else if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_3) ) + return GO_HARPOON_GUN_3; + else + return GO_HARPOON_GUN_4; + } + return 0; + } + + void SetData(uint32 id, uint32 value) override + { + switch (id) + { + case 1: // cleanup at the start of the fight + if (pInstance) + { + uint32 h_entry = GetHarpoonGunIdForThisHFS(); + if( GameObject* wh = me->FindNearestGameObject(h_entry, 5.0f) ) + { + wh->SetRespawnTime(0); + wh->Delete(); + } + if( GameObject* bh = me->FindNearestGameObject(GO_BROKEN_HARPOON, 5.0f) ) + if (bh->GetPhaseMask() != 1) + bh->SetPhaseMask(1, true); + } + Reset(); + break; + case 2: // repairing + if (repairPoints < REPAIR_POINTS) + { + if (++repairPoints >= REPAIR_POINTS) + { + if( GameObject* bh = me->FindNearestGameObject(GO_BROKEN_HARPOON, 4.0f) ) + bh->SetPhaseMask(2, true); + if( GameObject* wh = me->SummonGameObject(GetHarpoonGunIdForThisHFS(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 3 * M_PI / 2, 0.0f, 0.0f, 0.0f, 0.0f, 0) ) + { + me->RemoveGameObject(wh, false); + if (Creature* cr = me->SummonCreature(NPC_RAZORSCALE_CONTROLLER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 5000)) + cr->AI()->Talk(EMOTE_HARPOON); + } + } + } + break; + case 3: // shoot + if (pInstance) + { + Creature* razorscale = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_RAZORSCALE)); + if (!razorscale) + return; + if (!razorscale->HasAura(value)) + me->CastSpell(razorscale, SPELL_LAUNCH_CHAIN, true); + } + break; + } + } + + uint32 GetData(uint32 id) const override + { + switch (id) + { + case 2: + return (repairPoints >= REPAIR_POINTS ? 1 : 0); + } + return 0; + } + }; +}; + +class npc_ulduar_expedition_engineer : public CreatureScript +{ +public: + npc_ulduar_expedition_engineer() : CreatureScript("npc_ulduar_expedition_engineer") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_expedition_engineerAI : public NullCreatureAI + { + npc_ulduar_expedition_engineerAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + pInstance = me->GetInstanceScript(); + } + + InstanceScript* pInstance; + bool working; + uint16 timer; + ObjectGuid fixingGUID; + + void Reset() override + { + working = false; + timer = 0; + fixingGUID.Clear(); + } + + void SetData(uint32 id, uint32 /*value*/) override + { + switch (id) + { + case 1: // start/resume repairing + working = true; + timer = 0; + fixingGUID.Clear(); + break; + case 2: // stop repairing + Reset(); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND); + me->GetMotionMaster()->MoveTargetedHome(); + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (working) + { + if (timer <= diff) + { + timer = 3000; + + if (fixingGUID) + { + if (Creature* c = ObjectAccessor::GetCreature(*me, fixingGUID)) + if (me->GetExactDist2dSq(c) <= 25.0f) + { + if( me->GetUInt32Value(UNIT_NPC_EMOTESTATE) != EMOTE_STATE_WORK ) + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_WORK); + + if (std::fabs(me->GetOrientation() - me->GetAngle(c)) > M_PI / 4) + me->SetFacingToObject(c); + + c->AI()->SetData(2, 0); + if (c->AI()->GetData(2)) + fixingGUID.Clear(); + } + } + + if (!fixingGUID) + { + Creature* razorscale = nullptr; + if( ObjectGuid rsGUID = pInstance->GetGuidData(TYPE_RAZORSCALE) ) + razorscale = ObjectAccessor::GetCreature(*me, rsGUID); + + if( !razorscale || !razorscale->IsInCombat() ) + { + Reset(); + me->GetMotionMaster()->MoveTargetedHome(); + return; + } + + for( int i = 0; i < 4; ++i ) + if( ObjectGuid fs_GUID = pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i) ) + if( Creature* fs = ObjectAccessor::GetCreature(*me, fs_GUID) ) + if (!fs->AI()->GetData(2)) + { + float a = rand_norm() * M_PI; + me->GetMotionMaster()->MovePoint(0, fs->GetPositionX() + 3.0f * cos(a), fs->GetPositionY() + 3.0f * std::sin(a), fs->GetPositionZ()); + fixingGUID = fs->GetGUID(); + return; + } + + Reset(); // all harpoons repaired + me->GetMotionMaster()->MoveTargetedHome(); + } + } + else + timer -= diff; + } + else if (me->GetUInt32Value(UNIT_NPC_EMOTESTATE) == EMOTE_STATE_WORK) + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND); + } + }; +}; + +class go_ulduar_working_harpoon : public GameObjectScript +{ +public: + go_ulduar_working_harpoon() : GameObjectScript("go_ulduar_working_harpoon") { } + + bool OnGossipHello(Player* user, GameObject* go) override + { + if( !user || !go ) + return true; + + InstanceScript* pInstance = go->GetInstanceScript(); + if( !pInstance ) + return true; + + Creature* rs = nullptr; + if( ObjectGuid rsGUID = pInstance->GetGuidData(TYPE_RAZORSCALE) ) + rs = ObjectAccessor::GetCreature(*go, rsGUID); + + if( !rs || !rs->IsInCombat() ) + { + go->SetRespawnTime(0); + go->Delete(); + return true; + } + + uint32 npc = 0; + uint32 spell = 0; + switch( go->GetEntry() ) + { + case GO_HARPOON_GUN_1: + npc = DATA_HARPOON_FIRE_STATE_1; + spell = SPELL_CHAIN_1; + break; + case GO_HARPOON_GUN_2: + npc = DATA_HARPOON_FIRE_STATE_2; + spell = SPELL_CHAIN_2; + break; + case GO_HARPOON_GUN_3: + npc = DATA_HARPOON_FIRE_STATE_3; + spell = SPELL_CHAIN_3; + break; + case GO_HARPOON_GUN_4: + npc = DATA_HARPOON_FIRE_STATE_4; + spell = SPELL_CHAIN_4; + break; + } + + if( ObjectGuid g = pInstance->GetGuidData(npc) ) + if( Creature* hfs = ObjectAccessor::GetCreature(*go, g) ) + hfs->AI()->SetData(3, spell); + + go->SetLootState(GO_JUST_DEACTIVATED); + return true; + } +}; + +class npc_ulduar_dark_rune_guardian : public CreatureScript +{ +public: + npc_ulduar_dark_rune_guardian() : CreatureScript("npc_ulduar_dark_rune_guardian") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_dark_rune_guardianAI : public ScriptedAI + { + npc_ulduar_dark_rune_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + uint32 timer2; + + void Reset() override + { + timer2 = 6000; + } + + bool CanAIAttack(Unit const* target) const override + { + return target && target->GetEntry() != NPC_RAZORSCALE; + } + + void UpdateAI(uint32 diff) override + { + if( !UpdateVictim() ) + return; + + if (timer2 <= diff) timer2 = 0; + else timer2 -= diff; + if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim())) + { + me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DMG, true); + me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DMG, true); // cast the same twice cus second one requires setting offhand damage + me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DEBUFF, true); + timer2 = urand(8000, 10000); + return; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class npc_ulduar_dark_rune_watcher : public CreatureScript +{ +public: + npc_ulduar_dark_rune_watcher() : CreatureScript("npc_ulduar_dark_rune_watcher") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_dark_rune_watcherAI : public ScriptedAI + { + npc_ulduar_dark_rune_watcherAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + uint32 timer1; + uint32 timer2; + + void Reset() override + { + timer1 = 6000; + timer2 = 2000; + } + + bool CanAIAttack(Unit const* target) const override + { + return target && target->GetEntry() != NPC_RAZORSCALE; + } + + void UpdateAI(uint32 diff) override + { + if( !UpdateVictim() ) + return; + + if( timer1 <= diff ) + { + me->CastSpell(me->GetVictim(), SPELL_CHAINLIGHTNING, false); + timer1 = urand(10000, 12000); + return; + } + else + timer1 -= diff; + + if (timer2 <= diff) + { + me->CastSpell(me->GetVictim(), SPELL_LIGHTINGBOLT, false); + timer2 = 4000; + return; + } + else + timer2 -= diff; + + DoMeleeAttackIfReady(); + } + }; +}; + +class npc_ulduar_dark_rune_sentinel : public CreatureScript +{ +public: + npc_ulduar_dark_rune_sentinel() : CreatureScript("npc_ulduar_dark_rune_sentinel") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_ulduar_dark_rune_sentinelAI : public ScriptedAI + { + npc_ulduar_dark_rune_sentinelAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + uint32 timer1; + uint32 timer2; + + void Reset() override + { + timer1 = urand(1000, 2000); + timer2 = 6000; + } + + bool CanAIAttack(Unit const* target) const override + { + return target && target->GetEntry() != NPC_RAZORSCALE; + } + + void UpdateAI(uint32 diff) override + { + if( !UpdateVictim() ) + return; + + if( timer1 <= diff ) + { + me->CastSpell(me, SPELL_BATTLE_SHOUT, false); + timer1 = urand(15000, 20000); + } + else + timer1 -= diff; + + if (timer2 <= diff) timer2 = 0; + else timer2 -= diff; + if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim())) + { + me->CastSpell(me, SPELL_WHIRLWIND, false); + timer2 = urand(10000, 12000); + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class achievement_quick_shave : public AchievementCriteriaScript +{ +public: + achievement_quick_shave() : AchievementCriteriaScript("achievement_quick_shave") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetTypeId() == TYPEID_UNIT && target->GetEntry() == NPC_RAZORSCALE && target->ToCreature()->AI()->GetData(1); + } +}; + +class achievement_iron_dwarf_medium_rare : public AchievementCriteriaScript +{ +public: + achievement_iron_dwarf_medium_rare() : AchievementCriteriaScript("achievement_iron_dwarf_medium_rare") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_RAZORSCALE; + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp index 5894409bef73f0..c85ed2d4c2971a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_thorim.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "GameObjectScript.h" @@ -27,1787 +28,6 @@ #include "SpellScriptLoader.h" #include "ulduar.h" -enum ThorimSpells -{ - // THORIM - SPELL_LIGHTNING_DESTRUCTION = 62393, - SPELL_SHEATH_OF_LIGHTNING = 62276, - SPELL_STORMHAMMER = 62042, - SPELL_BERSERK_FRIENDS = 62560, - SPELL_CHAIN_LIGHTNING_10 = 62131, - SPELL_CHAIN_LIGHTNING_25 = 64390, - SPELL_UNBALANCING_STRIKE = 62130, - SPELL_BERSERK = 26662, - - SPELL_CHARGE_ORB = 62016, - SPELL_LIGHTNING_PILLAR_P1 = 63238, - - SPELL_LIGHTNING_ORB_VISUAL = 62186, - SPELL_LIGHTNING_CHARGE_DAMAGE = 62466, - SPELL_LIGHTNING_CHARGE_BUFF = 62279, - SPELL_LIGHTNING_PILLAR_P2 = 62976, - SPELL_LIGHTNING_ORB_CHARGER = 62278, - - // SIF - SPELL_TOUCH_OF_DOMINION = 62507, - SPELL_SIF_TRANSFORM = 64778, - SPELL_SIF_CHANNEL_HOLOGRAM = 64324, - SPELL_FROSTBOLT = 62601, - SPELL_FROSTBOLT_VALLEY = 62604, - SPELL_BLIZZARD_10 = 62577, - SPELL_BLIZZARD_25 = 62603, - SPELL_FROST_NOVA = 62605, - - // DARK RUNE ACOLYTE - SPELL_GREATER_HEAL_10 = 62334, - SPELL_GREATER_HEAL_25 = 62442, - SPELL_HOLY_SMITE_10 = 62335, - SPELL_HOLY_SMITE_25 = 62443, - SPELL_RENEW_10 = 62333, - SPELL_RENEW_25 = 62441, - - // CAPTURED MERCENARY SOLDIER - SPELL_BARBED_SHOT = 62318, - SPELL_WING_CLIP = 40652, - SPELL_SHOOT = 16496, - - // CAPTURED MERCENARY CAPTAIN - SPELL_DEVASTATE = 62317, - SPELL_HEROIC_STRIKE = 62444, - - // JORMUNGAR BEHEMOTH - SPELL_ACID_BREATH_10 = 62315, - SPELL_ACID_BREATH_25 = 62415, - SPELL_SWEEP_10 = 62316, - SPELL_SWEEP_25 = 62417, - - // IRON RING GUARD - SPELL_IMPALE_10 = 62331, - SPELL_IMPALE_25 = 62418, - SPELL_WHIRLING_TRIP = 64151, - - // IRON HONOR GUARD - SPELL_SHIELD_SMASH_10 = 62332, - SPELL_SHIELD_SMASH_25 = 62420, - SPELL_CLEAVE = 42724, - SPELL_HAMSTRING = 48639, - - // DARK RUNE WARBRINGER - SPELL_AURA_OF_CELERITY = 62320, - SPELL_RUNIC_STRIKE = 62322, - - // DARK RUNE EVOKER - SPELL_RUNIC_LIGHTNING_10 = 62327, - SPELL_RUNIC_LIGHTNING_25 = 62445, - SPELL_RUNIC_MENDING_10 = 62328, - SPELL_RUNIC_MENDING_25 = 62446, - SPELL_RUNIC_SHIELD_10 = 62321, - SPELL_RUNIC_SHIELD_25 = 62529, - - // DARK RUNE CHAMPION - SPELL_CHARGE = 32323, - SPELL_MORTAL_STRIKE = 35054, - SPELL_WHIRLWIND = 15578, - - // DARK RUNE COMMONER - SPELL_LOW_BLOW = 62326, - SPELL_PUMMEL = 38313, - - // RUNIC COLOSSUS - SPELL_COLOSSUS_CHARGE_10 = 62613, - SPELL_COLOSSUS_CHARGE_25 = 62614, - SPELL_RUNIC_BARRIER = 62338, - SPELL_SMASH = 62339, - SPELL_RUNIC_SMASH_LEFT = 62057, - SPELL_RUNIC_SMASH_RIGHT = 62058, - SPELL_RUNIC_SMASH_DAMAGE = 62465, - - // ANCIENT RUNE GIANT - SPELL_RUNE_DETONATION = 62526, - SPELL_RUNIC_FORTIFICATION = 62942, - SPELL_STOMP_10 = 62411, - SPELL_STOMP_25 = 62413, - - // TRAPS - SPELL_LIGHTNING_FIELD = 64972, - SPELL_PARALYTIC_FIELD_FIRST = 62241, - SPELL_PARALYTIC_FIELD_SECOND = 63540, -}; - -#define SPELL_GREATER_HEAL RAID_MODE(SPELL_GREATER_HEAL_10, SPELL_GREATER_HEAL_25) -#define SPELL_HOLY_SMITE RAID_MODE(SPELL_HOLY_SMITE_10, SPELL_HOLY_SMITE_25) -#define SPELL_RENEW RAID_MODE(SPELL_RENEW_10, SPELL_RENEW_25) -#define SPELL_ACID_BREATH RAID_MODE(SPELL_ACID_BREATH_10, SPELL_ACID_BREATH_25) -#define SPELL_SWEEP RAID_MODE(SPELL_SWEEP_10, SPELL_SWEEP_25) -#define SPELL_IMPALE RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25) -#define SPELL_COLOSSUS_CHARGE RAID_MODE(SPELL_COLOSSUS_CHARGE_10, SPELL_COLOSSUS_CHARGE_25) -#define SPELL_STOMP RAID_MODE(SPELL_STOMP_10, SPELL_STOMP_25) -#define SPELL_SHIELD_SMASH RAID_MODE(SPELL_SHIELD_SMASH_10, SPELL_SHIELD_SMASH_25) -#define SPELL_RUNIC_LIGHTNING RAID_MODE(SPELL_RUNIC_LIGHTNING_10, SPELL_RUNIC_LIGHTNING_25) -#define SPELL_RUNIC_MENDING RAID_MODE(SPELL_RUNIC_MENDING_10, SPELL_RUNIC_MENDING_25) -#define SPELL_RUNIC_SHIELD RAID_MODE(SPELL_RUNIC_SHIELD_10, SPELL_RUNIC_SHIELD_25) -#define SPELL_CHAIN_LIGHTNING RAID_MODE(SPELL_CHAIN_LIGHTNING_10, SPELL_CHAIN_LIGHTNING_25) - -enum ThormNPCandGOs : uint32 -{ - // ARENA INIT - NPC_DARK_RUNE_ACOLYTE_I = 32886, - NPC_CAPTURED_MERCENARY_SOLDIER_ALLY = 32885, - NPC_CAPTURED_MERCENARY_SOLDIER_HORDE = 32883, - NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY = 32908, - NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE = 32907, - NPC_JORMUNGAR_BEHEMOT = 32882, - - // ARENA PHASE - NPC_DARK_RUNE_WARBRINGER = 32877, - NPC_DARK_RUNE_EVOKER = 32878, - NPC_DARK_RUNE_CHAMPION = 32876, - NPC_DARK_RUNE_COMMONER = 32904, - - // GAUNTLET - NPC_IRON_RING_GUARD = 32874, - NPC_RUNIC_COLOSSUS = 32872, - NPC_ANCIENT_RUNE_GIANT = 32873, - NPC_DARK_RUNE_ACOLYTE_G = 33110, - NPC_IRON_HONOR_GUARD = 32875, - - // TRIGGERS - NPC_LIGHTNING_ORB = 33138, - NPC_THUNDER_ORB = 33378, - NPC_PILLAR = 32892, - NPC_SIF_BLIZZARD = 32879, - - NPC_SIF = 33196, -}; - -enum ThorimEvents -{ - EVENT_THORIM_START_PHASE1 = 1, - EVENT_THORIM_STORMHAMMER = 2, - EVENT_THORIM_CHARGE_ORB = 3, - EVENT_THORIM_LIGHTNING_ORB = 4, - EVENT_THORIM_NOT_REACH_IN_TIME = 5, - EVENT_THORIM_FILL_ARENA = 6, - EVENT_THORIM_UNBALANCING_STRIKE = 7, - EVENT_THORIM_LIGHTNING_CHARGE = 8, - EVENT_THORIM_CHAIN_LIGHTNING = 9, - EVENT_THORIM_BERSERK = 10, - EVENT_THORIM_AGGRO = 11, - EVENT_THORIM_AGGRO2 = 12, - EVENT_THORIM_OUTRO1 = 13, - EVENT_THORIM_OUTRO2 = 14, - EVENT_THORIM_OUTRO3 = 15, - - EVENT_DR_ACOLYTE_GH = 20, - EVENT_DR_ACOLYTE_HS = 21, - EVENT_DR_ACOLYTE_R = 22, - - EVENT_CM_SOLDIER_BS = 30, - EVENT_CM_SOLDIER_S = 31, - EVENT_CM_SOLDIER_WC = 32, - - EVENT_CM_CAPTAIN_D = 40, - EVENT_CM_CAPTAIN_HC = 41, - - EVENT_JB_ACID_BREATH = 50, - EVENT_JB_SWEEP = 51, - - EVENT_IR_GUARD_IMPALE = 60, - EVENT_IR_GUARD_WHIRL = 61, - - EVENT_RC_RUNIC_BARRIER = 70, - EVENT_RC_SMASH = 71, - EVENT_RC_RUNIC_SMASH = 72, - EVENT_RC_RUNIC_SMASH_TRIGGER = 73, - EVENT_RC_CHARGE = 74, - - EVENT_ARG_RD = 80, - EVENT_ARG_RF = 81, - EVENT_ARG_STOMP = 82, - EVENT_ARG_SPAWN = 83, - - EVENT_IH_GUARD_CLEAVE = 90, - EVENT_IH_GUARD_HAMSTRING = 91, - EVENT_IH_GUARD_SHIELD_SMASH = 92, - - EVENT_SIF_START_TALK = 100, - EVENT_SIF_JOIN_TALK = 101, - EVENT_SIF_FINISH_DOMINION = 102, - EVENT_SIF_FROSTBOLT_VALLEY = 103, - EVENT_SIF_BLIZZARD = 104, - EVENT_SIF_FROST_NOVA_START = 105, - EVENT_SIF_FROST_NOVA_CAST = 106, - - EVENT_DR_WARBRINGER_RS = 110, - - EVENT_DR_EVOKER_RL = 120, - EVENT_DR_EVOKER_RM = 121, - EVENT_DR_EVOKER_RS = 122, - - EVENT_DR_CHAMPION_WH = 130, - EVENT_DR_CHAMPION_CH = 131, - EVENT_DR_CHAMPION_MS = 132, - - EVENT_DR_COMMONER_PM = 140, - EVENT_DR_COMMONER_LB = 141, -}; - -const Position ArenaNPCs[] = -{ - {2178.5f, -300.2f, 441.97f, 2.5f}, - {2188.12f, -295.1f, 443.75, 2.5f}, - {2180.9f, -286.8f, 433.3f, 2.49f}, - {2193.2f, -280.6f, 443.14f, 2.79f}, - {2191.8f, -270.2f, 438.3f, 3.0f}, - {2186.84f, -238.5f, 439.7f, 3.4f}, - {2166.3f, -213.0f, 440.0f, 4.1f}, - {2100.5f, -213.5f, 441.66f, 5.4f}, - {2091.0f, -231.26f, 435.17f, 5.5f}, - {2083.2f, -239.2f, 438.77f, 5.85f}, - {2081.54f, -253.27f, 434.67f, 6.19f}, - {2077.65f, -272.73f, 439.12f, 0.15f}, - {2084.36f, -282.12f, 435.87f, 0.24f}, - {2087.46f, -298.71f, 440.5f, 0.59f} -}; - -enum Texts -{ - // Thorim - SAY_AGGRO_1 = 0, - SAY_AGGRO_2 = 1, - SAY_SPECIAL_1 = 2, // Unused - SAY_SPECIAL_2 = 3, - SAY_SPECIAL_3 = 4, // Unused - SAY_JUMPDOWN = 5, - SAY_SLAY = 6, - SAY_BERSERK = 7, - SAY_WIPE = 8, - SAY_DEATH = 9, - SAY_END_NORMAL_1 = 10, - SAY_END_NORMAL_2 = 11, - SAY_END_NORMAL_3 = 12, - SAY_END_HARD_1 = 13, - SAY_END_HARD_2 = 14, - SAY_END_HARD_3 = 15, - - // Sif - SAY_SIF_AGGRO = 0, - SAY_SIF_HM_MISSED = 1, - SAY_SIF_HM_REACHED = 2, - - // Ancient Rune Giant - SAY_GIANT_RUNIC_MIGHT = 0, - - // Runic Colossus - SAY_COLOSSUS_RUNIC_BARRIER = 0, -}; - -enum Misc -{ - ACTION_START_TRASH_DIED = 1, - ACTION_ALLOW_HIT = 2, - ACTION_SIF_JOIN_FIGHT = 3, - ACTION_SIF_START_TALK = 4, - ACTION_SIF_START_DOMINION = 5, - ACTION_SIF_TRANSFORM = 6, - ACTION_IRON_HONOR_DIED = 7, - - EVENT_PHASE_START = 1, - EVENT_PHASE_RING = 2, - EVENT_PHASE_OUTRO = 3, - - DATA_HIT_BY_LIGHTNING = 1, - DATA_LOSE_YOUR_ILLUSION = 2, -}; - -const Position Middle = {2134.68f, -263.13f, 419.44f, M_PI * 1.5f}; - -const uint32 RollTable[3] = { 32877, 32878, 32876 }; - -class boss_thorim : public CreatureScript -{ -public: - boss_thorim() : CreatureScript("boss_thorim") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorimAI : public ScriptedAI - { - boss_thorimAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) - { - m_pInstance = pCreature->GetInstanceScript(); - if ((_encounterFinished = (!me->IsAlive()))) - if (m_pInstance) - m_pInstance->SetData(TYPE_THORIM, DONE); - } - - bool _isArenaEmpty; - bool _encounterFinished; - bool _spawnCommoners; - bool _hardMode; - bool _isHitAllowed; - bool _isAlly; - uint8 _trashCounter; - - InstanceScript* m_pInstance; - EventMap events; - SummonList summons; - - bool _hitByLightning; - - void DisableThorim(bool apply) - { - if (apply) - { - me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED); - me->DisableRotate(true); - me->AddUnitState(UNIT_STATE_ROOT); - } - else - { - me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED); - me->DisableRotate(false); - me->ClearUnitState(UNIT_STATE_ROOT); - me->resetAttackTimer(BASE_ATTACK); - } - } - - GameObject* GetThorimObject(uint32 entry) - { - if (m_pInstance) - return ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(entry)); - return nullptr; - } - - void JustSummoned(Creature* cr) override { summons.Summon(cr); } - - void SpawnAllNPCs() - { - // Jormungar Behemoth 32882 - me->SummonCreature(NPC_JORMUNGAR_BEHEMOT, 2149.68f, -263.477f, 419.679f, 3.12102f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - - // Captured Mercenary Soldier 32885 - me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2127.24f, -251.309f, 419.793f, 5.89921f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2120.1f, -258.99f, 419.764f, 6.24828f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2123.32f, -254.771f, 419.789f, 6.17846f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - - // Captured Mercenary Captain 32908 - me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY : NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE, 2131.31f, -259.182f, 419.974f, 5.91667f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - - // Dark Rune Acolyte (arena) 32886 - me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_I, 2129.09f, -277.142f, 419.756f, 1.22173f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - - // Iron Ring Guard 32874 - me->SummonCreature(NPC_IRON_RING_GUARD, 2217.69f, -337.394f, 412.177f, 1.23918f); - me->SummonCreature(NPC_IRON_RING_GUARD, 2218.38f, -297.505f, 412.176f, 1.02974f); - me->SummonCreature(NPC_IRON_RING_GUARD, 2235.26f, -338.345f, 412.134f, 1.58979f); - me->SummonCreature(NPC_IRON_RING_GUARD, 2235.07f, -297.985f, 412.134f, 1.61336f); - - // Dark Rune Acolyte (gauntlet) 33110 - me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2198.29f, -436.92f, 419.985f, 0.261799f); - me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2227.58f, -308.303f, 412.134f, 1.59372f); - me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2227.47f, -345.375f, 412.134f, 1.56622f); - - // Iron Honor Guard 32875 - me->SummonCreature(NPC_IRON_HONOR_GUARD, 2198.05f, -428.769f, 419.985f, 6.05629f); - me->SummonCreature(NPC_IRON_HONOR_GUARD, 2220.31f, -436.22f, 412.26f, 1.06465f); - - // Runic Colossus 32872 - me->SummonCreature(NPC_RUNIC_COLOSSUS, 2227.5f, -396.179f, 412.176f, 1.79769f); - - // Ancient Rune Giant 32873 - me->SummonCreature(NPC_ANCIENT_RUNE_GIANT, 2134.57f, -440.318f, 438.331f, 0.226893f); - - // Sif 33196 - me->SummonCreature(NPC_SIF, 2147.86f, -301.2f, 438.246f, 2.488f); - } - - void CloseDoors() - { - GameObject* go; - if ((go = GetThorimObject(DATA_THORIM_LEVER))) - { - go->ReplaceAllGameObjectFlags((GameObjectFlags)48); - go->SetGoState(GO_STATE_READY); - } - if ((go = GetThorimObject(DATA_THORIM_FIRST_DOORS))) - go->SetGoState(GO_STATE_READY); - - if ((go = GetThorimObject(DATA_THORIM_SECOND_DOORS))) - go->SetGoState(GO_STATE_READY); - - if ((go = GetThorimObject(DATA_THORIM_FENCE))) - go->SetGoState(GO_STATE_ACTIVE); - } - - void EnterEvadeMode(EvadeReason why) override - { - DisableThorim(false); - CreatureAI::EnterEvadeMode(why); - } - - void Reset() override - { - if (m_pInstance && !_encounterFinished) - m_pInstance->SetData(TYPE_THORIM, NOT_STARTED); - - events.Reset(); - events.SetPhase(0); - summons.DespawnAll(); - - _trashCounter = 0; - _isAlly = true; - _isHitAllowed = false; - _spawnCommoners = false; - _hardMode = false; - _isArenaEmpty = false; - _hitByLightning = false; - - if (Player* t = SelectTargetFromPlayerList(1000)) - if (t->GetTeamId() == TEAM_HORDE) - _isAlly = false; - - SpawnAllNPCs(); - - CloseDoors(); - DisableThorim(false); - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_HIT_BY_LIGHTNING) - return !_hitByLightning; - if (param == DATA_LOSE_YOUR_ILLUSION) - return _hardMode; - - return 0; - } - - void DoAction(int32 param) override - { - if (param == ACTION_START_TRASH_DIED) - { - _trashCounter++; - // activate levar - if (_trashCounter >= 6) - { - if (GameObject* go = GetThorimObject(DATA_THORIM_LEVER)) - go->RemoveGameObjectFlag((GameObjectFlags)48); - - events.ScheduleEvent(EVENT_THORIM_AGGRO, 0ms); - events.SetPhase(EVENT_PHASE_START); - events.ScheduleEvent(EVENT_THORIM_START_PHASE1, 20s); - _trashCounter = 0; - } - } - else if (param == ACTION_ALLOW_HIT) - _isHitAllowed = true; - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - void JustReachedHome() override { me->setActive(false); } - - void JustEngagedWith(Unit*) override - { - if (m_pInstance && !_encounterFinished) - m_pInstance->SetData(TYPE_THORIM, IN_PROGRESS); - me->setActive(true); - DisableThorim(true); - me->CastSpell(me, SPELL_SHEATH_OF_LIGHTNING, true); - //me->CastSpell(me, SPELL_TOUCH_OF_DOMINION, true); - } - - void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (who && _isHitAllowed && who->GetPositionZ() > 430 && who->GetTypeId() == TYPEID_PLAYER) - { - _isHitAllowed = false; - DisableThorim(false); - - events.SetPhase(EVENT_PHASE_RING); - events.ScheduleEvent(EVENT_THORIM_UNBALANCING_STRIKE, 8s, 0, EVENT_PHASE_RING); - events.ScheduleEvent(EVENT_THORIM_LIGHTNING_CHARGE, 12s + 500ms, 0, EVENT_PHASE_RING); - events.ScheduleEvent(EVENT_THORIM_CHAIN_LIGHTNING, 13s, 0, EVENT_PHASE_RING); - events.ScheduleEvent(EVENT_THORIM_BERSERK, 5min, 0, EVENT_PHASE_RING); - - me->GetMotionMaster()->MoveChase(me->GetVictim()); - me->GetMotionMaster()->MoveJump(Middle.GetPositionX(), Middle.GetPositionY(), Middle.GetPositionZ(), 20, 20); - me->RemoveAura(SPELL_SHEATH_OF_LIGHTNING); - - Talk(SAY_JUMPDOWN); - - // Hard Mode - if (!me->HasAura(62565 /*TOUCH OF DOMINION TRIGGER*/)) - { - if (m_pInstance) - m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 64980 /*SIFFED ACHIEVEMENT*/); - - _hardMode = true; - EntryCheckPredicate pred(NPC_SIF); - summons.DoAction(ACTION_SIF_JOIN_FIGHT, pred); - } - - DoResetThreatList(); - if (Player* player = GetArenaPlayer()) - me->AddThreat(player, 1000.0f); - } - - if (damage >= me->GetHealth()) - { - damage = 0; - if (!_encounterFinished) - { - _encounterFinished = true; - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetFaction(FACTION_FRIENDLY); - me->SetHealth(me->GetMaxHealth()); - me->CombatStop(); - me->RemoveAllAuras(); - events.Reset(); - DisableThorim(true); - - Talk(SAY_DEATH); - - events.SetPhase(EVENT_PHASE_OUTRO); - events.ScheduleEvent(EVENT_THORIM_OUTRO1, 2s, 0, EVENT_PHASE_OUTRO); - - GameObject* go = nullptr; - if ((go = GetThorimObject(DATA_THORIM_FENCE))) - go->SetGoState(GO_STATE_ACTIVE); - - uint32 chestId = me->GetMap()->Is25ManRaid() ? GO_THORIM_CHEST_HERO : GO_THORIM_CHEST; - if (_hardMode) - chestId += 1; // hard mode offset - - if ((go = me->SummonGameObject(chestId, 2134.73f, -286.32f, 419.51f, 4.65f, 0, 0, 0, 0, 0))) - { - go->ReplaceAllGameObjectFlags((GameObjectFlags)0); - go->SetLootRecipient(me->GetMap()); - } - - // Defeat credit - if (m_pInstance) - { - me->CastSpell(me, 64985, true); // credit - m_pInstance->SetData(TYPE_THORIM, DONE); - } - } - } - } - - void SpawnArenaNPCs() - { - Creature* cr; - uint8 rnd; - if (_spawnCommoners || urand(0, 2)) - _spawnCommoners = !_spawnCommoners; - - for (uint8 i = 0; i < (_spawnCommoners ? 7 : 2); ++i) - { - rnd = urand(0, 13); - if ((cr = me->SummonCreature((_spawnCommoners ? NPC_DARK_RUNE_COMMONER : RollTable[urand(0, 2)]), ArenaNPCs[rnd], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))) - cr->GetMotionMaster()->MoveJump( - Middle.GetPositionX() + urand(19, 24) * cos(Middle.GetAngle(cr)), - Middle.GetPositionY() + urand(19, 24) * std::sin(Middle.GetAngle(cr)), - Middle.GetPositionZ(), 20, 20); - } - } - - void SpellHit(Unit* caster, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_LIGHTNING_ORB_CHARGER) - { - me->SetOrientation(me->GetAngle(caster)); - me->CastSpell(caster, SPELL_LIGHTNING_CHARGE_DAMAGE, true); - me->CastSpell(me, SPELL_LIGHTNING_CHARGE_BUFF, true); - events.RescheduleEvent(EVENT_THORIM_LIGHTNING_CHARGE, 10s, 0, EVENT_PHASE_RING); - } - } - - void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_LIGHTNING_CHARGE_DAMAGE && target->GetTypeId() == TYPEID_PLAYER) - _hitByLightning = true; - } - - Player* GetArenaPlayer() - { - Map::PlayerList const& pList = me->GetMap()->GetPlayers(); - for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) - if (Player* p = itr->GetSource()) - if (p->GetPositionX() > 2085 && p->GetPositionX() < 2185 && p->GetPositionY() < -214 && p->GetPositionY() > -305 && p->IsAlive() && p->GetPositionZ() < 425) - return p; - return nullptr; - } - - void UpdateAI(uint32 diff) override - { - if (!_encounterFinished && !UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_THORIM_AGGRO: - Talk(SAY_AGGRO_1); - events.ScheduleEvent(EVENT_THORIM_AGGRO2, 9s); - - if (GameObject* go = GetThorimObject(DATA_THORIM_FENCE)) - go->SetGoState(GO_STATE_READY); - - break; - case EVENT_THORIM_AGGRO2: - { - Talk(SAY_AGGRO_2); - - EntryCheckPredicate pred(NPC_SIF); - summons.DoAction(ACTION_SIF_START_TALK, pred); - break; - } - case EVENT_THORIM_START_PHASE1: - { - events.ScheduleEvent(EVENT_THORIM_STORMHAMMER, 8s, 0, EVENT_PHASE_START); - events.ScheduleEvent(EVENT_THORIM_CHARGE_ORB, 14s, 0, EVENT_PHASE_START); - events.ScheduleEvent(EVENT_THORIM_FILL_ARENA, 0ms, 0, EVENT_PHASE_START); - events.ScheduleEvent(EVENT_THORIM_LIGHTNING_ORB, 5s, 0, EVENT_PHASE_START); // checked every 5 secs if there are players on arena - events.ScheduleEvent(EVENT_THORIM_NOT_REACH_IN_TIME, 5min, 0, EVENT_PHASE_START); - - EntryCheckPredicate pred(NPC_SIF); - summons.DoAction(ACTION_SIF_START_DOMINION, pred); - break; - } - case EVENT_THORIM_STORMHAMMER: - me->CastCustomSpell(SPELL_STORMHAMMER, SPELLVALUE_MAX_TARGETS, 1, me->GetVictim(), false); - events.Repeat(16s); - break; - case EVENT_THORIM_CHARGE_ORB: - me->CastCustomSpell(SPELL_CHARGE_ORB, SPELLVALUE_MAX_TARGETS, 1, me, false); - events.Repeat(16s); - break; - case EVENT_THORIM_LIGHTNING_ORB: - { - if (GetArenaPlayer()) - { - // Player found, repeat and return - events.Repeat(5s); - return; - } - - // No players found - Talk(SAY_WIPE); - me->SummonCreature(NPC_LIGHTNING_ORB, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); - - _isArenaEmpty = true; - events.CancelEvent(EVENT_THORIM_NOT_REACH_IN_TIME); - break; - } - case EVENT_THORIM_NOT_REACH_IN_TIME: - _isArenaEmpty = true; - events.CancelEvent(EVENT_THORIM_LIGHTNING_ORB); - me->CastSpell(me, SPELL_BERSERK_FRIENDS, true); - me->SummonCreature(NPC_LIGHTNING_ORB, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); - break; - case EVENT_THORIM_FILL_ARENA: - SpawnArenaNPCs(); - events.Repeat(10s); - break; - case EVENT_THORIM_UNBALANCING_STRIKE: - me->CastSpell(me->GetVictim(), SPELL_UNBALANCING_STRIKE, false); - events.Repeat(20s); - break; - case EVENT_THORIM_LIGHTNING_CHARGE: - me->CastSpell(me, SPELL_LIGHTNING_PILLAR_P2, true); - break; - case EVENT_THORIM_CHAIN_LIGHTNING: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_CHAIN_LIGHTNING, false); - events.Repeat(15s); - break; - case EVENT_THORIM_BERSERK: - me->CastSpell(me, SPELL_BERSERK, true); - Talk(SAY_BERSERK); - break; - case EVENT_THORIM_OUTRO1: - if (_hardMode) - { - Talk(SAY_END_HARD_1); - events.ScheduleEvent(EVENT_THORIM_OUTRO2, 5s, 0, 3); - EntryCheckPredicate pred(NPC_SIF); - summons.DoAction(ACTION_SIF_TRANSFORM, pred); - } - else - { - Talk(SAY_END_NORMAL_1); - events.ScheduleEvent(EVENT_THORIM_OUTRO2, 9s, 0, 3); - } - break; - case EVENT_THORIM_OUTRO2: - if (_hardMode) - { - Talk(SAY_END_HARD_2); - events.ScheduleEvent(EVENT_THORIM_OUTRO3, 12s, 0, 3); - } - else - { - Talk(SAY_END_NORMAL_2); - events.ScheduleEvent(EVENT_THORIM_OUTRO3, 10s, 0, 3); - } - break; - case EVENT_THORIM_OUTRO3: - if (_hardMode) - { - Talk(SAY_END_HARD_3); - } - else - { - Talk(SAY_END_NORMAL_3); - } - - // Defeat credit - if (m_pInstance) - m_pInstance->SetData(TYPE_THORIM, DONE); - - me->DespawnOrUnsummon(8000); - break; - } - - if (!_encounterFinished) - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_thorim_sif : public CreatureScript -{ -public: - boss_thorim_sif() : CreatureScript("boss_thorim_sif") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorim_sifAI : public ScriptedAI - { - boss_thorim_sifAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - void MoveInLineOfSight(Unit*) override {} - void AttackStart(Unit*) override {} - - bool _allowCast; - EventMap events; - - void Reset() override - { - events.Reset(); - me->SetReactState(REACT_PASSIVE); - _allowCast = false; - } - - void DoAction(int32 param) override - { - if (param == ACTION_SIF_START_TALK) - events.ScheduleEvent(EVENT_SIF_START_TALK, 9s); - else if (param == ACTION_SIF_START_DOMINION) - { - if (me->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) - me->CastSpell(cr, SPELL_TOUCH_OF_DOMINION, false); - - events.ScheduleEvent(EVENT_SIF_FINISH_DOMINION, 150s); - } - else if (param == ACTION_SIF_JOIN_FIGHT) - { - me->InterruptNonMeleeSpells(false); - events.ScheduleEvent(EVENT_SIF_JOIN_TALK, 9s); - events.CancelEvent(EVENT_SIF_START_TALK); - events.CancelEvent(EVENT_SIF_FINISH_DOMINION); - } - else if (param == ACTION_SIF_TRANSFORM) - { - me->CastSpell(me, SPELL_SIF_TRANSFORM, true); - me->DespawnOrUnsummon(5000); - events.Reset(); - _allowCast = false; - } - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SIF_FINISH_DOMINION: - Talk(SAY_SIF_HM_MISSED); - me->DespawnOrUnsummon(5000); - break; - case EVENT_SIF_START_TALK: - Talk(SAY_SIF_AGGRO); - break; - case EVENT_SIF_JOIN_TALK: - Talk(SAY_SIF_HM_REACHED); - events.ScheduleEvent(EVENT_SIF_FROST_NOVA_START, 1s); - events.ScheduleEvent(EVENT_SIF_FROSTBOLT_VALLEY, 11s); - events.ScheduleEvent(EVENT_SIF_BLIZZARD, 15s); - break; - case EVENT_SIF_FROSTBOLT_VALLEY: - me->CastSpell(me, SPELL_FROSTBOLT_VALLEY, false); - events.Repeat(13s); - return; - case EVENT_SIF_BLIZZARD: - me->SummonCreature(NPC_SIF_BLIZZARD, 2108.7f, -280.04f, 419.42f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); - events.Repeat(30s); - return; - case EVENT_SIF_FROST_NOVA_START: - me->NearTeleportTo(2108 + urand(0, 42), -238 - irand(0, 46), 420.02f, me->GetAngle(&Middle)); - events.Repeat(20s); - events.DelayEvents(5s); - events.ScheduleEvent(EVENT_SIF_FROST_NOVA_CAST, 2500ms); - _allowCast = false; - return; - case EVENT_SIF_FROST_NOVA_CAST: - _allowCast = true; - me->CastSpell(me, SPELL_FROST_NOVA, false); - return; - } - - // has casting check before event select (return in events) - if (_allowCast) - if (Player* target = SelectTargetFromPlayerList(70)) - { - me->CastSpell(target, SPELL_FROSTBOLT, false); - me->StopMoving(); - } - } - }; -}; - -class boss_thorim_lightning_orb : public CreatureScript -{ -public: - boss_thorim_lightning_orb() : CreatureScript("boss_thorim_lightning_orb") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorim_lightning_orbAI : public npc_escortAI - { - boss_thorim_lightning_orbAI(Creature* pCreature) : npc_escortAI(pCreature) - { - InitWaypoint(); - Reset(); - Start(false, true); - } - - uint32 Timer; - - void EnterEvadeMode(EvadeReason /*why*/) override {} - void MoveInLineOfSight(Unit*) override {} - void AttackStart(Unit*) override {} - - void InitWaypoint() - { - AddWaypoint(1, 2135, -304, 438.24f, 0); - AddWaypoint(2, 2132, -441, 438.24f, 0); - AddWaypoint(3, 2167, -442, 438.24f, 0); - AddWaypoint(4, 2227, -432, 412.18f, 0); - AddWaypoint(5, 2227, -263, 412.17f, 0); - AddWaypoint(6, 2179, -262, 414.7f, 0); - AddWaypoint(7, 2169, -261, 419.3f, 0); - AddWaypoint(8, 2110, -251, 419.42f, 0); - } - - void Reset() override - { - me->CastSpell(me, SPELL_LIGHTNING_DESTRUCTION, true); - } - - void WaypointReached(uint32 /*point*/) override - { - } - }; -}; - -class boss_thorim_trap : public CreatureScript -{ -public: - boss_thorim_trap() : CreatureScript("boss_thorim_trap") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorim_trapAI : public NullCreatureAI - { - boss_thorim_trapAI(Creature* pCreature) : NullCreatureAI(pCreature) { } - - uint32 _checkTimer; - - void Reset() override { _checkTimer = 1; } - void UpdateAI(uint32 diff) override - { - if (_checkTimer) - { - _checkTimer += diff; - if ((_checkTimer >= 1000 && _checkTimer < 10000) || _checkTimer >= 60000) - { - if (me->SelectNearbyTarget(nullptr, 12.0f)) - { - me->CastSpell(me, SPELL_LIGHTNING_FIELD, true); - me->CastSpell(me, (me->GetEntry() == 33054 /*NPC_THORIM_TRAP_BUNNY*/ ? SPELL_PARALYTIC_FIELD_FIRST : SPELL_PARALYTIC_FIELD_SECOND), true); - _checkTimer = 10000; - return; - } - _checkTimer = 1; - } - } - } - }; -}; - -class boss_thorim_sif_blizzard : public CreatureScript -{ -public: - boss_thorim_sif_blizzard() : CreatureScript("boss_thorim_sif_blizzard") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorim_sif_blizzardAI : public npc_escortAI - { - boss_thorim_sif_blizzardAI(Creature* pCreature) : npc_escortAI(pCreature) - { - InitWaypoint(); - Reset(); - Start(false, true); - SetDespawnAtEnd(false); - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - void JustEngagedWith(Unit* /*who*/) override {} - void AttackStart(Unit* /*who*/) override {} - - void InitWaypoint() - { - AddWaypoint(1, 2104.6f, -268.5f, 419.4f, 0); - AddWaypoint(2, 2104.3f, -256.3f, 419.4f, 0); - AddWaypoint(3, 2109.3f, -246.4f, 419.4f, 0); - AddWaypoint(4, 2117.9f, -238.6f, 419.4f, 0); - AddWaypoint(5, 2128.8f, -232.1f, 419.4f, 0); - AddWaypoint(6, 2151.9f, -237.5f, 419.4f, 0); - AddWaypoint(7, 2164.9f, -256.3f, 419.4f, 0); - AddWaypoint(8, 2161.5f, -280.0f, 419.4f, 0); - } - - void Reset() override - { - me->SetSpeed(MOVE_RUN, 1); - me->SetSpeed(MOVE_WALK, 1); - me->CastSpell(me, RAID_MODE(SPELL_BLIZZARD_10, SPELL_BLIZZARD_25), true); - } - - void WaypointReached(uint32 /*point*/) override - { - } - }; -}; - -class boss_thorim_pillar : public CreatureScript -{ -public: - boss_thorim_pillar() : CreatureScript("boss_thorim_pillar") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorim_pillarAI : public NullCreatureAI - { - boss_thorim_pillarAI(Creature* pCreature) : NullCreatureAI(pCreature) { } - - uint32 _resetTimer; - - void Reset() override - { - _resetTimer = 0; - me->SetControlled(true, UNIT_STATE_STUNNED); - me->SetDisableGravity(true); - } - - void SpellHit(Unit*, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_CHARGE_ORB) - me->CastSpell(me, SPELL_LIGHTNING_PILLAR_P1, true); - else if (spellInfo->Id == SPELL_LIGHTNING_PILLAR_P2) - { - if (Creature* cr = me->FindNearestCreature(NPC_THUNDER_ORB, 100)) - cr->CastSpell(cr, SPELL_LIGHTNING_ORB_VISUAL, true); - } - } - - void UpdateAI(uint32 diff) override - { - _resetTimer += diff; - if (_resetTimer >= 10000) - Reset(); // _resetTimer set to 0 - } - }; -}; - -class boss_thorim_start_npcs : public CreatureScript -{ -public: - boss_thorim_start_npcs() : CreatureScript("boss_thorim_start_npcs") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorim_start_npcsAI : public ScriptedAI - { - boss_thorim_start_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - EventMap events; - bool _isCaster; - bool _playerAttack; - - void Reset() override - { - events.Reset(); - _isCaster = (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I); - _playerAttack = false; - if (me->GetEntry() != NPC_JORMUNGAR_BEHEMOT) - if (Creature* cr = me->FindNearestCreature(NPC_JORMUNGAR_BEHEMOT, 30.0f)) - AttackStart(cr); - } - - void DamageTaken(Unit* who, uint32&, DamageEffectType, SpellSchoolMask) override - { - if (!_playerAttack && who && (who->GetTypeId() == TYPEID_PLAYER || who->GetOwnerGUID().IsPlayer())) - { - if (me->GetInstanceScript()) - if (Creature* thorim = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) - { - if (!thorim->IsInCombat()) - { - thorim->SetInCombatWithZone(); - thorim->AI()->AttackStart(who); - } - } - _playerAttack = true; - me->GetThreatMgr().ResetAllThreat(); - me->CallForHelp(40.0f); - AttackStart(who); - } - - if (!_playerAttack && me->HealthBelowPct(60)) - me->SetHealth(me->GetMaxHealth()); - } - - void JustDied(Unit*) override - { - if (me->GetInstanceScript()) - if (Creature* thorim = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) - thorim->AI()->DoAction(ACTION_START_TRASH_DIED); - } - - void JustEngagedWith(Unit* /*who*/) override - { - if (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I) - { - events.ScheduleEvent(EVENT_DR_ACOLYTE_GH, 10s); - events.ScheduleEvent(EVENT_DR_ACOLYTE_HS, 5s); - events.ScheduleEvent(EVENT_DR_ACOLYTE_R, 7s); - } - else if (me->GetEntry() == NPC_CAPTURED_MERCENARY_SOLDIER_ALLY || me->GetEntry() == NPC_CAPTURED_MERCENARY_SOLDIER_HORDE) - { - events.ScheduleEvent(EVENT_CM_SOLDIER_BS, 9s); - events.ScheduleEvent(EVENT_CM_SOLDIER_WC, 5s); - events.ScheduleEvent(EVENT_CM_SOLDIER_S, 0ms); - } - else if (me->GetEntry() == NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY || me->GetEntry() == NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE) - { - events.ScheduleEvent(EVENT_CM_CAPTAIN_D, 9s); - events.ScheduleEvent(EVENT_CM_CAPTAIN_HC, 5s); - } - else if (me->GetEntry() == NPC_JORMUNGAR_BEHEMOT) - { - events.ScheduleEvent(EVENT_JB_ACID_BREATH, 12s); - events.ScheduleEvent(EVENT_JB_SWEEP, 5s); - } - - me->CallForHelp(10); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_DR_ACOLYTE_GH: - if (HealthBelowPct(60)) - me->CastSpell(me, SPELL_GREATER_HEAL, false); - else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 20)) - me->CastSpell(target, SPELL_GREATER_HEAL, false); - events.Repeat(10s); - break; - case EVENT_DR_ACOLYTE_HS: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_HOLY_SMITE, false); - events.Repeat(1600ms); - break; - case EVENT_DR_ACOLYTE_R: - if (HealthBelowPct(75) && !me->HasAura(SPELL_RENEW)) - me->CastSpell(me, SPELL_GREATER_HEAL, false); - else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 10)) - me->CastSpell(target, SPELL_RENEW, false); - events.Repeat(7s); - break; - case EVENT_CM_SOLDIER_BS: - me->CastSpell(me->GetVictim(), SPELL_BARBED_SHOT, false); - events.Repeat(9s); - break; - case EVENT_CM_SOLDIER_WC: - me->CastSpell(me->GetVictim(), SPELL_WING_CLIP, false); - events.Repeat(5s); - break; - case EVENT_CM_SOLDIER_S: - if (me->GetDistance(me->GetVictim()) > 8) - me->CastSpell(me->GetVictim(), SPELL_SHOOT, false); - - events.Repeat(1500ms); - break; - case EVENT_CM_CAPTAIN_D: - me->CastSpell(me->GetVictim(), SPELL_DEVASTATE, false); - events.Repeat(9s); - break; - case EVENT_CM_CAPTAIN_HC: - me->CastSpell(me->GetVictim(), SPELL_HEROIC_STRIKE, false); - events.Repeat(5s); - break; - case EVENT_JB_ACID_BREATH: - me->CastSpell(me->GetVictim(), SPELL_ACID_BREATH, false); - events.Repeat(12s); - break; - case EVENT_JB_SWEEP: - me->CastSpell(me->GetVictim(), SPELL_SWEEP, false); - events.Repeat(5s); - break; - } - - if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10)) - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_thorim_gauntlet_npcs : public CreatureScript -{ -public: - boss_thorim_gauntlet_npcs() : CreatureScript("boss_thorim_gauntlet_npcs") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorim_gauntlet_npcsAI : public ScriptedAI - { - boss_thorim_gauntlet_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - EventMap events; - bool _isCaster; - - void Reset() override - { - events.Reset(); - _isCaster = (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_G); - } - - void JustEngagedWith(Unit* /*who*/) override - { - if (me->GetEntry() == NPC_IRON_RING_GUARD) - { - events.ScheduleEvent(EVENT_IR_GUARD_IMPALE, 12s); - events.ScheduleEvent(EVENT_IR_GUARD_WHIRL, 5s); - } - else if (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I) - { - events.ScheduleEvent(EVENT_DR_ACOLYTE_GH, 10s); - events.ScheduleEvent(EVENT_DR_ACOLYTE_HS, 5s); - events.ScheduleEvent(EVENT_DR_ACOLYTE_R, 7s); - } - else if (me->GetEntry() == NPC_IRON_HONOR_GUARD) - { - events.ScheduleEvent(EVENT_IH_GUARD_CLEAVE, 6s); - events.ScheduleEvent(EVENT_IH_GUARD_HAMSTRING, 9s); - events.ScheduleEvent(EVENT_IH_GUARD_SHIELD_SMASH, 15s); - - if (Creature* runeGiant = me->FindNearestCreature(NPC_ANCIENT_RUNE_GIANT, 200.0f)) - runeGiant->AI()->DoAction(ACTION_IRON_HONOR_DIED); - } - - me->CallForHelp(25); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_IR_GUARD_IMPALE: - me->CastSpell(me->GetVictim(), SPELL_IMPALE, false); - events.Repeat(12s); - break; - case EVENT_IR_GUARD_WHIRL: - me->CastSpell(me->GetVictim(), SPELL_WHIRLING_TRIP, false); - events.Repeat(5s); - break; - case EVENT_DR_ACOLYTE_GH: - if (HealthBelowPct(60)) - me->CastSpell(me, SPELL_GREATER_HEAL, false); - else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 20)) - me->CastSpell(target, SPELL_GREATER_HEAL, false); - events.Repeat(10s); - break; - case EVENT_DR_ACOLYTE_HS: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_HOLY_SMITE, false); - events.Repeat(1600ms); - break; - case EVENT_DR_ACOLYTE_R: - if (HealthBelowPct(75) && !me->HasAura(SPELL_RENEW)) - me->CastSpell(me, SPELL_GREATER_HEAL, false); - else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 10)) - me->CastSpell(target, SPELL_RENEW, false); - events.Repeat(7s); - break; - case EVENT_IH_GUARD_CLEAVE: - me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false); - events.Repeat(6s); - break; - case EVENT_IH_GUARD_HAMSTRING: - me->CastSpell(me->GetVictim(), SPELL_HAMSTRING, false); - events.Repeat(9s); - break; - case EVENT_IH_GUARD_SHIELD_SMASH: - me->CastSpell(me->GetVictim(), SPELL_SHIELD_SMASH, false); - events.Repeat(15s); - break; - } - - if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10)) - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_thorim_runic_colossus : public CreatureScript -{ -public: - boss_thorim_runic_colossus() : CreatureScript("boss_thorim_runic_colossus") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorim_runic_colossusAI : public ScriptedAI - { - boss_thorim_runic_colossusAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - EventMap events; - bool _leftHand; - bool _checkTarget; - float _nextTriggerPos; - ObjectGuid _triggerLeftGUID[2], _triggerRightGUID[2]; - - void Reset() override - { - _nextTriggerPos = 0.0f; - _leftHand = false; - _checkTarget = false; - events.Reset(); - events.ScheduleEvent(EVENT_RC_RUNIC_SMASH, 0ms); - Creature* c; - - if ((c = me->SummonCreature(33140, 2221, -385, me->GetPositionZ()))) - _triggerRightGUID[0] = c->GetGUID(); - if ((c = me->SummonCreature(33140, 2210, -385, me->GetPositionZ()))) - _triggerRightGUID[1] = c->GetGUID(); - - if ((c = me->SummonCreature(33141, 2235, -385, me->GetPositionZ()))) - _triggerLeftGUID[0] = c->GetGUID(); - if ((c = me->SummonCreature(33141, 2246, -385, me->GetPositionZ()))) - _triggerLeftGUID[1] = c->GetGUID(); - } - - void JustDied(Unit*) override - { - if (me->GetInstanceScript()) - { - if (GameObject* go = ObjectAccessor::GetGameObject(*me, me->GetInstanceScript()->GetGuidData(DATA_THORIM_FIRST_DOORS))) - go->SetGoState(GO_STATE_ACTIVE); - - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) - cr->AI()->Talk(SAY_SPECIAL_2); - } - } - - void JustEngagedWith(Unit*) override - { - events.CancelEvent(EVENT_RC_RUNIC_SMASH); - events.ScheduleEvent(EVENT_RC_RUNIC_BARRIER, 10s); - events.ScheduleEvent(EVENT_RC_SMASH, 18s); - events.ScheduleEvent(EVENT_RC_CHARGE, 15s); - - me->InterruptNonMeleeSpells(false); - _checkTarget = true; - } - - void SpellHit(Unit*, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_RUNIC_SMASH_LEFT || spellInfo->Id == SPELL_RUNIC_SMASH_RIGHT) - { - _leftHand = spellInfo->Id == SPELL_RUNIC_SMASH_LEFT; - events.RescheduleEvent(EVENT_RC_RUNIC_SMASH_TRIGGER, 1s); - } - } - - void RunRunicSmash(bool cast) - { - if (Creature* cr = ObjectAccessor::GetCreature(*me, _leftHand ? _triggerLeftGUID[0] : _triggerRightGUID[0]) ) - { - if (cast) - cr->CastSpell(cr, SPELL_RUNIC_SMASH_DAMAGE, true); - cr->SetPosition(_leftHand ? 2235.0f : 2221.0f, _nextTriggerPos, cr->GetPositionZ(), 0.0f); - cr->StopMovingOnCurrentPos(); - } - if( Creature* cr = ObjectAccessor::GetCreature(*me, _leftHand ? _triggerLeftGUID[1] : _triggerRightGUID[1]) ) - { - if (cast) - cr->CastSpell(cr, SPELL_RUNIC_SMASH_DAMAGE, true); - cr->SetPosition(_leftHand ? 2246.0f : 2210.0f, _nextTriggerPos, cr->GetPositionZ(), 0.0f); - cr->StopMovingOnCurrentPos(); - } - } - - void UpdateAI(uint32 diff) override - { - if (_checkTarget && !UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_RC_RUNIC_SMASH_TRIGGER: - _nextTriggerPos += 16.0f; - if (_nextTriggerPos <= -260.0f) - { - events.RescheduleEvent(EVENT_RC_RUNIC_SMASH_TRIGGER, 500ms); - } - - RunRunicSmash(true); - break; - case EVENT_RC_RUNIC_SMASH: - if (urand(0, 1)) - me->CastSpell(me, SPELL_RUNIC_SMASH_LEFT, false); - else - me->CastSpell(me, SPELL_RUNIC_SMASH_RIGHT, false); - - _nextTriggerPos = -385.0f; - RunRunicSmash(false); - events.Repeat(11s); - break; - case EVENT_RC_RUNIC_BARRIER: - me->CastSpell(me, SPELL_RUNIC_BARRIER, false); - Talk(SAY_COLOSSUS_RUNIC_BARRIER); - events.Repeat(20s); - break; - case EVENT_RC_SMASH: - me->CastSpell(me->GetVictim(), SPELL_SMASH, false); - events.Repeat(10s); - break; - case EVENT_RC_CHARGE: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_CHARGE, false); - events.Repeat(15s); - break; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_thorim_ancient_rune_giant : public CreatureScript -{ -public: - boss_thorim_ancient_rune_giant() : CreatureScript("boss_thorim_ancient_rune_giant") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorim_ancient_rune_giantAI : public ScriptedAI - { - boss_thorim_ancient_rune_giantAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - EventMap events; - bool _isInCombat; - - void Reset() override - { - _isInCombat = false; - events.Reset(); - } - - void JustEngagedWith(Unit*) override - { - _isInCombat = true; - events.CancelEvent(EVENT_ARG_SPAWN); - events.ScheduleEvent(EVENT_ARG_RD, 12s); - events.ScheduleEvent(EVENT_ARG_STOMP, 8s); - - me->CastSpell(me, SPELL_RUNIC_FORTIFICATION, false); - Talk(SAY_GIANT_RUNIC_MIGHT); - } - - void JustDied(Unit*) override - { - if (InstanceScript* pInstance = me->GetInstanceScript()) - { - if (GameObject* go = ObjectAccessor::GetGameObject(*me, pInstance->GetGuidData(DATA_THORIM_SECOND_DOORS))) - go->SetGoState(GO_STATE_ACTIVE); - - if (Creature* thorim = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_THORIM))) - thorim->AI()->DoAction(ACTION_ALLOW_HIT); - } - } - - void DoAction(int32 param) override - { - if (param == ACTION_IRON_HONOR_DIED) - events.RescheduleEvent(EVENT_ARG_SPAWN, 20s); - } - - void UpdateAI(uint32 diff) override - { - if (_isInCombat && !UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_ARG_RD: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_RUNE_DETONATION, false); - events.Repeat(12s); - break; - case EVENT_ARG_STOMP: - me->CastSpell(me->GetVictim(), SPELL_STOMP, false); - events.Repeat(8s); - break; - case EVENT_ARG_SPAWN: - if (Creature* cr = me->SummonCreature(NPC_IRON_HONOR_GUARD, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000)) - if (Unit* target = SelectTargetFromPlayerList(150.0f)) - cr->AI()->AttackStart(target); - events.Repeat(10s); - break; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_thorim_arena_npcs : public CreatureScript -{ -public: - boss_thorim_arena_npcs() : CreatureScript("boss_thorim_arena_npcs") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_thorim_arena_npcsAI : public ScriptedAI - { - boss_thorim_arena_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - EventMap events; - bool _isCaster; - - void Reset() override - { - _isCaster = (me->GetEntry() == NPC_DARK_RUNE_EVOKER); - events.Reset(); - if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER) - me->CastSpell(me, SPELL_AURA_OF_CELERITY, true); - } - - void JustEngagedWith(Unit*) override - { - if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER) - { - events.ScheduleEvent(EVENT_DR_WARBRINGER_RS, 8s); - } - else if (me->GetEntry() == NPC_DARK_RUNE_EVOKER) - { - events.ScheduleEvent(EVENT_DR_EVOKER_RL, 2500ms); - events.ScheduleEvent(EVENT_DR_EVOKER_RM, 4s); - events.ScheduleEvent(EVENT_DR_EVOKER_RS, 10s); - } - else if (me->GetEntry() == NPC_DARK_RUNE_CHAMPION) - { - events.ScheduleEvent(EVENT_DR_CHAMPION_WH, 6s); - events.ScheduleEvent(EVENT_DR_CHAMPION_CH, 12s); - events.ScheduleEvent(EVENT_DR_CHAMPION_MS, 8s); - } - else if (me->GetEntry() == NPC_DARK_RUNE_COMMONER) - { - events.ScheduleEvent(EVENT_DR_COMMONER_LB, 5s); - events.ScheduleEvent(EVENT_DR_COMMONER_PM, 6s); - } - } - - bool CanAIAttack(Unit const* target) const override - { - return target->GetPositionX() < 2180 && target->GetPositionZ() < 425; - } - - bool SelectT() - { - Player* target = nullptr; - Map::PlayerList const& pList = me->GetMap()->GetPlayers(); - uint8 num = urand(0, pList.getSize() - 1); - uint8 count = 0; - for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr, ++count) - { - if (itr->GetSource()->GetPositionX() > 2180 || !itr->GetSource()->IsAlive() || itr->GetSource()->GetPositionZ() > 425) - continue; - - if (count <= num || !target) - target = itr->GetSource(); - else - break; - } - - if (target) - { - AttackStart(target); - me->AddThreat(target, 500.0f); - if (me->GetEntry() == NPC_DARK_RUNE_EVOKER && urand(0, 1)) - me->CastSpell(me, SPELL_RUNIC_SHIELD, false); - else if (me->GetEntry() == NPC_DARK_RUNE_CHAMPION && !urand(0, 2)) - me->CastSpell(target, SPELL_CHARGE, false); - return true; - } - return false; - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim() && !SelectT()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_DR_WARBRINGER_RS: - me->CastSpell(me->GetVictim(), SPELL_RUNIC_STRIKE, false); - events.Repeat(8s); - break; - case EVENT_DR_EVOKER_RL: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_RUNIC_LIGHTNING, false); - events.Repeat(2500ms); - break; - case EVENT_DR_EVOKER_RM: - if (Unit* target = DoSelectLowestHpFriendly(40.0f, 15)) - me->CastSpell(target, SPELL_RUNIC_MENDING, false); - else - me->CastSpell(me, SPELL_RUNIC_MENDING, false); - events.Repeat(4s); - break; - case EVENT_DR_EVOKER_RS: - me->CastSpell(me, SPELL_RUNIC_SHIELD, false); - events.Repeat(10s); - break; - case EVENT_DR_CHAMPION_CH: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_CHARGE, false); - events.Repeat(12s); - break; - case EVENT_DR_CHAMPION_WH: - if (!me->HasUnitFlag(UNIT_FLAG_DISARMED)) - me->CastSpell(me, SPELL_WHIRLWIND, false); - events.Repeat(6s); - break; - case EVENT_DR_CHAMPION_MS: - me->CastSpell(me->GetVictim(), SPELL_MORTAL_STRIKE, false); - events.Repeat(8s); - break; - case EVENT_DR_COMMONER_LB: - me->CastSpell(me->GetVictim(), SPELL_LOW_BLOW, false); - events.Repeat(5s); - break; - case EVENT_DR_COMMONER_PM: - me->CastSpell(me->GetVictim(), SPELL_PUMMEL, false); - events.Repeat(6s); - break; - } - - if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10)) - DoMeleeAttackIfReady(); - } - }; -}; - -class go_thorim_lever : public GameObjectScript -{ -public: - go_thorim_lever() : GameObjectScript("go_thorim_lever") { } - - bool OnGossipHello(Player* pPlayer, GameObject* go) override - { - if (GameObject* g = pPlayer->FindNearestGameObject(GO_ARENA_LEVER_GATE, 50)) - g->UseDoorOrButton(); - - go->UseDoorOrButton(); - return true; - } -}; - -class spell_thorim_lightning_pillar_P2 : public SpellScriptLoader -{ -public: - spell_thorim_lightning_pillar_P2() : SpellScriptLoader("spell_thorim_lightning_pillar_P2") { } - - class spell_thorim_lightning_pillar_P2_AuraScript : public AuraScript - { - PrepareAuraScript(spell_thorim_lightning_pillar_P2_AuraScript); - - void OnPeriodic(AuraEffect const* aurEff) - { - PreventDefaultAction(); - if (Unit* caster = GetCaster()) - GetUnitOwner()->CastSpell(caster, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_thorim_lightning_pillar_P2_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_thorim_lightning_pillar_P2_AuraScript(); - } -}; - -class spell_thorim_trash_impale : public SpellScriptLoader -{ -public: - spell_thorim_trash_impale() : SpellScriptLoader("spell_thorim_trash_impale") { } - - class spell_thorim_trash_impale_AuraScript : public AuraScript - { - PrepareAuraScript(spell_thorim_trash_impale_AuraScript); - - void OnPeriodic(AuraEffect const* /*aurEff*/) - { - // deals damage until target is healed above 90% - if (GetUnitOwner()->HealthAbovePct(90)) - SetDuration(0); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_thorim_trash_impale_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_thorim_trash_impale_AuraScript(); - } -}; - -class achievement_thorim_stand_in_the_lightning : public AchievementCriteriaScript -{ -public: - achievement_thorim_stand_in_the_lightning() : AchievementCriteriaScript("achievement_thorim_stand_in_the_lightning") {} - - bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override - { - if (InstanceScript* instance = player->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*player, instance->GetGuidData(TYPE_THORIM))) - return cr->AI()->GetData(DATA_HIT_BY_LIGHTNING); - - return false; - } -}; - -class achievement_thorim_lose_your_illusion : public AchievementCriteriaScript -{ -public: - achievement_thorim_lose_your_illusion() : AchievementCriteriaScript("achievement_thorim_lose_your_illusion") {} - - bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override - { - if (InstanceScript* instance = player->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*player, instance->GetGuidData(TYPE_THORIM))) - return cr->AI()->GetData(DATA_LOSE_YOUR_ILLUSION); - - return false; - } -}; - void AddSC_boss_thorim() { // Main encounter diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.h new file mode 100644 index 00000000000000..96ba29d4a110de --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.h @@ -0,0 +1,1797 @@ +#ifndef BOSS_THORIM_H_ +#define BOSS_THORIM_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "GameObjectScript.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "ScriptedEscortAI.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "ulduar.h" + +enum ThorimSpells +{ + // THORIM + SPELL_LIGHTNING_DESTRUCTION = 62393, + SPELL_SHEATH_OF_LIGHTNING = 62276, + SPELL_STORMHAMMER = 62042, + SPELL_BERSERK_FRIENDS = 62560, + SPELL_CHAIN_LIGHTNING_10 = 62131, + SPELL_CHAIN_LIGHTNING_25 = 64390, + SPELL_UNBALANCING_STRIKE = 62130, + SPELL_BERSERK = 26662, + + SPELL_CHARGE_ORB = 62016, + SPELL_LIGHTNING_PILLAR_P1 = 63238, + + SPELL_LIGHTNING_ORB_VISUAL = 62186, + SPELL_LIGHTNING_CHARGE_DAMAGE = 62466, + SPELL_LIGHTNING_CHARGE_BUFF = 62279, + SPELL_LIGHTNING_PILLAR_P2 = 62976, + SPELL_LIGHTNING_ORB_CHARGER = 62278, + + // SIF + SPELL_TOUCH_OF_DOMINION = 62507, + SPELL_SIF_TRANSFORM = 64778, + SPELL_SIF_CHANNEL_HOLOGRAM = 64324, + SPELL_FROSTBOLT = 62601, + SPELL_FROSTBOLT_VALLEY = 62604, + SPELL_BLIZZARD_10 = 62577, + SPELL_BLIZZARD_25 = 62603, + SPELL_FROST_NOVA = 62605, + + // DARK RUNE ACOLYTE + SPELL_GREATER_HEAL_10 = 62334, + SPELL_GREATER_HEAL_25 = 62442, + SPELL_HOLY_SMITE_10 = 62335, + SPELL_HOLY_SMITE_25 = 62443, + SPELL_RENEW_10 = 62333, + SPELL_RENEW_25 = 62441, + + // CAPTURED MERCENARY SOLDIER + SPELL_BARBED_SHOT = 62318, + SPELL_WING_CLIP = 40652, + SPELL_SHOOT = 16496, + + // CAPTURED MERCENARY CAPTAIN + SPELL_DEVASTATE = 62317, + SPELL_HEROIC_STRIKE = 62444, + + // JORMUNGAR BEHEMOTH + SPELL_ACID_BREATH_10 = 62315, + SPELL_ACID_BREATH_25 = 62415, + SPELL_SWEEP_10 = 62316, + SPELL_SWEEP_25 = 62417, + + // IRON RING GUARD + SPELL_IMPALE_10 = 62331, + SPELL_IMPALE_25 = 62418, + SPELL_WHIRLING_TRIP = 64151, + + // IRON HONOR GUARD + SPELL_SHIELD_SMASH_10 = 62332, + SPELL_SHIELD_SMASH_25 = 62420, + SPELL_CLEAVE = 42724, + SPELL_HAMSTRING = 48639, + + // DARK RUNE WARBRINGER + SPELL_AURA_OF_CELERITY = 62320, + SPELL_RUNIC_STRIKE = 62322, + + // DARK RUNE EVOKER + SPELL_RUNIC_LIGHTNING_10 = 62327, + SPELL_RUNIC_LIGHTNING_25 = 62445, + SPELL_RUNIC_MENDING_10 = 62328, + SPELL_RUNIC_MENDING_25 = 62446, + SPELL_RUNIC_SHIELD_10 = 62321, + SPELL_RUNIC_SHIELD_25 = 62529, + + // DARK RUNE CHAMPION + SPELL_CHARGE = 32323, + SPELL_MORTAL_STRIKE = 35054, + SPELL_WHIRLWIND = 15578, + + // DARK RUNE COMMONER + SPELL_LOW_BLOW = 62326, + SPELL_PUMMEL = 38313, + + // RUNIC COLOSSUS + SPELL_COLOSSUS_CHARGE_10 = 62613, + SPELL_COLOSSUS_CHARGE_25 = 62614, + SPELL_RUNIC_BARRIER = 62338, + SPELL_SMASH = 62339, + SPELL_RUNIC_SMASH_LEFT = 62057, + SPELL_RUNIC_SMASH_RIGHT = 62058, + SPELL_RUNIC_SMASH_DAMAGE = 62465, + + // ANCIENT RUNE GIANT + SPELL_RUNE_DETONATION = 62526, + SPELL_RUNIC_FORTIFICATION = 62942, + SPELL_STOMP_10 = 62411, + SPELL_STOMP_25 = 62413, + + // TRAPS + SPELL_LIGHTNING_FIELD = 64972, + SPELL_PARALYTIC_FIELD_FIRST = 62241, + SPELL_PARALYTIC_FIELD_SECOND = 63540, +}; + +#define SPELL_GREATER_HEAL RAID_MODE(SPELL_GREATER_HEAL_10, SPELL_GREATER_HEAL_25) +#define SPELL_HOLY_SMITE RAID_MODE(SPELL_HOLY_SMITE_10, SPELL_HOLY_SMITE_25) +#define SPELL_RENEW RAID_MODE(SPELL_RENEW_10, SPELL_RENEW_25) +#define SPELL_ACID_BREATH RAID_MODE(SPELL_ACID_BREATH_10, SPELL_ACID_BREATH_25) +#define SPELL_SWEEP RAID_MODE(SPELL_SWEEP_10, SPELL_SWEEP_25) +#define SPELL_IMPALE RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25) +#define SPELL_COLOSSUS_CHARGE RAID_MODE(SPELL_COLOSSUS_CHARGE_10, SPELL_COLOSSUS_CHARGE_25) +#define SPELL_STOMP RAID_MODE(SPELL_STOMP_10, SPELL_STOMP_25) +#define SPELL_SHIELD_SMASH RAID_MODE(SPELL_SHIELD_SMASH_10, SPELL_SHIELD_SMASH_25) +#define SPELL_RUNIC_LIGHTNING RAID_MODE(SPELL_RUNIC_LIGHTNING_10, SPELL_RUNIC_LIGHTNING_25) +#define SPELL_RUNIC_MENDING RAID_MODE(SPELL_RUNIC_MENDING_10, SPELL_RUNIC_MENDING_25) +#define SPELL_RUNIC_SHIELD RAID_MODE(SPELL_RUNIC_SHIELD_10, SPELL_RUNIC_SHIELD_25) +#define SPELL_CHAIN_LIGHTNING RAID_MODE(SPELL_CHAIN_LIGHTNING_10, SPELL_CHAIN_LIGHTNING_25) + +enum ThormNPCandGOs : uint32 +{ + // ARENA INIT + NPC_DARK_RUNE_ACOLYTE_I = 32886, + NPC_CAPTURED_MERCENARY_SOLDIER_ALLY = 32885, + NPC_CAPTURED_MERCENARY_SOLDIER_HORDE = 32883, + NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY = 32908, + NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE = 32907, + NPC_JORMUNGAR_BEHEMOT = 32882, + + // ARENA PHASE + NPC_DARK_RUNE_WARBRINGER = 32877, + NPC_DARK_RUNE_EVOKER = 32878, + NPC_DARK_RUNE_CHAMPION = 32876, + NPC_DARK_RUNE_COMMONER = 32904, + + // GAUNTLET + NPC_IRON_RING_GUARD = 32874, + NPC_RUNIC_COLOSSUS = 32872, + NPC_ANCIENT_RUNE_GIANT = 32873, + NPC_DARK_RUNE_ACOLYTE_G = 33110, + NPC_IRON_HONOR_GUARD = 32875, + + // TRIGGERS + NPC_LIGHTNING_ORB = 33138, + NPC_THUNDER_ORB = 33378, + NPC_PILLAR = 32892, + NPC_SIF_BLIZZARD = 32879, + + NPC_SIF = 33196, +}; + +enum ThorimEvents +{ + EVENT_THORIM_START_PHASE1 = 1, + EVENT_THORIM_STORMHAMMER = 2, + EVENT_THORIM_CHARGE_ORB = 3, + EVENT_THORIM_LIGHTNING_ORB = 4, + EVENT_THORIM_NOT_REACH_IN_TIME = 5, + EVENT_THORIM_FILL_ARENA = 6, + EVENT_THORIM_UNBALANCING_STRIKE = 7, + EVENT_THORIM_LIGHTNING_CHARGE = 8, + EVENT_THORIM_CHAIN_LIGHTNING = 9, + EVENT_THORIM_BERSERK = 10, + EVENT_THORIM_AGGRO = 11, + EVENT_THORIM_AGGRO2 = 12, + EVENT_THORIM_OUTRO1 = 13, + EVENT_THORIM_OUTRO2 = 14, + EVENT_THORIM_OUTRO3 = 15, + + EVENT_DR_ACOLYTE_GH = 20, + EVENT_DR_ACOLYTE_HS = 21, + EVENT_DR_ACOLYTE_R = 22, + + EVENT_CM_SOLDIER_BS = 30, + EVENT_CM_SOLDIER_S = 31, + EVENT_CM_SOLDIER_WC = 32, + + EVENT_CM_CAPTAIN_D = 40, + EVENT_CM_CAPTAIN_HC = 41, + + EVENT_JB_ACID_BREATH = 50, + EVENT_JB_SWEEP = 51, + + EVENT_IR_GUARD_IMPALE = 60, + EVENT_IR_GUARD_WHIRL = 61, + + EVENT_RC_RUNIC_BARRIER = 70, + EVENT_RC_SMASH = 71, + EVENT_RC_RUNIC_SMASH = 72, + EVENT_RC_RUNIC_SMASH_TRIGGER = 73, + EVENT_RC_CHARGE = 74, + + EVENT_ARG_RD = 80, + EVENT_ARG_RF = 81, + EVENT_ARG_STOMP = 82, + EVENT_ARG_SPAWN = 83, + + EVENT_IH_GUARD_CLEAVE = 90, + EVENT_IH_GUARD_HAMSTRING = 91, + EVENT_IH_GUARD_SHIELD_SMASH = 92, + + EVENT_SIF_START_TALK = 100, + EVENT_SIF_JOIN_TALK = 101, + EVENT_SIF_FINISH_DOMINION = 102, + EVENT_SIF_FROSTBOLT_VALLEY = 103, + EVENT_SIF_BLIZZARD = 104, + EVENT_SIF_FROST_NOVA_START = 105, + EVENT_SIF_FROST_NOVA_CAST = 106, + + EVENT_DR_WARBRINGER_RS = 110, + + EVENT_DR_EVOKER_RL = 120, + EVENT_DR_EVOKER_RM = 121, + EVENT_DR_EVOKER_RS = 122, + + EVENT_DR_CHAMPION_WH = 130, + EVENT_DR_CHAMPION_CH = 131, + EVENT_DR_CHAMPION_MS = 132, + + EVENT_DR_COMMONER_PM = 140, + EVENT_DR_COMMONER_LB = 141, +}; + +const Position ArenaNPCs[] = +{ + {2178.5f, -300.2f, 441.97f, 2.5f}, + {2188.12f, -295.1f, 443.75, 2.5f}, + {2180.9f, -286.8f, 433.3f, 2.49f}, + {2193.2f, -280.6f, 443.14f, 2.79f}, + {2191.8f, -270.2f, 438.3f, 3.0f}, + {2186.84f, -238.5f, 439.7f, 3.4f}, + {2166.3f, -213.0f, 440.0f, 4.1f}, + {2100.5f, -213.5f, 441.66f, 5.4f}, + {2091.0f, -231.26f, 435.17f, 5.5f}, + {2083.2f, -239.2f, 438.77f, 5.85f}, + {2081.54f, -253.27f, 434.67f, 6.19f}, + {2077.65f, -272.73f, 439.12f, 0.15f}, + {2084.36f, -282.12f, 435.87f, 0.24f}, + {2087.46f, -298.71f, 440.5f, 0.59f} +}; + +enum Texts +{ + // Thorim + SAY_AGGRO_1 = 0, + SAY_AGGRO_2 = 1, + SAY_SPECIAL_1 = 2, // Unused + SAY_SPECIAL_2 = 3, + SAY_SPECIAL_3 = 4, // Unused + SAY_JUMPDOWN = 5, + SAY_SLAY = 6, + SAY_BERSERK = 7, + SAY_WIPE = 8, + SAY_DEATH = 9, + SAY_END_NORMAL_1 = 10, + SAY_END_NORMAL_2 = 11, + SAY_END_NORMAL_3 = 12, + SAY_END_HARD_1 = 13, + SAY_END_HARD_2 = 14, + SAY_END_HARD_3 = 15, + + // Sif + SAY_SIF_AGGRO = 0, + SAY_SIF_HM_MISSED = 1, + SAY_SIF_HM_REACHED = 2, + + // Ancient Rune Giant + SAY_GIANT_RUNIC_MIGHT = 0, + + // Runic Colossus + SAY_COLOSSUS_RUNIC_BARRIER = 0, +}; + +enum Misc +{ + ACTION_START_TRASH_DIED = 1, + ACTION_ALLOW_HIT = 2, + ACTION_SIF_JOIN_FIGHT = 3, + ACTION_SIF_START_TALK = 4, + ACTION_SIF_START_DOMINION = 5, + ACTION_SIF_TRANSFORM = 6, + ACTION_IRON_HONOR_DIED = 7, + + EVENT_PHASE_START = 1, + EVENT_PHASE_RING = 2, + EVENT_PHASE_OUTRO = 3, + + DATA_HIT_BY_LIGHTNING = 1, + DATA_LOSE_YOUR_ILLUSION = 2, +}; + +const Position Middle = {2134.68f, -263.13f, 419.44f, M_PI * 1.5f}; + +const uint32 RollTable[3] = { 32877, 32878, 32876 }; + +class boss_thorim : public CreatureScript +{ +public: + boss_thorim() : CreatureScript("boss_thorim") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorimAI : public ScriptedAI + { + boss_thorimAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + { + m_pInstance = pCreature->GetInstanceScript(); + if ((_encounterFinished = (!me->IsAlive()))) + if (m_pInstance) + m_pInstance->SetData(TYPE_THORIM, DONE); + } + + bool _isArenaEmpty; + bool _encounterFinished; + bool _spawnCommoners; + bool _hardMode; + bool _isHitAllowed; + bool _isAlly; + uint8 _trashCounter; + + InstanceScript* m_pInstance; + EventMap events; + SummonList summons; + + bool _hitByLightning; + + void DisableThorim(bool apply) + { + if (apply) + { + me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED); + me->DisableRotate(true); + me->AddUnitState(UNIT_STATE_ROOT); + } + else + { + me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED); + me->DisableRotate(false); + me->ClearUnitState(UNIT_STATE_ROOT); + me->resetAttackTimer(BASE_ATTACK); + } + } + + GameObject* GetThorimObject(uint32 entry) + { + if (m_pInstance) + return ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(entry)); + return nullptr; + } + + void JustSummoned(Creature* cr) override { summons.Summon(cr); } + + void SpawnAllNPCs() + { + // Jormungar Behemoth 32882 + me->SummonCreature(NPC_JORMUNGAR_BEHEMOT, 2149.68f, -263.477f, 419.679f, 3.12102f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + + // Captured Mercenary Soldier 32885 + me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2127.24f, -251.309f, 419.793f, 5.89921f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2120.1f, -258.99f, 419.764f, 6.24828f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2123.32f, -254.771f, 419.789f, 6.17846f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + + // Captured Mercenary Captain 32908 + me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY : NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE, 2131.31f, -259.182f, 419.974f, 5.91667f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + + // Dark Rune Acolyte (arena) 32886 + me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_I, 2129.09f, -277.142f, 419.756f, 1.22173f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + + // Iron Ring Guard 32874 + me->SummonCreature(NPC_IRON_RING_GUARD, 2217.69f, -337.394f, 412.177f, 1.23918f); + me->SummonCreature(NPC_IRON_RING_GUARD, 2218.38f, -297.505f, 412.176f, 1.02974f); + me->SummonCreature(NPC_IRON_RING_GUARD, 2235.26f, -338.345f, 412.134f, 1.58979f); + me->SummonCreature(NPC_IRON_RING_GUARD, 2235.07f, -297.985f, 412.134f, 1.61336f); + + // Dark Rune Acolyte (gauntlet) 33110 + me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2198.29f, -436.92f, 419.985f, 0.261799f); + me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2227.58f, -308.303f, 412.134f, 1.59372f); + me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2227.47f, -345.375f, 412.134f, 1.56622f); + + // Iron Honor Guard 32875 + me->SummonCreature(NPC_IRON_HONOR_GUARD, 2198.05f, -428.769f, 419.985f, 6.05629f); + me->SummonCreature(NPC_IRON_HONOR_GUARD, 2220.31f, -436.22f, 412.26f, 1.06465f); + + // Runic Colossus 32872 + me->SummonCreature(NPC_RUNIC_COLOSSUS, 2227.5f, -396.179f, 412.176f, 1.79769f); + + // Ancient Rune Giant 32873 + me->SummonCreature(NPC_ANCIENT_RUNE_GIANT, 2134.57f, -440.318f, 438.331f, 0.226893f); + + // Sif 33196 + me->SummonCreature(NPC_SIF, 2147.86f, -301.2f, 438.246f, 2.488f); + } + + void CloseDoors() + { + GameObject* go; + if ((go = GetThorimObject(DATA_THORIM_LEVER))) + { + go->ReplaceAllGameObjectFlags((GameObjectFlags)48); + go->SetGoState(GO_STATE_READY); + } + if ((go = GetThorimObject(DATA_THORIM_FIRST_DOORS))) + go->SetGoState(GO_STATE_READY); + + if ((go = GetThorimObject(DATA_THORIM_SECOND_DOORS))) + go->SetGoState(GO_STATE_READY); + + if ((go = GetThorimObject(DATA_THORIM_FENCE))) + go->SetGoState(GO_STATE_ACTIVE); + } + + void EnterEvadeMode(EvadeReason why) override + { + DisableThorim(false); + CreatureAI::EnterEvadeMode(why); + } + + void Reset() override + { + if (m_pInstance && !_encounterFinished) + m_pInstance->SetData(TYPE_THORIM, NOT_STARTED); + + events.Reset(); + events.SetPhase(0); + summons.DespawnAll(); + + _trashCounter = 0; + _isAlly = true; + _isHitAllowed = false; + _spawnCommoners = false; + _hardMode = false; + _isArenaEmpty = false; + _hitByLightning = false; + + if (Player* t = SelectTargetFromPlayerList(1000)) + if (t->GetTeamId() == TEAM_HORDE) + _isAlly = false; + + SpawnAllNPCs(); + + CloseDoors(); + DisableThorim(false); + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_HIT_BY_LIGHTNING) + return !_hitByLightning; + if (param == DATA_LOSE_YOUR_ILLUSION) + return _hardMode; + + return 0; + } + + void DoAction(int32 param) override + { + if (param == ACTION_START_TRASH_DIED) + { + _trashCounter++; + // activate levar + if (_trashCounter >= 6) + { + if (GameObject* go = GetThorimObject(DATA_THORIM_LEVER)) + go->RemoveGameObjectFlag((GameObjectFlags)48); + + events.ScheduleEvent(EVENT_THORIM_AGGRO, 0ms); + events.SetPhase(EVENT_PHASE_START); + events.ScheduleEvent(EVENT_THORIM_START_PHASE1, 20s); + _trashCounter = 0; + } + } + else if (param == ACTION_ALLOW_HIT) + _isHitAllowed = true; + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void JustReachedHome() override { me->setActive(false); } + + void JustEngagedWith(Unit*) override + { + if (m_pInstance && !_encounterFinished) + m_pInstance->SetData(TYPE_THORIM, IN_PROGRESS); + me->setActive(true); + DisableThorim(true); + me->CastSpell(me, SPELL_SHEATH_OF_LIGHTNING, true); + //me->CastSpell(me, SPELL_TOUCH_OF_DOMINION, true); + } + + void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (who && _isHitAllowed && who->GetPositionZ() > 430 && who->GetTypeId() == TYPEID_PLAYER) + { + _isHitAllowed = false; + DisableThorim(false); + + events.SetPhase(EVENT_PHASE_RING); + events.ScheduleEvent(EVENT_THORIM_UNBALANCING_STRIKE, 8s, 0, EVENT_PHASE_RING); + events.ScheduleEvent(EVENT_THORIM_LIGHTNING_CHARGE, 12s + 500ms, 0, EVENT_PHASE_RING); + events.ScheduleEvent(EVENT_THORIM_CHAIN_LIGHTNING, 13s, 0, EVENT_PHASE_RING); + events.ScheduleEvent(EVENT_THORIM_BERSERK, 5min, 0, EVENT_PHASE_RING); + + me->GetMotionMaster()->MoveChase(me->GetVictim()); + me->GetMotionMaster()->MoveJump(Middle.GetPositionX(), Middle.GetPositionY(), Middle.GetPositionZ(), 20, 20); + me->RemoveAura(SPELL_SHEATH_OF_LIGHTNING); + + Talk(SAY_JUMPDOWN); + + // Hard Mode + if (!me->HasAura(62565 /*TOUCH OF DOMINION TRIGGER*/)) + { + if (m_pInstance) + m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 64980 /*SIFFED ACHIEVEMENT*/); + + _hardMode = true; + EntryCheckPredicate pred(NPC_SIF); + summons.DoAction(ACTION_SIF_JOIN_FIGHT, pred); + } + + DoResetThreatList(); + if (Player* player = GetArenaPlayer()) + me->AddThreat(player, 1000.0f); + } + + if (damage >= me->GetHealth()) + { + damage = 0; + if (!_encounterFinished) + { + _encounterFinished = true; + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetFaction(FACTION_FRIENDLY); + me->SetHealth(me->GetMaxHealth()); + me->CombatStop(); + me->RemoveAllAuras(); + events.Reset(); + DisableThorim(true); + + Talk(SAY_DEATH); + + events.SetPhase(EVENT_PHASE_OUTRO); + events.ScheduleEvent(EVENT_THORIM_OUTRO1, 2s, 0, EVENT_PHASE_OUTRO); + + GameObject* go = nullptr; + if ((go = GetThorimObject(DATA_THORIM_FENCE))) + go->SetGoState(GO_STATE_ACTIVE); + + uint32 chestId = me->GetMap()->Is25ManRaid() ? GO_THORIM_CHEST_HERO : GO_THORIM_CHEST; + if (_hardMode) + chestId += 1; // hard mode offset + + if ((go = me->SummonGameObject(chestId, 2134.73f, -286.32f, 419.51f, 4.65f, 0, 0, 0, 0, 0))) + { + go->ReplaceAllGameObjectFlags((GameObjectFlags)0); + go->SetLootRecipient(me->GetMap()); + } + + // Defeat credit + if (m_pInstance) + { + me->CastSpell(me, 64985, true); // credit + m_pInstance->SetData(TYPE_THORIM, DONE); + } + } + } + } + + void SpawnArenaNPCs() + { + Creature* cr; + uint8 rnd; + if (_spawnCommoners || urand(0, 2)) + _spawnCommoners = !_spawnCommoners; + + for (uint8 i = 0; i < (_spawnCommoners ? 7 : 2); ++i) + { + rnd = urand(0, 13); + if ((cr = me->SummonCreature((_spawnCommoners ? NPC_DARK_RUNE_COMMONER : RollTable[urand(0, 2)]), ArenaNPCs[rnd], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))) + cr->GetMotionMaster()->MoveJump( + Middle.GetPositionX() + urand(19, 24) * cos(Middle.GetAngle(cr)), + Middle.GetPositionY() + urand(19, 24) * std::sin(Middle.GetAngle(cr)), + Middle.GetPositionZ(), 20, 20); + } + } + + void SpellHit(Unit* caster, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_LIGHTNING_ORB_CHARGER) + { + me->SetOrientation(me->GetAngle(caster)); + me->CastSpell(caster, SPELL_LIGHTNING_CHARGE_DAMAGE, true); + me->CastSpell(me, SPELL_LIGHTNING_CHARGE_BUFF, true); + events.RescheduleEvent(EVENT_THORIM_LIGHTNING_CHARGE, 10s, 0, EVENT_PHASE_RING); + } + } + + void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_LIGHTNING_CHARGE_DAMAGE && target->GetTypeId() == TYPEID_PLAYER) + _hitByLightning = true; + } + + Player* GetArenaPlayer() + { + Map::PlayerList const& pList = me->GetMap()->GetPlayers(); + for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) + if (Player* p = itr->GetSource()) + if (p->GetPositionX() > 2085 && p->GetPositionX() < 2185 && p->GetPositionY() < -214 && p->GetPositionY() > -305 && p->IsAlive() && p->GetPositionZ() < 425) + return p; + return nullptr; + } + + void UpdateAI(uint32 diff) override + { + if (!_encounterFinished && !UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_THORIM_AGGRO: + Talk(SAY_AGGRO_1); + events.ScheduleEvent(EVENT_THORIM_AGGRO2, 9s); + + if (GameObject* go = GetThorimObject(DATA_THORIM_FENCE)) + go->SetGoState(GO_STATE_READY); + + break; + case EVENT_THORIM_AGGRO2: + { + Talk(SAY_AGGRO_2); + + EntryCheckPredicate pred(NPC_SIF); + summons.DoAction(ACTION_SIF_START_TALK, pred); + break; + } + case EVENT_THORIM_START_PHASE1: + { + events.ScheduleEvent(EVENT_THORIM_STORMHAMMER, 8s, 0, EVENT_PHASE_START); + events.ScheduleEvent(EVENT_THORIM_CHARGE_ORB, 14s, 0, EVENT_PHASE_START); + events.ScheduleEvent(EVENT_THORIM_FILL_ARENA, 0ms, 0, EVENT_PHASE_START); + events.ScheduleEvent(EVENT_THORIM_LIGHTNING_ORB, 5s, 0, EVENT_PHASE_START); // checked every 5 secs if there are players on arena + events.ScheduleEvent(EVENT_THORIM_NOT_REACH_IN_TIME, 5min, 0, EVENT_PHASE_START); + + EntryCheckPredicate pred(NPC_SIF); + summons.DoAction(ACTION_SIF_START_DOMINION, pred); + break; + } + case EVENT_THORIM_STORMHAMMER: + me->CastCustomSpell(SPELL_STORMHAMMER, SPELLVALUE_MAX_TARGETS, 1, me->GetVictim(), false); + events.Repeat(16s); + break; + case EVENT_THORIM_CHARGE_ORB: + me->CastCustomSpell(SPELL_CHARGE_ORB, SPELLVALUE_MAX_TARGETS, 1, me, false); + events.Repeat(16s); + break; + case EVENT_THORIM_LIGHTNING_ORB: + { + if (GetArenaPlayer()) + { + // Player found, repeat and return + events.Repeat(5s); + return; + } + + // No players found + Talk(SAY_WIPE); + me->SummonCreature(NPC_LIGHTNING_ORB, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); + + _isArenaEmpty = true; + events.CancelEvent(EVENT_THORIM_NOT_REACH_IN_TIME); + break; + } + case EVENT_THORIM_NOT_REACH_IN_TIME: + _isArenaEmpty = true; + events.CancelEvent(EVENT_THORIM_LIGHTNING_ORB); + me->CastSpell(me, SPELL_BERSERK_FRIENDS, true); + me->SummonCreature(NPC_LIGHTNING_ORB, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); + break; + case EVENT_THORIM_FILL_ARENA: + SpawnArenaNPCs(); + events.Repeat(10s); + break; + case EVENT_THORIM_UNBALANCING_STRIKE: + me->CastSpell(me->GetVictim(), SPELL_UNBALANCING_STRIKE, false); + events.Repeat(20s); + break; + case EVENT_THORIM_LIGHTNING_CHARGE: + me->CastSpell(me, SPELL_LIGHTNING_PILLAR_P2, true); + break; + case EVENT_THORIM_CHAIN_LIGHTNING: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_CHAIN_LIGHTNING, false); + events.Repeat(15s); + break; + case EVENT_THORIM_BERSERK: + me->CastSpell(me, SPELL_BERSERK, true); + Talk(SAY_BERSERK); + break; + case EVENT_THORIM_OUTRO1: + if (_hardMode) + { + Talk(SAY_END_HARD_1); + events.ScheduleEvent(EVENT_THORIM_OUTRO2, 5s, 0, 3); + EntryCheckPredicate pred(NPC_SIF); + summons.DoAction(ACTION_SIF_TRANSFORM, pred); + } + else + { + Talk(SAY_END_NORMAL_1); + events.ScheduleEvent(EVENT_THORIM_OUTRO2, 9s, 0, 3); + } + break; + case EVENT_THORIM_OUTRO2: + if (_hardMode) + { + Talk(SAY_END_HARD_2); + events.ScheduleEvent(EVENT_THORIM_OUTRO3, 12s, 0, 3); + } + else + { + Talk(SAY_END_NORMAL_2); + events.ScheduleEvent(EVENT_THORIM_OUTRO3, 10s, 0, 3); + } + break; + case EVENT_THORIM_OUTRO3: + if (_hardMode) + { + Talk(SAY_END_HARD_3); + } + else + { + Talk(SAY_END_NORMAL_3); + } + + // Defeat credit + if (m_pInstance) + m_pInstance->SetData(TYPE_THORIM, DONE); + + me->DespawnOrUnsummon(8000); + break; + } + + if (!_encounterFinished) + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_thorim_sif : public CreatureScript +{ +public: + boss_thorim_sif() : CreatureScript("boss_thorim_sif") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorim_sifAI : public ScriptedAI + { + boss_thorim_sifAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + void MoveInLineOfSight(Unit*) override {} + void AttackStart(Unit*) override {} + + bool _allowCast; + EventMap events; + + void Reset() override + { + events.Reset(); + me->SetReactState(REACT_PASSIVE); + _allowCast = false; + } + + void DoAction(int32 param) override + { + if (param == ACTION_SIF_START_TALK) + events.ScheduleEvent(EVENT_SIF_START_TALK, 9s); + else if (param == ACTION_SIF_START_DOMINION) + { + if (me->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) + me->CastSpell(cr, SPELL_TOUCH_OF_DOMINION, false); + + events.ScheduleEvent(EVENT_SIF_FINISH_DOMINION, 150s); + } + else if (param == ACTION_SIF_JOIN_FIGHT) + { + me->InterruptNonMeleeSpells(false); + events.ScheduleEvent(EVENT_SIF_JOIN_TALK, 9s); + events.CancelEvent(EVENT_SIF_START_TALK); + events.CancelEvent(EVENT_SIF_FINISH_DOMINION); + } + else if (param == ACTION_SIF_TRANSFORM) + { + me->CastSpell(me, SPELL_SIF_TRANSFORM, true); + me->DespawnOrUnsummon(5000); + events.Reset(); + _allowCast = false; + } + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_SIF_FINISH_DOMINION: + Talk(SAY_SIF_HM_MISSED); + me->DespawnOrUnsummon(5000); + break; + case EVENT_SIF_START_TALK: + Talk(SAY_SIF_AGGRO); + break; + case EVENT_SIF_JOIN_TALK: + Talk(SAY_SIF_HM_REACHED); + events.ScheduleEvent(EVENT_SIF_FROST_NOVA_START, 1s); + events.ScheduleEvent(EVENT_SIF_FROSTBOLT_VALLEY, 11s); + events.ScheduleEvent(EVENT_SIF_BLIZZARD, 15s); + break; + case EVENT_SIF_FROSTBOLT_VALLEY: + me->CastSpell(me, SPELL_FROSTBOLT_VALLEY, false); + events.Repeat(13s); + return; + case EVENT_SIF_BLIZZARD: + me->SummonCreature(NPC_SIF_BLIZZARD, 2108.7f, -280.04f, 419.42f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); + events.Repeat(30s); + return; + case EVENT_SIF_FROST_NOVA_START: + me->NearTeleportTo(2108 + urand(0, 42), -238 - irand(0, 46), 420.02f, me->GetAngle(&Middle)); + events.Repeat(20s); + events.DelayEvents(5s); + events.ScheduleEvent(EVENT_SIF_FROST_NOVA_CAST, 2500ms); + _allowCast = false; + return; + case EVENT_SIF_FROST_NOVA_CAST: + _allowCast = true; + me->CastSpell(me, SPELL_FROST_NOVA, false); + return; + } + + // has casting check before event select (return in events) + if (_allowCast) + if (Player* target = SelectTargetFromPlayerList(70)) + { + me->CastSpell(target, SPELL_FROSTBOLT, false); + me->StopMoving(); + } + } + }; +}; + +class boss_thorim_lightning_orb : public CreatureScript +{ +public: + boss_thorim_lightning_orb() : CreatureScript("boss_thorim_lightning_orb") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorim_lightning_orbAI : public npc_escortAI + { + boss_thorim_lightning_orbAI(Creature* pCreature) : npc_escortAI(pCreature) + { + InitWaypoint(); + Reset(); + Start(false, true); + } + + uint32 Timer; + + void EnterEvadeMode(EvadeReason /*why*/) override {} + void MoveInLineOfSight(Unit*) override {} + void AttackStart(Unit*) override {} + + void InitWaypoint() + { + AddWaypoint(1, 2135, -304, 438.24f, 0); + AddWaypoint(2, 2132, -441, 438.24f, 0); + AddWaypoint(3, 2167, -442, 438.24f, 0); + AddWaypoint(4, 2227, -432, 412.18f, 0); + AddWaypoint(5, 2227, -263, 412.17f, 0); + AddWaypoint(6, 2179, -262, 414.7f, 0); + AddWaypoint(7, 2169, -261, 419.3f, 0); + AddWaypoint(8, 2110, -251, 419.42f, 0); + } + + void Reset() override + { + me->CastSpell(me, SPELL_LIGHTNING_DESTRUCTION, true); + } + + void WaypointReached(uint32 /*point*/) override + { + } + }; +}; + +class boss_thorim_trap : public CreatureScript +{ +public: + boss_thorim_trap() : CreatureScript("boss_thorim_trap") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorim_trapAI : public NullCreatureAI + { + boss_thorim_trapAI(Creature* pCreature) : NullCreatureAI(pCreature) { } + + uint32 _checkTimer; + + void Reset() override { _checkTimer = 1; } + void UpdateAI(uint32 diff) override + { + if (_checkTimer) + { + _checkTimer += diff; + if ((_checkTimer >= 1000 && _checkTimer < 10000) || _checkTimer >= 60000) + { + if (me->SelectNearbyTarget(nullptr, 12.0f)) + { + me->CastSpell(me, SPELL_LIGHTNING_FIELD, true); + me->CastSpell(me, (me->GetEntry() == 33054 /*NPC_THORIM_TRAP_BUNNY*/ ? SPELL_PARALYTIC_FIELD_FIRST : SPELL_PARALYTIC_FIELD_SECOND), true); + _checkTimer = 10000; + return; + } + _checkTimer = 1; + } + } + } + }; +}; + +class boss_thorim_sif_blizzard : public CreatureScript +{ +public: + boss_thorim_sif_blizzard() : CreatureScript("boss_thorim_sif_blizzard") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorim_sif_blizzardAI : public npc_escortAI + { + boss_thorim_sif_blizzardAI(Creature* pCreature) : npc_escortAI(pCreature) + { + InitWaypoint(); + Reset(); + Start(false, true); + SetDespawnAtEnd(false); + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + void JustEngagedWith(Unit* /*who*/) override {} + void AttackStart(Unit* /*who*/) override {} + + void InitWaypoint() + { + AddWaypoint(1, 2104.6f, -268.5f, 419.4f, 0); + AddWaypoint(2, 2104.3f, -256.3f, 419.4f, 0); + AddWaypoint(3, 2109.3f, -246.4f, 419.4f, 0); + AddWaypoint(4, 2117.9f, -238.6f, 419.4f, 0); + AddWaypoint(5, 2128.8f, -232.1f, 419.4f, 0); + AddWaypoint(6, 2151.9f, -237.5f, 419.4f, 0); + AddWaypoint(7, 2164.9f, -256.3f, 419.4f, 0); + AddWaypoint(8, 2161.5f, -280.0f, 419.4f, 0); + } + + void Reset() override + { + me->SetSpeed(MOVE_RUN, 1); + me->SetSpeed(MOVE_WALK, 1); + me->CastSpell(me, RAID_MODE(SPELL_BLIZZARD_10, SPELL_BLIZZARD_25), true); + } + + void WaypointReached(uint32 /*point*/) override + { + } + }; +}; + +class boss_thorim_pillar : public CreatureScript +{ +public: + boss_thorim_pillar() : CreatureScript("boss_thorim_pillar") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorim_pillarAI : public NullCreatureAI + { + boss_thorim_pillarAI(Creature* pCreature) : NullCreatureAI(pCreature) { } + + uint32 _resetTimer; + + void Reset() override + { + _resetTimer = 0; + me->SetControlled(true, UNIT_STATE_STUNNED); + me->SetDisableGravity(true); + } + + void SpellHit(Unit*, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_CHARGE_ORB) + me->CastSpell(me, SPELL_LIGHTNING_PILLAR_P1, true); + else if (spellInfo->Id == SPELL_LIGHTNING_PILLAR_P2) + { + if (Creature* cr = me->FindNearestCreature(NPC_THUNDER_ORB, 100)) + cr->CastSpell(cr, SPELL_LIGHTNING_ORB_VISUAL, true); + } + } + + void UpdateAI(uint32 diff) override + { + _resetTimer += diff; + if (_resetTimer >= 10000) + Reset(); // _resetTimer set to 0 + } + }; +}; + +class boss_thorim_start_npcs : public CreatureScript +{ +public: + boss_thorim_start_npcs() : CreatureScript("boss_thorim_start_npcs") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorim_start_npcsAI : public ScriptedAI + { + boss_thorim_start_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + EventMap events; + bool _isCaster; + bool _playerAttack; + + void Reset() override + { + events.Reset(); + _isCaster = (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I); + _playerAttack = false; + if (me->GetEntry() != NPC_JORMUNGAR_BEHEMOT) + if (Creature* cr = me->FindNearestCreature(NPC_JORMUNGAR_BEHEMOT, 30.0f)) + AttackStart(cr); + } + + void DamageTaken(Unit* who, uint32&, DamageEffectType, SpellSchoolMask) override + { + if (!_playerAttack && who && (who->GetTypeId() == TYPEID_PLAYER || who->GetOwnerGUID().IsPlayer())) + { + if (me->GetInstanceScript()) + if (Creature* thorim = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) + { + if (!thorim->IsInCombat()) + { + thorim->SetInCombatWithZone(); + thorim->AI()->AttackStart(who); + } + } + _playerAttack = true; + me->GetThreatMgr().ResetAllThreat(); + me->CallForHelp(40.0f); + AttackStart(who); + } + + if (!_playerAttack && me->HealthBelowPct(60)) + me->SetHealth(me->GetMaxHealth()); + } + + void JustDied(Unit*) override + { + if (me->GetInstanceScript()) + if (Creature* thorim = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) + thorim->AI()->DoAction(ACTION_START_TRASH_DIED); + } + + void JustEngagedWith(Unit* /*who*/) override + { + if (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I) + { + events.ScheduleEvent(EVENT_DR_ACOLYTE_GH, 10s); + events.ScheduleEvent(EVENT_DR_ACOLYTE_HS, 5s); + events.ScheduleEvent(EVENT_DR_ACOLYTE_R, 7s); + } + else if (me->GetEntry() == NPC_CAPTURED_MERCENARY_SOLDIER_ALLY || me->GetEntry() == NPC_CAPTURED_MERCENARY_SOLDIER_HORDE) + { + events.ScheduleEvent(EVENT_CM_SOLDIER_BS, 9s); + events.ScheduleEvent(EVENT_CM_SOLDIER_WC, 5s); + events.ScheduleEvent(EVENT_CM_SOLDIER_S, 0ms); + } + else if (me->GetEntry() == NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY || me->GetEntry() == NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE) + { + events.ScheduleEvent(EVENT_CM_CAPTAIN_D, 9s); + events.ScheduleEvent(EVENT_CM_CAPTAIN_HC, 5s); + } + else if (me->GetEntry() == NPC_JORMUNGAR_BEHEMOT) + { + events.ScheduleEvent(EVENT_JB_ACID_BREATH, 12s); + events.ScheduleEvent(EVENT_JB_SWEEP, 5s); + } + + me->CallForHelp(10); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_DR_ACOLYTE_GH: + if (HealthBelowPct(60)) + me->CastSpell(me, SPELL_GREATER_HEAL, false); + else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 20)) + me->CastSpell(target, SPELL_GREATER_HEAL, false); + events.Repeat(10s); + break; + case EVENT_DR_ACOLYTE_HS: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_HOLY_SMITE, false); + events.Repeat(1600ms); + break; + case EVENT_DR_ACOLYTE_R: + if (HealthBelowPct(75) && !me->HasAura(SPELL_RENEW)) + me->CastSpell(me, SPELL_GREATER_HEAL, false); + else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 10)) + me->CastSpell(target, SPELL_RENEW, false); + events.Repeat(7s); + break; + case EVENT_CM_SOLDIER_BS: + me->CastSpell(me->GetVictim(), SPELL_BARBED_SHOT, false); + events.Repeat(9s); + break; + case EVENT_CM_SOLDIER_WC: + me->CastSpell(me->GetVictim(), SPELL_WING_CLIP, false); + events.Repeat(5s); + break; + case EVENT_CM_SOLDIER_S: + if (me->GetDistance(me->GetVictim()) > 8) + me->CastSpell(me->GetVictim(), SPELL_SHOOT, false); + + events.Repeat(1500ms); + break; + case EVENT_CM_CAPTAIN_D: + me->CastSpell(me->GetVictim(), SPELL_DEVASTATE, false); + events.Repeat(9s); + break; + case EVENT_CM_CAPTAIN_HC: + me->CastSpell(me->GetVictim(), SPELL_HEROIC_STRIKE, false); + events.Repeat(5s); + break; + case EVENT_JB_ACID_BREATH: + me->CastSpell(me->GetVictim(), SPELL_ACID_BREATH, false); + events.Repeat(12s); + break; + case EVENT_JB_SWEEP: + me->CastSpell(me->GetVictim(), SPELL_SWEEP, false); + events.Repeat(5s); + break; + } + + if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10)) + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_thorim_gauntlet_npcs : public CreatureScript +{ +public: + boss_thorim_gauntlet_npcs() : CreatureScript("boss_thorim_gauntlet_npcs") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorim_gauntlet_npcsAI : public ScriptedAI + { + boss_thorim_gauntlet_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + EventMap events; + bool _isCaster; + + void Reset() override + { + events.Reset(); + _isCaster = (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_G); + } + + void JustEngagedWith(Unit* /*who*/) override + { + if (me->GetEntry() == NPC_IRON_RING_GUARD) + { + events.ScheduleEvent(EVENT_IR_GUARD_IMPALE, 12s); + events.ScheduleEvent(EVENT_IR_GUARD_WHIRL, 5s); + } + else if (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I) + { + events.ScheduleEvent(EVENT_DR_ACOLYTE_GH, 10s); + events.ScheduleEvent(EVENT_DR_ACOLYTE_HS, 5s); + events.ScheduleEvent(EVENT_DR_ACOLYTE_R, 7s); + } + else if (me->GetEntry() == NPC_IRON_HONOR_GUARD) + { + events.ScheduleEvent(EVENT_IH_GUARD_CLEAVE, 6s); + events.ScheduleEvent(EVENT_IH_GUARD_HAMSTRING, 9s); + events.ScheduleEvent(EVENT_IH_GUARD_SHIELD_SMASH, 15s); + + if (Creature* runeGiant = me->FindNearestCreature(NPC_ANCIENT_RUNE_GIANT, 200.0f)) + runeGiant->AI()->DoAction(ACTION_IRON_HONOR_DIED); + } + + me->CallForHelp(25); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_IR_GUARD_IMPALE: + me->CastSpell(me->GetVictim(), SPELL_IMPALE, false); + events.Repeat(12s); + break; + case EVENT_IR_GUARD_WHIRL: + me->CastSpell(me->GetVictim(), SPELL_WHIRLING_TRIP, false); + events.Repeat(5s); + break; + case EVENT_DR_ACOLYTE_GH: + if (HealthBelowPct(60)) + me->CastSpell(me, SPELL_GREATER_HEAL, false); + else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 20)) + me->CastSpell(target, SPELL_GREATER_HEAL, false); + events.Repeat(10s); + break; + case EVENT_DR_ACOLYTE_HS: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_HOLY_SMITE, false); + events.Repeat(1600ms); + break; + case EVENT_DR_ACOLYTE_R: + if (HealthBelowPct(75) && !me->HasAura(SPELL_RENEW)) + me->CastSpell(me, SPELL_GREATER_HEAL, false); + else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 10)) + me->CastSpell(target, SPELL_RENEW, false); + events.Repeat(7s); + break; + case EVENT_IH_GUARD_CLEAVE: + me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false); + events.Repeat(6s); + break; + case EVENT_IH_GUARD_HAMSTRING: + me->CastSpell(me->GetVictim(), SPELL_HAMSTRING, false); + events.Repeat(9s); + break; + case EVENT_IH_GUARD_SHIELD_SMASH: + me->CastSpell(me->GetVictim(), SPELL_SHIELD_SMASH, false); + events.Repeat(15s); + break; + } + + if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10)) + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_thorim_runic_colossus : public CreatureScript +{ +public: + boss_thorim_runic_colossus() : CreatureScript("boss_thorim_runic_colossus") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorim_runic_colossusAI : public ScriptedAI + { + boss_thorim_runic_colossusAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + EventMap events; + bool _leftHand; + bool _checkTarget; + float _nextTriggerPos; + ObjectGuid _triggerLeftGUID[2], _triggerRightGUID[2]; + + void Reset() override + { + _nextTriggerPos = 0.0f; + _leftHand = false; + _checkTarget = false; + events.Reset(); + events.ScheduleEvent(EVENT_RC_RUNIC_SMASH, 0ms); + Creature* c; + + if ((c = me->SummonCreature(33140, 2221, -385, me->GetPositionZ()))) + _triggerRightGUID[0] = c->GetGUID(); + if ((c = me->SummonCreature(33140, 2210, -385, me->GetPositionZ()))) + _triggerRightGUID[1] = c->GetGUID(); + + if ((c = me->SummonCreature(33141, 2235, -385, me->GetPositionZ()))) + _triggerLeftGUID[0] = c->GetGUID(); + if ((c = me->SummonCreature(33141, 2246, -385, me->GetPositionZ()))) + _triggerLeftGUID[1] = c->GetGUID(); + } + + void JustDied(Unit*) override + { + if (me->GetInstanceScript()) + { + if (GameObject* go = ObjectAccessor::GetGameObject(*me, me->GetInstanceScript()->GetGuidData(DATA_THORIM_FIRST_DOORS))) + go->SetGoState(GO_STATE_ACTIVE); + + if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) + cr->AI()->Talk(SAY_SPECIAL_2); + } + } + + void JustEngagedWith(Unit*) override + { + events.CancelEvent(EVENT_RC_RUNIC_SMASH); + events.ScheduleEvent(EVENT_RC_RUNIC_BARRIER, 10s); + events.ScheduleEvent(EVENT_RC_SMASH, 18s); + events.ScheduleEvent(EVENT_RC_CHARGE, 15s); + + me->InterruptNonMeleeSpells(false); + _checkTarget = true; + } + + void SpellHit(Unit*, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_RUNIC_SMASH_LEFT || spellInfo->Id == SPELL_RUNIC_SMASH_RIGHT) + { + _leftHand = spellInfo->Id == SPELL_RUNIC_SMASH_LEFT; + events.RescheduleEvent(EVENT_RC_RUNIC_SMASH_TRIGGER, 1s); + } + } + + void RunRunicSmash(bool cast) + { + if (Creature* cr = ObjectAccessor::GetCreature(*me, _leftHand ? _triggerLeftGUID[0] : _triggerRightGUID[0]) ) + { + if (cast) + cr->CastSpell(cr, SPELL_RUNIC_SMASH_DAMAGE, true); + cr->SetPosition(_leftHand ? 2235.0f : 2221.0f, _nextTriggerPos, cr->GetPositionZ(), 0.0f); + cr->StopMovingOnCurrentPos(); + } + if( Creature* cr = ObjectAccessor::GetCreature(*me, _leftHand ? _triggerLeftGUID[1] : _triggerRightGUID[1]) ) + { + if (cast) + cr->CastSpell(cr, SPELL_RUNIC_SMASH_DAMAGE, true); + cr->SetPosition(_leftHand ? 2246.0f : 2210.0f, _nextTriggerPos, cr->GetPositionZ(), 0.0f); + cr->StopMovingOnCurrentPos(); + } + } + + void UpdateAI(uint32 diff) override + { + if (_checkTarget && !UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_RC_RUNIC_SMASH_TRIGGER: + _nextTriggerPos += 16.0f; + if (_nextTriggerPos <= -260.0f) + { + events.RescheduleEvent(EVENT_RC_RUNIC_SMASH_TRIGGER, 500ms); + } + + RunRunicSmash(true); + break; + case EVENT_RC_RUNIC_SMASH: + if (urand(0, 1)) + me->CastSpell(me, SPELL_RUNIC_SMASH_LEFT, false); + else + me->CastSpell(me, SPELL_RUNIC_SMASH_RIGHT, false); + + _nextTriggerPos = -385.0f; + RunRunicSmash(false); + events.Repeat(11s); + break; + case EVENT_RC_RUNIC_BARRIER: + me->CastSpell(me, SPELL_RUNIC_BARRIER, false); + Talk(SAY_COLOSSUS_RUNIC_BARRIER); + events.Repeat(20s); + break; + case EVENT_RC_SMASH: + me->CastSpell(me->GetVictim(), SPELL_SMASH, false); + events.Repeat(10s); + break; + case EVENT_RC_CHARGE: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_CHARGE, false); + events.Repeat(15s); + break; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_thorim_ancient_rune_giant : public CreatureScript +{ +public: + boss_thorim_ancient_rune_giant() : CreatureScript("boss_thorim_ancient_rune_giant") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorim_ancient_rune_giantAI : public ScriptedAI + { + boss_thorim_ancient_rune_giantAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + EventMap events; + bool _isInCombat; + + void Reset() override + { + _isInCombat = false; + events.Reset(); + } + + void JustEngagedWith(Unit*) override + { + _isInCombat = true; + events.CancelEvent(EVENT_ARG_SPAWN); + events.ScheduleEvent(EVENT_ARG_RD, 12s); + events.ScheduleEvent(EVENT_ARG_STOMP, 8s); + + me->CastSpell(me, SPELL_RUNIC_FORTIFICATION, false); + Talk(SAY_GIANT_RUNIC_MIGHT); + } + + void JustDied(Unit*) override + { + if (InstanceScript* pInstance = me->GetInstanceScript()) + { + if (GameObject* go = ObjectAccessor::GetGameObject(*me, pInstance->GetGuidData(DATA_THORIM_SECOND_DOORS))) + go->SetGoState(GO_STATE_ACTIVE); + + if (Creature* thorim = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_THORIM))) + thorim->AI()->DoAction(ACTION_ALLOW_HIT); + } + } + + void DoAction(int32 param) override + { + if (param == ACTION_IRON_HONOR_DIED) + events.RescheduleEvent(EVENT_ARG_SPAWN, 20s); + } + + void UpdateAI(uint32 diff) override + { + if (_isInCombat && !UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_ARG_RD: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_RUNE_DETONATION, false); + events.Repeat(12s); + break; + case EVENT_ARG_STOMP: + me->CastSpell(me->GetVictim(), SPELL_STOMP, false); + events.Repeat(8s); + break; + case EVENT_ARG_SPAWN: + if (Creature* cr = me->SummonCreature(NPC_IRON_HONOR_GUARD, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000)) + if (Unit* target = SelectTargetFromPlayerList(150.0f)) + cr->AI()->AttackStart(target); + events.Repeat(10s); + break; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_thorim_arena_npcs : public CreatureScript +{ +public: + boss_thorim_arena_npcs() : CreatureScript("boss_thorim_arena_npcs") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_thorim_arena_npcsAI : public ScriptedAI + { + boss_thorim_arena_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + EventMap events; + bool _isCaster; + + void Reset() override + { + _isCaster = (me->GetEntry() == NPC_DARK_RUNE_EVOKER); + events.Reset(); + if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER) + me->CastSpell(me, SPELL_AURA_OF_CELERITY, true); + } + + void JustEngagedWith(Unit*) override + { + if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER) + { + events.ScheduleEvent(EVENT_DR_WARBRINGER_RS, 8s); + } + else if (me->GetEntry() == NPC_DARK_RUNE_EVOKER) + { + events.ScheduleEvent(EVENT_DR_EVOKER_RL, 2500ms); + events.ScheduleEvent(EVENT_DR_EVOKER_RM, 4s); + events.ScheduleEvent(EVENT_DR_EVOKER_RS, 10s); + } + else if (me->GetEntry() == NPC_DARK_RUNE_CHAMPION) + { + events.ScheduleEvent(EVENT_DR_CHAMPION_WH, 6s); + events.ScheduleEvent(EVENT_DR_CHAMPION_CH, 12s); + events.ScheduleEvent(EVENT_DR_CHAMPION_MS, 8s); + } + else if (me->GetEntry() == NPC_DARK_RUNE_COMMONER) + { + events.ScheduleEvent(EVENT_DR_COMMONER_LB, 5s); + events.ScheduleEvent(EVENT_DR_COMMONER_PM, 6s); + } + } + + bool CanAIAttack(Unit const* target) const override + { + return target->GetPositionX() < 2180 && target->GetPositionZ() < 425; + } + + bool SelectT() + { + Player* target = nullptr; + Map::PlayerList const& pList = me->GetMap()->GetPlayers(); + uint8 num = urand(0, pList.getSize() - 1); + uint8 count = 0; + for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr, ++count) + { + if (itr->GetSource()->GetPositionX() > 2180 || !itr->GetSource()->IsAlive() || itr->GetSource()->GetPositionZ() > 425) + continue; + + if (count <= num || !target) + target = itr->GetSource(); + else + break; + } + + if (target) + { + AttackStart(target); + me->AddThreat(target, 500.0f); + if (me->GetEntry() == NPC_DARK_RUNE_EVOKER && urand(0, 1)) + me->CastSpell(me, SPELL_RUNIC_SHIELD, false); + else if (me->GetEntry() == NPC_DARK_RUNE_CHAMPION && !urand(0, 2)) + me->CastSpell(target, SPELL_CHARGE, false); + return true; + } + return false; + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !SelectT()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_DR_WARBRINGER_RS: + me->CastSpell(me->GetVictim(), SPELL_RUNIC_STRIKE, false); + events.Repeat(8s); + break; + case EVENT_DR_EVOKER_RL: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_RUNIC_LIGHTNING, false); + events.Repeat(2500ms); + break; + case EVENT_DR_EVOKER_RM: + if (Unit* target = DoSelectLowestHpFriendly(40.0f, 15)) + me->CastSpell(target, SPELL_RUNIC_MENDING, false); + else + me->CastSpell(me, SPELL_RUNIC_MENDING, false); + events.Repeat(4s); + break; + case EVENT_DR_EVOKER_RS: + me->CastSpell(me, SPELL_RUNIC_SHIELD, false); + events.Repeat(10s); + break; + case EVENT_DR_CHAMPION_CH: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_CHARGE, false); + events.Repeat(12s); + break; + case EVENT_DR_CHAMPION_WH: + if (!me->HasUnitFlag(UNIT_FLAG_DISARMED)) + me->CastSpell(me, SPELL_WHIRLWIND, false); + events.Repeat(6s); + break; + case EVENT_DR_CHAMPION_MS: + me->CastSpell(me->GetVictim(), SPELL_MORTAL_STRIKE, false); + events.Repeat(8s); + break; + case EVENT_DR_COMMONER_LB: + me->CastSpell(me->GetVictim(), SPELL_LOW_BLOW, false); + events.Repeat(5s); + break; + case EVENT_DR_COMMONER_PM: + me->CastSpell(me->GetVictim(), SPELL_PUMMEL, false); + events.Repeat(6s); + break; + } + + if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10)) + DoMeleeAttackIfReady(); + } + }; +}; + +class go_thorim_lever : public GameObjectScript +{ +public: + go_thorim_lever() : GameObjectScript("go_thorim_lever") { } + + bool OnGossipHello(Player* pPlayer, GameObject* go) override + { + if (GameObject* g = pPlayer->FindNearestGameObject(GO_ARENA_LEVER_GATE, 50)) + g->UseDoorOrButton(); + + go->UseDoorOrButton(); + return true; + } +}; + +class spell_thorim_lightning_pillar_P2 : public SpellScriptLoader +{ +public: + spell_thorim_lightning_pillar_P2() : SpellScriptLoader("spell_thorim_lightning_pillar_P2") { } + + class spell_thorim_lightning_pillar_P2_AuraScript : public AuraScript + { + PrepareAuraScript(spell_thorim_lightning_pillar_P2_AuraScript); + + void OnPeriodic(AuraEffect const* aurEff) + { + PreventDefaultAction(); + if (Unit* caster = GetCaster()) + GetUnitOwner()->CastSpell(caster, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_thorim_lightning_pillar_P2_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_thorim_lightning_pillar_P2_AuraScript(); + } +}; + +class spell_thorim_trash_impale : public SpellScriptLoader +{ +public: + spell_thorim_trash_impale() : SpellScriptLoader("spell_thorim_trash_impale") { } + + class spell_thorim_trash_impale_AuraScript : public AuraScript + { + PrepareAuraScript(spell_thorim_trash_impale_AuraScript); + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + // deals damage until target is healed above 90% + if (GetUnitOwner()->HealthAbovePct(90)) + SetDuration(0); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_thorim_trash_impale_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_thorim_trash_impale_AuraScript(); + } +}; + +class achievement_thorim_stand_in_the_lightning : public AchievementCriteriaScript +{ +public: + achievement_thorim_stand_in_the_lightning() : AchievementCriteriaScript("achievement_thorim_stand_in_the_lightning") {} + + bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override + { + if (InstanceScript* instance = player->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*player, instance->GetGuidData(TYPE_THORIM))) + return cr->AI()->GetData(DATA_HIT_BY_LIGHTNING); + + return false; + } +}; + +class achievement_thorim_lose_your_illusion : public AchievementCriteriaScript +{ +public: + achievement_thorim_lose_your_illusion() : AchievementCriteriaScript("achievement_thorim_lose_your_illusion") {} + + bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override + { + if (InstanceScript* instance = player->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*player, instance->GetGuidData(TYPE_THORIM))) + return cr->AI()->GetData(DATA_LOSE_YOUR_ILLUSION); + + return false; + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp index 9168fa4b5e5e4d..cadd8da47bffc2 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_xt002.h" #include "AchievementCriteriaScript.h" #include "CreatureScript.h" #include "Opcodes.h" @@ -27,1056 +28,6 @@ #include "Vehicle.h" #include "ulduar.h" -enum XT002Spells -{ - // BASIC - SPELL_GRAVITY_BOMB_10 = 63024, - SPELL_GRAVITY_BOMB_25 = 64234, - SPELL_SEARING_LIGHT_10 = 63018, - SPELL_SEARING_LIGHT_25 = 65121, - SPELL_TYMPANIC_TANTARUM = 62776, - SPELL_XT002_ENRAGE = 26662, - - // HELPERS - SPELL_ARCING_SMASH = 8374, - SPELL_TRAMPLE = 5568, - SPELL_UPPERCUT = 10966, - SPELL_BOOM = 62834, - - // HEARTBREAK - SPELL_HEART_OVERLOAD = 62789, - SPELL_EXPOSED_HEART = 63849, - SPELL_ENERGY_ORB = 62790, - SPELL_ENERGY_ORB_TRIGGER = 62826, - SPELL_HEARTBREAK_10 = 65737, - SPELL_HEARTBREAK_25 = 64193, - - // VOID ZONE - SPELL_VOID_ZONE_SUMMON_10 = 64203, - SPELL_VOID_ZONE_SUMMON_25 = 64235, - //SPELL_VOID_ZONE_SUMMON = RAID_MODE(SPELL_VOID_ZONE_SUMMON_10, SPELL_VOID_ZONE_SUMMON_25, SPELL_VOID_ZONE_SUMMON_10, SPELL_VOID_ZONE_SUMMON_25), - SPELL_VOID_ZONE_DAMAGE = 46262, - - // SPARK - SPELL_SPARK_SUMMON = 64210, - SPELL_SPARK_DAMAGE_10 = 64227, - SPELL_SPARK_DAMAGE_25 = 64236, - SPELL_SPARK_MELEE = 64230, -}; - -#define SPELL_GRAVITY_BOMB RAID_MODE(SPELL_GRAVITY_BOMB_10, SPELL_GRAVITY_BOMB_25) -#define SPELL_SEARING_LIGHT RAID_MODE(SPELL_SEARING_LIGHT_10, SPELL_SEARING_LIGHT_25) -#define SPELL_HEARTBREAK RAID_MODE(SPELL_HEARTBREAK_10, SPELL_HEARTBREAK_25) -#define SPELL_SPARK_DAMAGE RAID_MODE(SPELL_SPARK_DAMAGE_10, SPELL_SPARK_DAMAGE_25) - -enum XT002Events -{ - EVENT_HEALTH_CHECK = 1, - EVENT_GRAVITY_BOMB = 2, - EVENT_SEARING_LIGHT = 3, - EVENT_ENRAGE = 4, - EVENT_TYMPANIC_TANTARUM = 5, - EVENT_RESTORE = 6, - EVENT_START_SECOND_PHASE = 7, - EVENT_REMOVE_EMOTE = 8, - EVENT_CHECK_ROOM = 9, -}; - -enum NPCs -{ - NPC_VOID_ZONE = 34001, - NPC_LIFE_SPARK = 34004, - NPC_XT002_HEART = 33329, - NPC_XS013_SCRAPBOT = 33343, - NPC_XM024_PUMMELLER = 33344, - NPC_XE321_BOOMBOT = 33346, - NPC_PILE_TRIGGER = 33337, -}; - -enum Texts -{ - SAY_AGGRO = 0, - SAY_HEART_OPENED = 1, - SAY_HEART_CLOSED = 2, - SAY_TYMPANIC_TANTRUM = 3, - SAY_SLAY = 4, - SAY_BERSERK = 5, - SAY_DEATH = 6, - SAY_SUMMON = 7, - EMOTE_HEART_OPENED = 8, - EMOTE_HEART_CLOSED = 9, - EMOTE_TYMPANIC_TANTRUM = 10, - EMOTE_SCRAPBOT = 11, -}; - -enum Misc -{ - HEART_VEHICLE_SEAT = 0, - - ACTION_AWAKEN_HEART = -5, - ACTION_HIDE_HEART = -4, - ACTION_HEART_BROKEN = -3, - - ACHIEVEMENT_MUST_DECONSTRUCT_FASTER = 21027, - - DATA_XT002_NERF_ENGINEERING = 50, - DATA_XT002_GRAVITY_ACHIEV = 51, -}; - -class boss_xt002 : public CreatureScript -{ -public: - boss_xt002() : CreatureScript("boss_xt002") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_xt002AI : public ScriptedAI - { - boss_xt002AI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) - { - m_pInstance = pCreature->GetInstanceScript(); - } - - InstanceScript* m_pInstance; - uint8 _healthCheck; - bool _hardMode; - bool _nerfAchievement; - bool _gravityAchievement; - EventMap events; - SummonList summons; - - void RescheduleEvents() - { - events.RescheduleEvent(EVENT_GRAVITY_BOMB, 1s, 1); - events.RescheduleEvent(EVENT_TYMPANIC_TANTARUM, 1min, 1); - if (!_hardMode) - events.RescheduleEvent(EVENT_HEALTH_CHECK, 2s, 1); - } - - void Reset() override - { - summons.DespawnAll(); - events.Reset(); - - me->ResetLootMode(); - me->RemoveAllAuras(); - - // first heart expose - _healthCheck = 75; - _hardMode = false; - _nerfAchievement = true; - _gravityAchievement = true; - - me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetControlled(false, UNIT_STATE_STUNNED); - - if (m_pInstance) - { - m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_MUST_DECONSTRUCT_FASTER); - m_pInstance->SetData(TYPE_XT002, NOT_STARTED); - if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS))) - pGo->SetGoState(GO_STATE_ACTIVE); - } - } - - void JustSummoned(Creature* cr) override { summons.Summon(cr); } - void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } - - void AttachHeart() - { - if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr) - heart->SetHealth(heart->GetMaxHealth()); - else if (Creature* accessory = me->SummonCreature(NPC_XT002_HEART, *me, TEMPSUMMON_MANUAL_DESPAWN)) - { - accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY); - if (!me->HandleSpellClick(accessory, 0)) - accessory->DespawnOrUnsummon(); - } - } - - void JustReachedHome() override { me->setActive(false); } - - void JustEngagedWith(Unit*) override - { - me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - events.ScheduleEvent(EVENT_ENRAGE, 10min, 0, 0); - events.ScheduleEvent(EVENT_CHECK_ROOM, 5s, 0, 0); - RescheduleEvents(); // Other events are scheduled here - - me->setActive(true); - Talk(SAY_AGGRO); - - if (m_pInstance) - { - m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_MUST_DECONSTRUCT_FASTER); - m_pInstance->SetData(TYPE_XT002, IN_PROGRESS); - if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS))) - pGo->SetGoState(GO_STATE_READY); - } - - me->CallForHelp(175); - me->SetInCombatWithZone(); - AttachHeart(); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER && !urand(0, 2)) - { - Talk(SAY_SLAY); - } - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - - if (m_pInstance) - { - m_pInstance->SetData(TYPE_XT002, DONE); - if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS))) - pGo->SetGoState(GO_STATE_ACTIVE); - } - - // Despawn summons - summons.DespawnAll(); - } - - void DoAction(int32 param) override - { - if (param == DATA_XT002_NERF_ENGINEERING) - { - _nerfAchievement = false; - return; - } - if (param == DATA_XT002_GRAVITY_ACHIEV) - { - _gravityAchievement = false; - return; - } - - if (!me->IsAlive() || _hardMode) - return; - - // heart destory - if (param == ACTION_HEART_BROKEN) - { - _hardMode = true; - me->SetLootMode(3); // hard mode + normal loot - me->SetMaxHealth(me->GetMaxHealth()); - me->SetHealth(me->GetMaxHealth()); - me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge - - me->CastSpell(me, SPELL_HEARTBREAK, true); - - Talk(EMOTE_HEART_CLOSED); - events.ScheduleEvent(EVENT_REMOVE_EMOTE, 4s); - return; - } - - // damage from heart - if (param > 0) - { - // avoid reducing health under 1 - int32 _final = std::min(param, int32(me->GetHealth() - 1)); - - me->ModifyHealth(-_final); - me->LowerPlayerDamageReq(_final); - } - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_XT002_NERF_ENGINEERING) - return _nerfAchievement; - else if (param == DATA_XT002_GRAVITY_ACHIEV) - return _gravityAchievement; - - return 0; - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch(events.ExecuteEvent()) - { - // Control events - case EVENT_HEALTH_CHECK: - if (_hardMode) - { - return; - } - - if (me->HealthBelowPct(_healthCheck)) - { - _healthCheck -= 25; - me->SetControlled(true, UNIT_STATE_STUNNED); - me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_SUBMERGED); // submerge with animation - - Talk(SAY_HEART_OPENED); - - events.CancelEventGroup(1); - events.ScheduleEvent(EVENT_START_SECOND_PHASE, 5s); - return; - } - events.Repeat(1s); - break; - case EVENT_CHECK_ROOM: - events.Repeat(5s); - if (me->GetPositionX() < 722 || me->GetPositionX() > 987 || me->GetPositionY() < -139 || me->GetPositionY() > 124) - EnterEvadeMode(); - - return; - - // Abilities events - case EVENT_GRAVITY_BOMB: - me->CastCustomSpell(SPELL_GRAVITY_BOMB, SPELLVALUE_MAX_TARGETS, 1, me, true); - events.ScheduleEvent(EVENT_SEARING_LIGHT, 10s, 1); - break; - case EVENT_SEARING_LIGHT: - me->CastCustomSpell(SPELL_SEARING_LIGHT, SPELLVALUE_MAX_TARGETS, 1, me, true); - events.ScheduleEvent(EVENT_GRAVITY_BOMB, 10s, 1); - break; - case EVENT_TYMPANIC_TANTARUM: - Talk(EMOTE_TYMPANIC_TANTRUM); - Talk(SAY_TYMPANIC_TANTRUM); - me->CastSpell(me, SPELL_TYMPANIC_TANTARUM, true); - events.Repeat(1min); - return; - case EVENT_ENRAGE: - Talk(SAY_BERSERK); - me->CastSpell(me, SPELL_XT002_ENRAGE, true); - break; - - // Animation events - case EVENT_START_SECOND_PHASE: - Talk(EMOTE_HEART_OPENED); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr) - heart->GetAI()->DoAction(ACTION_AWAKEN_HEART); - - events.ScheduleEvent(EVENT_RESTORE, 30s); - return; - // Restore from heartbreak - case EVENT_RESTORE: - if (_hardMode) - { - return; - } - - Talk(SAY_HEART_CLOSED); - - me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge - // Hide heart - if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr) - heart->GetAI()->DoAction(ACTION_HIDE_HEART); - - events.ScheduleEvent(EVENT_REMOVE_EMOTE, 4s); - return; - case EVENT_REMOVE_EMOTE: - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - me->SetControlled(false, UNIT_STATE_STUNNED); - - RescheduleEvents(); - return; - } - - // Disabled by stunned state - DoMeleeAttackIfReady(); - } - }; -}; - -class npc_xt002_heart : public CreatureScript -{ -public: - npc_xt002_heart() : CreatureScript("npc_xt002_heart") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_xt002_heartAI : public PassiveAI - { - npc_xt002_heartAI(Creature* pCreature) : PassiveAI(pCreature), summons(me) - { - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - } - - SummonList summons; - uint32 _damageDone; - uint32 _timerSpawn; - - uint8 _spawnSelection; - uint8 _pummelerCount; - - void MoveInLineOfSight(Unit*) override { } - void AttackStart(Unit*) override { } - void JustSummoned(Creature* cr) override - { - summons.Summon(cr); - if (Unit* owner = me->GetVehicleBase()) - if (owner->GetTypeId() == TYPEID_UNIT) - owner->ToCreature()->AI()->JustSummoned(cr); - } - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - _damageDone += damage; - } - - void SummonPiles() - { - me->SummonCreature(NPC_PILE_TRIGGER, 893.290f, 66.820f, 409.81f, 4.2f); - me->SummonCreature(NPC_PILE_TRIGGER, 898.099f, -88.9115f, 409.887f, 2.23402f); - me->SummonCreature(NPC_PILE_TRIGGER, 793.096f, -95.158f, 409.887f, 0.855211f); - me->SummonCreature(NPC_PILE_TRIGGER, 794.600f, 59.660f, 409.82f, 5.34f); - } - - void DoAction(int32 param) override - { - if (param == ACTION_AWAKEN_HEART) - { - _pummelerCount = 0; - _spawnSelection = 0; - _damageDone = 0; - _timerSpawn = 0; - me->SetHealth(me->GetMaxHealth()); - me->CastSpell(me, SPELL_HEART_OVERLOAD, true); - me->CastSpell(me, SPELL_EXPOSED_HEART, false); // Channeled - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - - if (!summons.HasEntry(NPC_PILE_TRIGGER)) - SummonPiles(); - } - else if (param == ACTION_HIDE_HEART) - { - if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) - if (pXT002->AI()) - { - pXT002->AI()->DoAction(_damageDone); - _damageDone = 0; - } - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - } - } - - void SendEnergyToCorner() - { - Unit* pile = nullptr; - uint8 num = urand(1, 4); - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) - if (Creature* summon = ObjectAccessor::GetCreature(*me, *itr)) - if (summon->GetEntry() == NPC_PILE_TRIGGER) - { - pile = summon; - if ((--num) == 0) - break; - } - - if (pile) - me->CastSpell(pile, SPELL_ENERGY_ORB, true); - } - - void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override - { - // spawn not-so-random robots - if (spellInfo->Id == SPELL_ENERGY_ORB_TRIGGER && target->GetEntry() == NPC_PILE_TRIGGER) - switch (_spawnSelection) - { - case 0: - for (uint8 i = 0; i < 5; ++i) - me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000); - _spawnSelection++; - break; - case 1: - me->SummonCreature(NPC_XE321_BOOMBOT, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - _spawnSelection++; - break; - case 2: - for (uint8 i = 0; i < 5; ++i) - me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000); - _spawnSelection++; - break; - case 3: - if(_pummelerCount < 2) - me->SummonCreature(NPC_XM024_PUMMELLER, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - - _pummelerCount++; - _spawnSelection++; - break; - case 4: - for (uint8 i = 0; i < 5; ++i) - me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000); - _spawnSelection = 0; - break; - } - } - - void JustDied(Unit* /*killer*/) override - { - me->SetVisible(false); - if (me->GetInstanceScript()) - if (Creature* XT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) - if (XT002->AI()) - XT002->AI()->DoAction(ACTION_HEART_BROKEN); - } - - void UpdateAI(uint32 diff) override - { - if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) - { - _timerSpawn += diff; - if (_timerSpawn >= 1900) - { - SendEnergyToCorner(); - _timerSpawn -= 1900; - } - } - } - }; -}; - -class npc_xt002_scrapbot : public CreatureScript -{ -public: - npc_xt002_scrapbot() : CreatureScript("npc_xt002_scrapbot") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_xt002_scrapbotAI : public PassiveAI - { - npc_xt002_scrapbotAI(Creature* pCreature) : PassiveAI(pCreature) { } - - bool _locked; - void Reset() override - { - me->StopMoving(); - _locked = true; - me->SetWalk(true); - - if (me->GetInstanceScript()) - if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) - { - if (pXT002->GetPositionZ() > 411.0f) // he is on stairs... idiot cryness protection - me->GetMotionMaster()->MovePoint(0, 884.028931f, -14.593809f, 409.786987f); - else - _locked = false; - } - } - - void JustDied(Unit* killer) override - { - // Nerf Scrapbots achievement - if (killer && killer->GetEntry() == NPC_XE321_BOOMBOT) - if (me->GetInstanceScript()) - { - me->GetInstanceScript()->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, 65037); - me->GetInstanceScript()->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 65037); - } - } - - // tc use updateAI, while we have movementinform - void MovementInform(uint32 type, uint32 /*param*/) override - { - if (type == POINT_MOTION_TYPE) - { - _locked = false; - return; - } - - // we reached the target :) - if (type == FOLLOW_MOTION_TYPE && me->GetInstanceScript()) - if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) - { - if (pXT002->IsAlive()) - { - pXT002->AI()->DoAction(DATA_XT002_NERF_ENGINEERING); - pXT002->ModifyHealth(pXT002->GetMaxHealth() * 0.01f); - } - - if (!urand(0, 2)) - pXT002->AI()->Talk(EMOTE_SCRAPBOT); - - me->DespawnOrUnsummon(1); - } - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!_locked) - { - if (me->GetInstanceScript()) - if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) - { - me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); - _locked = true; - } - } - } - }; -}; - -class npc_xt002_pummeller : public CreatureScript -{ -public: - npc_xt002_pummeller() : CreatureScript("npc_xt002_pummeller") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_xt002_pummellerAI : public ScriptedAI - { - npc_xt002_pummellerAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - int32 _arcingSmashTimer; - int32 _trampleTimer; - int32 _uppercutTimer; - - void Reset() override - { - _arcingSmashTimer = 0; - _trampleTimer = 0; - _uppercutTimer = 0; - - if (Unit* target = SelectTargetFromPlayerList(200)) - AttackStart(target); - else - me->DespawnOrUnsummon(500); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - _arcingSmashTimer += diff; - _trampleTimer += diff; - _uppercutTimer += diff; - - if (_arcingSmashTimer >= 8000) - { - me->CastSpell(me->GetVictim(), SPELL_ARCING_SMASH, false); - _arcingSmashTimer = 0; - return; - } - if (_trampleTimer >= 11000) - { - me->CastSpell(me->GetVictim(), SPELL_TRAMPLE, false); - _trampleTimer = 0; - return; - } - if (_uppercutTimer >= 14000) - { - me->CastSpell(me->GetVictim(), SPELL_UPPERCUT, false); - _uppercutTimer = 0; - return; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class BoomEvent : public BasicEvent -{ -public: - BoomEvent(Creature* me) : _me(me) - { - } - - bool Execute(uint64 /*time*/, uint32 /*diff*/) override - { - // This hack is here because we suspect our implementation of spell effect execution on targets - // is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets, - // then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc. - // The above situation causes the visual for this spell to be bugged, so we remove the instakill - // effect and implement a script hack for that. - - _me->CastSpell(_me, SPELL_BOOM, false); - return true; - } - -private: - Creature* _me; -}; - -class npc_xt002_boombot : public CreatureScript -{ -public: - npc_xt002_boombot() : CreatureScript("npc_xt002_boombot") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_xt002_boombotAI : public PassiveAI - { - npc_xt002_boombotAI(Creature* pCreature) : PassiveAI(pCreature) { } - - bool _locked; - bool _boomed; - void Reset() override - { - me->StopMoving(); - _locked = true; - _boomed = false; - me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); - - if (me->GetInstanceScript()) - if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) - { - if (pXT002->GetPositionZ() > 411.0f) // he is on stairs... idiot cryness protection - me->GetMotionMaster()->MovePoint(0, 884.028931f, -14.593809f, 409.786987f); - else - _locked = false; - } - } - - void Explode() - { - if (_boomed) - return; - - _boomed = true; // Prevent recursive calls - - WorldPacket data(SMSG_SPELLINSTAKILLLOG, 8 + 8 + 4); - data << me->GetGUID(); - data << me->GetGUID(); - data << uint32(SPELL_BOOM); - me->SendMessageToSet(&data, false); - - me->KillSelf(); - - // Visual only seems to work if the instant kill event is delayed or the spell itself is delayed - // Casting done from player and caster source has the same targetinfo flags, - // so that can't be the issue - // See BoomEvent class - // Schedule 1s delayed - me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1 * IN_MILLISECONDS)); - } - - void JustDied(Unit* /*killer*/) override - { - me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1 * IN_MILLISECONDS)); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (_boomed) - damage = 0; - - if (me->HealthBelowPctDamaged(50, damage) && !_boomed) - { - damage = 0; - Explode(); - } - } - - // tc they use updateAI, while we have movementinform - void MovementInform(uint32 type, uint32 /*param*/) override - { - if (type == POINT_MOTION_TYPE) - { - _locked = false; - return; - } - // we reached the target :) - //if (type == FOLLOW_MOTION_TYPE) - // _kill = true; - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!_locked) - { - if (me->GetInstanceScript()) - if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) - { - me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); - _locked = true; - } - } - } - }; -}; - -class npc_xt002_life_spark : public CreatureScript -{ -public: - npc_xt002_life_spark() : CreatureScript("npc_xt002_life_spark") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct npc_xt002_life_sparkAI : public ScriptedAI - { - npc_xt002_life_sparkAI(Creature* pCreature) : ScriptedAI(pCreature) - { - me->SetMaxHealth(RAID_MODE(54000, 172000)); - me->SetHealth(me->GetMaxHealth()); - me->CastSpell(me, SPELL_SPARK_DAMAGE, true); - } - - uint32 _attackTimer; - void Reset() override - { - if (Unit* target = SelectTargetFromPlayerList(200)) - AttackStart(target); - else - me->DespawnOrUnsummon(); - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!UpdateVictim()) - return; - - me->CastSpell(me->GetVictim(), SPELL_SPARK_MELEE, false); - DoMeleeAttackIfReady(); - } - }; -}; - -// 62775 - Tympanic Tantrum -class spell_xt002_tympanic_tantrum : public SpellScriptLoader -{ -public: - spell_xt002_tympanic_tantrum() : SpellScriptLoader("spell_xt002_tympanic_tantrum") { } - - class spell_xt002_tympanic_tantrum_SpellScript : public SpellScript - { - PrepareSpellScript(spell_xt002_tympanic_tantrum_SpellScript); - - void FilterTargets(std::list& targets) - { - targets.remove_if(PlayerOrPetCheck()); - } - - void RecalculateDamage() - { - if (GetHitUnit()) - SetHitDamage(GetHitUnit()->CountPctFromMaxHealth(GetHitDamage())); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); - OnHit += SpellHitFn(spell_xt002_tympanic_tantrum_SpellScript::RecalculateDamage); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_xt002_tympanic_tantrum_SpellScript(); - } -}; - -// 64234, 63024 - Gravity Bomb -class spell_xt002_gravity_bomb_aura : public SpellScriptLoader -{ -public: - spell_xt002_gravity_bomb_aura() : SpellScriptLoader("spell_xt002_gravity_bomb_aura") { } - - class spell_xt002_gravity_bomb_aura_AuraScript : public AuraScript - { - PrepareAuraScript(spell_xt002_gravity_bomb_aura_AuraScript); - - void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - if (Player* player = GetOwner()->ToPlayer()) - if (Unit* xt002 = GetCaster()) - if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode - if (Creature* cr = xt002->SummonCreature(NPC_VOID_ZONE, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 180000)) - { - int32 damage = GetSpellInfo()->Id == 63025 ? 5000 : 7500; - cr->CastCustomSpell(cr, SPELL_VOID_ZONE_DAMAGE, &damage, 0, 0, true); - } - } - - void OnPeriodic(AuraEffect const* aurEff) - { - Unit* xt002 = GetCaster(); - if (!xt002) - return; - - Unit* owner = GetOwner()->ToUnit(); - if (!owner) - return; - - if (aurEff->GetAmount() >= int32(owner->GetHealth())) - if (xt002->GetAI()) - xt002->GetAI()->DoAction(DATA_XT002_GRAVITY_ACHIEV); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_xt002_gravity_bomb_aura_AuraScript::OnPeriodic, EFFECT_2, SPELL_AURA_PERIODIC_DAMAGE); - AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_gravity_bomb_aura_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_xt002_gravity_bomb_aura_AuraScript(); - } - - class spell_xt002_gravity_bomb_aura_SpellScript : public SpellScript - { - PrepareSpellScript(spell_xt002_gravity_bomb_aura_SpellScript); - - void SelectTarget(std::list& targets) - { - if (Unit* victim = GetCaster()->GetVictim()) - targets.remove_if(Acore::ObjectGUIDCheck(victim->GetGUID(), true)); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_gravity_bomb_aura_SpellScript::SelectTarget, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_xt002_gravity_bomb_aura_SpellScript(); - } -}; - -// 64233, 63025 - Gravity Bomb -class spell_xt002_gravity_bomb_damage : public SpellScriptLoader -{ -public: - spell_xt002_gravity_bomb_damage() : SpellScriptLoader("spell_xt002_gravity_bomb_damage") { } - - class spell_xt002_gravity_bomb_damage_SpellScript : public SpellScript - { - PrepareSpellScript(spell_xt002_gravity_bomb_damage_SpellScript); - - void HandleScript(SpellEffIndex /*eff*/) - { - Unit* caster = GetCaster(); - if (!caster) - return; - - if (GetHitDamage() >= int32(GetHitUnit()->GetHealth())) - if (caster->GetAI()) - caster->GetAI()->DoAction(DATA_XT002_GRAVITY_ACHIEV); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_xt002_gravity_bomb_damage_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_xt002_gravity_bomb_damage_SpellScript(); - } -}; - -// 63018, 65121 - Searing Light -class spell_xt002_searing_light_spawn_life_spark : public SpellScriptLoader -{ -public: - spell_xt002_searing_light_spawn_life_spark() : SpellScriptLoader("spell_xt002_searing_light_spawn_life_spark") { } - - class spell_xt002_searing_light_spawn_life_spark_AuraScript : public AuraScript - { - PrepareAuraScript(spell_xt002_searing_light_spawn_life_spark_AuraScript); - - void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - if (Player* player = GetOwner()->ToPlayer()) - if (Unit* xt002 = GetCaster()) - if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode - xt002->SummonCreature(NPC_LIFE_SPARK, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 180000); - } - - void Register() override - { - OnEffectRemove += AuraEffectRemoveFn(spell_xt002_searing_light_spawn_life_spark_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_xt002_searing_light_spawn_life_spark_AuraScript(); - } - - class spell_xt002_searing_light_spawn_life_spark_SpellScript : public SpellScript - { - PrepareSpellScript(spell_xt002_searing_light_spawn_life_spark_SpellScript); - - void SelectTarget(std::list& targets) - { - if (Unit* victim = GetCaster()->GetVictim()) - targets.remove_if(Acore::ObjectGUIDCheck(victim->GetGUID(), true)); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_searing_light_spawn_life_spark_SpellScript::SelectTarget, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_xt002_searing_light_spawn_life_spark_SpellScript(); - } -}; - -class achievement_xt002_nerf_engineering : public AchievementCriteriaScript -{ -public: - achievement_xt002_nerf_engineering() : AchievementCriteriaScript("achievement_xt002_nerf_engineering") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - if (target) - if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_XT002))) - return cr->AI()->GetData(DATA_XT002_NERF_ENGINEERING); - - return false; - } -}; - -class achievement_xt002_nerf_gravity_bombs : public AchievementCriteriaScript -{ -public: - achievement_xt002_nerf_gravity_bombs() : AchievementCriteriaScript("achievement_xt002_nerf_gravity_bombs") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - if (target) - if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_XT002))) - return cr->AI()->GetData(DATA_XT002_GRAVITY_ACHIEV); - - return false; - } -}; - void AddSC_boss_xt002() { // Npcs diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.h new file mode 100644 index 00000000000000..9b0b9cfeaddd6c --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.h @@ -0,0 +1,1066 @@ +#ifndef BOSS_XT002_H_ +#define BOSS_XT002_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureScript.h" +#include "Opcodes.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "Vehicle.h" +#include "ulduar.h" + +enum XT002Spells +{ + // BASIC + SPELL_GRAVITY_BOMB_10 = 63024, + SPELL_GRAVITY_BOMB_25 = 64234, + SPELL_SEARING_LIGHT_10 = 63018, + SPELL_SEARING_LIGHT_25 = 65121, + SPELL_TYMPANIC_TANTARUM = 62776, + SPELL_XT002_ENRAGE = 26662, + + // HELPERS + SPELL_ARCING_SMASH = 8374, + SPELL_TRAMPLE = 5568, + SPELL_UPPERCUT = 10966, + SPELL_BOOM = 62834, + + // HEARTBREAK + SPELL_HEART_OVERLOAD = 62789, + SPELL_EXPOSED_HEART = 63849, + SPELL_ENERGY_ORB = 62790, + SPELL_ENERGY_ORB_TRIGGER = 62826, + SPELL_HEARTBREAK_10 = 65737, + SPELL_HEARTBREAK_25 = 64193, + + // VOID ZONE + SPELL_VOID_ZONE_SUMMON_10 = 64203, + SPELL_VOID_ZONE_SUMMON_25 = 64235, + //SPELL_VOID_ZONE_SUMMON = RAID_MODE(SPELL_VOID_ZONE_SUMMON_10, SPELL_VOID_ZONE_SUMMON_25, SPELL_VOID_ZONE_SUMMON_10, SPELL_VOID_ZONE_SUMMON_25), + SPELL_VOID_ZONE_DAMAGE = 46262, + + // SPARK + SPELL_SPARK_SUMMON = 64210, + SPELL_SPARK_DAMAGE_10 = 64227, + SPELL_SPARK_DAMAGE_25 = 64236, + SPELL_SPARK_MELEE = 64230, +}; + +#define SPELL_GRAVITY_BOMB RAID_MODE(SPELL_GRAVITY_BOMB_10, SPELL_GRAVITY_BOMB_25) +#define SPELL_SEARING_LIGHT RAID_MODE(SPELL_SEARING_LIGHT_10, SPELL_SEARING_LIGHT_25) +#define SPELL_HEARTBREAK RAID_MODE(SPELL_HEARTBREAK_10, SPELL_HEARTBREAK_25) +#define SPELL_SPARK_DAMAGE RAID_MODE(SPELL_SPARK_DAMAGE_10, SPELL_SPARK_DAMAGE_25) + +enum XT002Events +{ + EVENT_HEALTH_CHECK = 1, + EVENT_GRAVITY_BOMB = 2, + EVENT_SEARING_LIGHT = 3, + EVENT_ENRAGE = 4, + EVENT_TYMPANIC_TANTARUM = 5, + EVENT_RESTORE = 6, + EVENT_START_SECOND_PHASE = 7, + EVENT_REMOVE_EMOTE = 8, + EVENT_CHECK_ROOM = 9, +}; + +enum NPCs +{ + NPC_VOID_ZONE = 34001, + NPC_LIFE_SPARK = 34004, + NPC_XT002_HEART = 33329, + NPC_XS013_SCRAPBOT = 33343, + NPC_XM024_PUMMELLER = 33344, + NPC_XE321_BOOMBOT = 33346, + NPC_PILE_TRIGGER = 33337, +}; + +enum Texts +{ + SAY_AGGRO = 0, + SAY_HEART_OPENED = 1, + SAY_HEART_CLOSED = 2, + SAY_TYMPANIC_TANTRUM = 3, + SAY_SLAY = 4, + SAY_BERSERK = 5, + SAY_DEATH = 6, + SAY_SUMMON = 7, + EMOTE_HEART_OPENED = 8, + EMOTE_HEART_CLOSED = 9, + EMOTE_TYMPANIC_TANTRUM = 10, + EMOTE_SCRAPBOT = 11, +}; + +enum Misc +{ + HEART_VEHICLE_SEAT = 0, + + ACTION_AWAKEN_HEART = -5, + ACTION_HIDE_HEART = -4, + ACTION_HEART_BROKEN = -3, + + ACHIEVEMENT_MUST_DECONSTRUCT_FASTER = 21027, + + DATA_XT002_NERF_ENGINEERING = 50, + DATA_XT002_GRAVITY_ACHIEV = 51, +}; + +class boss_xt002 : public CreatureScript +{ +public: + boss_xt002() : CreatureScript("boss_xt002") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_xt002AI : public ScriptedAI + { + boss_xt002AI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + { + m_pInstance = pCreature->GetInstanceScript(); + } + + InstanceScript* m_pInstance; + uint8 _healthCheck; + bool _hardMode; + bool _nerfAchievement; + bool _gravityAchievement; + EventMap events; + SummonList summons; + + void RescheduleEvents() + { + events.RescheduleEvent(EVENT_GRAVITY_BOMB, 1s, 1); + events.RescheduleEvent(EVENT_TYMPANIC_TANTARUM, 1min, 1); + if (!_hardMode) + events.RescheduleEvent(EVENT_HEALTH_CHECK, 2s, 1); + } + + void Reset() override + { + summons.DespawnAll(); + events.Reset(); + + me->ResetLootMode(); + me->RemoveAllAuras(); + + // first heart expose + _healthCheck = 75; + _hardMode = false; + _nerfAchievement = true; + _gravityAchievement = true; + + me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(false, UNIT_STATE_STUNNED); + + if (m_pInstance) + { + m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_MUST_DECONSTRUCT_FASTER); + m_pInstance->SetData(TYPE_XT002, NOT_STARTED); + if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS))) + pGo->SetGoState(GO_STATE_ACTIVE); + } + } + + void JustSummoned(Creature* cr) override { summons.Summon(cr); } + void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } + + void AttachHeart() + { + if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr) + heart->SetHealth(heart->GetMaxHealth()); + else if (Creature* accessory = me->SummonCreature(NPC_XT002_HEART, *me, TEMPSUMMON_MANUAL_DESPAWN)) + { + accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY); + if (!me->HandleSpellClick(accessory, 0)) + accessory->DespawnOrUnsummon(); + } + } + + void JustReachedHome() override { me->setActive(false); } + + void JustEngagedWith(Unit*) override + { + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + events.ScheduleEvent(EVENT_ENRAGE, 10min, 0, 0); + events.ScheduleEvent(EVENT_CHECK_ROOM, 5s, 0, 0); + RescheduleEvents(); // Other events are scheduled here + + me->setActive(true); + Talk(SAY_AGGRO); + + if (m_pInstance) + { + m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_MUST_DECONSTRUCT_FASTER); + m_pInstance->SetData(TYPE_XT002, IN_PROGRESS); + if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS))) + pGo->SetGoState(GO_STATE_READY); + } + + me->CallForHelp(175); + me->SetInCombatWithZone(); + AttachHeart(); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER && !urand(0, 2)) + { + Talk(SAY_SLAY); + } + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_XT002, DONE); + if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS))) + pGo->SetGoState(GO_STATE_ACTIVE); + } + + // Despawn summons + summons.DespawnAll(); + } + + void DoAction(int32 param) override + { + if (param == DATA_XT002_NERF_ENGINEERING) + { + _nerfAchievement = false; + return; + } + if (param == DATA_XT002_GRAVITY_ACHIEV) + { + _gravityAchievement = false; + return; + } + + if (!me->IsAlive() || _hardMode) + return; + + // heart destory + if (param == ACTION_HEART_BROKEN) + { + _hardMode = true; + me->SetLootMode(3); // hard mode + normal loot + me->SetMaxHealth(me->GetMaxHealth()); + me->SetHealth(me->GetMaxHealth()); + me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge + + me->CastSpell(me, SPELL_HEARTBREAK, true); + + Talk(EMOTE_HEART_CLOSED); + events.ScheduleEvent(EVENT_REMOVE_EMOTE, 4s); + return; + } + + // damage from heart + if (param > 0) + { + // avoid reducing health under 1 + int32 _final = std::min(param, int32(me->GetHealth() - 1)); + + me->ModifyHealth(-_final); + me->LowerPlayerDamageReq(_final); + } + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_XT002_NERF_ENGINEERING) + return _nerfAchievement; + else if (param == DATA_XT002_GRAVITY_ACHIEV) + return _gravityAchievement; + + return 0; + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch(events.ExecuteEvent()) + { + // Control events + case EVENT_HEALTH_CHECK: + if (_hardMode) + { + return; + } + + if (me->HealthBelowPct(_healthCheck)) + { + _healthCheck -= 25; + me->SetControlled(true, UNIT_STATE_STUNNED); + me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_SUBMERGED); // submerge with animation + + Talk(SAY_HEART_OPENED); + + events.CancelEventGroup(1); + events.ScheduleEvent(EVENT_START_SECOND_PHASE, 5s); + return; + } + events.Repeat(1s); + break; + case EVENT_CHECK_ROOM: + events.Repeat(5s); + if (me->GetPositionX() < 722 || me->GetPositionX() > 987 || me->GetPositionY() < -139 || me->GetPositionY() > 124) + EnterEvadeMode(); + + return; + + // Abilities events + case EVENT_GRAVITY_BOMB: + me->CastCustomSpell(SPELL_GRAVITY_BOMB, SPELLVALUE_MAX_TARGETS, 1, me, true); + events.ScheduleEvent(EVENT_SEARING_LIGHT, 10s, 1); + break; + case EVENT_SEARING_LIGHT: + me->CastCustomSpell(SPELL_SEARING_LIGHT, SPELLVALUE_MAX_TARGETS, 1, me, true); + events.ScheduleEvent(EVENT_GRAVITY_BOMB, 10s, 1); + break; + case EVENT_TYMPANIC_TANTARUM: + Talk(EMOTE_TYMPANIC_TANTRUM); + Talk(SAY_TYMPANIC_TANTRUM); + me->CastSpell(me, SPELL_TYMPANIC_TANTARUM, true); + events.Repeat(1min); + return; + case EVENT_ENRAGE: + Talk(SAY_BERSERK); + me->CastSpell(me, SPELL_XT002_ENRAGE, true); + break; + + // Animation events + case EVENT_START_SECOND_PHASE: + Talk(EMOTE_HEART_OPENED); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr) + heart->GetAI()->DoAction(ACTION_AWAKEN_HEART); + + events.ScheduleEvent(EVENT_RESTORE, 30s); + return; + // Restore from heartbreak + case EVENT_RESTORE: + if (_hardMode) + { + return; + } + + Talk(SAY_HEART_CLOSED); + + me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge + // Hide heart + if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr) + heart->GetAI()->DoAction(ACTION_HIDE_HEART); + + events.ScheduleEvent(EVENT_REMOVE_EMOTE, 4s); + return; + case EVENT_REMOVE_EMOTE: + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetControlled(false, UNIT_STATE_STUNNED); + + RescheduleEvents(); + return; + } + + // Disabled by stunned state + DoMeleeAttackIfReady(); + } + }; +}; + +class npc_xt002_heart : public CreatureScript +{ +public: + npc_xt002_heart() : CreatureScript("npc_xt002_heart") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_xt002_heartAI : public PassiveAI + { + npc_xt002_heartAI(Creature* pCreature) : PassiveAI(pCreature), summons(me) + { + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + } + + SummonList summons; + uint32 _damageDone; + uint32 _timerSpawn; + + uint8 _spawnSelection; + uint8 _pummelerCount; + + void MoveInLineOfSight(Unit*) override { } + void AttackStart(Unit*) override { } + void JustSummoned(Creature* cr) override + { + summons.Summon(cr); + if (Unit* owner = me->GetVehicleBase()) + if (owner->GetTypeId() == TYPEID_UNIT) + owner->ToCreature()->AI()->JustSummoned(cr); + } + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + _damageDone += damage; + } + + void SummonPiles() + { + me->SummonCreature(NPC_PILE_TRIGGER, 893.290f, 66.820f, 409.81f, 4.2f); + me->SummonCreature(NPC_PILE_TRIGGER, 898.099f, -88.9115f, 409.887f, 2.23402f); + me->SummonCreature(NPC_PILE_TRIGGER, 793.096f, -95.158f, 409.887f, 0.855211f); + me->SummonCreature(NPC_PILE_TRIGGER, 794.600f, 59.660f, 409.82f, 5.34f); + } + + void DoAction(int32 param) override + { + if (param == ACTION_AWAKEN_HEART) + { + _pummelerCount = 0; + _spawnSelection = 0; + _damageDone = 0; + _timerSpawn = 0; + me->SetHealth(me->GetMaxHealth()); + me->CastSpell(me, SPELL_HEART_OVERLOAD, true); + me->CastSpell(me, SPELL_EXPOSED_HEART, false); // Channeled + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + + if (!summons.HasEntry(NPC_PILE_TRIGGER)) + SummonPiles(); + } + else if (param == ACTION_HIDE_HEART) + { + if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) + if (pXT002->AI()) + { + pXT002->AI()->DoAction(_damageDone); + _damageDone = 0; + } + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + } + } + + void SendEnergyToCorner() + { + Unit* pile = nullptr; + uint8 num = urand(1, 4); + for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) + if (Creature* summon = ObjectAccessor::GetCreature(*me, *itr)) + if (summon->GetEntry() == NPC_PILE_TRIGGER) + { + pile = summon; + if ((--num) == 0) + break; + } + + if (pile) + me->CastSpell(pile, SPELL_ENERGY_ORB, true); + } + + void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override + { + // spawn not-so-random robots + if (spellInfo->Id == SPELL_ENERGY_ORB_TRIGGER && target->GetEntry() == NPC_PILE_TRIGGER) + switch (_spawnSelection) + { + case 0: + for (uint8 i = 0; i < 5; ++i) + me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000); + _spawnSelection++; + break; + case 1: + me->SummonCreature(NPC_XE321_BOOMBOT, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + _spawnSelection++; + break; + case 2: + for (uint8 i = 0; i < 5; ++i) + me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000); + _spawnSelection++; + break; + case 3: + if(_pummelerCount < 2) + me->SummonCreature(NPC_XM024_PUMMELLER, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + + _pummelerCount++; + _spawnSelection++; + break; + case 4: + for (uint8 i = 0; i < 5; ++i) + me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000); + _spawnSelection = 0; + break; + } + } + + void JustDied(Unit* /*killer*/) override + { + me->SetVisible(false); + if (me->GetInstanceScript()) + if (Creature* XT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) + if (XT002->AI()) + XT002->AI()->DoAction(ACTION_HEART_BROKEN); + } + + void UpdateAI(uint32 diff) override + { + if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) + { + _timerSpawn += diff; + if (_timerSpawn >= 1900) + { + SendEnergyToCorner(); + _timerSpawn -= 1900; + } + } + } + }; +}; + +class npc_xt002_scrapbot : public CreatureScript +{ +public: + npc_xt002_scrapbot() : CreatureScript("npc_xt002_scrapbot") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_xt002_scrapbotAI : public PassiveAI + { + npc_xt002_scrapbotAI(Creature* pCreature) : PassiveAI(pCreature) { } + + bool _locked; + void Reset() override + { + me->StopMoving(); + _locked = true; + me->SetWalk(true); + + if (me->GetInstanceScript()) + if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) + { + if (pXT002->GetPositionZ() > 411.0f) // he is on stairs... idiot cryness protection + me->GetMotionMaster()->MovePoint(0, 884.028931f, -14.593809f, 409.786987f); + else + _locked = false; + } + } + + void JustDied(Unit* killer) override + { + // Nerf Scrapbots achievement + if (killer && killer->GetEntry() == NPC_XE321_BOOMBOT) + if (me->GetInstanceScript()) + { + me->GetInstanceScript()->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, 65037); + me->GetInstanceScript()->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 65037); + } + } + + // tc use updateAI, while we have movementinform + void MovementInform(uint32 type, uint32 /*param*/) override + { + if (type == POINT_MOTION_TYPE) + { + _locked = false; + return; + } + + // we reached the target :) + if (type == FOLLOW_MOTION_TYPE && me->GetInstanceScript()) + if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) + { + if (pXT002->IsAlive()) + { + pXT002->AI()->DoAction(DATA_XT002_NERF_ENGINEERING); + pXT002->ModifyHealth(pXT002->GetMaxHealth() * 0.01f); + } + + if (!urand(0, 2)) + pXT002->AI()->Talk(EMOTE_SCRAPBOT); + + me->DespawnOrUnsummon(1); + } + } + + void UpdateAI(uint32 /*diff*/) override + { + if (!_locked) + { + if (me->GetInstanceScript()) + if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) + { + me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); + _locked = true; + } + } + } + }; +}; + +class npc_xt002_pummeller : public CreatureScript +{ +public: + npc_xt002_pummeller() : CreatureScript("npc_xt002_pummeller") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_xt002_pummellerAI : public ScriptedAI + { + npc_xt002_pummellerAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + int32 _arcingSmashTimer; + int32 _trampleTimer; + int32 _uppercutTimer; + + void Reset() override + { + _arcingSmashTimer = 0; + _trampleTimer = 0; + _uppercutTimer = 0; + + if (Unit* target = SelectTargetFromPlayerList(200)) + AttackStart(target); + else + me->DespawnOrUnsummon(500); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _arcingSmashTimer += diff; + _trampleTimer += diff; + _uppercutTimer += diff; + + if (_arcingSmashTimer >= 8000) + { + me->CastSpell(me->GetVictim(), SPELL_ARCING_SMASH, false); + _arcingSmashTimer = 0; + return; + } + if (_trampleTimer >= 11000) + { + me->CastSpell(me->GetVictim(), SPELL_TRAMPLE, false); + _trampleTimer = 0; + return; + } + if (_uppercutTimer >= 14000) + { + me->CastSpell(me->GetVictim(), SPELL_UPPERCUT, false); + _uppercutTimer = 0; + return; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class BoomEvent : public BasicEvent +{ +public: + BoomEvent(Creature* me) : _me(me) + { + } + + bool Execute(uint64 /*time*/, uint32 /*diff*/) override + { + // This hack is here because we suspect our implementation of spell effect execution on targets + // is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets, + // then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc. + // The above situation causes the visual for this spell to be bugged, so we remove the instakill + // effect and implement a script hack for that. + + _me->CastSpell(_me, SPELL_BOOM, false); + return true; + } + +private: + Creature* _me; +}; + +class npc_xt002_boombot : public CreatureScript +{ +public: + npc_xt002_boombot() : CreatureScript("npc_xt002_boombot") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_xt002_boombotAI : public PassiveAI + { + npc_xt002_boombotAI(Creature* pCreature) : PassiveAI(pCreature) { } + + bool _locked; + bool _boomed; + void Reset() override + { + me->StopMoving(); + _locked = true; + _boomed = false; + me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); + + if (me->GetInstanceScript()) + if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) + { + if (pXT002->GetPositionZ() > 411.0f) // he is on stairs... idiot cryness protection + me->GetMotionMaster()->MovePoint(0, 884.028931f, -14.593809f, 409.786987f); + else + _locked = false; + } + } + + void Explode() + { + if (_boomed) + return; + + _boomed = true; // Prevent recursive calls + + WorldPacket data(SMSG_SPELLINSTAKILLLOG, 8 + 8 + 4); + data << me->GetGUID(); + data << me->GetGUID(); + data << uint32(SPELL_BOOM); + me->SendMessageToSet(&data, false); + + me->KillSelf(); + + // Visual only seems to work if the instant kill event is delayed or the spell itself is delayed + // Casting done from player and caster source has the same targetinfo flags, + // so that can't be the issue + // See BoomEvent class + // Schedule 1s delayed + me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1 * IN_MILLISECONDS)); + } + + void JustDied(Unit* /*killer*/) override + { + me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1 * IN_MILLISECONDS)); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (_boomed) + damage = 0; + + if (me->HealthBelowPctDamaged(50, damage) && !_boomed) + { + damage = 0; + Explode(); + } + } + + // tc they use updateAI, while we have movementinform + void MovementInform(uint32 type, uint32 /*param*/) override + { + if (type == POINT_MOTION_TYPE) + { + _locked = false; + return; + } + // we reached the target :) + //if (type == FOLLOW_MOTION_TYPE) + // _kill = true; + } + + void UpdateAI(uint32 /*diff*/) override + { + if (!_locked) + { + if (me->GetInstanceScript()) + if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002))) + { + me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); + _locked = true; + } + } + } + }; +}; + +class npc_xt002_life_spark : public CreatureScript +{ +public: + npc_xt002_life_spark() : CreatureScript("npc_xt002_life_spark") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct npc_xt002_life_sparkAI : public ScriptedAI + { + npc_xt002_life_sparkAI(Creature* pCreature) : ScriptedAI(pCreature) + { + me->SetMaxHealth(RAID_MODE(54000, 172000)); + me->SetHealth(me->GetMaxHealth()); + me->CastSpell(me, SPELL_SPARK_DAMAGE, true); + } + + uint32 _attackTimer; + void Reset() override + { + if (Unit* target = SelectTargetFromPlayerList(200)) + AttackStart(target); + else + me->DespawnOrUnsummon(); + } + + void UpdateAI(uint32 /*diff*/) override + { + if (!UpdateVictim()) + return; + + me->CastSpell(me->GetVictim(), SPELL_SPARK_MELEE, false); + DoMeleeAttackIfReady(); + } + }; +}; + +// 62775 - Tympanic Tantrum +class spell_xt002_tympanic_tantrum : public SpellScriptLoader +{ +public: + spell_xt002_tympanic_tantrum() : SpellScriptLoader("spell_xt002_tympanic_tantrum") { } + + class spell_xt002_tympanic_tantrum_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xt002_tympanic_tantrum_SpellScript); + + void FilterTargets(std::list& targets) + { + targets.remove_if(PlayerOrPetCheck()); + } + + void RecalculateDamage() + { + if (GetHitUnit()) + SetHitDamage(GetHitUnit()->CountPctFromMaxHealth(GetHitDamage())); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); + OnHit += SpellHitFn(spell_xt002_tympanic_tantrum_SpellScript::RecalculateDamage); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_xt002_tympanic_tantrum_SpellScript(); + } +}; + +// 64234, 63024 - Gravity Bomb +class spell_xt002_gravity_bomb_aura : public SpellScriptLoader +{ +public: + spell_xt002_gravity_bomb_aura() : SpellScriptLoader("spell_xt002_gravity_bomb_aura") { } + + class spell_xt002_gravity_bomb_aura_AuraScript : public AuraScript + { + PrepareAuraScript(spell_xt002_gravity_bomb_aura_AuraScript); + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Player* player = GetOwner()->ToPlayer()) + if (Unit* xt002 = GetCaster()) + if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode + if (Creature* cr = xt002->SummonCreature(NPC_VOID_ZONE, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 180000)) + { + int32 damage = GetSpellInfo()->Id == 63025 ? 5000 : 7500; + cr->CastCustomSpell(cr, SPELL_VOID_ZONE_DAMAGE, &damage, 0, 0, true); + } + } + + void OnPeriodic(AuraEffect const* aurEff) + { + Unit* xt002 = GetCaster(); + if (!xt002) + return; + + Unit* owner = GetOwner()->ToUnit(); + if (!owner) + return; + + if (aurEff->GetAmount() >= int32(owner->GetHealth())) + if (xt002->GetAI()) + xt002->GetAI()->DoAction(DATA_XT002_GRAVITY_ACHIEV); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_xt002_gravity_bomb_aura_AuraScript::OnPeriodic, EFFECT_2, SPELL_AURA_PERIODIC_DAMAGE); + AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_gravity_bomb_aura_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_xt002_gravity_bomb_aura_AuraScript(); + } + + class spell_xt002_gravity_bomb_aura_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xt002_gravity_bomb_aura_SpellScript); + + void SelectTarget(std::list& targets) + { + if (Unit* victim = GetCaster()->GetVictim()) + targets.remove_if(Acore::ObjectGUIDCheck(victim->GetGUID(), true)); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_gravity_bomb_aura_SpellScript::SelectTarget, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_xt002_gravity_bomb_aura_SpellScript(); + } +}; + +// 64233, 63025 - Gravity Bomb +class spell_xt002_gravity_bomb_damage : public SpellScriptLoader +{ +public: + spell_xt002_gravity_bomb_damage() : SpellScriptLoader("spell_xt002_gravity_bomb_damage") { } + + class spell_xt002_gravity_bomb_damage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xt002_gravity_bomb_damage_SpellScript); + + void HandleScript(SpellEffIndex /*eff*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + if (GetHitDamage() >= int32(GetHitUnit()->GetHealth())) + if (caster->GetAI()) + caster->GetAI()->DoAction(DATA_XT002_GRAVITY_ACHIEV); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_xt002_gravity_bomb_damage_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_xt002_gravity_bomb_damage_SpellScript(); + } +}; + +// 63018, 65121 - Searing Light +class spell_xt002_searing_light_spawn_life_spark : public SpellScriptLoader +{ +public: + spell_xt002_searing_light_spawn_life_spark() : SpellScriptLoader("spell_xt002_searing_light_spawn_life_spark") { } + + class spell_xt002_searing_light_spawn_life_spark_AuraScript : public AuraScript + { + PrepareAuraScript(spell_xt002_searing_light_spawn_life_spark_AuraScript); + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Player* player = GetOwner()->ToPlayer()) + if (Unit* xt002 = GetCaster()) + if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode + xt002->SummonCreature(NPC_LIFE_SPARK, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 180000); + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_xt002_searing_light_spawn_life_spark_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_xt002_searing_light_spawn_life_spark_AuraScript(); + } + + class spell_xt002_searing_light_spawn_life_spark_SpellScript : public SpellScript + { + PrepareSpellScript(spell_xt002_searing_light_spawn_life_spark_SpellScript); + + void SelectTarget(std::list& targets) + { + if (Unit* victim = GetCaster()->GetVictim()) + targets.remove_if(Acore::ObjectGUIDCheck(victim->GetGUID(), true)); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_searing_light_spawn_life_spark_SpellScript::SelectTarget, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_xt002_searing_light_spawn_life_spark_SpellScript(); + } +}; + +class achievement_xt002_nerf_engineering : public AchievementCriteriaScript +{ +public: + achievement_xt002_nerf_engineering() : AchievementCriteriaScript("achievement_xt002_nerf_engineering") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + if (target) + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_XT002))) + return cr->AI()->GetData(DATA_XT002_NERF_ENGINEERING); + + return false; + } +}; + +class achievement_xt002_nerf_gravity_bombs : public AchievementCriteriaScript +{ +public: + achievement_xt002_nerf_gravity_bombs() : AchievementCriteriaScript("achievement_xt002_nerf_gravity_bombs") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + if (target) + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_XT002))) + return cr->AI()->GetData(DATA_XT002_GRAVITY_ACHIEV); + + return false; + } +}; + +#endif \ No newline at end of file diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp index a064933e396349..4f4a9b16a984ec 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "boss_yoggsaron.h" #include "AchievementCriteriaScript.h" #include "CreatureAI.h" #include "CreatureScript.h" @@ -29,2998 +30,6 @@ #include "SpellScriptLoader.h" #include "ulduar.h" -enum YoggSpells -{ - // KEEPERS - SPELL_KEEPER_ACTIVE = 62647, - SPELL_MIMIRON_PASSIVE = 62671, - SPELL_THORIM_PASSIVE = 62702, - SPELL_HODIR_PASSIVE = 62650, - SPELL_FREYA_PASSIVE = 62670, - - SPELL_DESTABILIZATION_MATRIX = 65206, - SPELL_DESTABILIZATION_MATRIX_ATTACK = 65210, - SPELL_SANITY_WELL_VISUAL = 63288, - SPELL_SANITY_WELL_BUFF = 64169, - SPELL_PROTECTIVE_GAZE = 64174, // COOLDOWN 25 SECS BEFORE NEXT USE - SPELL_HODIR_FLASH_FREEZE = 64175, - SPELL_CONJURE_SANITY_WELL = 64170, - - SPELL_TITANIC_STORM_PASSIVE = 64171, - SPELL_WEAKENED = 64162, - - // GLOBAL - SPELL_SANITY_BASE = 63786, - SPELL_SANITY = 63050, - SPELL_EXTINGUISH_ALL_LIFE = 64166, - SPELL_CLOUD_VISUAL = 63084, - SPELL_SUMMON_GUARDIAN_OF_YS = 63031, - SPELL_INSANE1 = 63120, - SPELL_INSANE2 = 64464, - SPELL_INSANE_PERIODIC = 64554, // this checks if player dc'ed and insanes him instantly after logging in - - // SARA P1 - SPELL_SARAS_FAVOR = 63138, - SPELL_SARAS_FAVOR_TARGET_SELECTOR = 63747, - SPELL_SARAS_BLESSING = 63134, - SPELL_SARAS_BLESSING_TARGET_SELECTOR = 63745, - SPELL_SARAS_ANGER = 63147, - SPELL_SARAS_ANGER_TARGET_SELECTOR = 63744, - SPELL_SHADOWY_BARRIER = 64775, - - // GUARDIANS OF YOGG-SARON - SPELL_SHADOW_NOVA = 62714, - SPELL_DARK_VOLLEY = 63038, - - // SARA P2 - SPELL_SARA_PSYCHOSIS_10 = 63795, - SPELL_SARA_PSYCHOSIS_25 = 65301, - SPELL_MALADY_OF_THE_MIND = 63830, - SPELL_MALADY_OF_THE_MIND_TRIGGER = 63881, - SPELL_BRAIN_LINK = 63802, - SPELL_BRAIN_LINK_DAMAGE = 63803, - SPELL_BRAIN_LINK_OK = 63804, - - SPELL_DEATH_RAY_DAMAGE_VISUAL = 63886, - SPELL_DEATH_RAY_ORIGIN_VISUAL = 63893, - SPELL_DEATH_RAY_WARNING = 63882, - SPELL_DEATH_RAY_DAMAGE = 63883, - SPELL_DEATH_RAY_DAMAGE_REAL = 63884, - - // YOGG-SARON P2 - SPELL_SHADOW_BARRIER = 63894, - SPELL_KNOCK_AWAY = 64022, - - // TENTACLES - SPELL_VOID_ZONE_SMALL = 64384, - SPELL_VOID_ZONE_LARGE = 64017, - SPELL_TENTACLE_ERUPT = 64144, - - // CRUSHER TENTACLE - SPELL_CRUSH = 64146, - SPELL_DIMINISH_POWER = 64145, - SPELL_FOCUSED_ANGER = 57688, - - // CONSTRICTOR TENTACLE - SPELL_LUNGE = 64123, - SPELL_SQUEEZE_10 = 64125, - SPELL_SQUEEZE_25 = 64126, - - // CORRUPTOR TENTACLE - SPELL_APATHY = 64156, - SPELL_BLACK_PLAGUE = 64153, - SPELL_CURSE_OF_DOOM = 64157, - SPELL_DRAINING_POISON = 64152, - - // MISC - SPELL_REVEALED_TENTACLE = 64012, - SPELL_IN_THE_MAWS_OF_THE_OLD_GOD = 64184, - - // BRAIN OF YOGG-SARON - SPELL_SHATTERED_ILLUSION = 64173, - SPELL_INDUCE_MADNESS = 64059, - SPELL_BRAIN_HURT_VISUAL = 64361, - - // PORTALS - SPELL_TELEPORT_TO_CHAMBER = 63997, - SPELL_TELEPORT_TO_ICECROWN = 63998, - SPELL_TELEPORT_TO_STORMWIND = 63989, - SPELL_TELEPORT_BACK = 63992, - SPELL_CANCEL_ILLUSION_AURA = 63993, - - // LAUGHING SKULL AND INFLUENCE TENTACLE AND OTHERS - SPELL_LUNATIC_GAZE = 64167, - SPELL_GRIM_REPRISAL = 63305, - SPELL_GRIM_REPRISAL_DAMAGE = 64039, - SPELL_DEATHGRASP = 63037, - - // YOGG-SARON P3 - SPELL_LUNATIC_GAZE_YS = 64163, - SPELL_DEAFENING_ROAR = 64189, - SPELL_SHADOW_BEACON = 64465, - - // IMMORTAL GUARDIAN - SPELL_SIMPLE_TELEPORT = 64195, - SPELL_EMPOWERED = 65294, - SPELL_EMPOWERED_PASSIVE = 64161, - SPELL_DRAIN_LIFE_10 = 64159, - SPELL_DRAIN_LIFE_25 = 64160, - SPELL_RECENTLY_SPAWNED = 64497, -}; - -#define SPELL_PSYCHOSIS RAID_MODE(SPELL_SARA_PSYCHOSIS_10, SPELL_SARA_PSYCHOSIS_25) -#define SPELL_SQUEEZE RAID_MODE(SPELL_SQUEEZE_10, SPELL_SQUEEZE_25) -#define SPELL_DRAIN_LIFE RAID_MODE(SPELL_DRAIN_LIFE_10, SPELL_DRAIN_LIFE_25) - -enum YoggEvents -{ - EVENT_SARA_P1_DOORS_CLOSE = 1, - EVENT_SARA_P1_SUMMON = 2, - EVENT_SARA_P1_SPELLS = 3, - EVENT_SARA_P1_BERSERK = 4, - - EVENT_SARA_P2_START = 10, - EVENT_SARA_P2_SUMMON_T1 = 11, - EVENT_SARA_P2_SUMMON_T2 = 12, - EVENT_SARA_P2_SUMMON_T3 = 13, - EVENT_SARA_P2_BRAIN_LINK = 14, - EVENT_SARA_P2_DEATH_RAY = 15, - EVENT_SARA_P2_MALADY = 16, - EVENT_SARA_P2_PSYCHOSIS = 17, - EVENT_SARA_P2_OPEN_PORTALS = 18, - EVENT_SARA_P2_REMOVE_STUN = 19, - EVENT_SARA_P2_SPAWN_START_TENTACLES = 20, - - EVENT_YS_LUNATIC_GAZE = 30, - EVENT_YS_DEAFENING_ROAR = 31, - EVENT_YS_SUMMON_GUARDIAN = 32, - EVENT_YS_SHADOW_BEACON = 33, -}; - -enum NPCsGOs -{ - // NPCs - NPC_OMINOUS_CLOUD = 33292, - NPC_GUARDIAN_OF_YS = 33136, - NPC_SANITY_WELL = 33991, - NPC_YOGG_SARON = 33288, - NPC_VOICE_OF_YOGG_SARON = 33280, - NPC_YOGG_SARON_VISION = 33552, - - NPC_CRUSHER_TENTACLE = 33966, // 50 secs ? - NPC_CONSTRICTOR_TENTACLE = 33983, // 15-20 secs ? - NPC_CORRUPTOR_TENTACLE = 33985, // 30-40 secs ? - - NPC_INFLUENCE_TENTACLE = 33943, - NPC_DEATH_ORB = 33882, - NPC_DESCEND_INTO_MADNESS = 34072, - NPC_LAUGHING_SKULL = 33990, - - NPC_IMMORTAL_GUARDIAN = 33988, - NPC_MARKED_IMMORTAL_GUARDIAN = 36064, - - // CHAMBER ILLUSION - NPC_CONSORT_FIRST = 33716, - NPC_CONSORT_LAST = 33720, - NPC_ALEXTRASZA = 33536, - NPC_MALYGOS = 33535, - NPC_NELTHARION = 33523, - NPC_YSERA = 33495, - GO_DRAGON_SOUL = 194462, - - // ICECROWN ILLUSION - NPC_DEATHSWORN_ZEALOT = 33567, - NPC_LICH_KING = 33441, - NPC_IMMOLATED_CHAMPION = 33442, - - // STORMWIND ILLUSION - NPC_SUIT_OF_ARMOR = 33433, - NPC_GARONA = 33436, - NPC_KING_LLANE = 33437, - - // GOs - GO_DOORS = 194773, - GO_FLEE_TO_THE_SURFACE_PORTAL = 194625, - GO_CHAMBER_ILLUSION_DOORS = 194635, - GO_ICECROWN_ILLUSION_DOORS = 194636, - GO_STORMWIND_ILLUSION_DOORS = 194637, - - // MODELs - SARA_TRANSFORM_MODEL = 29182, -}; - -enum Misc -{ - ACTION_UNSUMMON_CLOUDS = -16, - ACTION_DESPAWN_ADDS = -15, - ACTION_START_SUMMONING = -14, - ACTION_YOGG_SARON_APPEAR = -13, - ACTION_YOGG_SARON_DEATH = -12, - ACTION_YOGG_SARON_START_YELL = -11, - ACTION_YOGG_SARON_OPEN_PORTAL_YELL = -10, - ACTION_INFLUENCE_TENTACLE_DIED = -9, - ACTION_BRAIN_DAMAGED = -8, - ACTION_REMOVE_STUN = -7, - ACTION_YOGG_SARON_START_P3 = -6, - ACTION_YOGG_SARON_HARD_MODE = -5, - ACTION_YOGG_SARON_SHADOW_BEACON = -4, - ACTION_THORIM_START_STORM = -3, - ACTION_FAILED_DRIVE_ME_CRAZY = -2, - - ACTION_ILLUSION_DRAGONS = 1, - ACTION_ILLUSION_ICECROWN = 2, - ACTION_ILLUSION_STORMWIND = 3, - - EVENT_PHASE_ONE = 1, - EVENT_PHASE_TWO = 2, - EVENT_PHASE_THREE = 3, - - CRITERIA_NOT_GETTING_OLDER = 21001, - - // YOGG-SARON (laugh) - YS_P3_LUNATIC_GAZE = 15757, - - DATA_GET_KEEPERS_COUNT = 1, - DATA_GET_CURRENT_ILLUSION = 2, - DATA_GET_SARA_PHASE = 3, - DATA_GET_DRIVE_ME_CRAZY = 4, -}; - -struct LocationsXY -{ - float x, y, z; -}; - -static LocationsXY yoggPortalLoc[] = -{ - {1970.48f, -9.75f, 325.5f}, - {1992.76f, -10.21f, 325.5f}, - {1995.53f, -39.78f, 325.5f}, - {1969.25f, -42.00f, 325.5f}, - {1960.62f, -32.00f, 325.5f}, - {1981.98f, -5.69f, 325.5f}, - {1982.78f, -45.73f, 325.5f}, - {2000.66f, -29.68f, 325.5f}, - {1999.88f, -19.61f, 325.5f}, - {1961.37f, -19.54f, 325.5f} -}; - -enum Texts -{ - // Sara - SAY_SARA_ULDUAR_SCREAM_0 = 0, // Unused - SAY_SARA_ULDUAR_SCREAM_1 = 1, // Unused - SAY_SARA_AGGRO = 2, - SAY_SARA_FERVOR_HIT = 3, - SAY_SARA_ANGER = 4, // Comment in DB is for BLESSING_HIT, but it's wrong. - SAY_SARA_KILL = 5, - SAY_SARA_TRANSFORM_1 = 6, // "I am the lucid dream." - SAY_SARA_TRANSFORM_2 = 7, // "The monster in your nightmares." - SAY_SARA_TRANSFORM_3 = 8, // "The fiend of a thousand faces." - SAY_SARA_TRANSFORM_4 = 9, // "Cower before my true form." - SAY_SARA_DEATH_RAY = 10, - SAY_SARA_PSYCHOSIS_HIT = 11, - - // Voice of Yogg-Saron - WHISPER_VOICE_PHASE_1_WIPE = 0, - WHISPER_VOICE_INSANE = 1, - - // Brain of Yogg-Saron - EMOTE_YOGG_SARON_BRAIN_SHATTERED = 0, - - // Yogg-Saron - SAY_YOGG_SARON_SPAWN = 0, - SAY_YOGG_SARON_MADNESS = 1, // Open Portals - EMOTE_YOGG_SARON_MADNESS = 2, - SAY_YOGG_SARON_PHASE_3 = 3, - SAY_YOGG_SARON_DEAFENING_ROAR = 4, - EMOTE_YOGG_SARON_DEAFENING_ROAR = 5, - SAY_YOGG_SARON_DEATH = 6, - EMOTE_YOGG_SARON_EMPOWERING_SHADOWS = 7, // Shadow Beacon - EMOTE_YOGG_SARON_BERSERK = 8, - - // Visions - Text is in order of Roleplay - // The Assassination of King Llane vision - SAY_GARONA_1 = 0, - SAY_GARONA_2 = 1, - SAY_GARONA_3 = 2, - SAY_YOGG_1 = 0, - SAY_YOGG_2 = 1, - SAY_LLANE_1 = 0, - SAY_GARONA_4 = 3, - SAY_YOGG_3 = 2, - - // The Forging of the Demon Soul vision - SAY_NEL_1 = 0, - SAY_YAS_1 = 0, - SAY_NEL_2 = 1, - SAY_MAL_1 = 0, - SAY_YOGG_4 = 5, - - // The Tortured Champion vision - SAY_LK_1 = 0, - SAY_IC_1 = 0, - SAY_IC_2 = 1, - SAY_LK_2 = 1, - SAY_YOGG_5 = 3, - SAY_YOGG_6 = 4, - -}; - -const Position Middle = {1980.28f, -25.5868f, 329.397f, M_PI * 1.5f}; - -class boss_yoggsaron_sara : public CreatureScript -{ -public: - boss_yoggsaron_sara() : CreatureScript("boss_yoggsaron_sara") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_saraAI : public ScriptedAI - { - boss_yoggsaron_saraAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) - { - m_pInstance = pCreature->GetInstanceScript(); - } - - InstanceScript* m_pInstance; - EventMap events; - SummonList summons; - - uint32 _initFight; - ObjectGuid _keepersGUID[4]; - uint8 _summonedGuardiansCount; - uint32 _p2TalkTimer; - bool _secondPhase; - float _summonSpeed; - uint8 _currentIllusion; - bool _isIllusionReversed; - - void AttackStart(Unit*) override { } - void MoveInLineOfSight(Unit*) override { } - - void JustSummoned(Creature* cr) override - { - summons.Summon(cr); - if (cr->GetEntry() >= NPC_FREYA_KEEPER && cr->GetEntry() <= NPC_THORIM_KEEPER) - { - if (cr->GetEntry() == NPC_FREYA_KEEPER) - cr->CastSpell(cr, SPELL_CONJURE_SANITY_WELL, false); - _keepersGUID[cr->GetEntry() - NPC_FREYA_KEEPER] = cr->GetGUID(); - } - else if (cr->GetEntry() == NPC_SANITY_WELL) - cr->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_SCALE, true); - } - - void SpawnClouds() - { - for (uint8 i = 0; i < 6; ++i) - { - float Zplus = i > 2 ? (i - 2) * 1.6f : 0; - if (i % 2) - me->SummonCreature(NPC_OMINOUS_CLOUD, me->GetPositionX() + 8 + i * 7, me->GetPositionY() + 8 + i * 7, 326 + Zplus, 0); - else - me->SummonCreature(NPC_OMINOUS_CLOUD, me->GetPositionX() - 8 - i * 7, me->GetPositionY() - 8 - i * 7, 326 + Zplus, 0); - } - } - - void SpawnWeels() - { - me->SummonCreature(NPC_SANITY_WELL, 2042.56f, -40.3667f, 329.274f, 0.0f); - me->SummonCreature(NPC_SANITY_WELL, 1975.89f, 40.0216f, 331.1f, 0.0f); - me->SummonCreature(NPC_SANITY_WELL, 1987.12f, -91.2702f, 330.186f, 0.0f); - me->SummonCreature(NPC_SANITY_WELL, 1900.48f, -51.2386f, 332.13f, 0.0f); - me->SummonCreature(NPC_SANITY_WELL, 1899.94f, 0.330621f, 332.296f, 0.0f); - } - - void EnterEvadeMode(EvadeReason why) override - { - if (!_EnterEvadeMode(why)) - return; - - Position pos; - pos = me->GetHomePosition(); - me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); - Reset(); - me->setActive(false); - } - - void EnableSara(bool apply) - { - if (apply) - { - me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); - me->DisableRotate(false); - me->ClearUnitState(UNIT_STATE_ROOT); - } - else - { - me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); - me->DisableRotate(true); - me->AddUnitState(UNIT_STATE_ROOT); - } - } - - void Reset() override - { - if (!_secondPhase) // Phase 1 wipe - { - me->GetMap()->DoForAllPlayers([&](Player* player) - { - if (Creature* voice = me->FindNearestCreature(NPC_VOICE_OF_YOGG_SARON, 10.0f)) - { - voice->AI()->Talk(WHISPER_VOICE_PHASE_1_WIPE, player); - } - }); - } - - summons.DoAction(ACTION_DESPAWN_ADDS); - events.Reset(); - summons.DespawnAll(); - - me->SetVisible(true); - me->SetDisplayId(me->GetNativeDisplayId()); - me->SetDisableGravity(true); - EnableSara(false); - SpawnClouds(); - - _initFight = 1; - - for (uint8 i = 0; i < 4; ++i) - _keepersGUID[i].Clear(); - - _summonedGuardiansCount = 0; - _p2TalkTimer = 0; - _secondPhase = false; - _summonSpeed = 1.0f; - _currentIllusion = urand(1, 3); - _isIllusionReversed = urand(0, 1); - - if (m_pInstance) - { - m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_NOT_GETTING_OLDER); - m_pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_SANITY); - m_pInstance->SetData(TYPE_YOGGSARON, NOT_STARTED); - if (GameObject* go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_YOGG_SARON_DOORS))) - go->SetGoState(GO_STATE_ACTIVE); - } - } - - void InitFight(Unit* target) - { - if (!m_pInstance) - return; - - // some simple hack checks - if (m_pInstance->GetData(TYPE_VEZAX) != DONE || m_pInstance->GetData(TYPE_XT002) != DONE) - return; - - m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_NOT_GETTING_OLDER); - m_pInstance->SetData(TYPE_YOGGSARON, IN_PROGRESS); - me->SetInCombatWithZone(); - AttackStart(target); - - me->CastSpell(me, SPELL_SANITY_BASE, true); - - SaveKeepers(); - - events.ScheduleEvent(EVENT_SARA_P1_DOORS_CLOSE, 15s, 0, EVENT_PHASE_ONE); - events.ScheduleEvent(EVENT_SARA_P1_BERSERK, 15min, 0, 0); - events.ScheduleEvent(EVENT_SARA_P1_SUMMON, 0ms, 0, EVENT_PHASE_ONE); - events.SetPhase(EVENT_PHASE_ONE); - - Talk(SAY_SARA_AGGRO); - me->setActive(true); - } - - void SaveKeepers() - { - for (uint8 i = 0; i < 4; ++i) - if (m_pInstance->GetData(TYPE_WATCHERS) & (1 << i)) - switch (i) - { - case KEEPER_FREYA: - SpawnWeels(); - me->SummonCreature(NPC_FREYA_KEEPER, 1939.32f, 42.165f, 338.415f, 5.17955f); - break; - case KEEPER_HODIR: - me->SummonCreature(NPC_HODIR_KEEPER, 1939.13f, -90.8332f, 338.415f, 1.00123f); - break; - case KEEPER_MIMIRON: - me->SummonCreature(NPC_MIMIRON_KEEPER, 2036.81f, 25.6646f, 338.415f, 3.74227f); - break; - case KEEPER_THORIM: - me->SummonCreature(NPC_THORIM_KEEPER, 2036.59f, -73.8499f, 338.415f, 2.34819f); - break; - } - } - - void InformCloud() - { - Creature* cloud = nullptr; - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end();) - { - Creature* summon = ObjectAccessor::GetCreature(*me, *itr); - ++itr; - if (!summon || summon->GetEntry() != NPC_OMINOUS_CLOUD || me->GetDistance(summon) < 20) - continue; - - if ((!cloud || (urand(0, 1) && !summon->HasAura(SPELL_SUMMON_GUARDIAN_OF_YS)))) - cloud = summon; - } - - if (cloud) - cloud->AI()->DoAction(ACTION_START_SUMMONING); - } - - void SpawnTentacle(uint32 entry) - { - uint32 dist = urand(38, 48); - float o = rand_norm() * M_PI * 2; - float Zplus = (dist - 38) / 6.5f; - if (Creature* cr = me->SummonCreature(entry, me->GetPositionX() + dist * cos(o), me->GetPositionY() + dist * std::sin(o), 327.2 + Zplus, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000)) - { - cr->CastSpell(cr, SPELL_TENTACLE_ERUPT, true); - cr->CastSpell(cr, SPELL_VOID_ZONE_SMALL, true); - cr->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); - } - } - - void SummonDeathOrbs() - { - for (uint8 i = 0; i < 4; ++i) - { - uint32 dist = urand(38, 48); - float o = rand_norm() * M_PI * 2; - float Zplus = (dist - 38) / 6.5f; - me->SummonCreature(NPC_DEATH_ORB, me->GetPositionX() + dist * cos(o), me->GetPositionY() + dist * std::sin(o), 327.2 + Zplus, 0, TEMPSUMMON_TIMED_DESPAWN, 20000); - } - } - - void AddPortals() - { - _summonSpeed -= 0.1f; - Creature* cr = nullptr; - - // Spawn Portals - for (uint8 i = 0; i < RAID_MODE(4, 10); ++i) - { - if ((cr = me->SummonCreature(NPC_DESCEND_INTO_MADNESS, yoggPortalLoc[i].x, yoggPortalLoc[i].y, yoggPortalLoc[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 25000))) - { - cr->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE); - cr->SetArmor(_currentIllusion); - } - } - - EntryCheckPredicate pred(NPC_BRAIN_OF_YOGG_SARON); - summons.DoAction(_currentIllusion, pred); - - if (_isIllusionReversed) - _currentIllusion = _currentIllusion == 3 ? 1 : (_currentIllusion + 1); - else - _currentIllusion = _currentIllusion == 1 ? 3 : (_currentIllusion - 1); - } - - void KilledUnit(Unit* who) override - { - if (who->IsPlayer()) - { - Talk(SAY_SARA_KILL); - } - } - - void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_SANITY) - if (Aura* aur = target->GetAura(SPELL_SANITY)) - aur->SetStackAmount(100); - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_GET_KEEPERS_COUNT) - { - uint8 _count = 0; - for (uint8 i = 0; i < 4; ++i) - if (_keepersGUID[i]) - ++_count; - - return _count; - } - else if (param == DATA_GET_SARA_PHASE) - return _secondPhase; - - return 4; // just to be sure, return max numer of keepers - } - - void DoAction(int32 param) override - { - if (param == ACTION_BRAIN_DAMAGED) - { - summons.DoAction(ACTION_REMOVE_STUN); - - EntryCheckPredicate pred2(NPC_YOGG_SARON); - summons.DoAction(ACTION_YOGG_SARON_START_P3, pred2); - - EntryCheckPredicate pred3(NPC_THORIM_KEEPER); - summons.DoAction(ACTION_THORIM_START_STORM, pred3); - - if (!(_keepersGUID[0] && _keepersGUID[1] && _keepersGUID[2] && _keepersGUID[3]) && me->GetMap()->Is25ManRaid()) - summons.DoAction(ACTION_YOGG_SARON_HARD_MODE, pred2); - - summons.DespawnEntry(NPC_DEATH_ORB); - events.SetPhase(EVENT_PHASE_THREE); - - me->RemoveAllAuras(); - me->SetVisible(false); - return; - } - else if (param == ACTION_YOGG_SARON_DEATH) - { - summons.DespawnEntry(NPC_VOICE_OF_YOGG_SARON); - summons.DespawnEntry(NPC_BRAIN_OF_YOGG_SARON); - summons.DespawnEntry(NPC_MIMIRON_KEEPER); - summons.DespawnEntry(NPC_HODIR_KEEPER); - summons.DespawnEntry(NPC_FREYA_KEEPER); - summons.DespawnEntry(NPC_THORIM_KEEPER); - summons.DespawnEntry(NPC_SANITY_WELL); - me->KillSelf(); - return; - } - - // Determine shatter duration - if (param <= 0) - return; - - // Illusion shatters (param - stun time) - if (Creature* yoggb = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(NPC_BRAIN_OF_YOGG_SARON))) - { - yoggb->AI()->Talk(EMOTE_YOGG_SARON_BRAIN_SHATTERED); - } - - uint32 timer = events.GetNextEventTime(EVENT_SARA_P2_OPEN_PORTALS); - uint32 portalTime = (timer > events.GetTimer() ? timer - events.GetTimer() : 0); - events.DelayEvents(param + 100); - events.RescheduleEvent(EVENT_SARA_P2_OPEN_PORTALS, portalTime, 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_REMOVE_STUN, param, 0, EVENT_PHASE_TWO); - me->CastSpell(me, SPELL_SHATTERED_ILLUSION, true); - } - - void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (who && who->GetEntry() == NPC_GUARDIAN_OF_YS && !_secondPhase) - { - damage = 25000; - - // START PHASE 2 - if (me->GetHealth() <= damage) - { - _secondPhase = true; - damage = 0; - - events.SetPhase(EVENT_PHASE_TWO); - me->SetHealth(me->GetMaxHealth()); - - if (Creature* cr = me->SummonCreature(NPC_YOGG_SARON, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), M_PI)) - cr->SetVisible(false); - - _p2TalkTimer++; - Talk(SAY_SARA_TRANSFORM_1); - } - return; - } - - damage = 0; - } - - void UpdateAI(uint32 diff) override - { - if (_initFight) - { - _initFight += diff; - if (_initFight > 5000) - { - if (Unit* target = SelectTargetFromPlayerList(90)) - { - _initFight = 0; - InitFight(target); - } - else - _initFight = 1; - } - return; - } - - if (!SelectTargetFromPlayerList(90, SPELL_INSANE1)) - { - m_pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_INSANE1); - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - if (_p2TalkTimer) - { - _p2TalkTimer += diff; - if (_p2TalkTimer >= 4000 && _p2TalkTimer < 20000) - { - EntryCheckPredicate pred(NPC_OMINOUS_CLOUD); - summons.DoAction(ACTION_UNSUMMON_CLOUDS, pred); - Talk(SAY_SARA_TRANSFORM_2); - _p2TalkTimer = 20000; - } - else if (_p2TalkTimer >= 25000 && _p2TalkTimer < 40000) - { - summons.DespawnEntry(NPC_OMINOUS_CLOUD); - Talk(SAY_SARA_TRANSFORM_3); - _p2TalkTimer = 40000; - } - else if (_p2TalkTimer >= 44500 && _p2TalkTimer < 60000) - { - Talk(SAY_SARA_TRANSFORM_4); - _p2TalkTimer = 60000; - } - else if (_p2TalkTimer >= 64000) - { - EntryCheckPredicate pred(NPC_YOGG_SARON); - summons.DoAction(ACTION_YOGG_SARON_START_YELL, pred); - _p2TalkTimer = 0; - events.ScheduleEvent(EVENT_SARA_P2_START, 500ms, 0, EVENT_PHASE_TWO); - } - return; - } - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch(events.ExecuteEvent()) - { - case EVENT_SARA_P1_DOORS_CLOSE: - // Whispers of YS - me->SummonCreature(NPC_VOICE_OF_YOGG_SARON, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); - - if (m_pInstance) - if (GameObject* go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_YOGG_SARON_DOORS))) - go->SetGoState(GO_STATE_READY); - - events.ScheduleEvent(EVENT_SARA_P1_SPELLS, 0ms, 1, EVENT_PHASE_ONE); - break; - case EVENT_SARA_P1_SUMMON: - events.RepeatEvent(20000 - (std::min(_summonedGuardiansCount, (uint8)5) * 2000)); - ++_summonedGuardiansCount; - InformCloud(); - break; - case EVENT_SARA_P1_SPELLS: - { - uint32 spell = RAND(SPELL_SARAS_ANGER_TARGET_SELECTOR, SPELL_SARAS_BLESSING_TARGET_SELECTOR, SPELL_SARAS_FAVOR_TARGET_SELECTOR); - if (urand(0, 2)) - { - if (spell == SPELL_SARAS_ANGER_TARGET_SELECTOR) - { - Talk(SAY_SARA_ANGER); - } - else if (spell == SPELL_SARAS_FAVOR_TARGET_SELECTOR) - { - Talk(SAY_SARA_FERVOR_HIT); - } - } - - me->CastCustomSpell(spell, SPELLVALUE_MAX_TARGETS, 1, nullptr, false); - events.RepeatEvent(me->GetMap()->Is25ManRaid() ? urand(0, 3000) : 4000 + urand(0, 2000)); - break; - } - case EVENT_SARA_P2_START: - { - EntryCheckPredicate pred(NPC_YOGG_SARON); - summons.DoAction(ACTION_YOGG_SARON_APPEAR, pred); - events.RescheduleEvent(EVENT_SARA_P2_SPAWN_START_TENTACLES, 500, 0, EVENT_PHASE_TWO); - - // Spawn Brain! - me->SummonCreature(NPC_BRAIN_OF_YOGG_SARON, 1981.3f, -25.43f, 265); - break; - } - case EVENT_SARA_P2_MALADY: - me->CastCustomSpell(SPELL_MALADY_OF_THE_MIND, SPELLVALUE_MAX_TARGETS, 1, me, false); - events.Repeat(20s); - break; - case EVENT_SARA_P2_PSYCHOSIS: - if ((urand(0, 9)) == 0) // Rarely said (as it's casted every 3.5s) - { - Talk(SAY_SARA_PSYCHOSIS_HIT); - } - me->CastCustomSpell(SPELL_PSYCHOSIS, SPELLVALUE_MAX_TARGETS, 1, me, false); - events.Repeat(3500ms); - break; - case EVENT_SARA_P2_DEATH_RAY: - Talk(SAY_SARA_DEATH_RAY); - SummonDeathOrbs(); - events.Repeat(20s); - break; - case EVENT_SARA_P2_SUMMON_T1: // CRUSHER - SpawnTentacle(NPC_CRUSHER_TENTACLE); - events.RepeatEvent((50000 + urand(0, 10000)) * _summonSpeed); - break; - case EVENT_SARA_P2_SUMMON_T2: // CONSTRICTOR - SpawnTentacle(NPC_CONSTRICTOR_TENTACLE); - events.RepeatEvent((15000 + urand(0, 5000)) * _summonSpeed); - break; - case EVENT_SARA_P2_SUMMON_T3: // CORRUPTOR - SpawnTentacle(NPC_CORRUPTOR_TENTACLE); - events.RepeatEvent((30000 + urand(0, 10000)) * _summonSpeed); - break; - case EVENT_SARA_P2_BRAIN_LINK: - me->CastCustomSpell(SPELL_BRAIN_LINK, SPELLVALUE_MAX_TARGETS, 1, me, false); - events.Repeat(30s); - break; - case EVENT_SARA_P2_OPEN_PORTALS: - { - AddPortals(); - EntryCheckPredicate pred(NPC_YOGG_SARON); - summons.DoAction(ACTION_YOGG_SARON_OPEN_PORTAL_YELL, pred); - events.Repeat(80s); - break; - } - case EVENT_SARA_P2_REMOVE_STUN: - { - me->RemoveAura(SPELL_SHATTERED_ILLUSION); - summons.DoAction(ACTION_REMOVE_STUN); - break; - } - case EVENT_SARA_P2_SPAWN_START_TENTACLES: - me->SetOrientation(M_PI); - me->SetDisplayId(SARA_TRANSFORM_MODEL); - - me->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), 355, me->GetOrientation()); - me->SetPosition(me->GetPositionX(), me->GetPositionY(), 355, me->GetOrientation()); - - SpawnTentacle(NPC_CRUSHER_TENTACLE); - SpawnTentacle(NPC_CONSTRICTOR_TENTACLE); - SpawnTentacle(NPC_CORRUPTOR_TENTACLE); - SpawnTentacle(NPC_CORRUPTOR_TENTACLE); - - events.ScheduleEvent(EVENT_SARA_P2_MALADY, 7s, 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_PSYCHOSIS, 3s, 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_DEATH_RAY, 15s, 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_SUMMON_T1, 50s, 60s, 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_SUMMON_T2, 15s, 20s, 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_SUMMON_T3, 30000 + urand(0, 10000), 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_BRAIN_LINK, 0, 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_OPEN_PORTALS, 60000, 0, EVENT_PHASE_TWO); - break; - case EVENT_SARA_P1_BERSERK: - if (me->GetInstanceScript()) - { - if (Creature* yogg = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_YOGGSARON))) - { - yogg->AI()->Talk(EMOTE_YOGG_SARON_BERSERK); - } - } - me->CastSpell(me, SPELL_EXTINGUISH_ALL_LIFE, true); - events.Repeat(5s); - break; - } - } - }; -}; - -class boss_yoggsaron_cloud : public CreatureScript -{ -public: - boss_yoggsaron_cloud() : CreatureScript("boss_yoggsaron_cloud") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_cloudAI : public npc_escortAI - { - boss_yoggsaron_cloudAI(Creature* pCreature) : npc_escortAI(pCreature) - { - InitWaypoint(); - Reset(); - Start(false, true, ObjectGuid::Empty, nullptr, false, true); - } - - uint32 _checkTimer; - bool _isSummoning; - - void JustSummoned(Creature* cr) override - { - cr->ToTempSummon()->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); - - _isSummoning = false; - if (me->GetInstanceScript()) - if (Creature* sara = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(NPC_SARA))) - sara->AI()->JustSummoned(cr); - } - - void MoveInLineOfSight(Unit* /*who*/) override {} - void AttackStart(Unit* /*who*/) override {} - void WaypointReached(uint32 /*point*/) override {} - - void Reset() override - { - me->CastSpell(me, SPELL_CLOUD_VISUAL, true); - _checkTimer = 0; - _isSummoning = false; - } - - void DoAction(int32 param) override - { - if (param == ACTION_UNSUMMON_CLOUDS) - { - me->RemoveAllAuras(); - } - else if (param == ACTION_START_SUMMONING) - { - _isSummoning = true; - me->CastSpell(me, SPELL_SUMMON_GUARDIAN_OF_YS, true); - } - } - - void InitWaypoint() - { - float dist = Middle.GetExactDist(me); - if (me->GetPositionX() > Middle.GetPositionX()) - { - for (uint8 i = 0; i <= dist; ++i) - { - float angle = M_PI * 2 / dist * i; - AddWaypoint(i, Middle.GetPositionX() + dist * cos(angle), Middle.GetPositionY() + dist * std::sin(angle), me->GetPositionZ(), 0); - } - } - else - { - for (uint8 i = 0; i <= dist; ++i) - { - float angle = M_PI * 2 - (M_PI * 2 / dist * i); - AddWaypoint(i, Middle.GetPositionX() + dist * cos(angle), Middle.GetPositionY() + dist * std::sin(angle), me->GetPositionZ(), 0); - } - } - } - - void UpdateEscortAI(uint32 diff) override - { - _checkTimer += diff; - if (_checkTimer >= 500 && !_isSummoning) - { - Unit* who = me->SelectNearbyTarget(nullptr, 6.0f); - if (who && who->IsPlayer() && !me->HasAura(SPELL_SUMMON_GUARDIAN_OF_YS) && !who->HasAura(SPELL_HODIR_FLASH_FREEZE)) - { - _isSummoning = true; - Talk(0, who); - me->CastSpell(me, SPELL_SUMMON_GUARDIAN_OF_YS, true); - } - - _checkTimer = 0; - } - } - }; -}; - -class boss_yoggsaron_guardian_of_ys : public CreatureScript -{ -public: - boss_yoggsaron_guardian_of_ys() : CreatureScript("boss_yoggsaron_guardian_of_ys") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_guardian_of_ysAI : public ScriptedAI - { - boss_yoggsaron_guardian_of_ysAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - uint32 _spellTimer; - - void Reset() override - { - _spellTimer = 0; - me->SetInCombatWithZone(); - } - - void JustDied(Unit*) override - { - me->CastSpell((Unit*)nullptr, SPELL_SHADOW_NOVA, true); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - _spellTimer += diff; - if (_spellTimer > 8000) - { - me->CastSpell(me, SPELL_DARK_VOLLEY, false); - _spellTimer = 0; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_yoggsaron : public CreatureScript -{ -public: - boss_yoggsaron() : CreatureScript("boss_yoggsaron") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaronAI : public ScriptedAI - { - boss_yoggsaronAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) - { - m_pInstance = me->GetInstanceScript(); - _thirdPhase = false; - _usedInsane = false; - summons.DespawnAll(); - events.Reset(); - - uint8 _count = 4; - me->SetLootMode(31); // 1 + 2 + 4 + 8 + 16, remove with watchers addition - if (m_pInstance) - { - for (uint8 i = 0; i < 4; ++i) - if (m_pInstance->GetData(TYPE_WATCHERS) & (1 << i)) - { - me->RemoveLootMode(1 << _count); - --_count; - } - } - } - - InstanceScript* m_pInstance; - EventMap events; - SummonList summons; - bool _thirdPhase; - bool _usedInsane; - - void AttackStart(Unit*) override { } - - void JustSummoned(Creature* cr) override { summons.Summon(cr); } - - void SummonImmortalGuardian() - { - uint32 dist = urand(38, 48); - float o = rand_norm() * M_PI * 2; - float Zplus = (dist - 38) / 6.5f; - me->SummonCreature(NPC_IMMORTAL_GUARDIAN, me->GetPositionX() + dist * cos(o), me->GetPositionY() + dist * std::sin(o), 327.2 + Zplus, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - } - - void JustDied(Unit* /*who*/) override - { - summons.DespawnAll(); - events.Reset(); - - Talk(SAY_YOGG_SARON_DEATH); - - if (m_pInstance) - { - m_pInstance->SetData(TYPE_YOGGSARON, DONE); - if (Creature* sara = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_SARA))) - sara->AI()->DoAction(ACTION_YOGG_SARON_DEATH); - if (GameObject* go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_YOGG_SARON_DOORS))) - go->SetGoState(GO_STATE_ACTIVE); - } - - Map::PlayerList const& pList = me->GetMap()->GetPlayers(); - for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) - { - itr->GetSource()->RemoveAura(SPELL_SANITY); - itr->GetSource()->RemoveAura(SPELL_INSANE1); - itr->GetSource()->RemoveAura(SPELL_INSANE2); - } - } - - void DoAction(int32 param) override - { - if (param == ACTION_DESPAWN_ADDS) - summons.DespawnAll(); - else if (param == ACTION_YOGG_SARON_APPEAR) - { - me->SetVisible(true); - me->CastSpell(me, SPELL_SHADOW_BARRIER, true); - me->CastSpell(me, SPELL_KNOCK_AWAY, true); - me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); - me->SetInCombatWithZone(); - - me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED); - } - else if (param == ACTION_YOGG_SARON_START_YELL) - { - Talk(SAY_YOGG_SARON_SPAWN); - } - else if (param == ACTION_YOGG_SARON_OPEN_PORTAL_YELL) - { - Talk(SAY_YOGG_SARON_MADNESS); - Talk(EMOTE_YOGG_SARON_MADNESS); - } - else if (param == ACTION_YOGG_SARON_START_P3) - { - me->SetHealth(me->GetMaxHealth() * 0.3f); - me->LowerPlayerDamageReq(me->GetMaxHealth() * 0.7f); - - me->RemoveAura(SPELL_SHADOW_BARRIER); - - events.ScheduleEvent(EVENT_YS_LUNATIC_GAZE, 7000); - events.ScheduleEvent(EVENT_YS_SHADOW_BEACON, 20000); - events.ScheduleEvent(EVENT_YS_SUMMON_GUARDIAN, 0); - _thirdPhase = true; - - Talk(SAY_YOGG_SARON_PHASE_3); - } - else if (param == ACTION_YOGG_SARON_HARD_MODE) - { - events.ScheduleEvent(EVENT_YS_DEAFENING_ROAR, 50000); - } - else if (param == ACTION_YOGG_SARON_SHADOW_BEACON) - { - events.RescheduleEvent(EVENT_YS_SHADOW_BEACON, 40000); - } - else if (param == ACTION_REMOVE_STUN) - { - me->RemoveAura(SPELL_SHATTERED_ILLUSION); - me->SetControlled(true, UNIT_STATE_ROOT); - } - else if (param == ACTION_FAILED_DRIVE_ME_CRAZY) - _usedInsane = true; - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_GET_DRIVE_ME_CRAZY) - return !_usedInsane; - - return 0; - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_IN_THE_MAWS_OF_THE_OLD_GOD) - me->AddLootMode(32); - } - - void UpdateAI(uint32 diff) override - { - if (!_thirdPhase) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_YS_LUNATIC_GAZE: - me->PlayDirectSound(YS_P3_LUNATIC_GAZE); - me->CastSpell(me, SPELL_LUNATIC_GAZE_YS, true); - events.Repeat(12s); - break; - case EVENT_YS_DEAFENING_ROAR: - Talk(SAY_YOGG_SARON_DEAFENING_ROAR); - Talk(EMOTE_YOGG_SARON_DEAFENING_ROAR); - me->CastSpell(me, SPELL_DEAFENING_ROAR, false); - events.Repeat(50s); - break; - case EVENT_YS_SHADOW_BEACON: - events.Repeat(5s); - Talk(EMOTE_YOGG_SARON_EMPOWERING_SHADOWS); - me->CastCustomSpell(SPELL_SHADOW_BEACON, SPELLVALUE_MAX_TARGETS, RAID_MODE(1, 3), me, false); - break; - case EVENT_YS_SUMMON_GUARDIAN: - SummonImmortalGuardian(); - events.Repeat(10s); - break; - } - } - }; -}; - -class boss_yoggsaron_brain : public CreatureScript -{ -public: - boss_yoggsaron_brain() : CreatureScript("boss_yoggsaron_brain") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_brainAI : public NullCreatureAI - { - boss_yoggsaron_brainAI(Creature* pCreature) : NullCreatureAI(pCreature), summons(pCreature) - { - me->SetDisableGravity(true); - _tentacleCount = 0; - _activeIllusion = 0; - _induceTimer = 0; - _brainDamaged = false; - me->SetRegeneratingHealth(false); - } - - bool _brainDamaged; - uint8 _tentacleCount; - uint8 _activeIllusion; - uint32 _induceTimer; - SummonList summons; - - void Reset() override { } - void JustSummoned(Creature* cr) override - { - if (cr->GetEntry() == NPC_INFLUENCE_TENTACLE) - { - // Dragons Illusion - if (cr->GetPositionX() > 2000.0f && cr->GetPositionX() < 2150.0f) - cr->UpdateEntry(urand(NPC_CONSORT_FIRST, NPC_CONSORT_LAST)); - // Icecrown Illusion - else if (cr->GetPositionY() > -150.0f && cr->GetPositionY() < -90.0f) - { - cr->SetStandState(UNIT_STAND_STATE_KNEEL); - cr->UpdateEntry(NPC_DEATHSWORN_ZEALOT); - } - // Stormwind Illusion - else - cr->UpdateEntry(NPC_SUIT_OF_ARMOR); - } - else if (cr->GetEntry() == NPC_LICH_KING) - cr->CastSpell(cr, SPELL_DEATHGRASP, false); - - summons.Summon(cr); - } - - void PrepareChamberIllusion() - { - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2126.13f, -65.488f, 239.721f, 1.99171f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2141.05f, -50.5146f, 239.751f, 2.72998f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2148.83f, -23.9568f, 239.721f, 3.04807f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2064.39f, -42.0691f, 239.719f, 0.0949586f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2064.29f, -7.13128f, 239.756f, 5.96974f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2117.31f, 14.897f, 239.731f, 4.32041f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2136.7f, 2.43262f, 239.72f, 3.90023f); - - // Laughing Skulls - if (urand(0, 1)) - me->SummonCreature(NPC_LAUGHING_SKULL, 2139.13f, -59.0848f, 239.728f, 2.2974f); - else - me->SummonCreature(NPC_LAUGHING_SKULL, 2083, -25.66f, 244, 0); - if (urand(0, 1)) - me->SummonCreature(NPC_LAUGHING_SKULL, 2066.67f, -59.8984f, 239.72f, 0.718747f); - else - me->SummonCreature(NPC_LAUGHING_SKULL, 2126.22f, -25.86f, 244, 0); - - me->SummonCreature(NPC_LAUGHING_SKULL, 2133.09f, 15.341f, 239.72f, 4.0724f); - me->SummonCreature(NPC_LAUGHING_SKULL, 2065.83f, 12.3772f, 239.792f, 5.49789f); - - // Aspects - me->SummonCreature(NPC_ALEXTRASZA, 2091.92f, -25.8f, 242.647f, 0); - me->SummonCreature(NPC_YSERA, 2116, -25.8f, 242.647f, 3.14f); - me->SummonCreature(NPC_NELTHARION, 2103.6f, -35.8f, 242.64f, 1.5f); - me->SummonCreature(NPC_MALYGOS, 2103.6f, -15.8f, 242.64f, 4.7f); - - // Yogg Vision - me->SummonCreature(NPC_YOGG_SARON_VISION, 2109.695f, -25.09549f, 222.3250f, 0); - } - - void PrepareIceCrownIllusion() - { - // Laughing Skulls - me->SummonCreature(NPC_LAUGHING_SKULL, 1931.12f, -92.702f, 239.991f, 5.2819f); - if (urand(0, 1)) - me->SummonCreature(NPC_LAUGHING_SKULL, 1969.88f, -147.729f, 239.991f, 2.37593f); - else - me->SummonCreature(NPC_LAUGHING_SKULL, 1878, -93.3f, 240, 0); - if (urand(0, 1)) - me->SummonCreature(NPC_LAUGHING_SKULL, 1950.78f, -167.902f, 239.991f, 2.34844f); - else - me->SummonCreature(NPC_LAUGHING_SKULL, 1938.45f, -116.5f, 240, 0); - if (urand(0, 1)) - me->SummonCreature(NPC_LAUGHING_SKULL, 1896.45f, -141.469f, 239.991f, 6.12227f); - else - me->SummonCreature(NPC_LAUGHING_SKULL, 1921, -158, 240, 0); - - // Influence - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1958.29f, -128.65f, 239.99f, 3.61293f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1957.78f, -134.368f, 239.99f, 3.35375f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1953.04f, -137.843f, 239.99f, 3.55796f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1900.31f, -93.5241f, 239.99f, 4.50043f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1895.03f, -98.0773f, 239.99f, 4.88135f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1895.19f, -104.587f, 239.99f, 5.02271f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1923.31f, -125.98f, 240, 4.2f); - - // Others - me->SummonCreature(NPC_LICH_KING, 1906.98f, -153, 240, 4.2f); - me->SummonCreature(NPC_IMMOLATED_CHAMPION, 1902.03f, -161.7f, 240, 1.07f); - - // Yogg Vision - me->SummonCreature(NPC_YOGG_SARON_VISION, 1906.226f, -155.8941f, 223.4727, 0); - } - - void PrepareStormwindIllusion() - { - // Laughing Skulls - if (urand(0, 1)) - me->SummonCreature(NPC_LAUGHING_SKULL, 1916.36f, 28.05f, 239.666f, 1.30238f); - else - me->SummonCreature(NPC_LAUGHING_SKULL, 1966.7f, 57.8f, 239.66f, 0); - if (urand(0, 1)) - me->SummonCreature(NPC_LAUGHING_SKULL, 1902, 75.1362f, 239.666f, 6.06189f); - else - me->SummonCreature(NPC_LAUGHING_SKULL, 1933, 91, 240, 0); - me->SummonCreature(NPC_LAUGHING_SKULL, 1914.42f, 90.8465f, 239.666f, 5.25294f); - me->SummonCreature(NPC_LAUGHING_SKULL, 1963.68f, 89.7549f, 239.667f, 3.70571f); - - // Influence - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1931.41f, 39.0711f, 239.66f, 1.82467f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1908.67f, 45.5867f, 239.666f, 0.72119f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1897.68f, 66.1274f, 239.666f, 6.27395f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1950.73f, 49.3446f, 239.666f, 2.63756f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1923.16f, 97.5586f, 239.666f, 4.74635f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1956.16f, 72.1403f, 239.666f, 3.19518f); - me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1944.81f, 92.3154f, 239.666f, 4.03556f); - - // Others - me->SummonCreature(NPC_GARONA, 1928.58f, 65.64f, 242.37f, 2.1f); - me->SummonCreature(NPC_KING_LLANE, 1925.14f, 71.74f, 242.37f, 5.17f); - - // Yogg Vision - me->SummonCreature(NPC_YOGG_SARON_VISION, 1929.160f, 67.75694f, 221.7322f, 0); - } - - void DoAction(int32 param) override - { - if (param == ACTION_DESPAWN_ADDS) - { - summons.DespawnAll(); - return; - } - else if (param == ACTION_INFLUENCE_TENTACLE_DIED) - { - _tentacleCount++; - if (_tentacleCount >= 7 /*TENTACLES COUNT*/) - { - // Stun - if (me->GetInstanceScript()) - if(Creature* sara = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(NPC_SARA))) - sara->AI()->DoAction(MINUTE * IN_MILLISECONDS - std::min((uint32)MINUTE * IN_MILLISECONDS, _induceTimer)); - - _induceTimer = 0; - summons.DespawnEntry(NPC_LAUGHING_SKULL); - if (GameObject* go = me->FindNearestGameObject(GO_CHAMBER_ILLUSION_DOORS + _activeIllusion, 150.0f)) - go->SetGoState(GO_STATE_ACTIVE); - } - return; - } - else if (param == ACTION_REMOVE_STUN) - return; - - summons.DespawnAll(); - switch(param) - { - case ACTION_ILLUSION_STORMWIND: - PrepareStormwindIllusion(); - break; - case ACTION_ILLUSION_DRAGONS: - PrepareChamberIllusion(); - break; - case ACTION_ILLUSION_ICECROWN: - PrepareIceCrownIllusion(); - break; - } - - for (uint32 i = GO_CHAMBER_ILLUSION_DOORS; i <= GO_STORMWIND_ILLUSION_DOORS; ++i) - if (GameObject* go = me->FindNearestGameObject(i, 150.0f)) - go->SetGoState(GO_STATE_READY); - - _activeIllusion = param - 1; - _tentacleCount = 0; - _induceTimer = 1; - - me->CastSpell(me, SPELL_INDUCE_MADNESS, false); - } - - uint32 GetData(uint32 param) const override - { - if (param == DATA_GET_CURRENT_ILLUSION) - return _activeIllusion + 1; - - return 0; - } - - void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (_tentacleCount < 7) // if all tentacles aren't killed - { - damage = 0; - if (who) - Unit::Kill(who, who); - return; - } - - if (!_brainDamaged) - { - // START PHASE 3 - if (me->HealthBelowPctDamaged(30, damage)) - { - me->SetRegeneratingHealth(false); - _EnterEvadeMode(); - _brainDamaged = true; - - me->CastSpell(me, SPELL_BRAIN_HURT_VISUAL, true); - if (me->GetInstanceScript()) - if(Creature* sara = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(NPC_SARA))) - sara->AI()->DoAction(ACTION_BRAIN_DAMAGED); - } - } - } - - void UpdateAI(uint32 diff) override - { - if (_induceTimer) - _induceTimer += diff; - } - }; -}; - -class boss_yoggsaron_death_orb : public CreatureScript -{ -public: - boss_yoggsaron_death_orb() : CreatureScript("boss_yoggsaron_death_orb") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_death_orbAI : public NullCreatureAI - { - boss_yoggsaron_death_orbAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - me->CastSpell(me, SPELL_DEATH_RAY_WARNING, true); - _startTimer = 1; - } - - uint32 _startTimer; - - void UpdateAI(uint32 diff) override - { - if (_startTimer) - { - _startTimer += diff; - if (_startTimer > 4000) - { - me->CastSpell(me, SPELL_DEATH_RAY_DAMAGE_VISUAL, true); - me->CastSpell(me, SPELL_DEATH_RAY_DAMAGE, true); - - _startTimer = 0; - me->SetSpeed(MOVE_WALK, 2); - me->SetSpeed(MOVE_RUN, 2); - me->GetMotionMaster()->MoveRandom(20.0f); - } - } - } - }; -}; - -class boss_yoggsaron_crusher_tentacle : public CreatureScript -{ -public: - boss_yoggsaron_crusher_tentacle() : CreatureScript("boss_yoggsaron_crusher_tentacle") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_crusher_tentacleAI : public ScriptedAI - { - boss_yoggsaron_crusher_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) - { - me->SetCombatMovement(false); - me->CastSpell(me, SPELL_CRUSH, true); - me->CastSpell(me, SPELL_FOCUSED_ANGER, true); - me->CastSpell(me, SPELL_DIMINISH_POWER, false); - } - - void Reset() override - { - me->SetInCombatWithZone(); - } - - void DamageTaken(Unit* who, uint32&, DamageEffectType damagetype, SpellSchoolMask) override - { - if (who && damagetype == DIRECT_DAMAGE) - { - DoResetThreatList(); - me->AddThreat(who, 100000); - AttackStart(who); - me->InterruptNonMeleeSpells(false); - } - } - - void DoAction(int32 param) override - { - if (param == ACTION_REMOVE_STUN) - me->RemoveAura(SPELL_SHATTERED_ILLUSION); - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!UpdateVictim()) - return; - - if (me->IsWithinMeleeRange(me->GetVictim())) - { - DoMeleeAttackIfReady(); - return; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - me->CastSpell(me, SPELL_DIMINISH_POWER, false); - DoResetThreatList(); - } - }; -}; - -class boss_yoggsaron_corruptor_tentacle : public CreatureScript -{ -public: - boss_yoggsaron_corruptor_tentacle() : CreatureScript("boss_yoggsaron_corruptor_tentacle") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_corruptor_tentacleAI : public ScriptedAI - { - boss_yoggsaron_corruptor_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) - { - me->SetCombatMovement(false); - } - - void DoAction(int32 param) override - { - if (param == ACTION_REMOVE_STUN) - me->RemoveAura(SPELL_SHATTERED_ILLUSION); - } - - Unit* SelectCorruptionTarget() - { - Player* target = nullptr; - Map::PlayerList const& pList = me->GetMap()->GetPlayers(); - uint8 num = urand(0, pList.getSize() - 1); - uint8 count = 0; - for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr, ++count) - { - if (me->GetDistance(itr->GetSource()) > 200 || itr->GetSource()->GetPositionZ() < 300 || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster()) - continue; - - if (count <= num || !target) - target = itr->GetSource(); - else - break; - } - - return target; - } - - void UpdateAI(uint32 /*diff*/) override - { - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - if (Unit* target = SelectCorruptionTarget()) - { - uint32 spellid = RAND(SPELL_APATHY, SPELL_BLACK_PLAGUE, SPELL_DRAINING_POISON, SPELL_CURSE_OF_DOOM); - me->CastSpell(target, spellid, false); - } - } - }; -}; - -class boss_yoggsaron_constrictor_tentacle : public CreatureScript -{ -public: - boss_yoggsaron_constrictor_tentacle() : CreatureScript("boss_yoggsaron_constrictor_tentacle") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_constrictor_tentacleAI : public ScriptedAI - { - boss_yoggsaron_constrictor_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) - { - me->SetCombatMovement(false); - _checkTimer = 1; - _playerGUID.Clear(); - } - - uint32 _checkTimer; - ObjectGuid _playerGUID; - - Unit* SelectConstrictTarget() - { - Player* target = nullptr; - Map::PlayerList const& pList = me->GetMap()->GetPlayers(); - uint8 num = urand(0, pList.getSize() - 1); - uint8 count = 0; - for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr, ++count) - { - if (me->GetDistance(itr->GetSource()) > 10 || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster()) - continue; - if (itr->GetSource()->HasAura(SPELL_SQUEEZE) || itr->GetSource()->HasAura(SPELL_INSANE1)) - continue; - - if (count <= num || !target) - target = itr->GetSource(); - else - break; - } - - return target; - } - - void UpdateAI(uint32 diff) override - { - if (_checkTimer) - { - _checkTimer += diff; - if (_checkTimer >= 1000 && !me->HasUnitState(UNIT_STATE_STUNNED)) - { - if (Unit* target = SelectConstrictTarget()) - { - target->CastSpell(me, SPELL_LUNGE, true); - target->CastSpell(target, SPELL_SQUEEZE, true); - _playerGUID = target->GetGUID(); - _checkTimer = 0; - return; - } - - _checkTimer = 1; - } - } - } - - void DoAction(int32 param) override - { - if (param == ACTION_REMOVE_STUN) - me->RemoveAura(SPELL_SHATTERED_ILLUSION); - } - - void JustDied(Unit*) override - { - if (Unit* player = ObjectAccessor::GetUnit(*me, _playerGUID)) - player->RemoveAura(SPELL_SQUEEZE); - } - }; -}; - -class boss_yoggsaron_keeper : public CreatureScript -{ -public: - boss_yoggsaron_keeper() : CreatureScript("boss_yoggsaron_keeper") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_keeperAI : public NullCreatureAI - { - boss_yoggsaron_keeperAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - _checkTimer = 0; - me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_SCALE, true); - } - - uint32 _checkTimer; - - void DoAction(int32 param) override - { - if (me->GetEntry() == NPC_THORIM_KEEPER && param == ACTION_THORIM_START_STORM) - me->CastSpell(me, SPELL_TITANIC_STORM_PASSIVE, false); - } - - void UpdateAI(uint32 diff) override - { - if (me->GetInstanceScript()) - if (me->GetInstanceScript()->GetData(TYPE_YOGGSARON) != IN_PROGRESS) - return; - - _checkTimer += diff; - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - if (me->GetEntry() == NPC_MIMIRON_KEEPER) - { - if (_checkTimer >= 2000) - { - me->CastSpell(me, SPELL_DESTABILIZATION_MATRIX, false); - _checkTimer = 0; - } - } - } - }; -}; - -class boss_yoggsaron_descend_portal : public CreatureScript -{ -public: - boss_yoggsaron_descend_portal() : CreatureScript("boss_yoggsaron_descend_portal") { } - - struct boss_yoggsaron_descend_portalAI : public PassiveAI - { - boss_yoggsaron_descend_portalAI(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) {} - - void OnSpellClick(Unit* clicker, bool& spellClickHandled) override - { - if (!spellClickHandled) - return; - - if (!me->GetUInt32Value(UNIT_NPC_FLAGS)) - return; - - switch (me->GetArmor()) - { - case ACTION_ILLUSION_DRAGONS: - clicker->CastSpell(clicker, SPELL_TELEPORT_TO_CHAMBER, true); - break; - case ACTION_ILLUSION_ICECROWN: - clicker->CastSpell(clicker, SPELL_TELEPORT_TO_ICECROWN, true); - break; - case ACTION_ILLUSION_STORMWIND: - clicker->CastSpell(clicker, SPELL_TELEPORT_TO_STORMWIND, true); - break; - } - - me->SetUInt32Value(UNIT_NPC_FLAGS, 0); - me->DespawnOrUnsummon(1000); - } - - private: - InstanceScript* _instance; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); - } -}; - -class boss_yoggsaron_influence_tentacle : public CreatureScript -{ -public: - boss_yoggsaron_influence_tentacle() : CreatureScript("boss_yoggsaron_influence_tentacle") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_influence_tentacleAI : public NullCreatureAI - { - boss_yoggsaron_influence_tentacleAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - me->CastSpell(me, SPELL_GRIM_REPRISAL, true); - } - - void DamageTaken(Unit*, uint32&, DamageEffectType, SpellSchoolMask) override - { - if (me->GetEntry() != NPC_INFLUENCE_TENTACLE) - me->UpdateEntry(NPC_INFLUENCE_TENTACLE, 0, false); - } - - void JustDied(Unit*) override - { - if (me->IsSummon()) - if (Unit* sara = me->ToTempSummon()->GetSummonerUnit()) - sara->GetAI()->DoAction(ACTION_INFLUENCE_TENTACLE_DIED); - } - }; -}; - -class boss_yoggsaron_immortal_guardian : public CreatureScript -{ -public: - boss_yoggsaron_immortal_guardian() : CreatureScript("boss_yoggsaron_immortal_guardian") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_immortal_guardianAI : public ScriptedAI - { - boss_yoggsaron_immortal_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) - { - Reset(); - } - - uint32 _visualTimer; - uint32 _spellTimer; - - void Reset() override - { - me->CastSpell(me, SPELL_RECENTLY_SPAWNED, true); - //me->CastSpell(me, SPELL_EMPOWERED_PASSIVE, true); - if (Aura* aur = me->AddAura(SPELL_EMPOWERED_PASSIVE, me)) - aur->SetStackAmount(9); - - _spellTimer = 0; - _visualTimer = 1; - me->SetControlled(true, UNIT_STATE_ROOT); - me->SetInCombatWithZone(); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (damage >= me->GetHealth()) - damage = me->GetHealth() - 1; - } - - void SpellHit(Unit* caster, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_SHADOW_BEACON) - caster->GetAI()->DoAction(ACTION_YOGG_SARON_SHADOW_BEACON); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (_visualTimer) - { - _visualTimer += diff; - if (_visualTimer >= 100 && _visualTimer < 10000 ) - { - me->CastSpell(me, SPELL_SIMPLE_TELEPORT, false); - _visualTimer = 10000; - } - else if (_visualTimer >= 11000) - { - me->SetControlled(false, UNIT_STATE_ROOT); - _visualTimer = 0; - } - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - _spellTimer += diff; - if (_spellTimer >= 9500) - { - if (me->HealthBelowPct(85)) - { - if (Unit* target = SelectTargetFromPlayerList(40.0f)) - { - me->CastSpell(target, SPELL_DRAIN_LIFE, false); - _spellTimer = 0; - } - } - else - _spellTimer = 7500; - } - - DoMeleeAttackIfReady(); - } - }; -}; - -class boss_yoggsaron_lich_king : public CreatureScript -{ -public: - boss_yoggsaron_lich_king() : CreatureScript("boss_yoggsaron_lich_king") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_lich_kingAI : public NullCreatureAI - { - boss_yoggsaron_lich_kingAI(Creature* c) : NullCreatureAI(c) { } - - bool _running; - int32 _checkTimer; - uint8 _step; - - void Reset() override - { - _running = true; - _checkTimer = 0; - _step = 0; - } - - void NextStep(const uint32 time) - { - _step++; - _checkTimer = time; - } - - void Say(uint8 text, uint32 id) - { - Creature* creature = me->FindNearestCreature(id, 50); - if (!creature) - return; - - creature->AI()->Talk(text); - return; - } - - void UpdateAI(uint32 diff) override - { - if (!_running) - return; - - if (_checkTimer != 0) - { - _checkTimer -= diff; - if (_checkTimer < 0 ) - _checkTimer = 0; - } - else - switch (_step) - { - case 0: - NextStep(5000); - break; - case 1: - Say(SAY_LK_1, NPC_LICH_KING); - NextStep(7000); - break; - case 2: - Say(SAY_IC_1, NPC_IMMOLATED_CHAMPION); - NextStep(6000); - break; - case 3: - Say(SAY_IC_2, NPC_IMMOLATED_CHAMPION); - NextStep(6500); - break; - case 4: - Say(SAY_LK_2, NPC_LICH_KING); - NextStep(7500); - break; - case 5: - Say(SAY_YOGG_5, NPC_YOGG_SARON_VISION); - NextStep(5000); - break; - case 6: - Say(SAY_YOGG_6, NPC_YOGG_SARON_VISION); - _running = false; - break; - } - } - }; -}; - -class boss_yoggsaron_llane : public CreatureScript -{ -public: - boss_yoggsaron_llane() : CreatureScript("boss_yoggsaron_llane") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_llaneAI : public NullCreatureAI - { - boss_yoggsaron_llaneAI(Creature* c) : NullCreatureAI(c) { } - - bool _running; - int32 _checkTimer; - uint8 _step; - - void Reset() override - { - _running = true; - _checkTimer = 0; - _step = 0; - } - - void NextStep(const uint32 time) - { - _step++; - _checkTimer = time; - } - - void Say(uint8 text, uint32 id) - { - Creature* creature = me->FindNearestCreature(id, 50); - if (!creature) - return; - - creature->AI()->Talk(text); - return; - } - - void UpdateAI(uint32 diff) override - { - if (!_running) - return; - - if (_checkTimer != 0) - { - _checkTimer -= diff; - if (_checkTimer < 0 ) - _checkTimer = 0; - } - else - switch (_step) - { - case 0: - NextStep(5000); - break; - case 1: - Say(SAY_GARONA_1, NPC_GARONA); - NextStep(2000); - break; - case 2: - Say(SAY_GARONA_2, NPC_GARONA); - NextStep(6500); - break; - case 3: - Say(SAY_GARONA_3, NPC_GARONA); - NextStep(11000); - break; - case 4: - Say(SAY_YOGG_1, NPC_YOGG_SARON_VISION); - NextStep(2500); - break; - case 5: - Say(SAY_YOGG_2, NPC_YOGG_SARON_VISION); - NextStep(2500); - break; - case 6: - Say(SAY_LLANE_1, NPC_KING_LLANE); - NextStep(10000); - break; - case 7: - Say(SAY_GARONA_4, NPC_GARONA); - NextStep(5000); - break; - case 8: - Say(SAY_YOGG_3, NPC_YOGG_SARON_VISION); - _running = false; - break; - } - } - }; -}; - -class boss_yoggsaron_neltharion : public CreatureScript -{ -public: - boss_yoggsaron_neltharion() : CreatureScript("boss_yoggsaron_neltharion") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_neltharionAI : public ScriptedAI - { - boss_yoggsaron_neltharionAI(Creature* c) : ScriptedAI(c) { } - - bool _running; - int32 _checkTimer; - uint8 _step; - - void Reset() override - { - _running = true; - _checkTimer = 0; - _step = 0; - } - - void NextStep(const uint32 time) - { - _step++; - _checkTimer = time; - } - - void Say(uint8 text, uint32 id) - { - Creature* creature = me->FindNearestCreature(id, 50); - if (!creature) - return; - - creature->AI()->Talk(text); - return; - } - - void UpdateAI(uint32 diff) override - { - if (!_running) - return; - - if (_checkTimer != 0) - { - _checkTimer -= diff; - if (_checkTimer < 0 ) - _checkTimer = 0; - } - else - switch (_step) - { - case 0: - NextStep(5000); - break; - case 1: - Say(SAY_NEL_1, NPC_NELTHARION); - NextStep(10000); - break; - case 2: - Say(SAY_YAS_1, NPC_YSERA); - NextStep(4000); - break; - case 3: - Say(SAY_NEL_2, NPC_NELTHARION); - NextStep(4000); - break; - case 4: - Say(SAY_MAL_1, NPC_MALYGOS); - NextStep(8000); - break; - case 5: - Say(SAY_YOGG_4, NPC_YOGG_SARON_VISION); - _running = false; - break; - } - } - }; -}; - -class boss_yoggsaron_voice : public CreatureScript -{ -public: - boss_yoggsaron_voice() : CreatureScript("boss_yoggsaron_voice") { } - - CreatureAI* GetAI(Creature* pCreature) const override - { - return GetUlduarAI(pCreature); - } - - struct boss_yoggsaron_voiceAI : public NullCreatureAI - { - boss_yoggsaron_voiceAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - _targets.clear(); - _current = 0; - } - - EventMap events; - GuidVector _targets; - uint32 _current; - - void Reset() override - { - me->CastSpell(me, SPELL_INSANE_PERIODIC, true); - } - - void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_INSANE1) - { - // Drive Me Crazy achievement failed - if (me->GetInstanceScript()) - if (Creature* yogg = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_YOGGSARON))) - yogg->AI()->DoAction(ACTION_FAILED_DRIVE_ME_CRAZY); - - events.ScheduleEvent(40, 2s); - _targets.push_back(target->GetGUID()); - } - } - - void UpdateAI(uint32 diff) override - { - events.Update(diff); - switch (events.ExecuteEvent()) - { - case 40: - { - ObjectGuid _guid = _targets.at(_current); - ++_current; - - if (Player* player = ObjectAccessor::GetPlayer(*me, _guid)) - { - Talk(WHISPER_VOICE_INSANE, player); - } - break; - } - } - } - }; -}; - -// 63830, 63881 - Malady of the Mind -class spell_yogg_saron_malady_of_the_mind : public SpellScriptLoader -{ -public: - spell_yogg_saron_malady_of_the_mind() : SpellScriptLoader("spell_yogg_saron_malady_of_the_mind") { } - - class spell_yogg_saron_malady_of_the_mind_AuraScript : public AuraScript - { - PrepareAuraScript(spell_yogg_saron_malady_of_the_mind_AuraScript); - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetUnitOwner()->ApplySpellImmune(SPELL_DEATH_RAY_DAMAGE_REAL, IMMUNITY_ID, SPELL_DEATH_RAY_DAMAGE_REAL, true); - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetUnitOwner()->ApplySpellImmune(SPELL_DEATH_RAY_DAMAGE_REAL, IMMUNITY_ID, SPELL_DEATH_RAY_DAMAGE_REAL, false); - GetUnitOwner()->CastCustomSpell(SPELL_MALADY_OF_THE_MIND_TRIGGER, SPELLVALUE_MAX_TARGETS, 1, GetUnitOwner(), true); - } - - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_yogg_saron_malady_of_the_mind_AuraScript::OnApply, EFFECT_1, SPELL_AURA_MOD_FEAR, AURA_EFFECT_HANDLE_REAL); - OnEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_malady_of_the_mind_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_MOD_FEAR, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_yogg_saron_malady_of_the_mind_AuraScript(); - } -}; - -// 63802 - Brain Link -class spell_yogg_saron_brain_link : public SpellScriptLoader -{ -public: - spell_yogg_saron_brain_link() : SpellScriptLoader("spell_yogg_saron_brain_link") { } - - class spell_yogg_saron_brain_link_AuraScript : public AuraScript - { - PrepareAuraScript(spell_yogg_saron_brain_link_AuraScript); - - void HandleOnEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - PreventDefaultAction(); - Player* target = nullptr; - Map::PlayerList const& pList = GetUnitOwner()->GetMap()->GetPlayers(); - uint8 _offset = urand(0, pList.getSize() - 1); - uint8 _counter = 0; - for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr, ++_counter) - { - if (itr->GetSource() == GetUnitOwner() || GetUnitOwner()->GetDistance(itr->GetSource()) > 50.0f || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster()) - continue; - - if (_counter <= _offset || !target) - target = itr->GetSource(); - else - break; - } - - if (!target) - SetDuration(0); - else - _targetGUID = target->GetGUID(); - } - - void OnPeriodic(AuraEffect const* /*aurEff*/) - { - Unit* owner = GetUnitOwner(); - if (!owner) - { - SetDuration(0); - return; - } - - Unit* _target = ObjectAccessor::GetUnit(*owner, _targetGUID); - if (!_target || !_target->IsAlive() || std::fabs(owner->GetPositionZ() - _target->GetPositionZ()) > 10.0f) // Target or owner underground - { - SetDuration(0); - return; - } - - if (owner->GetDistance(_target) > 20.0f) - { - owner->CastSpell(_target, SPELL_BRAIN_LINK_DAMAGE, true); - owner->CastSpell(owner, SPELL_BRAIN_LINK_DAMAGE, true); - } - else - owner->CastSpell(_target, SPELL_BRAIN_LINK_OK, true); - } - - void Register() override - { - OnEffectApply += AuraEffectApplyFn(spell_yogg_saron_brain_link_AuraScript::HandleOnEffectApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); - OnEffectPeriodic += AuraEffectPeriodicFn(spell_yogg_saron_brain_link_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - - protected: - ObjectGuid _targetGUID; - }; - - AuraScript* GetAuraScript() const override - { - return new spell_yogg_saron_brain_link_AuraScript(); - } - - class spell_yogg_saron_brain_link_SpellScript : public SpellScript - { - PrepareSpellScript(spell_yogg_saron_brain_link_SpellScript); - - void FilterTargets(std::list& targets) - { - std::list tempList; - for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) - if ((*itr)->GetPositionZ() > 300.0f) - tempList.push_back(*itr); - - targets.clear(); - for (std::list::iterator itr = tempList.begin(); itr != tempList.end(); ++itr) - targets.push_back(*itr); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_brain_link_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_yogg_saron_brain_link_SpellScript(); - } -}; - -// 64465 - Shadow Beacon -class spell_yogg_saron_shadow_beacon : public SpellScriptLoader -{ - public: - spell_yogg_saron_shadow_beacon() : SpellScriptLoader("spell_yogg_saron_shadow_beacon") { } - - class spell_yogg_saron_shadow_beacon_AuraScript : public AuraScript - { - PrepareAuraScript(spell_yogg_saron_shadow_beacon_AuraScript); - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Creature* target = GetTarget()->ToCreature()) - { - target->SetEntry(NPC_MARKED_IMMORTAL_GUARDIAN); - } - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Creature* target = GetTarget()->ToCreature()) - { - target->SetEntry(NPC_IMMORTAL_GUARDIAN); - } - } - - void Register() override - { - AfterEffectApply += AuraEffectApplyFn(spell_yogg_saron_shadow_beacon_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_shadow_beacon_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_yogg_saron_shadow_beacon_AuraScript(); - } -}; - -// 65206 - Destabilization Matrix -class spell_yogg_saron_destabilization_matrix : public SpellScriptLoader -{ -public: - spell_yogg_saron_destabilization_matrix() : SpellScriptLoader("spell_yogg_saron_destabilization_matrix") { } - - class spell_yogg_saron_destabilization_matrix_SpellScript : public SpellScript - { - PrepareSpellScript(spell_yogg_saron_destabilization_matrix_SpellScript); - - void HandleDummyEffect(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - if (Unit* target = GetHitUnit()) - GetCaster()->CastSpell(target, SPELL_DESTABILIZATION_MATRIX_ATTACK, false); - } - - void FilterTargets(std::list& targets) - { - WorldObject* target = nullptr; - for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) - if (!(*itr)->ToUnit()->HasAura(SPELL_DESTABILIZATION_MATRIX_ATTACK)) - { - target = *itr; - break; - } - - targets.clear(); - if (target) - targets.push_back(target); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_destabilization_matrix_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_destabilization_matrix_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_yogg_saron_destabilization_matrix_SpellScript(); - } -}; - -// 64172 - Titanic Storm -class spell_yogg_saron_titanic_storm : public SpellScriptLoader -{ -public: - spell_yogg_saron_titanic_storm() : SpellScriptLoader("spell_yogg_saron_titanic_storm") { } - - class spell_yogg_saron_titanic_storm_SpellScript : public SpellScript - { - PrepareSpellScript(spell_yogg_saron_titanic_storm_SpellScript); - - void HandleDummyEffect(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - if (Unit* target = GetHitUnit()) - Unit::Kill(GetCaster(), target); - } - - void FilterTargets(std::list& targets) - { - WorldObject* target = nullptr; - for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) - if ((*itr)->ToUnit()->HasAura(SPELL_WEAKENED)) - { - target = *itr; - break; - } - - targets.clear(); - if (target) - targets.push_back(target); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_titanic_storm_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_titanic_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_yogg_saron_titanic_storm_SpellScript(); - } -}; - -// 64164, 64168 - Lunatic Gaze -class spell_yogg_saron_lunatic_gaze : public SpellScriptLoader -{ -public: - spell_yogg_saron_lunatic_gaze() : SpellScriptLoader("spell_yogg_saron_lunatic_gaze") { } - - class spell_yogg_saron_lunatic_gaze_SpellScript : public SpellScript - { - PrepareSpellScript(spell_yogg_saron_lunatic_gaze_SpellScript); - - void FilterTargets(std::list& targets) - { - std::list tmplist; - for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) - if ((*itr)->HasInArc(M_PI, GetCaster())) - tmplist.push_back(*itr); - - targets.clear(); - for (std::list::iterator itr = tmplist.begin(); itr != tmplist.end(); ++itr) - targets.push_back(*itr); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_lunatic_gaze_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_yogg_saron_lunatic_gaze_SpellScript(); - } -}; - -// 64174 - Protective Gaze -class spell_yogg_saron_protective_gaze : public SpellScriptLoader -{ -public: - spell_yogg_saron_protective_gaze() : SpellScriptLoader("spell_yogg_saron_protective_gaze") { } - - class spell_yogg_saron_protective_gaze_AuraScript : public AuraScript - { - PrepareAuraScript(spell_yogg_saron_protective_gaze_AuraScript); - - void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) - { - // Set absorbtion amount to unlimited - amount = -1; - } - - void Absorb(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& absorbAmount) - { - Unit* target = GetTarget(); - if (dmgInfo.GetDamage() < target->GetHealth() || !GetCaster() || GetCaster()->ToCreature()->HasSpellCooldown(SPELL_HODIR_FLASH_FREEZE)) - return; - - target->CastSpell(target, SPELL_HODIR_FLASH_FREEZE, true); - GetCaster()->AddSpellCooldown(SPELL_HODIR_FLASH_FREEZE, 0, 0); - absorbAmount = dmgInfo.GetDamage(); - } - - void Register() override - { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_yogg_saron_protective_gaze_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); - OnEffectAbsorb += AuraEffectAbsorbFn(spell_yogg_saron_protective_gaze_AuraScript::Absorb, EFFECT_0); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_yogg_saron_protective_gaze_AuraScript(); - } -}; - -// 64161 - Empowered -class spell_yogg_saron_empowered : public SpellScriptLoader -{ -public: - spell_yogg_saron_empowered() : SpellScriptLoader("spell_yogg_saron_empowered") { } - - class spell_yogg_saron_empowered_AuraScript : public AuraScript - { - PrepareAuraScript(spell_yogg_saron_empowered_AuraScript); - - void OnPeriodic(AuraEffect const* /*aurEff*/) - { - Unit* target = GetUnitOwner(); - uint8 stack = std::min(uint8(target->GetHealthPct() / 10), (uint8)9); - - if (!stack) - { - target->RemoveAura(SPELL_EMPOWERED); - target->CastSpell(target, SPELL_WEAKENED, true); - } - else if (Aura* aur = target->AddAura(SPELL_EMPOWERED, target)) - { - aur->SetStackAmount(stack); - target->RemoveAurasDueToSpell(SPELL_WEAKENED); - } - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_yogg_saron_empowered_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_yogg_saron_empowered_AuraScript(); - } -}; - -// 64555 - Insane Periodic -class spell_yogg_saron_insane_periodic_trigger : public SpellScriptLoader -{ -public: - spell_yogg_saron_insane_periodic_trigger() : SpellScriptLoader("spell_yogg_saron_insane_periodic_trigger") { } - - class spell_yogg_saron_insane_periodic_trigger_SpellScript : public SpellScript - { - PrepareSpellScript(spell_yogg_saron_insane_periodic_trigger_SpellScript); - - void HandleDummyEffect(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - Player* target = GetHitPlayer(); - if (!target) - return; - - Unit* caster = GetCaster(); - caster->CastSpell(target, SPELL_INSANE1, true); - target->CastSpell(target, SPELL_INSANE2, true); - } - - void FilterTargets(std::list& targets) - { - std::list tmplist; - for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) - if ((*itr)->IsPlayer() && !(*itr)->ToPlayer()->HasAuraType(SPELL_AURA_AOE_CHARM) && !(*itr)->ToPlayer()->HasAura(SPELL_SANITY)) - tmplist.push_back(*itr); - - targets.clear(); - for (std::list::iterator itr = tmplist.begin(); itr != tmplist.end(); ++itr) - targets.push_back(*itr); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_insane_periodic_trigger_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_insane_periodic_trigger_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_yogg_saron_insane_periodic_trigger_SpellScript(); - } -}; - -// 63120 - Insane -class spell_yogg_saron_insane : public SpellScriptLoader -{ -public: - spell_yogg_saron_insane() : SpellScriptLoader("spell_yogg_saron_insane") { } - - class spell_yogg_saron_insane_AuraScript : public AuraScript - { - PrepareAuraScript(spell_yogg_saron_insane_AuraScript); - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit::Kill(GetUnitOwner(), GetUnitOwner()); - } - - void Register() override - { - OnEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_insane_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_yogg_saron_insane_AuraScript(); - } -}; - -// 64169 - Sanity Well -class spell_yogg_saron_sanity_well : public SpellScriptLoader -{ -public: - spell_yogg_saron_sanity_well() : SpellScriptLoader("spell_yogg_saron_sanity_well") { } - - class spell_yogg_saron_sanity_well_AuraScript : public AuraScript - { - PrepareAuraScript(spell_yogg_saron_sanity_well_AuraScript); - - void HandleEffectCalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude) - { - isPeriodic = true; - amplitude = 2 * IN_MILLISECONDS; - } - - void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) - { - Unit* target = GetTarget(); - if (!target || !target->IsPlayer()) - return; - - if (Aura* aur = target->GetAura(SPELL_SANITY)) - aur->SetStackAmount(std::min(100, aur->GetStackAmount() + 20)); - } - - void Register() override - { - DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_yogg_saron_sanity_well_AuraScript::HandleEffectCalcPeriodic, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - OnEffectPeriodic += AuraEffectPeriodicFn(spell_yogg_saron_sanity_well_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_yogg_saron_sanity_well_AuraScript(); - } -}; - -/* 63881 - Malady of the Mind - 63795 - Psychosis - 63830 - Malady of the Mind - 64164 - Lunatic Gaze - 64059 - Induce Madness - 63803 - Brain Link - 65301 - Psychosis - 64168 - Lunatic Gaze */ -class spell_yogg_saron_sanity_reduce : public SpellScriptLoader -{ -public: - spell_yogg_saron_sanity_reduce() : SpellScriptLoader("spell_yogg_saron_sanity_reduce") { } - - class spell_yogg_saron_sanity_reduce_SpellScript : public SpellScript - { - PrepareSpellScript(spell_yogg_saron_sanity_reduce_SpellScript); - - void HandleScriptEffect(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - Player* target = GetHitPlayer(); - if (!target) - return; - - uint8 _reduceAmount = 0; - switch (GetSpellInfo()->Id) - { - case SPELL_SARA_PSYCHOSIS_10: - _reduceAmount = 9; - break; - case SPELL_SARA_PSYCHOSIS_25: - _reduceAmount = 12; - break; - case SPELL_MALADY_OF_THE_MIND: - _reduceAmount = 3; - break; - case SPELL_MALADY_OF_THE_MIND_TRIGGER: - _reduceAmount = 3; - break; - case SPELL_BRAIN_LINK_DAMAGE: - _reduceAmount = 2; - break; - case 64168 /*SPELL_LUNATIC_GAZE*/: - _reduceAmount = 2; - break; - case 64164 /*SPELL_YS_LUNATIC_GAZE*/: - _reduceAmount = 4; - break; - case SPELL_INDUCE_MADNESS: - // Teleported out of brain - if (target->GetPositionZ() > 300.0f) - return; - else - target->CastSpell(target, SPELL_CANCEL_ILLUSION_AURA, true); // else we are underground, remove illusion aura and teleport outside - _reduceAmount = 100; - break; - } - - if (Aura* aur = target->GetAura(SPELL_SANITY)) - { - if ((aur->GetStackAmount() - _reduceAmount) <= 20) - target->CastSpell(target, 63752 /*SANITY_SCREEN_EFFECT*/, true); - aur->ModStackAmount(-_reduceAmount); - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_sanity_reduce_SpellScript::HandleScriptEffect, EFFECT_FIRST_FOUND, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_yogg_saron_sanity_reduce_SpellScript(); - } -}; - -// 64467 - Empowering Shadows -class spell_yogg_saron_empowering_shadows : public SpellScriptLoader -{ -public: - spell_yogg_saron_empowering_shadows() : SpellScriptLoader("spell_yogg_saron_empowering_shadows") { } - - class spell_yogg_saron_empowering_shadows_SpellScript : public SpellScript - { - PrepareSpellScript(spell_yogg_saron_empowering_shadows_SpellScript); - - void HandleScriptEffect(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - if (Unit* target = GetHitUnit()) - target->CastSpell(target, target->GetMap()->Is25ManRaid() ? 64486 : 64468, true); // SPELL_EMPOWERING_SHADOWS_HEAL - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_empowering_shadows_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_yogg_saron_empowering_shadows_SpellScript(); - } -}; - -// 64184 - In the Maws of the Old God -class spell_yogg_saron_in_the_maws_of_the_old_god : public SpellScriptLoader -{ -public: - spell_yogg_saron_in_the_maws_of_the_old_god() : SpellScriptLoader("spell_yogg_saron_in_the_maws_of_the_old_god") {} - - class spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript : public SpellScript - { - PrepareSpellScript(spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript); - - SpellCastResult CheckCast() - { - if (!GetCaster()->IsPlayer()) - return SPELL_FAILED_BAD_TARGETS; - - Unit* target = GetCaster()->ToPlayer()->GetSelectedUnit(); - if (!target || target->GetEntry() != NPC_YOGG_SARON) - return SPELL_FAILED_BAD_TARGETS; - - Spell* spell = target->GetCurrentSpell(CURRENT_GENERIC_SPELL); - if (!spell || spell->GetSpellInfo()->Id != SPELL_DEAFENING_ROAR) - return SPELL_FAILED_TARGET_AURASTATE; - - return SPELL_CAST_OK; - } - - void Register() override - { - OnCheckCast += SpellCheckCastFn(spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript::CheckCast); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript(); - } -}; - -/* 63744 - Sara's Anger - 63747 - Sara's Fervor - 63745 - Sara's Blessing */ -class spell_yogg_saron_target_selectors : public SpellScriptLoader -{ -public: - spell_yogg_saron_target_selectors() : SpellScriptLoader("spell_yogg_saron_target_selectors") { } - - class spell_yogg_saron_target_selectors_SpellScript : public SpellScript - { - PrepareSpellScript(spell_yogg_saron_target_selectors_SpellScript); - - void HandleScript(SpellEffIndex /*effIndex*/) - { - if (Unit* target = GetHitUnit()) - { - GetCaster()->SetFacingToObject(target); - GetCaster()->CastSpell(target, uint32(GetEffectValue())); - } - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_target_selectors_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_yogg_saron_target_selectors_SpellScript(); - } -}; - -// 63305 - Grim Reprisal -class spell_yogg_saron_grim_reprisal : public SpellScriptLoader -{ -public: - spell_yogg_saron_grim_reprisal() : SpellScriptLoader("spell_yogg_saron_grim_reprisal") { } - - class spell_yogg_saron_grim_reprisal_AuraScript : public AuraScript - { - PrepareAuraScript(spell_yogg_saron_grim_reprisal_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_GRIM_REPRISAL_DAMAGE }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - DamageInfo* damageInfo = eventInfo.GetDamageInfo(); - - if (!damageInfo || !damageInfo->GetDamage()) - { - return; - } - - int32 damage = CalculatePct(static_cast(damageInfo->GetDamage()), 60); - GetTarget()->CastCustomSpell(SPELL_GRIM_REPRISAL_DAMAGE, SPELLVALUE_BASE_POINT0, damage, damageInfo->GetAttacker(), true, nullptr, aurEff); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_yogg_saron_grim_reprisal_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_yogg_saron_grim_reprisal_AuraScript(); - } -}; - -class achievement_yogg_saron_drive_me_crazy : public AchievementCriteriaScript -{ -public: - achievement_yogg_saron_drive_me_crazy() : AchievementCriteriaScript("achievement_yogg_saron_drive_me_crazy") {} - - bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override - { - return target && target->GetAI()->GetData(DATA_GET_DRIVE_ME_CRAZY); // target = Yogg-Saron - } -}; - -class achievement_yogg_saron_darkness : public AchievementCriteriaScript -{ -public: - achievement_yogg_saron_darkness(char const* name, uint32 count) : AchievementCriteriaScript(name), - _keepersCount(count) - { - } - - bool OnCheck(Player* player, Unit* /*target*/ /*Yogg-Saron*/, uint32 /*criteria_id*/) override - { - if (player->GetInstanceScript()) - if (Creature* sara = ObjectAccessor::GetCreature(*player, player->GetInstanceScript()->GetGuidData(NPC_SARA))) - return sara->GetAI()->GetData(DATA_GET_KEEPERS_COUNT) <= _keepersCount; - - return false; - } - -private: - uint32 const _keepersCount; -}; - -class achievement_yogg_saron_he_waits_dreaming : public AchievementCriteriaScript -{ -public: - achievement_yogg_saron_he_waits_dreaming(char const* name, uint8 illusion) : AchievementCriteriaScript(name), - _requiredIllusion(illusion) - { - } - - bool OnCheck(Player* player, Unit* /*target*/ /*Yogg-Saron*/, uint32 /*criteria_id*/) override - { - if (player->GetInstanceScript()) - if (Creature* sara = ObjectAccessor::GetCreature(*player, player->GetInstanceScript()->GetGuidData(NPC_BRAIN_OF_YOGG_SARON))) - return sara->GetAI()->GetData(DATA_GET_CURRENT_ILLUSION) == _requiredIllusion; - - return false; - } - -private: - uint8 const _requiredIllusion; -}; - -class achievement_yogg_saron_kiss_and_make_up : public AchievementCriteriaScript -{ -public: - achievement_yogg_saron_kiss_and_make_up() : AchievementCriteriaScript("achievement_yogg_saron_kiss_and_make_up") {} - - bool OnCheck(Player* /*player*/, Unit* target /*Sara*/, uint32 /*criteria_id*/) override - { - return target && target->GetEntry() == NPC_SARA && target->GetAI() && target->GetAI()->GetData(DATA_GET_SARA_PHASE); - } -}; - void AddSC_boss_yoggsaron() { new boss_yoggsaron(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.h new file mode 100644 index 00000000000000..2e42f5d92b71a9 --- /dev/null +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.h @@ -0,0 +1,3010 @@ +#ifndef BOSS_YOGGSARON_H_ +#define BOSS_YOGGSARON_H_ + +#include "AchievementCriteriaScript.h" +#include "CreatureAI.h" +#include "CreatureScript.h" +#include "Object.h" +#include "Opcodes.h" +#include "PassiveAI.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "ScriptedEscortAI.h" +#include "SpellAuras.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" +#include "ulduar.h" + +enum YoggSpells +{ + // KEEPERS + SPELL_KEEPER_ACTIVE = 62647, + SPELL_MIMIRON_PASSIVE = 62671, + SPELL_THORIM_PASSIVE = 62702, + SPELL_HODIR_PASSIVE = 62650, + SPELL_FREYA_PASSIVE = 62670, + + SPELL_DESTABILIZATION_MATRIX = 65206, + SPELL_DESTABILIZATION_MATRIX_ATTACK = 65210, + SPELL_SANITY_WELL_VISUAL = 63288, + SPELL_SANITY_WELL_BUFF = 64169, + SPELL_PROTECTIVE_GAZE = 64174, // COOLDOWN 25 SECS BEFORE NEXT USE + SPELL_HODIR_FLASH_FREEZE = 64175, + SPELL_CONJURE_SANITY_WELL = 64170, + + SPELL_TITANIC_STORM_PASSIVE = 64171, + SPELL_WEAKENED = 64162, + + // GLOBAL + SPELL_SANITY_BASE = 63786, + SPELL_SANITY = 63050, + SPELL_EXTINGUISH_ALL_LIFE = 64166, + SPELL_CLOUD_VISUAL = 63084, + SPELL_SUMMON_GUARDIAN_OF_YS = 63031, + SPELL_INSANE1 = 63120, + SPELL_INSANE2 = 64464, + SPELL_INSANE_PERIODIC = 64554, // this checks if player dc'ed and insanes him instantly after logging in + + // SARA P1 + SPELL_SARAS_FAVOR = 63138, + SPELL_SARAS_FAVOR_TARGET_SELECTOR = 63747, + SPELL_SARAS_BLESSING = 63134, + SPELL_SARAS_BLESSING_TARGET_SELECTOR = 63745, + SPELL_SARAS_ANGER = 63147, + SPELL_SARAS_ANGER_TARGET_SELECTOR = 63744, + SPELL_SHADOWY_BARRIER = 64775, + + // GUARDIANS OF YOGG-SARON + SPELL_SHADOW_NOVA = 62714, + SPELL_DARK_VOLLEY = 63038, + + // SARA P2 + SPELL_SARA_PSYCHOSIS_10 = 63795, + SPELL_SARA_PSYCHOSIS_25 = 65301, + SPELL_MALADY_OF_THE_MIND = 63830, + SPELL_MALADY_OF_THE_MIND_TRIGGER = 63881, + SPELL_BRAIN_LINK = 63802, + SPELL_BRAIN_LINK_DAMAGE = 63803, + SPELL_BRAIN_LINK_OK = 63804, + + SPELL_DEATH_RAY_DAMAGE_VISUAL = 63886, + SPELL_DEATH_RAY_ORIGIN_VISUAL = 63893, + SPELL_DEATH_RAY_WARNING = 63882, + SPELL_DEATH_RAY_DAMAGE = 63883, + SPELL_DEATH_RAY_DAMAGE_REAL = 63884, + + // YOGG-SARON P2 + SPELL_SHADOW_BARRIER = 63894, + SPELL_KNOCK_AWAY = 64022, + + // TENTACLES + SPELL_VOID_ZONE_SMALL = 64384, + SPELL_VOID_ZONE_LARGE = 64017, + SPELL_TENTACLE_ERUPT = 64144, + + // CRUSHER TENTACLE + SPELL_CRUSH = 64146, + SPELL_DIMINISH_POWER = 64145, + SPELL_FOCUSED_ANGER = 57688, + + // CONSTRICTOR TENTACLE + SPELL_LUNGE = 64123, + SPELL_SQUEEZE_10 = 64125, + SPELL_SQUEEZE_25 = 64126, + + // CORRUPTOR TENTACLE + SPELL_APATHY = 64156, + SPELL_BLACK_PLAGUE = 64153, + SPELL_CURSE_OF_DOOM = 64157, + SPELL_DRAINING_POISON = 64152, + + // MISC + SPELL_REVEALED_TENTACLE = 64012, + SPELL_IN_THE_MAWS_OF_THE_OLD_GOD = 64184, + + // BRAIN OF YOGG-SARON + SPELL_SHATTERED_ILLUSION = 64173, + SPELL_INDUCE_MADNESS = 64059, + SPELL_BRAIN_HURT_VISUAL = 64361, + + // PORTALS + SPELL_TELEPORT_TO_CHAMBER = 63997, + SPELL_TELEPORT_TO_ICECROWN = 63998, + SPELL_TELEPORT_TO_STORMWIND = 63989, + SPELL_TELEPORT_BACK = 63992, + SPELL_CANCEL_ILLUSION_AURA = 63993, + + // LAUGHING SKULL AND INFLUENCE TENTACLE AND OTHERS + SPELL_LUNATIC_GAZE = 64167, + SPELL_GRIM_REPRISAL = 63305, + SPELL_GRIM_REPRISAL_DAMAGE = 64039, + SPELL_DEATHGRASP = 63037, + + // YOGG-SARON P3 + SPELL_LUNATIC_GAZE_YS = 64163, + SPELL_DEAFENING_ROAR = 64189, + SPELL_SHADOW_BEACON = 64465, + + // IMMORTAL GUARDIAN + SPELL_SIMPLE_TELEPORT = 64195, + SPELL_EMPOWERED = 65294, + SPELL_EMPOWERED_PASSIVE = 64161, + SPELL_DRAIN_LIFE_10 = 64159, + SPELL_DRAIN_LIFE_25 = 64160, + SPELL_RECENTLY_SPAWNED = 64497, +}; + +#define SPELL_PSYCHOSIS RAID_MODE(SPELL_SARA_PSYCHOSIS_10, SPELL_SARA_PSYCHOSIS_25) +#define SPELL_SQUEEZE RAID_MODE(SPELL_SQUEEZE_10, SPELL_SQUEEZE_25) +#define SPELL_DRAIN_LIFE RAID_MODE(SPELL_DRAIN_LIFE_10, SPELL_DRAIN_LIFE_25) + +enum YoggEvents +{ + EVENT_SARA_P1_DOORS_CLOSE = 1, + EVENT_SARA_P1_SUMMON = 2, + EVENT_SARA_P1_SPELLS = 3, + EVENT_SARA_P1_BERSERK = 4, + + EVENT_SARA_P2_START = 10, + EVENT_SARA_P2_SUMMON_T1 = 11, + EVENT_SARA_P2_SUMMON_T2 = 12, + EVENT_SARA_P2_SUMMON_T3 = 13, + EVENT_SARA_P2_BRAIN_LINK = 14, + EVENT_SARA_P2_DEATH_RAY = 15, + EVENT_SARA_P2_MALADY = 16, + EVENT_SARA_P2_PSYCHOSIS = 17, + EVENT_SARA_P2_OPEN_PORTALS = 18, + EVENT_SARA_P2_REMOVE_STUN = 19, + EVENT_SARA_P2_SPAWN_START_TENTACLES = 20, + + EVENT_YS_LUNATIC_GAZE = 30, + EVENT_YS_DEAFENING_ROAR = 31, + EVENT_YS_SUMMON_GUARDIAN = 32, + EVENT_YS_SHADOW_BEACON = 33, +}; + +enum NPCsGOs +{ + // NPCs + NPC_OMINOUS_CLOUD = 33292, + NPC_GUARDIAN_OF_YS = 33136, + NPC_SANITY_WELL = 33991, + NPC_YOGG_SARON = 33288, + NPC_VOICE_OF_YOGG_SARON = 33280, + NPC_YOGG_SARON_VISION = 33552, + + NPC_CRUSHER_TENTACLE = 33966, // 50 secs ? + NPC_CONSTRICTOR_TENTACLE = 33983, // 15-20 secs ? + NPC_CORRUPTOR_TENTACLE = 33985, // 30-40 secs ? + + NPC_INFLUENCE_TENTACLE = 33943, + NPC_DEATH_ORB = 33882, + NPC_DESCEND_INTO_MADNESS = 34072, + NPC_LAUGHING_SKULL = 33990, + + NPC_IMMORTAL_GUARDIAN = 33988, + NPC_MARKED_IMMORTAL_GUARDIAN = 36064, + + // CHAMBER ILLUSION + NPC_CONSORT_FIRST = 33716, + NPC_CONSORT_LAST = 33720, + NPC_ALEXTRASZA = 33536, + NPC_MALYGOS = 33535, + NPC_NELTHARION = 33523, + NPC_YSERA = 33495, + GO_DRAGON_SOUL = 194462, + + // ICECROWN ILLUSION + NPC_DEATHSWORN_ZEALOT = 33567, + NPC_LICH_KING = 33441, + NPC_IMMOLATED_CHAMPION = 33442, + + // STORMWIND ILLUSION + NPC_SUIT_OF_ARMOR = 33433, + NPC_GARONA = 33436, + NPC_KING_LLANE = 33437, + + // GOs + GO_DOORS = 194773, + GO_FLEE_TO_THE_SURFACE_PORTAL = 194625, + GO_CHAMBER_ILLUSION_DOORS = 194635, + GO_ICECROWN_ILLUSION_DOORS = 194636, + GO_STORMWIND_ILLUSION_DOORS = 194637, + + // MODELs + SARA_TRANSFORM_MODEL = 29182, +}; + +enum Misc +{ + ACTION_UNSUMMON_CLOUDS = -16, + ACTION_DESPAWN_ADDS = -15, + ACTION_START_SUMMONING = -14, + ACTION_YOGG_SARON_APPEAR = -13, + ACTION_YOGG_SARON_DEATH = -12, + ACTION_YOGG_SARON_START_YELL = -11, + ACTION_YOGG_SARON_OPEN_PORTAL_YELL = -10, + ACTION_INFLUENCE_TENTACLE_DIED = -9, + ACTION_BRAIN_DAMAGED = -8, + ACTION_REMOVE_STUN = -7, + ACTION_YOGG_SARON_START_P3 = -6, + ACTION_YOGG_SARON_HARD_MODE = -5, + ACTION_YOGG_SARON_SHADOW_BEACON = -4, + ACTION_THORIM_START_STORM = -3, + ACTION_FAILED_DRIVE_ME_CRAZY = -2, + + ACTION_ILLUSION_DRAGONS = 1, + ACTION_ILLUSION_ICECROWN = 2, + ACTION_ILLUSION_STORMWIND = 3, + + EVENT_PHASE_ONE = 1, + EVENT_PHASE_TWO = 2, + EVENT_PHASE_THREE = 3, + + CRITERIA_NOT_GETTING_OLDER = 21001, + + // YOGG-SARON (laugh) + YS_P3_LUNATIC_GAZE = 15757, + + DATA_GET_KEEPERS_COUNT = 1, + DATA_GET_CURRENT_ILLUSION = 2, + DATA_GET_SARA_PHASE = 3, + DATA_GET_DRIVE_ME_CRAZY = 4, +}; + +struct LocationsXY +{ + float x, y, z; +}; + +static LocationsXY yoggPortalLoc[] = +{ + {1970.48f, -9.75f, 325.5f}, + {1992.76f, -10.21f, 325.5f}, + {1995.53f, -39.78f, 325.5f}, + {1969.25f, -42.00f, 325.5f}, + {1960.62f, -32.00f, 325.5f}, + {1981.98f, -5.69f, 325.5f}, + {1982.78f, -45.73f, 325.5f}, + {2000.66f, -29.68f, 325.5f}, + {1999.88f, -19.61f, 325.5f}, + {1961.37f, -19.54f, 325.5f} +}; + +enum Texts +{ + // Sara + SAY_SARA_ULDUAR_SCREAM_0 = 0, // Unused + SAY_SARA_ULDUAR_SCREAM_1 = 1, // Unused + SAY_SARA_AGGRO = 2, + SAY_SARA_FERVOR_HIT = 3, + SAY_SARA_ANGER = 4, // Comment in DB is for BLESSING_HIT, but it's wrong. + SAY_SARA_KILL = 5, + SAY_SARA_TRANSFORM_1 = 6, // "I am the lucid dream." + SAY_SARA_TRANSFORM_2 = 7, // "The monster in your nightmares." + SAY_SARA_TRANSFORM_3 = 8, // "The fiend of a thousand faces." + SAY_SARA_TRANSFORM_4 = 9, // "Cower before my true form." + SAY_SARA_DEATH_RAY = 10, + SAY_SARA_PSYCHOSIS_HIT = 11, + + // Voice of Yogg-Saron + WHISPER_VOICE_PHASE_1_WIPE = 0, + WHISPER_VOICE_INSANE = 1, + + // Brain of Yogg-Saron + EMOTE_YOGG_SARON_BRAIN_SHATTERED = 0, + + // Yogg-Saron + SAY_YOGG_SARON_SPAWN = 0, + SAY_YOGG_SARON_MADNESS = 1, // Open Portals + EMOTE_YOGG_SARON_MADNESS = 2, + SAY_YOGG_SARON_PHASE_3 = 3, + SAY_YOGG_SARON_DEAFENING_ROAR = 4, + EMOTE_YOGG_SARON_DEAFENING_ROAR = 5, + SAY_YOGG_SARON_DEATH = 6, + EMOTE_YOGG_SARON_EMPOWERING_SHADOWS = 7, // Shadow Beacon + EMOTE_YOGG_SARON_BERSERK = 8, + + // Visions - Text is in order of Roleplay + // The Assassination of King Llane vision + SAY_GARONA_1 = 0, + SAY_GARONA_2 = 1, + SAY_GARONA_3 = 2, + SAY_YOGG_1 = 0, + SAY_YOGG_2 = 1, + SAY_LLANE_1 = 0, + SAY_GARONA_4 = 3, + SAY_YOGG_3 = 2, + + // The Forging of the Demon Soul vision + SAY_NEL_1 = 0, + SAY_YAS_1 = 0, + SAY_NEL_2 = 1, + SAY_MAL_1 = 0, + SAY_YOGG_4 = 5, + + // The Tortured Champion vision + SAY_LK_1 = 0, + SAY_IC_1 = 0, + SAY_IC_2 = 1, + SAY_LK_2 = 1, + SAY_YOGG_5 = 3, + SAY_YOGG_6 = 4, + +}; + +const Position Middle = {1980.28f, -25.5868f, 329.397f, M_PI * 1.5f}; + +class boss_yoggsaron_sara : public CreatureScript +{ +public: + boss_yoggsaron_sara() : CreatureScript("boss_yoggsaron_sara") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_saraAI : public ScriptedAI + { + boss_yoggsaron_saraAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) + { + m_pInstance = pCreature->GetInstanceScript(); + } + + InstanceScript* m_pInstance; + EventMap events; + SummonList summons; + + uint32 _initFight; + ObjectGuid _keepersGUID[4]; + uint8 _summonedGuardiansCount; + uint32 _p2TalkTimer; + bool _secondPhase; + float _summonSpeed; + uint8 _currentIllusion; + bool _isIllusionReversed; + + void AttackStart(Unit*) override { } + void MoveInLineOfSight(Unit*) override { } + + void JustSummoned(Creature* cr) override + { + summons.Summon(cr); + if (cr->GetEntry() >= NPC_FREYA_KEEPER && cr->GetEntry() <= NPC_THORIM_KEEPER) + { + if (cr->GetEntry() == NPC_FREYA_KEEPER) + cr->CastSpell(cr, SPELL_CONJURE_SANITY_WELL, false); + _keepersGUID[cr->GetEntry() - NPC_FREYA_KEEPER] = cr->GetGUID(); + } + else if (cr->GetEntry() == NPC_SANITY_WELL) + cr->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_SCALE, true); + } + + void SpawnClouds() + { + for (uint8 i = 0; i < 6; ++i) + { + float Zplus = i > 2 ? (i - 2) * 1.6f : 0; + if (i % 2) + me->SummonCreature(NPC_OMINOUS_CLOUD, me->GetPositionX() + 8 + i * 7, me->GetPositionY() + 8 + i * 7, 326 + Zplus, 0); + else + me->SummonCreature(NPC_OMINOUS_CLOUD, me->GetPositionX() - 8 - i * 7, me->GetPositionY() - 8 - i * 7, 326 + Zplus, 0); + } + } + + void SpawnWeels() + { + me->SummonCreature(NPC_SANITY_WELL, 2042.56f, -40.3667f, 329.274f, 0.0f); + me->SummonCreature(NPC_SANITY_WELL, 1975.89f, 40.0216f, 331.1f, 0.0f); + me->SummonCreature(NPC_SANITY_WELL, 1987.12f, -91.2702f, 330.186f, 0.0f); + me->SummonCreature(NPC_SANITY_WELL, 1900.48f, -51.2386f, 332.13f, 0.0f); + me->SummonCreature(NPC_SANITY_WELL, 1899.94f, 0.330621f, 332.296f, 0.0f); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (!_EnterEvadeMode(why)) + return; + + Position pos; + pos = me->GetHomePosition(); + me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); + Reset(); + me->setActive(false); + } + + void EnableSara(bool apply) + { + if (apply) + { + me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); + me->DisableRotate(false); + me->ClearUnitState(UNIT_STATE_ROOT); + } + else + { + me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); + me->DisableRotate(true); + me->AddUnitState(UNIT_STATE_ROOT); + } + } + + void Reset() override + { + if (!_secondPhase) // Phase 1 wipe + { + me->GetMap()->DoForAllPlayers([&](Player* player) + { + if (Creature* voice = me->FindNearestCreature(NPC_VOICE_OF_YOGG_SARON, 10.0f)) + { + voice->AI()->Talk(WHISPER_VOICE_PHASE_1_WIPE, player); + } + }); + } + + summons.DoAction(ACTION_DESPAWN_ADDS); + events.Reset(); + summons.DespawnAll(); + + me->SetVisible(true); + me->SetDisplayId(me->GetNativeDisplayId()); + me->SetDisableGravity(true); + EnableSara(false); + SpawnClouds(); + + _initFight = 1; + + for (uint8 i = 0; i < 4; ++i) + _keepersGUID[i].Clear(); + + _summonedGuardiansCount = 0; + _p2TalkTimer = 0; + _secondPhase = false; + _summonSpeed = 1.0f; + _currentIllusion = urand(1, 3); + _isIllusionReversed = urand(0, 1); + + if (m_pInstance) + { + m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_NOT_GETTING_OLDER); + m_pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_SANITY); + m_pInstance->SetData(TYPE_YOGGSARON, NOT_STARTED); + if (GameObject* go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_YOGG_SARON_DOORS))) + go->SetGoState(GO_STATE_ACTIVE); + } + } + + void InitFight(Unit* target) + { + if (!m_pInstance) + return; + + // some simple hack checks + if (m_pInstance->GetData(TYPE_VEZAX) != DONE || m_pInstance->GetData(TYPE_XT002) != DONE) + return; + + m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_NOT_GETTING_OLDER); + m_pInstance->SetData(TYPE_YOGGSARON, IN_PROGRESS); + me->SetInCombatWithZone(); + AttackStart(target); + + me->CastSpell(me, SPELL_SANITY_BASE, true); + + SaveKeepers(); + + events.ScheduleEvent(EVENT_SARA_P1_DOORS_CLOSE, 15s, 0, EVENT_PHASE_ONE); + events.ScheduleEvent(EVENT_SARA_P1_BERSERK, 15min, 0, 0); + events.ScheduleEvent(EVENT_SARA_P1_SUMMON, 0ms, 0, EVENT_PHASE_ONE); + events.SetPhase(EVENT_PHASE_ONE); + + Talk(SAY_SARA_AGGRO); + me->setActive(true); + } + + void SaveKeepers() + { + for (uint8 i = 0; i < 4; ++i) + if (m_pInstance->GetData(TYPE_WATCHERS) & (1 << i)) + switch (i) + { + case KEEPER_FREYA: + SpawnWeels(); + me->SummonCreature(NPC_FREYA_KEEPER, 1939.32f, 42.165f, 338.415f, 5.17955f); + break; + case KEEPER_HODIR: + me->SummonCreature(NPC_HODIR_KEEPER, 1939.13f, -90.8332f, 338.415f, 1.00123f); + break; + case KEEPER_MIMIRON: + me->SummonCreature(NPC_MIMIRON_KEEPER, 2036.81f, 25.6646f, 338.415f, 3.74227f); + break; + case KEEPER_THORIM: + me->SummonCreature(NPC_THORIM_KEEPER, 2036.59f, -73.8499f, 338.415f, 2.34819f); + break; + } + } + + void InformCloud() + { + Creature* cloud = nullptr; + for (SummonList::const_iterator itr = summons.begin(); itr != summons.end();) + { + Creature* summon = ObjectAccessor::GetCreature(*me, *itr); + ++itr; + if (!summon || summon->GetEntry() != NPC_OMINOUS_CLOUD || me->GetDistance(summon) < 20) + continue; + + if ((!cloud || (urand(0, 1) && !summon->HasAura(SPELL_SUMMON_GUARDIAN_OF_YS)))) + cloud = summon; + } + + if (cloud) + cloud->AI()->DoAction(ACTION_START_SUMMONING); + } + + void SpawnTentacle(uint32 entry) + { + uint32 dist = urand(38, 48); + float o = rand_norm() * M_PI * 2; + float Zplus = (dist - 38) / 6.5f; + if (Creature* cr = me->SummonCreature(entry, me->GetPositionX() + dist * cos(o), me->GetPositionY() + dist * std::sin(o), 327.2 + Zplus, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000)) + { + cr->CastSpell(cr, SPELL_TENTACLE_ERUPT, true); + cr->CastSpell(cr, SPELL_VOID_ZONE_SMALL, true); + cr->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + } + } + + void SummonDeathOrbs() + { + for (uint8 i = 0; i < 4; ++i) + { + uint32 dist = urand(38, 48); + float o = rand_norm() * M_PI * 2; + float Zplus = (dist - 38) / 6.5f; + me->SummonCreature(NPC_DEATH_ORB, me->GetPositionX() + dist * cos(o), me->GetPositionY() + dist * std::sin(o), 327.2 + Zplus, 0, TEMPSUMMON_TIMED_DESPAWN, 20000); + } + } + + void AddPortals() + { + _summonSpeed -= 0.1f; + Creature* cr = nullptr; + + // Spawn Portals + for (uint8 i = 0; i < RAID_MODE(4, 10); ++i) + { + if ((cr = me->SummonCreature(NPC_DESCEND_INTO_MADNESS, yoggPortalLoc[i].x, yoggPortalLoc[i].y, yoggPortalLoc[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 25000))) + { + cr->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE); + cr->SetArmor(_currentIllusion); + } + } + + EntryCheckPredicate pred(NPC_BRAIN_OF_YOGG_SARON); + summons.DoAction(_currentIllusion, pred); + + if (_isIllusionReversed) + _currentIllusion = _currentIllusion == 3 ? 1 : (_currentIllusion + 1); + else + _currentIllusion = _currentIllusion == 1 ? 3 : (_currentIllusion - 1); + } + + void KilledUnit(Unit* who) override + { + if (who->IsPlayer()) + { + Talk(SAY_SARA_KILL); + } + } + + void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_SANITY) + if (Aura* aur = target->GetAura(SPELL_SANITY)) + aur->SetStackAmount(100); + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_GET_KEEPERS_COUNT) + { + uint8 _count = 0; + for (uint8 i = 0; i < 4; ++i) + if (_keepersGUID[i]) + ++_count; + + return _count; + } + else if (param == DATA_GET_SARA_PHASE) + return _secondPhase; + + return 4; // just to be sure, return max numer of keepers + } + + void DoAction(int32 param) override + { + if (param == ACTION_BRAIN_DAMAGED) + { + summons.DoAction(ACTION_REMOVE_STUN); + + EntryCheckPredicate pred2(NPC_YOGG_SARON); + summons.DoAction(ACTION_YOGG_SARON_START_P3, pred2); + + EntryCheckPredicate pred3(NPC_THORIM_KEEPER); + summons.DoAction(ACTION_THORIM_START_STORM, pred3); + + if (!(_keepersGUID[0] && _keepersGUID[1] && _keepersGUID[2] && _keepersGUID[3]) && me->GetMap()->Is25ManRaid()) + summons.DoAction(ACTION_YOGG_SARON_HARD_MODE, pred2); + + summons.DespawnEntry(NPC_DEATH_ORB); + events.SetPhase(EVENT_PHASE_THREE); + + me->RemoveAllAuras(); + me->SetVisible(false); + return; + } + else if (param == ACTION_YOGG_SARON_DEATH) + { + summons.DespawnEntry(NPC_VOICE_OF_YOGG_SARON); + summons.DespawnEntry(NPC_BRAIN_OF_YOGG_SARON); + summons.DespawnEntry(NPC_MIMIRON_KEEPER); + summons.DespawnEntry(NPC_HODIR_KEEPER); + summons.DespawnEntry(NPC_FREYA_KEEPER); + summons.DespawnEntry(NPC_THORIM_KEEPER); + summons.DespawnEntry(NPC_SANITY_WELL); + me->KillSelf(); + return; + } + + // Determine shatter duration + if (param <= 0) + return; + + // Illusion shatters (param - stun time) + if (Creature* yoggb = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(NPC_BRAIN_OF_YOGG_SARON))) + { + yoggb->AI()->Talk(EMOTE_YOGG_SARON_BRAIN_SHATTERED); + } + + uint32 timer = events.GetNextEventTime(EVENT_SARA_P2_OPEN_PORTALS); + uint32 portalTime = (timer > events.GetTimer() ? timer - events.GetTimer() : 0); + events.DelayEvents(param + 100); + events.RescheduleEvent(EVENT_SARA_P2_OPEN_PORTALS, portalTime, 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_REMOVE_STUN, param, 0, EVENT_PHASE_TWO); + me->CastSpell(me, SPELL_SHATTERED_ILLUSION, true); + } + + void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (who && who->GetEntry() == NPC_GUARDIAN_OF_YS && !_secondPhase) + { + damage = 25000; + + // START PHASE 2 + if (me->GetHealth() <= damage) + { + _secondPhase = true; + damage = 0; + + events.SetPhase(EVENT_PHASE_TWO); + me->SetHealth(me->GetMaxHealth()); + + if (Creature* cr = me->SummonCreature(NPC_YOGG_SARON, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), M_PI)) + cr->SetVisible(false); + + _p2TalkTimer++; + Talk(SAY_SARA_TRANSFORM_1); + } + return; + } + + damage = 0; + } + + void UpdateAI(uint32 diff) override + { + if (_initFight) + { + _initFight += diff; + if (_initFight > 5000) + { + if (Unit* target = SelectTargetFromPlayerList(90)) + { + _initFight = 0; + InitFight(target); + } + else + _initFight = 1; + } + return; + } + + if (!SelectTargetFromPlayerList(90, SPELL_INSANE1)) + { + m_pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_INSANE1); + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } + + if (_p2TalkTimer) + { + _p2TalkTimer += diff; + if (_p2TalkTimer >= 4000 && _p2TalkTimer < 20000) + { + EntryCheckPredicate pred(NPC_OMINOUS_CLOUD); + summons.DoAction(ACTION_UNSUMMON_CLOUDS, pred); + Talk(SAY_SARA_TRANSFORM_2); + _p2TalkTimer = 20000; + } + else if (_p2TalkTimer >= 25000 && _p2TalkTimer < 40000) + { + summons.DespawnEntry(NPC_OMINOUS_CLOUD); + Talk(SAY_SARA_TRANSFORM_3); + _p2TalkTimer = 40000; + } + else if (_p2TalkTimer >= 44500 && _p2TalkTimer < 60000) + { + Talk(SAY_SARA_TRANSFORM_4); + _p2TalkTimer = 60000; + } + else if (_p2TalkTimer >= 64000) + { + EntryCheckPredicate pred(NPC_YOGG_SARON); + summons.DoAction(ACTION_YOGG_SARON_START_YELL, pred); + _p2TalkTimer = 0; + events.ScheduleEvent(EVENT_SARA_P2_START, 500ms, 0, EVENT_PHASE_TWO); + } + return; + } + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch(events.ExecuteEvent()) + { + case EVENT_SARA_P1_DOORS_CLOSE: + // Whispers of YS + me->SummonCreature(NPC_VOICE_OF_YOGG_SARON, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()); + + if (m_pInstance) + if (GameObject* go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_YOGG_SARON_DOORS))) + go->SetGoState(GO_STATE_READY); + + events.ScheduleEvent(EVENT_SARA_P1_SPELLS, 0ms, 1, EVENT_PHASE_ONE); + break; + case EVENT_SARA_P1_SUMMON: + events.RepeatEvent(20000 - (std::min(_summonedGuardiansCount, (uint8)5) * 2000)); + ++_summonedGuardiansCount; + InformCloud(); + break; + case EVENT_SARA_P1_SPELLS: + { + uint32 spell = RAND(SPELL_SARAS_ANGER_TARGET_SELECTOR, SPELL_SARAS_BLESSING_TARGET_SELECTOR, SPELL_SARAS_FAVOR_TARGET_SELECTOR); + if (urand(0, 2)) + { + if (spell == SPELL_SARAS_ANGER_TARGET_SELECTOR) + { + Talk(SAY_SARA_ANGER); + } + else if (spell == SPELL_SARAS_FAVOR_TARGET_SELECTOR) + { + Talk(SAY_SARA_FERVOR_HIT); + } + } + + me->CastCustomSpell(spell, SPELLVALUE_MAX_TARGETS, 1, nullptr, false); + events.RepeatEvent(me->GetMap()->Is25ManRaid() ? urand(0, 3000) : 4000 + urand(0, 2000)); + break; + } + case EVENT_SARA_P2_START: + { + EntryCheckPredicate pred(NPC_YOGG_SARON); + summons.DoAction(ACTION_YOGG_SARON_APPEAR, pred); + events.RescheduleEvent(EVENT_SARA_P2_SPAWN_START_TENTACLES, 500, 0, EVENT_PHASE_TWO); + + // Spawn Brain! + me->SummonCreature(NPC_BRAIN_OF_YOGG_SARON, 1981.3f, -25.43f, 265); + break; + } + case EVENT_SARA_P2_MALADY: + me->CastCustomSpell(SPELL_MALADY_OF_THE_MIND, SPELLVALUE_MAX_TARGETS, 1, me, false); + events.Repeat(20s); + break; + case EVENT_SARA_P2_PSYCHOSIS: + if ((urand(0, 9)) == 0) // Rarely said (as it's casted every 3.5s) + { + Talk(SAY_SARA_PSYCHOSIS_HIT); + } + me->CastCustomSpell(SPELL_PSYCHOSIS, SPELLVALUE_MAX_TARGETS, 1, me, false); + events.Repeat(3500ms); + break; + case EVENT_SARA_P2_DEATH_RAY: + Talk(SAY_SARA_DEATH_RAY); + SummonDeathOrbs(); + events.Repeat(20s); + break; + case EVENT_SARA_P2_SUMMON_T1: // CRUSHER + SpawnTentacle(NPC_CRUSHER_TENTACLE); + events.RepeatEvent((50000 + urand(0, 10000)) * _summonSpeed); + break; + case EVENT_SARA_P2_SUMMON_T2: // CONSTRICTOR + SpawnTentacle(NPC_CONSTRICTOR_TENTACLE); + events.RepeatEvent((15000 + urand(0, 5000)) * _summonSpeed); + break; + case EVENT_SARA_P2_SUMMON_T3: // CORRUPTOR + SpawnTentacle(NPC_CORRUPTOR_TENTACLE); + events.RepeatEvent((30000 + urand(0, 10000)) * _summonSpeed); + break; + case EVENT_SARA_P2_BRAIN_LINK: + me->CastCustomSpell(SPELL_BRAIN_LINK, SPELLVALUE_MAX_TARGETS, 1, me, false); + events.Repeat(30s); + break; + case EVENT_SARA_P2_OPEN_PORTALS: + { + AddPortals(); + EntryCheckPredicate pred(NPC_YOGG_SARON); + summons.DoAction(ACTION_YOGG_SARON_OPEN_PORTAL_YELL, pred); + events.Repeat(80s); + break; + } + case EVENT_SARA_P2_REMOVE_STUN: + { + me->RemoveAura(SPELL_SHATTERED_ILLUSION); + summons.DoAction(ACTION_REMOVE_STUN); + break; + } + case EVENT_SARA_P2_SPAWN_START_TENTACLES: + me->SetOrientation(M_PI); + me->SetDisplayId(SARA_TRANSFORM_MODEL); + + me->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), 355, me->GetOrientation()); + me->SetPosition(me->GetPositionX(), me->GetPositionY(), 355, me->GetOrientation()); + + SpawnTentacle(NPC_CRUSHER_TENTACLE); + SpawnTentacle(NPC_CONSTRICTOR_TENTACLE); + SpawnTentacle(NPC_CORRUPTOR_TENTACLE); + SpawnTentacle(NPC_CORRUPTOR_TENTACLE); + + events.ScheduleEvent(EVENT_SARA_P2_MALADY, 7s, 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_PSYCHOSIS, 3s, 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_DEATH_RAY, 15s, 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_SUMMON_T1, 50s, 60s, 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_SUMMON_T2, 15s, 20s, 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_SUMMON_T3, 30000 + urand(0, 10000), 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_BRAIN_LINK, 0, 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_OPEN_PORTALS, 60000, 0, EVENT_PHASE_TWO); + break; + case EVENT_SARA_P1_BERSERK: + if (me->GetInstanceScript()) + { + if (Creature* yogg = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_YOGGSARON))) + { + yogg->AI()->Talk(EMOTE_YOGG_SARON_BERSERK); + } + } + me->CastSpell(me, SPELL_EXTINGUISH_ALL_LIFE, true); + events.Repeat(5s); + break; + } + } + }; +}; + +class boss_yoggsaron_cloud : public CreatureScript +{ +public: + boss_yoggsaron_cloud() : CreatureScript("boss_yoggsaron_cloud") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_cloudAI : public npc_escortAI + { + boss_yoggsaron_cloudAI(Creature* pCreature) : npc_escortAI(pCreature) + { + InitWaypoint(); + Reset(); + Start(false, true, ObjectGuid::Empty, nullptr, false, true); + } + + uint32 _checkTimer; + bool _isSummoning; + + void JustSummoned(Creature* cr) override + { + cr->ToTempSummon()->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); + + _isSummoning = false; + if (me->GetInstanceScript()) + if (Creature* sara = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(NPC_SARA))) + sara->AI()->JustSummoned(cr); + } + + void MoveInLineOfSight(Unit* /*who*/) override {} + void AttackStart(Unit* /*who*/) override {} + void WaypointReached(uint32 /*point*/) override {} + + void Reset() override + { + me->CastSpell(me, SPELL_CLOUD_VISUAL, true); + _checkTimer = 0; + _isSummoning = false; + } + + void DoAction(int32 param) override + { + if (param == ACTION_UNSUMMON_CLOUDS) + { + me->RemoveAllAuras(); + } + else if (param == ACTION_START_SUMMONING) + { + _isSummoning = true; + me->CastSpell(me, SPELL_SUMMON_GUARDIAN_OF_YS, true); + } + } + + void InitWaypoint() + { + float dist = Middle.GetExactDist(me); + if (me->GetPositionX() > Middle.GetPositionX()) + { + for (uint8 i = 0; i <= dist; ++i) + { + float angle = M_PI * 2 / dist * i; + AddWaypoint(i, Middle.GetPositionX() + dist * cos(angle), Middle.GetPositionY() + dist * std::sin(angle), me->GetPositionZ(), 0); + } + } + else + { + for (uint8 i = 0; i <= dist; ++i) + { + float angle = M_PI * 2 - (M_PI * 2 / dist * i); + AddWaypoint(i, Middle.GetPositionX() + dist * cos(angle), Middle.GetPositionY() + dist * std::sin(angle), me->GetPositionZ(), 0); + } + } + } + + void UpdateEscortAI(uint32 diff) override + { + _checkTimer += diff; + if (_checkTimer >= 500 && !_isSummoning) + { + Unit* who = me->SelectNearbyTarget(nullptr, 6.0f); + if (who && who->IsPlayer() && !me->HasAura(SPELL_SUMMON_GUARDIAN_OF_YS) && !who->HasAura(SPELL_HODIR_FLASH_FREEZE)) + { + _isSummoning = true; + Talk(0, who); + me->CastSpell(me, SPELL_SUMMON_GUARDIAN_OF_YS, true); + } + + _checkTimer = 0; + } + } + }; +}; + +class boss_yoggsaron_guardian_of_ys : public CreatureScript +{ +public: + boss_yoggsaron_guardian_of_ys() : CreatureScript("boss_yoggsaron_guardian_of_ys") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_guardian_of_ysAI : public ScriptedAI + { + boss_yoggsaron_guardian_of_ysAI(Creature* pCreature) : ScriptedAI(pCreature) { } + + uint32 _spellTimer; + + void Reset() override + { + _spellTimer = 0; + me->SetInCombatWithZone(); + } + + void JustDied(Unit*) override + { + me->CastSpell((Unit*)nullptr, SPELL_SHADOW_NOVA, true); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _spellTimer += diff; + if (_spellTimer > 8000) + { + me->CastSpell(me, SPELL_DARK_VOLLEY, false); + _spellTimer = 0; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_yoggsaron : public CreatureScript +{ +public: + boss_yoggsaron() : CreatureScript("boss_yoggsaron") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaronAI : public ScriptedAI + { + boss_yoggsaronAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) + { + m_pInstance = me->GetInstanceScript(); + _thirdPhase = false; + _usedInsane = false; + summons.DespawnAll(); + events.Reset(); + + uint8 _count = 4; + me->SetLootMode(31); // 1 + 2 + 4 + 8 + 16, remove with watchers addition + if (m_pInstance) + { + for (uint8 i = 0; i < 4; ++i) + if (m_pInstance->GetData(TYPE_WATCHERS) & (1 << i)) + { + me->RemoveLootMode(1 << _count); + --_count; + } + } + } + + InstanceScript* m_pInstance; + EventMap events; + SummonList summons; + bool _thirdPhase; + bool _usedInsane; + + void AttackStart(Unit*) override { } + + void JustSummoned(Creature* cr) override { summons.Summon(cr); } + + void SummonImmortalGuardian() + { + uint32 dist = urand(38, 48); + float o = rand_norm() * M_PI * 2; + float Zplus = (dist - 38) / 6.5f; + me->SummonCreature(NPC_IMMORTAL_GUARDIAN, me->GetPositionX() + dist * cos(o), me->GetPositionY() + dist * std::sin(o), 327.2 + Zplus, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + } + + void JustDied(Unit* /*who*/) override + { + summons.DespawnAll(); + events.Reset(); + + Talk(SAY_YOGG_SARON_DEATH); + + if (m_pInstance) + { + m_pInstance->SetData(TYPE_YOGGSARON, DONE); + if (Creature* sara = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_SARA))) + sara->AI()->DoAction(ACTION_YOGG_SARON_DEATH); + if (GameObject* go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_YOGG_SARON_DOORS))) + go->SetGoState(GO_STATE_ACTIVE); + } + + Map::PlayerList const& pList = me->GetMap()->GetPlayers(); + for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) + { + itr->GetSource()->RemoveAura(SPELL_SANITY); + itr->GetSource()->RemoveAura(SPELL_INSANE1); + itr->GetSource()->RemoveAura(SPELL_INSANE2); + } + } + + void DoAction(int32 param) override + { + if (param == ACTION_DESPAWN_ADDS) + summons.DespawnAll(); + else if (param == ACTION_YOGG_SARON_APPEAR) + { + me->SetVisible(true); + me->CastSpell(me, SPELL_SHADOW_BARRIER, true); + me->CastSpell(me, SPELL_KNOCK_AWAY, true); + me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE); + me->SetInCombatWithZone(); + + me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED); + } + else if (param == ACTION_YOGG_SARON_START_YELL) + { + Talk(SAY_YOGG_SARON_SPAWN); + } + else if (param == ACTION_YOGG_SARON_OPEN_PORTAL_YELL) + { + Talk(SAY_YOGG_SARON_MADNESS); + Talk(EMOTE_YOGG_SARON_MADNESS); + } + else if (param == ACTION_YOGG_SARON_START_P3) + { + me->SetHealth(me->GetMaxHealth() * 0.3f); + me->LowerPlayerDamageReq(me->GetMaxHealth() * 0.7f); + + me->RemoveAura(SPELL_SHADOW_BARRIER); + + events.ScheduleEvent(EVENT_YS_LUNATIC_GAZE, 7000); + events.ScheduleEvent(EVENT_YS_SHADOW_BEACON, 20000); + events.ScheduleEvent(EVENT_YS_SUMMON_GUARDIAN, 0); + _thirdPhase = true; + + Talk(SAY_YOGG_SARON_PHASE_3); + } + else if (param == ACTION_YOGG_SARON_HARD_MODE) + { + events.ScheduleEvent(EVENT_YS_DEAFENING_ROAR, 50000); + } + else if (param == ACTION_YOGG_SARON_SHADOW_BEACON) + { + events.RescheduleEvent(EVENT_YS_SHADOW_BEACON, 40000); + } + else if (param == ACTION_REMOVE_STUN) + { + me->RemoveAura(SPELL_SHATTERED_ILLUSION); + me->SetControlled(true, UNIT_STATE_ROOT); + } + else if (param == ACTION_FAILED_DRIVE_ME_CRAZY) + _usedInsane = true; + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_GET_DRIVE_ME_CRAZY) + return !_usedInsane; + + return 0; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_IN_THE_MAWS_OF_THE_OLD_GOD) + me->AddLootMode(32); + } + + void UpdateAI(uint32 diff) override + { + if (!_thirdPhase) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_YS_LUNATIC_GAZE: + me->PlayDirectSound(YS_P3_LUNATIC_GAZE); + me->CastSpell(me, SPELL_LUNATIC_GAZE_YS, true); + events.Repeat(12s); + break; + case EVENT_YS_DEAFENING_ROAR: + Talk(SAY_YOGG_SARON_DEAFENING_ROAR); + Talk(EMOTE_YOGG_SARON_DEAFENING_ROAR); + me->CastSpell(me, SPELL_DEAFENING_ROAR, false); + events.Repeat(50s); + break; + case EVENT_YS_SHADOW_BEACON: + events.Repeat(5s); + Talk(EMOTE_YOGG_SARON_EMPOWERING_SHADOWS); + me->CastCustomSpell(SPELL_SHADOW_BEACON, SPELLVALUE_MAX_TARGETS, RAID_MODE(1, 3), me, false); + break; + case EVENT_YS_SUMMON_GUARDIAN: + SummonImmortalGuardian(); + events.Repeat(10s); + break; + } + } + }; +}; + +class boss_yoggsaron_brain : public CreatureScript +{ +public: + boss_yoggsaron_brain() : CreatureScript("boss_yoggsaron_brain") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_brainAI : public NullCreatureAI + { + boss_yoggsaron_brainAI(Creature* pCreature) : NullCreatureAI(pCreature), summons(pCreature) + { + me->SetDisableGravity(true); + _tentacleCount = 0; + _activeIllusion = 0; + _induceTimer = 0; + _brainDamaged = false; + me->SetRegeneratingHealth(false); + } + + bool _brainDamaged; + uint8 _tentacleCount; + uint8 _activeIllusion; + uint32 _induceTimer; + SummonList summons; + + void Reset() override { } + void JustSummoned(Creature* cr) override + { + if (cr->GetEntry() == NPC_INFLUENCE_TENTACLE) + { + // Dragons Illusion + if (cr->GetPositionX() > 2000.0f && cr->GetPositionX() < 2150.0f) + cr->UpdateEntry(urand(NPC_CONSORT_FIRST, NPC_CONSORT_LAST)); + // Icecrown Illusion + else if (cr->GetPositionY() > -150.0f && cr->GetPositionY() < -90.0f) + { + cr->SetStandState(UNIT_STAND_STATE_KNEEL); + cr->UpdateEntry(NPC_DEATHSWORN_ZEALOT); + } + // Stormwind Illusion + else + cr->UpdateEntry(NPC_SUIT_OF_ARMOR); + } + else if (cr->GetEntry() == NPC_LICH_KING) + cr->CastSpell(cr, SPELL_DEATHGRASP, false); + + summons.Summon(cr); + } + + void PrepareChamberIllusion() + { + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2126.13f, -65.488f, 239.721f, 1.99171f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2141.05f, -50.5146f, 239.751f, 2.72998f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2148.83f, -23.9568f, 239.721f, 3.04807f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2064.39f, -42.0691f, 239.719f, 0.0949586f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2064.29f, -7.13128f, 239.756f, 5.96974f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2117.31f, 14.897f, 239.731f, 4.32041f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 2136.7f, 2.43262f, 239.72f, 3.90023f); + + // Laughing Skulls + if (urand(0, 1)) + me->SummonCreature(NPC_LAUGHING_SKULL, 2139.13f, -59.0848f, 239.728f, 2.2974f); + else + me->SummonCreature(NPC_LAUGHING_SKULL, 2083, -25.66f, 244, 0); + if (urand(0, 1)) + me->SummonCreature(NPC_LAUGHING_SKULL, 2066.67f, -59.8984f, 239.72f, 0.718747f); + else + me->SummonCreature(NPC_LAUGHING_SKULL, 2126.22f, -25.86f, 244, 0); + + me->SummonCreature(NPC_LAUGHING_SKULL, 2133.09f, 15.341f, 239.72f, 4.0724f); + me->SummonCreature(NPC_LAUGHING_SKULL, 2065.83f, 12.3772f, 239.792f, 5.49789f); + + // Aspects + me->SummonCreature(NPC_ALEXTRASZA, 2091.92f, -25.8f, 242.647f, 0); + me->SummonCreature(NPC_YSERA, 2116, -25.8f, 242.647f, 3.14f); + me->SummonCreature(NPC_NELTHARION, 2103.6f, -35.8f, 242.64f, 1.5f); + me->SummonCreature(NPC_MALYGOS, 2103.6f, -15.8f, 242.64f, 4.7f); + + // Yogg Vision + me->SummonCreature(NPC_YOGG_SARON_VISION, 2109.695f, -25.09549f, 222.3250f, 0); + } + + void PrepareIceCrownIllusion() + { + // Laughing Skulls + me->SummonCreature(NPC_LAUGHING_SKULL, 1931.12f, -92.702f, 239.991f, 5.2819f); + if (urand(0, 1)) + me->SummonCreature(NPC_LAUGHING_SKULL, 1969.88f, -147.729f, 239.991f, 2.37593f); + else + me->SummonCreature(NPC_LAUGHING_SKULL, 1878, -93.3f, 240, 0); + if (urand(0, 1)) + me->SummonCreature(NPC_LAUGHING_SKULL, 1950.78f, -167.902f, 239.991f, 2.34844f); + else + me->SummonCreature(NPC_LAUGHING_SKULL, 1938.45f, -116.5f, 240, 0); + if (urand(0, 1)) + me->SummonCreature(NPC_LAUGHING_SKULL, 1896.45f, -141.469f, 239.991f, 6.12227f); + else + me->SummonCreature(NPC_LAUGHING_SKULL, 1921, -158, 240, 0); + + // Influence + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1958.29f, -128.65f, 239.99f, 3.61293f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1957.78f, -134.368f, 239.99f, 3.35375f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1953.04f, -137.843f, 239.99f, 3.55796f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1900.31f, -93.5241f, 239.99f, 4.50043f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1895.03f, -98.0773f, 239.99f, 4.88135f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1895.19f, -104.587f, 239.99f, 5.02271f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1923.31f, -125.98f, 240, 4.2f); + + // Others + me->SummonCreature(NPC_LICH_KING, 1906.98f, -153, 240, 4.2f); + me->SummonCreature(NPC_IMMOLATED_CHAMPION, 1902.03f, -161.7f, 240, 1.07f); + + // Yogg Vision + me->SummonCreature(NPC_YOGG_SARON_VISION, 1906.226f, -155.8941f, 223.4727, 0); + } + + void PrepareStormwindIllusion() + { + // Laughing Skulls + if (urand(0, 1)) + me->SummonCreature(NPC_LAUGHING_SKULL, 1916.36f, 28.05f, 239.666f, 1.30238f); + else + me->SummonCreature(NPC_LAUGHING_SKULL, 1966.7f, 57.8f, 239.66f, 0); + if (urand(0, 1)) + me->SummonCreature(NPC_LAUGHING_SKULL, 1902, 75.1362f, 239.666f, 6.06189f); + else + me->SummonCreature(NPC_LAUGHING_SKULL, 1933, 91, 240, 0); + me->SummonCreature(NPC_LAUGHING_SKULL, 1914.42f, 90.8465f, 239.666f, 5.25294f); + me->SummonCreature(NPC_LAUGHING_SKULL, 1963.68f, 89.7549f, 239.667f, 3.70571f); + + // Influence + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1931.41f, 39.0711f, 239.66f, 1.82467f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1908.67f, 45.5867f, 239.666f, 0.72119f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1897.68f, 66.1274f, 239.666f, 6.27395f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1950.73f, 49.3446f, 239.666f, 2.63756f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1923.16f, 97.5586f, 239.666f, 4.74635f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1956.16f, 72.1403f, 239.666f, 3.19518f); + me->SummonCreature(NPC_INFLUENCE_TENTACLE, 1944.81f, 92.3154f, 239.666f, 4.03556f); + + // Others + me->SummonCreature(NPC_GARONA, 1928.58f, 65.64f, 242.37f, 2.1f); + me->SummonCreature(NPC_KING_LLANE, 1925.14f, 71.74f, 242.37f, 5.17f); + + // Yogg Vision + me->SummonCreature(NPC_YOGG_SARON_VISION, 1929.160f, 67.75694f, 221.7322f, 0); + } + + void DoAction(int32 param) override + { + if (param == ACTION_DESPAWN_ADDS) + { + summons.DespawnAll(); + return; + } + else if (param == ACTION_INFLUENCE_TENTACLE_DIED) + { + _tentacleCount++; + if (_tentacleCount >= 7 /*TENTACLES COUNT*/) + { + // Stun + if (me->GetInstanceScript()) + if(Creature* sara = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(NPC_SARA))) + sara->AI()->DoAction(MINUTE * IN_MILLISECONDS - std::min((uint32)MINUTE * IN_MILLISECONDS, _induceTimer)); + + _induceTimer = 0; + summons.DespawnEntry(NPC_LAUGHING_SKULL); + if (GameObject* go = me->FindNearestGameObject(GO_CHAMBER_ILLUSION_DOORS + _activeIllusion, 150.0f)) + go->SetGoState(GO_STATE_ACTIVE); + } + return; + } + else if (param == ACTION_REMOVE_STUN) + return; + + summons.DespawnAll(); + switch(param) + { + case ACTION_ILLUSION_STORMWIND: + PrepareStormwindIllusion(); + break; + case ACTION_ILLUSION_DRAGONS: + PrepareChamberIllusion(); + break; + case ACTION_ILLUSION_ICECROWN: + PrepareIceCrownIllusion(); + break; + } + + for (uint32 i = GO_CHAMBER_ILLUSION_DOORS; i <= GO_STORMWIND_ILLUSION_DOORS; ++i) + if (GameObject* go = me->FindNearestGameObject(i, 150.0f)) + go->SetGoState(GO_STATE_READY); + + _activeIllusion = param - 1; + _tentacleCount = 0; + _induceTimer = 1; + + me->CastSpell(me, SPELL_INDUCE_MADNESS, false); + } + + uint32 GetData(uint32 param) const override + { + if (param == DATA_GET_CURRENT_ILLUSION) + return _activeIllusion + 1; + + return 0; + } + + void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (_tentacleCount < 7) // if all tentacles aren't killed + { + damage = 0; + if (who) + Unit::Kill(who, who); + return; + } + + if (!_brainDamaged) + { + // START PHASE 3 + if (me->HealthBelowPctDamaged(30, damage)) + { + me->SetRegeneratingHealth(false); + _EnterEvadeMode(); + _brainDamaged = true; + + me->CastSpell(me, SPELL_BRAIN_HURT_VISUAL, true); + if (me->GetInstanceScript()) + if(Creature* sara = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(NPC_SARA))) + sara->AI()->DoAction(ACTION_BRAIN_DAMAGED); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (_induceTimer) + _induceTimer += diff; + } + }; +}; + +class boss_yoggsaron_death_orb : public CreatureScript +{ +public: + boss_yoggsaron_death_orb() : CreatureScript("boss_yoggsaron_death_orb") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_death_orbAI : public NullCreatureAI + { + boss_yoggsaron_death_orbAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + me->CastSpell(me, SPELL_DEATH_RAY_WARNING, true); + _startTimer = 1; + } + + uint32 _startTimer; + + void UpdateAI(uint32 diff) override + { + if (_startTimer) + { + _startTimer += diff; + if (_startTimer > 4000) + { + me->CastSpell(me, SPELL_DEATH_RAY_DAMAGE_VISUAL, true); + me->CastSpell(me, SPELL_DEATH_RAY_DAMAGE, true); + + _startTimer = 0; + me->SetSpeed(MOVE_WALK, 2); + me->SetSpeed(MOVE_RUN, 2); + me->GetMotionMaster()->MoveRandom(20.0f); + } + } + } + }; +}; + +class boss_yoggsaron_crusher_tentacle : public CreatureScript +{ +public: + boss_yoggsaron_crusher_tentacle() : CreatureScript("boss_yoggsaron_crusher_tentacle") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_crusher_tentacleAI : public ScriptedAI + { + boss_yoggsaron_crusher_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) + { + me->SetCombatMovement(false); + me->CastSpell(me, SPELL_CRUSH, true); + me->CastSpell(me, SPELL_FOCUSED_ANGER, true); + me->CastSpell(me, SPELL_DIMINISH_POWER, false); + } + + void Reset() override + { + me->SetInCombatWithZone(); + } + + void DamageTaken(Unit* who, uint32&, DamageEffectType damagetype, SpellSchoolMask) override + { + if (who && damagetype == DIRECT_DAMAGE) + { + DoResetThreatList(); + me->AddThreat(who, 100000); + AttackStart(who); + me->InterruptNonMeleeSpells(false); + } + } + + void DoAction(int32 param) override + { + if (param == ACTION_REMOVE_STUN) + me->RemoveAura(SPELL_SHATTERED_ILLUSION); + } + + void UpdateAI(uint32 /*diff*/) override + { + if (!UpdateVictim()) + return; + + if (me->IsWithinMeleeRange(me->GetVictim())) + { + DoMeleeAttackIfReady(); + return; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + me->CastSpell(me, SPELL_DIMINISH_POWER, false); + DoResetThreatList(); + } + }; +}; + +class boss_yoggsaron_corruptor_tentacle : public CreatureScript +{ +public: + boss_yoggsaron_corruptor_tentacle() : CreatureScript("boss_yoggsaron_corruptor_tentacle") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_corruptor_tentacleAI : public ScriptedAI + { + boss_yoggsaron_corruptor_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) + { + me->SetCombatMovement(false); + } + + void DoAction(int32 param) override + { + if (param == ACTION_REMOVE_STUN) + me->RemoveAura(SPELL_SHATTERED_ILLUSION); + } + + Unit* SelectCorruptionTarget() + { + Player* target = nullptr; + Map::PlayerList const& pList = me->GetMap()->GetPlayers(); + uint8 num = urand(0, pList.getSize() - 1); + uint8 count = 0; + for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr, ++count) + { + if (me->GetDistance(itr->GetSource()) > 200 || itr->GetSource()->GetPositionZ() < 300 || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster()) + continue; + + if (count <= num || !target) + target = itr->GetSource(); + else + break; + } + + return target; + } + + void UpdateAI(uint32 /*diff*/) override + { + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (Unit* target = SelectCorruptionTarget()) + { + uint32 spellid = RAND(SPELL_APATHY, SPELL_BLACK_PLAGUE, SPELL_DRAINING_POISON, SPELL_CURSE_OF_DOOM); + me->CastSpell(target, spellid, false); + } + } + }; +}; + +class boss_yoggsaron_constrictor_tentacle : public CreatureScript +{ +public: + boss_yoggsaron_constrictor_tentacle() : CreatureScript("boss_yoggsaron_constrictor_tentacle") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_constrictor_tentacleAI : public ScriptedAI + { + boss_yoggsaron_constrictor_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature) + { + me->SetCombatMovement(false); + _checkTimer = 1; + _playerGUID.Clear(); + } + + uint32 _checkTimer; + ObjectGuid _playerGUID; + + Unit* SelectConstrictTarget() + { + Player* target = nullptr; + Map::PlayerList const& pList = me->GetMap()->GetPlayers(); + uint8 num = urand(0, pList.getSize() - 1); + uint8 count = 0; + for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr, ++count) + { + if (me->GetDistance(itr->GetSource()) > 10 || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster()) + continue; + if (itr->GetSource()->HasAura(SPELL_SQUEEZE) || itr->GetSource()->HasAura(SPELL_INSANE1)) + continue; + + if (count <= num || !target) + target = itr->GetSource(); + else + break; + } + + return target; + } + + void UpdateAI(uint32 diff) override + { + if (_checkTimer) + { + _checkTimer += diff; + if (_checkTimer >= 1000 && !me->HasUnitState(UNIT_STATE_STUNNED)) + { + if (Unit* target = SelectConstrictTarget()) + { + target->CastSpell(me, SPELL_LUNGE, true); + target->CastSpell(target, SPELL_SQUEEZE, true); + _playerGUID = target->GetGUID(); + _checkTimer = 0; + return; + } + + _checkTimer = 1; + } + } + } + + void DoAction(int32 param) override + { + if (param == ACTION_REMOVE_STUN) + me->RemoveAura(SPELL_SHATTERED_ILLUSION); + } + + void JustDied(Unit*) override + { + if (Unit* player = ObjectAccessor::GetUnit(*me, _playerGUID)) + player->RemoveAura(SPELL_SQUEEZE); + } + }; +}; + +class boss_yoggsaron_keeper : public CreatureScript +{ +public: + boss_yoggsaron_keeper() : CreatureScript("boss_yoggsaron_keeper") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_keeperAI : public NullCreatureAI + { + boss_yoggsaron_keeperAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + _checkTimer = 0; + me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_SCALE, true); + } + + uint32 _checkTimer; + + void DoAction(int32 param) override + { + if (me->GetEntry() == NPC_THORIM_KEEPER && param == ACTION_THORIM_START_STORM) + me->CastSpell(me, SPELL_TITANIC_STORM_PASSIVE, false); + } + + void UpdateAI(uint32 diff) override + { + if (me->GetInstanceScript()) + if (me->GetInstanceScript()->GetData(TYPE_YOGGSARON) != IN_PROGRESS) + return; + + _checkTimer += diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (me->GetEntry() == NPC_MIMIRON_KEEPER) + { + if (_checkTimer >= 2000) + { + me->CastSpell(me, SPELL_DESTABILIZATION_MATRIX, false); + _checkTimer = 0; + } + } + } + }; +}; + +class boss_yoggsaron_descend_portal : public CreatureScript +{ +public: + boss_yoggsaron_descend_portal() : CreatureScript("boss_yoggsaron_descend_portal") { } + + struct boss_yoggsaron_descend_portalAI : public PassiveAI + { + boss_yoggsaron_descend_portalAI(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) {} + + void OnSpellClick(Unit* clicker, bool& spellClickHandled) override + { + if (!spellClickHandled) + return; + + if (!me->GetUInt32Value(UNIT_NPC_FLAGS)) + return; + + switch (me->GetArmor()) + { + case ACTION_ILLUSION_DRAGONS: + clicker->CastSpell(clicker, SPELL_TELEPORT_TO_CHAMBER, true); + break; + case ACTION_ILLUSION_ICECROWN: + clicker->CastSpell(clicker, SPELL_TELEPORT_TO_ICECROWN, true); + break; + case ACTION_ILLUSION_STORMWIND: + clicker->CastSpell(clicker, SPELL_TELEPORT_TO_STORMWIND, true); + break; + } + + me->SetUInt32Value(UNIT_NPC_FLAGS, 0); + me->DespawnOrUnsummon(1000); + } + + private: + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI(creature); + } +}; + +class boss_yoggsaron_influence_tentacle : public CreatureScript +{ +public: + boss_yoggsaron_influence_tentacle() : CreatureScript("boss_yoggsaron_influence_tentacle") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_influence_tentacleAI : public NullCreatureAI + { + boss_yoggsaron_influence_tentacleAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + me->CastSpell(me, SPELL_GRIM_REPRISAL, true); + } + + void DamageTaken(Unit*, uint32&, DamageEffectType, SpellSchoolMask) override + { + if (me->GetEntry() != NPC_INFLUENCE_TENTACLE) + me->UpdateEntry(NPC_INFLUENCE_TENTACLE, 0, false); + } + + void JustDied(Unit*) override + { + if (me->IsSummon()) + if (Unit* sara = me->ToTempSummon()->GetSummonerUnit()) + sara->GetAI()->DoAction(ACTION_INFLUENCE_TENTACLE_DIED); + } + }; +}; + +class boss_yoggsaron_immortal_guardian : public CreatureScript +{ +public: + boss_yoggsaron_immortal_guardian() : CreatureScript("boss_yoggsaron_immortal_guardian") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_immortal_guardianAI : public ScriptedAI + { + boss_yoggsaron_immortal_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) + { + Reset(); + } + + uint32 _visualTimer; + uint32 _spellTimer; + + void Reset() override + { + me->CastSpell(me, SPELL_RECENTLY_SPAWNED, true); + //me->CastSpell(me, SPELL_EMPOWERED_PASSIVE, true); + if (Aura* aur = me->AddAura(SPELL_EMPOWERED_PASSIVE, me)) + aur->SetStackAmount(9); + + _spellTimer = 0; + _visualTimer = 1; + me->SetControlled(true, UNIT_STATE_ROOT); + me->SetInCombatWithZone(); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + } + + void SpellHit(Unit* caster, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_SHADOW_BEACON) + caster->GetAI()->DoAction(ACTION_YOGG_SARON_SHADOW_BEACON); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (_visualTimer) + { + _visualTimer += diff; + if (_visualTimer >= 100 && _visualTimer < 10000 ) + { + me->CastSpell(me, SPELL_SIMPLE_TELEPORT, false); + _visualTimer = 10000; + } + else if (_visualTimer >= 11000) + { + me->SetControlled(false, UNIT_STATE_ROOT); + _visualTimer = 0; + } + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + _spellTimer += diff; + if (_spellTimer >= 9500) + { + if (me->HealthBelowPct(85)) + { + if (Unit* target = SelectTargetFromPlayerList(40.0f)) + { + me->CastSpell(target, SPELL_DRAIN_LIFE, false); + _spellTimer = 0; + } + } + else + _spellTimer = 7500; + } + + DoMeleeAttackIfReady(); + } + }; +}; + +class boss_yoggsaron_lich_king : public CreatureScript +{ +public: + boss_yoggsaron_lich_king() : CreatureScript("boss_yoggsaron_lich_king") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_lich_kingAI : public NullCreatureAI + { + boss_yoggsaron_lich_kingAI(Creature* c) : NullCreatureAI(c) { } + + bool _running; + int32 _checkTimer; + uint8 _step; + + void Reset() override + { + _running = true; + _checkTimer = 0; + _step = 0; + } + + void NextStep(const uint32 time) + { + _step++; + _checkTimer = time; + } + + void Say(uint8 text, uint32 id) + { + Creature* creature = me->FindNearestCreature(id, 50); + if (!creature) + return; + + creature->AI()->Talk(text); + return; + } + + void UpdateAI(uint32 diff) override + { + if (!_running) + return; + + if (_checkTimer != 0) + { + _checkTimer -= diff; + if (_checkTimer < 0 ) + _checkTimer = 0; + } + else + switch (_step) + { + case 0: + NextStep(5000); + break; + case 1: + Say(SAY_LK_1, NPC_LICH_KING); + NextStep(7000); + break; + case 2: + Say(SAY_IC_1, NPC_IMMOLATED_CHAMPION); + NextStep(6000); + break; + case 3: + Say(SAY_IC_2, NPC_IMMOLATED_CHAMPION); + NextStep(6500); + break; + case 4: + Say(SAY_LK_2, NPC_LICH_KING); + NextStep(7500); + break; + case 5: + Say(SAY_YOGG_5, NPC_YOGG_SARON_VISION); + NextStep(5000); + break; + case 6: + Say(SAY_YOGG_6, NPC_YOGG_SARON_VISION); + _running = false; + break; + } + } + }; +}; + +class boss_yoggsaron_llane : public CreatureScript +{ +public: + boss_yoggsaron_llane() : CreatureScript("boss_yoggsaron_llane") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_llaneAI : public NullCreatureAI + { + boss_yoggsaron_llaneAI(Creature* c) : NullCreatureAI(c) { } + + bool _running; + int32 _checkTimer; + uint8 _step; + + void Reset() override + { + _running = true; + _checkTimer = 0; + _step = 0; + } + + void NextStep(const uint32 time) + { + _step++; + _checkTimer = time; + } + + void Say(uint8 text, uint32 id) + { + Creature* creature = me->FindNearestCreature(id, 50); + if (!creature) + return; + + creature->AI()->Talk(text); + return; + } + + void UpdateAI(uint32 diff) override + { + if (!_running) + return; + + if (_checkTimer != 0) + { + _checkTimer -= diff; + if (_checkTimer < 0 ) + _checkTimer = 0; + } + else + switch (_step) + { + case 0: + NextStep(5000); + break; + case 1: + Say(SAY_GARONA_1, NPC_GARONA); + NextStep(2000); + break; + case 2: + Say(SAY_GARONA_2, NPC_GARONA); + NextStep(6500); + break; + case 3: + Say(SAY_GARONA_3, NPC_GARONA); + NextStep(11000); + break; + case 4: + Say(SAY_YOGG_1, NPC_YOGG_SARON_VISION); + NextStep(2500); + break; + case 5: + Say(SAY_YOGG_2, NPC_YOGG_SARON_VISION); + NextStep(2500); + break; + case 6: + Say(SAY_LLANE_1, NPC_KING_LLANE); + NextStep(10000); + break; + case 7: + Say(SAY_GARONA_4, NPC_GARONA); + NextStep(5000); + break; + case 8: + Say(SAY_YOGG_3, NPC_YOGG_SARON_VISION); + _running = false; + break; + } + } + }; +}; + +class boss_yoggsaron_neltharion : public CreatureScript +{ +public: + boss_yoggsaron_neltharion() : CreatureScript("boss_yoggsaron_neltharion") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_neltharionAI : public ScriptedAI + { + boss_yoggsaron_neltharionAI(Creature* c) : ScriptedAI(c) { } + + bool _running; + int32 _checkTimer; + uint8 _step; + + void Reset() override + { + _running = true; + _checkTimer = 0; + _step = 0; + } + + void NextStep(const uint32 time) + { + _step++; + _checkTimer = time; + } + + void Say(uint8 text, uint32 id) + { + Creature* creature = me->FindNearestCreature(id, 50); + if (!creature) + return; + + creature->AI()->Talk(text); + return; + } + + void UpdateAI(uint32 diff) override + { + if (!_running) + return; + + if (_checkTimer != 0) + { + _checkTimer -= diff; + if (_checkTimer < 0 ) + _checkTimer = 0; + } + else + switch (_step) + { + case 0: + NextStep(5000); + break; + case 1: + Say(SAY_NEL_1, NPC_NELTHARION); + NextStep(10000); + break; + case 2: + Say(SAY_YAS_1, NPC_YSERA); + NextStep(4000); + break; + case 3: + Say(SAY_NEL_2, NPC_NELTHARION); + NextStep(4000); + break; + case 4: + Say(SAY_MAL_1, NPC_MALYGOS); + NextStep(8000); + break; + case 5: + Say(SAY_YOGG_4, NPC_YOGG_SARON_VISION); + _running = false; + break; + } + } + }; +}; + +class boss_yoggsaron_voice : public CreatureScript +{ +public: + boss_yoggsaron_voice() : CreatureScript("boss_yoggsaron_voice") { } + + CreatureAI* GetAI(Creature* pCreature) const override + { + return GetUlduarAI(pCreature); + } + + struct boss_yoggsaron_voiceAI : public NullCreatureAI + { + boss_yoggsaron_voiceAI(Creature* pCreature) : NullCreatureAI(pCreature) + { + _targets.clear(); + _current = 0; + } + + EventMap events; + GuidVector _targets; + uint32 _current; + + void Reset() override + { + me->CastSpell(me, SPELL_INSANE_PERIODIC, true); + } + + void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_INSANE1) + { + // Drive Me Crazy achievement failed + if (me->GetInstanceScript()) + if (Creature* yogg = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_YOGGSARON))) + yogg->AI()->DoAction(ACTION_FAILED_DRIVE_ME_CRAZY); + + events.ScheduleEvent(40, 2s); + _targets.push_back(target->GetGUID()); + } + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + switch (events.ExecuteEvent()) + { + case 40: + { + ObjectGuid _guid = _targets.at(_current); + ++_current; + + if (Player* player = ObjectAccessor::GetPlayer(*me, _guid)) + { + Talk(WHISPER_VOICE_INSANE, player); + } + break; + } + } + } + }; +}; + +// 63830, 63881 - Malady of the Mind +class spell_yogg_saron_malady_of_the_mind : public SpellScriptLoader +{ +public: + spell_yogg_saron_malady_of_the_mind() : SpellScriptLoader("spell_yogg_saron_malady_of_the_mind") { } + + class spell_yogg_saron_malady_of_the_mind_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_malady_of_the_mind_AuraScript); + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetUnitOwner()->ApplySpellImmune(SPELL_DEATH_RAY_DAMAGE_REAL, IMMUNITY_ID, SPELL_DEATH_RAY_DAMAGE_REAL, true); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetUnitOwner()->ApplySpellImmune(SPELL_DEATH_RAY_DAMAGE_REAL, IMMUNITY_ID, SPELL_DEATH_RAY_DAMAGE_REAL, false); + GetUnitOwner()->CastCustomSpell(SPELL_MALADY_OF_THE_MIND_TRIGGER, SPELLVALUE_MAX_TARGETS, 1, GetUnitOwner(), true); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_yogg_saron_malady_of_the_mind_AuraScript::OnApply, EFFECT_1, SPELL_AURA_MOD_FEAR, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_malady_of_the_mind_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_MOD_FEAR, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_yogg_saron_malady_of_the_mind_AuraScript(); + } +}; + +// 63802 - Brain Link +class spell_yogg_saron_brain_link : public SpellScriptLoader +{ +public: + spell_yogg_saron_brain_link() : SpellScriptLoader("spell_yogg_saron_brain_link") { } + + class spell_yogg_saron_brain_link_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_brain_link_AuraScript); + + void HandleOnEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + PreventDefaultAction(); + Player* target = nullptr; + Map::PlayerList const& pList = GetUnitOwner()->GetMap()->GetPlayers(); + uint8 _offset = urand(0, pList.getSize() - 1); + uint8 _counter = 0; + for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr, ++_counter) + { + if (itr->GetSource() == GetUnitOwner() || GetUnitOwner()->GetDistance(itr->GetSource()) > 50.0f || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster()) + continue; + + if (_counter <= _offset || !target) + target = itr->GetSource(); + else + break; + } + + if (!target) + SetDuration(0); + else + _targetGUID = target->GetGUID(); + } + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + Unit* owner = GetUnitOwner(); + if (!owner) + { + SetDuration(0); + return; + } + + Unit* _target = ObjectAccessor::GetUnit(*owner, _targetGUID); + if (!_target || !_target->IsAlive() || std::fabs(owner->GetPositionZ() - _target->GetPositionZ()) > 10.0f) // Target or owner underground + { + SetDuration(0); + return; + } + + if (owner->GetDistance(_target) > 20.0f) + { + owner->CastSpell(_target, SPELL_BRAIN_LINK_DAMAGE, true); + owner->CastSpell(owner, SPELL_BRAIN_LINK_DAMAGE, true); + } + else + owner->CastSpell(_target, SPELL_BRAIN_LINK_OK, true); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_yogg_saron_brain_link_AuraScript::HandleOnEffectApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_yogg_saron_brain_link_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + + protected: + ObjectGuid _targetGUID; + }; + + AuraScript* GetAuraScript() const override + { + return new spell_yogg_saron_brain_link_AuraScript(); + } + + class spell_yogg_saron_brain_link_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_brain_link_SpellScript); + + void FilterTargets(std::list& targets) + { + std::list tempList; + for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) + if ((*itr)->GetPositionZ() > 300.0f) + tempList.push_back(*itr); + + targets.clear(); + for (std::list::iterator itr = tempList.begin(); itr != tempList.end(); ++itr) + targets.push_back(*itr); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_brain_link_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_yogg_saron_brain_link_SpellScript(); + } +}; + +// 64465 - Shadow Beacon +class spell_yogg_saron_shadow_beacon : public SpellScriptLoader +{ + public: + spell_yogg_saron_shadow_beacon() : SpellScriptLoader("spell_yogg_saron_shadow_beacon") { } + + class spell_yogg_saron_shadow_beacon_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_shadow_beacon_AuraScript); + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + { + target->SetEntry(NPC_MARKED_IMMORTAL_GUARDIAN); + } + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + { + target->SetEntry(NPC_IMMORTAL_GUARDIAN); + } + } + + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_yogg_saron_shadow_beacon_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_shadow_beacon_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_yogg_saron_shadow_beacon_AuraScript(); + } +}; + +// 65206 - Destabilization Matrix +class spell_yogg_saron_destabilization_matrix : public SpellScriptLoader +{ +public: + spell_yogg_saron_destabilization_matrix() : SpellScriptLoader("spell_yogg_saron_destabilization_matrix") { } + + class spell_yogg_saron_destabilization_matrix_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_destabilization_matrix_SpellScript); + + void HandleDummyEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (Unit* target = GetHitUnit()) + GetCaster()->CastSpell(target, SPELL_DESTABILIZATION_MATRIX_ATTACK, false); + } + + void FilterTargets(std::list& targets) + { + WorldObject* target = nullptr; + for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) + if (!(*itr)->ToUnit()->HasAura(SPELL_DESTABILIZATION_MATRIX_ATTACK)) + { + target = *itr; + break; + } + + targets.clear(); + if (target) + targets.push_back(target); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_destabilization_matrix_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_destabilization_matrix_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_yogg_saron_destabilization_matrix_SpellScript(); + } +}; + +// 64172 - Titanic Storm +class spell_yogg_saron_titanic_storm : public SpellScriptLoader +{ +public: + spell_yogg_saron_titanic_storm() : SpellScriptLoader("spell_yogg_saron_titanic_storm") { } + + class spell_yogg_saron_titanic_storm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_titanic_storm_SpellScript); + + void HandleDummyEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (Unit* target = GetHitUnit()) + Unit::Kill(GetCaster(), target); + } + + void FilterTargets(std::list& targets) + { + WorldObject* target = nullptr; + for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) + if ((*itr)->ToUnit()->HasAura(SPELL_WEAKENED)) + { + target = *itr; + break; + } + + targets.clear(); + if (target) + targets.push_back(target); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_titanic_storm_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_titanic_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_yogg_saron_titanic_storm_SpellScript(); + } +}; + +// 64164, 64168 - Lunatic Gaze +class spell_yogg_saron_lunatic_gaze : public SpellScriptLoader +{ +public: + spell_yogg_saron_lunatic_gaze() : SpellScriptLoader("spell_yogg_saron_lunatic_gaze") { } + + class spell_yogg_saron_lunatic_gaze_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_lunatic_gaze_SpellScript); + + void FilterTargets(std::list& targets) + { + std::list tmplist; + for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) + if ((*itr)->HasInArc(M_PI, GetCaster())) + tmplist.push_back(*itr); + + targets.clear(); + for (std::list::iterator itr = tmplist.begin(); itr != tmplist.end(); ++itr) + targets.push_back(*itr); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_lunatic_gaze_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_yogg_saron_lunatic_gaze_SpellScript(); + } +}; + +// 64174 - Protective Gaze +class spell_yogg_saron_protective_gaze : public SpellScriptLoader +{ +public: + spell_yogg_saron_protective_gaze() : SpellScriptLoader("spell_yogg_saron_protective_gaze") { } + + class spell_yogg_saron_protective_gaze_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_protective_gaze_AuraScript); + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + { + // Set absorbtion amount to unlimited + amount = -1; + } + + void Absorb(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& absorbAmount) + { + Unit* target = GetTarget(); + if (dmgInfo.GetDamage() < target->GetHealth() || !GetCaster() || GetCaster()->ToCreature()->HasSpellCooldown(SPELL_HODIR_FLASH_FREEZE)) + return; + + target->CastSpell(target, SPELL_HODIR_FLASH_FREEZE, true); + GetCaster()->AddSpellCooldown(SPELL_HODIR_FLASH_FREEZE, 0, 0); + absorbAmount = dmgInfo.GetDamage(); + } + + void Register() override + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_yogg_saron_protective_gaze_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_yogg_saron_protective_gaze_AuraScript::Absorb, EFFECT_0); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_yogg_saron_protective_gaze_AuraScript(); + } +}; + +// 64161 - Empowered +class spell_yogg_saron_empowered : public SpellScriptLoader +{ +public: + spell_yogg_saron_empowered() : SpellScriptLoader("spell_yogg_saron_empowered") { } + + class spell_yogg_saron_empowered_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_empowered_AuraScript); + + void OnPeriodic(AuraEffect const* /*aurEff*/) + { + Unit* target = GetUnitOwner(); + uint8 stack = std::min(uint8(target->GetHealthPct() / 10), (uint8)9); + + if (!stack) + { + target->RemoveAura(SPELL_EMPOWERED); + target->CastSpell(target, SPELL_WEAKENED, true); + } + else if (Aura* aur = target->AddAura(SPELL_EMPOWERED, target)) + { + aur->SetStackAmount(stack); + target->RemoveAurasDueToSpell(SPELL_WEAKENED); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_yogg_saron_empowered_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_yogg_saron_empowered_AuraScript(); + } +}; + +// 64555 - Insane Periodic +class spell_yogg_saron_insane_periodic_trigger : public SpellScriptLoader +{ +public: + spell_yogg_saron_insane_periodic_trigger() : SpellScriptLoader("spell_yogg_saron_insane_periodic_trigger") { } + + class spell_yogg_saron_insane_periodic_trigger_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_insane_periodic_trigger_SpellScript); + + void HandleDummyEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + Player* target = GetHitPlayer(); + if (!target) + return; + + Unit* caster = GetCaster(); + caster->CastSpell(target, SPELL_INSANE1, true); + target->CastSpell(target, SPELL_INSANE2, true); + } + + void FilterTargets(std::list& targets) + { + std::list tmplist; + for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr) + if ((*itr)->IsPlayer() && !(*itr)->ToPlayer()->HasAuraType(SPELL_AURA_AOE_CHARM) && !(*itr)->ToPlayer()->HasAura(SPELL_SANITY)) + tmplist.push_back(*itr); + + targets.clear(); + for (std::list::iterator itr = tmplist.begin(); itr != tmplist.end(); ++itr) + targets.push_back(*itr); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_insane_periodic_trigger_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_yogg_saron_insane_periodic_trigger_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_yogg_saron_insane_periodic_trigger_SpellScript(); + } +}; + +// 63120 - Insane +class spell_yogg_saron_insane : public SpellScriptLoader +{ +public: + spell_yogg_saron_insane() : SpellScriptLoader("spell_yogg_saron_insane") { } + + class spell_yogg_saron_insane_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_insane_AuraScript); + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit::Kill(GetUnitOwner(), GetUnitOwner()); + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_yogg_saron_insane_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_AOE_CHARM, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_yogg_saron_insane_AuraScript(); + } +}; + +// 64169 - Sanity Well +class spell_yogg_saron_sanity_well : public SpellScriptLoader +{ +public: + spell_yogg_saron_sanity_well() : SpellScriptLoader("spell_yogg_saron_sanity_well") { } + + class spell_yogg_saron_sanity_well_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_sanity_well_AuraScript); + + void HandleEffectCalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude) + { + isPeriodic = true; + amplitude = 2 * IN_MILLISECONDS; + } + + void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) + { + Unit* target = GetTarget(); + if (!target || !target->IsPlayer()) + return; + + if (Aura* aur = target->GetAura(SPELL_SANITY)) + aur->SetStackAmount(std::min(100, aur->GetStackAmount() + 20)); + } + + void Register() override + { + DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_yogg_saron_sanity_well_AuraScript::HandleEffectCalcPeriodic, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_yogg_saron_sanity_well_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_yogg_saron_sanity_well_AuraScript(); + } +}; + +/* 63881 - Malady of the Mind + 63795 - Psychosis + 63830 - Malady of the Mind + 64164 - Lunatic Gaze + 64059 - Induce Madness + 63803 - Brain Link + 65301 - Psychosis + 64168 - Lunatic Gaze */ +class spell_yogg_saron_sanity_reduce : public SpellScriptLoader +{ +public: + spell_yogg_saron_sanity_reduce() : SpellScriptLoader("spell_yogg_saron_sanity_reduce") { } + + class spell_yogg_saron_sanity_reduce_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_sanity_reduce_SpellScript); + + void HandleScriptEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + Player* target = GetHitPlayer(); + if (!target) + return; + + uint8 _reduceAmount = 0; + switch (GetSpellInfo()->Id) + { + case SPELL_SARA_PSYCHOSIS_10: + _reduceAmount = 9; + break; + case SPELL_SARA_PSYCHOSIS_25: + _reduceAmount = 12; + break; + case SPELL_MALADY_OF_THE_MIND: + _reduceAmount = 3; + break; + case SPELL_MALADY_OF_THE_MIND_TRIGGER: + _reduceAmount = 3; + break; + case SPELL_BRAIN_LINK_DAMAGE: + _reduceAmount = 2; + break; + case 64168 /*SPELL_LUNATIC_GAZE*/: + _reduceAmount = 2; + break; + case 64164 /*SPELL_YS_LUNATIC_GAZE*/: + _reduceAmount = 4; + break; + case SPELL_INDUCE_MADNESS: + // Teleported out of brain + if (target->GetPositionZ() > 300.0f) + return; + else + target->CastSpell(target, SPELL_CANCEL_ILLUSION_AURA, true); // else we are underground, remove illusion aura and teleport outside + _reduceAmount = 100; + break; + } + + if (Aura* aur = target->GetAura(SPELL_SANITY)) + { + if ((aur->GetStackAmount() - _reduceAmount) <= 20) + target->CastSpell(target, 63752 /*SANITY_SCREEN_EFFECT*/, true); + aur->ModStackAmount(-_reduceAmount); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_sanity_reduce_SpellScript::HandleScriptEffect, EFFECT_FIRST_FOUND, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_yogg_saron_sanity_reduce_SpellScript(); + } +}; + +// 64467 - Empowering Shadows +class spell_yogg_saron_empowering_shadows : public SpellScriptLoader +{ +public: + spell_yogg_saron_empowering_shadows() : SpellScriptLoader("spell_yogg_saron_empowering_shadows") { } + + class spell_yogg_saron_empowering_shadows_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_empowering_shadows_SpellScript); + + void HandleScriptEffect(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (Unit* target = GetHitUnit()) + target->CastSpell(target, target->GetMap()->Is25ManRaid() ? 64486 : 64468, true); // SPELL_EMPOWERING_SHADOWS_HEAL + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_empowering_shadows_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_yogg_saron_empowering_shadows_SpellScript(); + } +}; + +// 64184 - In the Maws of the Old God +class spell_yogg_saron_in_the_maws_of_the_old_god : public SpellScriptLoader +{ +public: + spell_yogg_saron_in_the_maws_of_the_old_god() : SpellScriptLoader("spell_yogg_saron_in_the_maws_of_the_old_god") {} + + class spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript); + + SpellCastResult CheckCast() + { + if (!GetCaster()->IsPlayer()) + return SPELL_FAILED_BAD_TARGETS; + + Unit* target = GetCaster()->ToPlayer()->GetSelectedUnit(); + if (!target || target->GetEntry() != NPC_YOGG_SARON) + return SPELL_FAILED_BAD_TARGETS; + + Spell* spell = target->GetCurrentSpell(CURRENT_GENERIC_SPELL); + if (!spell || spell->GetSpellInfo()->Id != SPELL_DEAFENING_ROAR) + return SPELL_FAILED_TARGET_AURASTATE; + + return SPELL_CAST_OK; + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript::CheckCast); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_yogg_saron_in_the_maws_of_the_old_god_SpellScript(); + } +}; + +/* 63744 - Sara's Anger + 63747 - Sara's Fervor + 63745 - Sara's Blessing */ +class spell_yogg_saron_target_selectors : public SpellScriptLoader +{ +public: + spell_yogg_saron_target_selectors() : SpellScriptLoader("spell_yogg_saron_target_selectors") { } + + class spell_yogg_saron_target_selectors_SpellScript : public SpellScript + { + PrepareSpellScript(spell_yogg_saron_target_selectors_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + GetCaster()->SetFacingToObject(target); + GetCaster()->CastSpell(target, uint32(GetEffectValue())); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_yogg_saron_target_selectors_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_yogg_saron_target_selectors_SpellScript(); + } +}; + +// 63305 - Grim Reprisal +class spell_yogg_saron_grim_reprisal : public SpellScriptLoader +{ +public: + spell_yogg_saron_grim_reprisal() : SpellScriptLoader("spell_yogg_saron_grim_reprisal") { } + + class spell_yogg_saron_grim_reprisal_AuraScript : public AuraScript + { + PrepareAuraScript(spell_yogg_saron_grim_reprisal_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_GRIM_REPRISAL_DAMAGE }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + DamageInfo* damageInfo = eventInfo.GetDamageInfo(); + + if (!damageInfo || !damageInfo->GetDamage()) + { + return; + } + + int32 damage = CalculatePct(static_cast(damageInfo->GetDamage()), 60); + GetTarget()->CastCustomSpell(SPELL_GRIM_REPRISAL_DAMAGE, SPELLVALUE_BASE_POINT0, damage, damageInfo->GetAttacker(), true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_yogg_saron_grim_reprisal_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_yogg_saron_grim_reprisal_AuraScript(); + } +}; + +class achievement_yogg_saron_drive_me_crazy : public AchievementCriteriaScript +{ +public: + achievement_yogg_saron_drive_me_crazy() : AchievementCriteriaScript("achievement_yogg_saron_drive_me_crazy") {} + + bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override + { + return target && target->GetAI()->GetData(DATA_GET_DRIVE_ME_CRAZY); // target = Yogg-Saron + } +}; + +class achievement_yogg_saron_darkness : public AchievementCriteriaScript +{ +public: + achievement_yogg_saron_darkness(char const* name, uint32 count) : AchievementCriteriaScript(name), + _keepersCount(count) + { + } + + bool OnCheck(Player* player, Unit* /*target*/ /*Yogg-Saron*/, uint32 /*criteria_id*/) override + { + if (player->GetInstanceScript()) + if (Creature* sara = ObjectAccessor::GetCreature(*player, player->GetInstanceScript()->GetGuidData(NPC_SARA))) + return sara->GetAI()->GetData(DATA_GET_KEEPERS_COUNT) <= _keepersCount; + + return false; + } + +private: + uint32 const _keepersCount; +}; + +class achievement_yogg_saron_he_waits_dreaming : public AchievementCriteriaScript +{ +public: + achievement_yogg_saron_he_waits_dreaming(char const* name, uint8 illusion) : AchievementCriteriaScript(name), + _requiredIllusion(illusion) + { + } + + bool OnCheck(Player* player, Unit* /*target*/ /*Yogg-Saron*/, uint32 /*criteria_id*/) override + { + if (player->GetInstanceScript()) + if (Creature* sara = ObjectAccessor::GetCreature(*player, player->GetInstanceScript()->GetGuidData(NPC_BRAIN_OF_YOGG_SARON))) + return sara->GetAI()->GetData(DATA_GET_CURRENT_ILLUSION) == _requiredIllusion; + + return false; + } + +private: + uint8 const _requiredIllusion; +}; + +class achievement_yogg_saron_kiss_and_make_up : public AchievementCriteriaScript +{ +public: + achievement_yogg_saron_kiss_and_make_up() : AchievementCriteriaScript("achievement_yogg_saron_kiss_and_make_up") {} + + bool OnCheck(Player* /*player*/, Unit* target /*Sara*/, uint32 /*criteria_id*/) override + { + return target && target->GetEntry() == NPC_SARA && target->GetAI() && target->GetAI()->GetData(DATA_GET_SARA_PHASE); + } +}; + +#endif \ No newline at end of file