From a05a43cee10ca02f09d0b7ba3d0ee9d0e56cb6bc Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Sun, 15 Feb 2026 08:57:57 -0300 Subject: [PATCH] refactor(Scripts/Ulduar): Update Ulduar to use boss states and other modernizations (#24714) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../rev_1771122450299085300.sql | 2 + .../Ulduar/boss_algalon_the_observer.cpp | 1493 ++++--- .../Ulduar/Ulduar/boss_assembly_of_iron.cpp | 1154 +++--- .../Northrend/Ulduar/Ulduar/boss_auriaya.cpp | 22 +- .../Ulduar/Ulduar/boss_flame_leviathan.cpp | 1664 ++++---- .../Northrend/Ulduar/Ulduar/boss_freya.cpp | 1675 ++++---- .../Ulduar/Ulduar/boss_general_vezax.cpp | 646 ++- .../Northrend/Ulduar/Ulduar/boss_hodir.cpp | 1710 ++++---- .../Northrend/Ulduar/Ulduar/boss_ignis.cpp | 556 ++- .../Northrend/Ulduar/Ulduar/boss_kologarn.cpp | 331 +- .../Northrend/Ulduar/Ulduar/boss_mimiron.cpp | 3630 ++++++++--------- .../Ulduar/Ulduar/boss_razorscale.cpp | 1407 +++---- .../Northrend/Ulduar/Ulduar/boss_thorim.cpp | 1417 +++---- .../Northrend/Ulduar/Ulduar/boss_xt002.cpp | 1184 +++--- .../Ulduar/Ulduar/boss_yoggsaron.cpp | 3306 +++++++-------- .../Ulduar/Ulduar/instance_ulduar.cpp | 881 ++-- .../Northrend/Ulduar/Ulduar/ulduar.cpp | 310 +- .../scripts/Northrend/Ulduar/Ulduar/ulduar.h | 102 +- 18 files changed, 9986 insertions(+), 11504 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1771122450299085300.sql diff --git a/data/sql/updates/pending_db_world/rev_1771122450299085300.sql b/data/sql/updates/pending_db_world/rev_1771122450299085300.sql new file mode 100644 index 000000000..21b165a32 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1771122450299085300.sql @@ -0,0 +1,2 @@ +-- Remove unused ScriptName from Pure Saronite Deposit +UPDATE `gameobject_template` SET `ScriptName` = '' WHERE `entry` = 195036; 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 8a47bd335..d6833a913 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 @@ -260,847 +260,792 @@ private: Unit* _caster; }; -class boss_algalon_the_observer : public CreatureScript +struct boss_algalon_the_observer : public ScriptedAI { -public: - boss_algalon_the_observer() : CreatureScript("boss_algalon_the_observer") {} - - struct boss_algalon_the_observerAI : public ScriptedAI + boss_algalon_the_observer(Creature* creature) : ScriptedAI(creature), summons(me) { - boss_algalon_the_observerAI(Creature* creature) : ScriptedAI(creature), summons(me) - { - _fedOnTears = true; - _firstPull = true; - _fightWon = false; - m_pInstance = me->GetInstanceScript(); - } + _fedOnTears = true; + _firstPull = true; + _fightWon = false; + m_pInstance = me->GetInstanceScript(); + } - EventMap events; - SummonList summons; - InstanceScript* m_pInstance; + EventMap events; + SummonList summons; + InstanceScript* m_pInstance; - bool _firstPull; - bool _fightWon; - bool _phaseTwo; - bool _fedOnTears; - bool _heraldOfTheTitans; + 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 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; + 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)) + 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*/) { - ++_count; - summon->AI()->DoAction(ACTION_ACTIVATE_STAR); - if (_count >= 3) - break; + 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; + } } - } - } - void EnterEvadeMode(EvadeReason why) override + 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(); ) { - if (_fightWon) - return; - - if (SelectTargetFromPlayerList(120.0f)) + Creature* summon = ObjectAccessor::GetCreature(*me, *i++); + if (summon && summon->GetEntry() == NPC_LIVING_CONSTELLATION && !summon->AI()->GetData(0)) { - 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->IsPlayer() || 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(39s); - - 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); + ++_count; + summon->AI()->DoAction(ACTION_ACTIVATE_STAR); + if (_count >= 3) 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 + void EnterEvadeMode(EvadeReason why) override + { + if (_fightWon) + return; + + if (SelectTargetFromPlayerList(120.0f)) { - me->setActive(false); - } - - void JustEngagedWith(Unit*) override - { - if (_fightWon) - return; - - if (!m_pInstance) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } - - Milliseconds introDelay = 0ms; - 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 = 8s; - } - else - { - summons.DespawnEntry(NPC_AZEROTH); - _firstPull = false; - Talk(SAY_ALGALON_START_TIMER); - introDelay = 22s; - events.ScheduleEvent(EVENT_START_COMBAT, 14s); - m_pInstance->SetData(DATA_DESPAWN_ALGALON, 0); - } - - events.ScheduleEvent(EVENT_REMOVE_UNNATTACKABLE, introDelay - 500ms); - events.ScheduleEvent(EVENT_INTRO_TIMER_DONE, introDelay); - events.ScheduleEvent(EVENT_QUANTUM_STRIKE, 3500ms + introDelay); - events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500ms + introDelay); - events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 16500ms + introDelay); - events.ScheduleEvent(EVENT_COSMIC_SMASH, 25s + introDelay); - events.ScheduleEvent(EVENT_ACTIVATE_LIVING_CONSTELLATION, 50500ms + introDelay); - events.ScheduleEvent(EVENT_BIG_BANG, 90s + introDelay); - events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 360s + introDelay); - - events.ScheduleEvent(EVENT_CHECK_HERALD_ITEMS, 5s); - DoCheckHeraldOfTheTitans(); + return; + } + else if (events.GetPhaseMask() & PHASE_NORMAL) + { + DoAction(ACTION_ASCEND); + return; } - void MovementInform(uint32 movementType, uint32 pointId) override - { - if (movementType != POINT_MOTION_TYPE) - return; + if (m_pInstance) + m_pInstance->SetData(BOSS_ALGALON, FAIL); - 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); - } + 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->GetBossState(BOSS_ALGALON) == FAIL) + { + _firstPull = false; } - void JustSummoned(Creature* summon) override + if (m_pInstance) + m_pInstance->SetData(BOSS_ALGALON, NOT_STARTED); + } + + void KilledUnit(Unit* victim) override + { + if (!victim->IsPlayer() || urand(0, 2)) + return; + + Talk(SAY_ALGALON_KILL); + } + + void DoAction(int32 action) override + { + switch (action) { - summons.Summon(summon); - switch (summon->GetEntry()) - { - case NPC_AZEROTH: - me->CastSpell(summon, SPELL_REORIGINATION, true); + 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 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.AddEventAtOffset(new CosmicSmashDamageEvent(summon), 4s); - 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) - { + } + case ACTION_DESPAWN_ALGALON: _fightWon = true; - damage = 0; + 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(39s); + 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); - } + if (m_pInstance) + m_pInstance->SetData(BOSS_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; } - bool IsInRoom() - { - if (me->GetExactDist2d(&me->GetHomePosition()) > 45.f || me->GetPositionZ() < 410.f) - { - DoAction(ACTION_ASCEND); - return false; - } + Milliseconds introDelay = 0ms; + me->setActive(true); + me->SetInCombatWithZone(); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToNPC(true); + events.Reset(); + events.SetPhase(PHASE_ROLE_PLAY); - return true; + if (!_firstPull) + { + events.ScheduleEvent(EVENT_START_COMBAT, 0ms); + introDelay = 8s; + } + else + { + summons.DespawnEntry(NPC_AZEROTH); + _firstPull = false; + Talk(SAY_ALGALON_START_TIMER); + introDelay = 22s; + events.ScheduleEvent(EVENT_START_COMBAT, 14s); + m_pInstance->SetData(DATA_DESPAWN_ALGALON, 0); } - void UpdateAI(uint32 diff) override + events.ScheduleEvent(EVENT_REMOVE_UNNATTACKABLE, introDelay - 500ms); + events.ScheduleEvent(EVENT_INTRO_TIMER_DONE, introDelay); + events.ScheduleEvent(EVENT_QUANTUM_STRIKE, 3500ms + introDelay); + events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500ms + introDelay); + events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 16500ms + introDelay); + events.ScheduleEvent(EVENT_COSMIC_SMASH, 25s + introDelay); + events.ScheduleEvent(EVENT_ACTIVATE_LIVING_CONSTELLATION, 50500ms + introDelay); + events.ScheduleEvent(EVENT_BIG_BANG, 90s + introDelay); + events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 360s + 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) { - if (!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && (!UpdateVictim() || !IsInRoom())) - return; + 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); + } + } - 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(3s, 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: + 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: { - Player* lootRecipent = me->GetLootRecipient(); - _EnterEvadeMode(); - // LootRecipent is cleared in _EnterEvadeMode, restore it - me->SetLootRecipient(lootRecipent); - me->GetMotionMaster()->MovePoint(POINT_ALGALON_OUTRO, AlgalonOutroPos); + 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.AddEventAtOffset(new CosmicSmashDamageEvent(summon), 4s); 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(3s); - 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(3s); - break; - case EVENT_CHECK_HERALD_ITEMS: - if (!DoCheckHeraldOfTheTitans()) - events.Repeat(5s); - break; - } - - DoMeleeAttackIfReady(); + 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; } - }; - - 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 + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { - npc_brann_bronzebeard_algalonAI(Creature* creature) : CreatureAI(creature) + if (_fightWon) { + damage = 0; + return; } - EventMap events; - uint32 _currentPoint; - - void DoAction(int32 action) override + if (!_phaseTwo && me->HealthBelowPctDamaged(20, damage)) { - 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; - } + _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); } - - void MovementInform(uint32 movementType, uint32 pointId) override - { - if (movementType != POINT_MOTION_TYPE) - return; - - Milliseconds delay = 1ms; - _currentPoint = pointId + 1; - switch (pointId) - { - case 2: - delay = 8s; - 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(1ms); - 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) + else if (me->HealthBelowPctDamaged(2, damage) && !_fightWon) { + _fightWon = true; + damage = 0; me->SetReactState(REACT_PASSIVE); - } - - EventMap events; - bool _isActive; - - void Reset() override - { + me->AttackStop(); + me->SetFaction(FACTION_FRIENDLY); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); events.Reset(); - events.ScheduleEvent(EVENT_ARCANE_BARRAGE, 2500ms); - _isActive = false; + 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); } + } - 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(9500ms); - events.ScheduleEvent(EVENT_RESUME_UPDATING, 9500ms); - break; - } - } - - void SpellHit(Unit* caster, SpellInfo const* spell) override - { - if (spell->Id != SPELL_CONSTELLATION_PHASE_EFFECT || !caster->IsCreature()) - 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(1ms); - me->DespawnOrUnsummon(1ms); - if (Creature* voidZone = caster->FindNearestCreature(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER, 10.0f)) - voidZone->DespawnOrUnsummon(1ms); - } - - 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 + bool IsInRoom() { - return GetUlduarAI(creature); + 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 = m_pInstance->GetCreature(DATA_BRANN_BRONZEBEARD_ALG)) + brann->AI()->DoAction(ACTION_FINISH_INTRO); + break; + case EVENT_START_COMBAT: + m_pInstance->SetData(BOSS_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(3s, 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(BOSS_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(3s); + 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(3s); + break; + case EVENT_CHECK_HERALD_ITEMS: + if (!DoCheckHeraldOfTheTitans()) + events.Repeat(5s); + break; + } + + DoMeleeAttackIfReady(); } }; -class npc_algalon_worm_hole : public CreatureScript +struct npc_brann_bronzebeard_algalon : public CreatureAI { -public: - npc_algalon_worm_hole() : CreatureScript("npc_algalon_worm_hole") { } - - struct npc_algalon_worm_holeAI : public NullCreatureAI + npc_brann_bronzebeard_algalon(Creature* creature) : CreatureAI(creature) { - npc_algalon_worm_holeAI(Creature* creature) : NullCreatureAI(creature) + } + + EventMap events; + uint32 _currentPoint; + + void DoAction(int32 action) override + { + switch (action) { - creature->CastSpell(creature, SPELL_WORM_HOLE_TRIGGER, true); - creature->CastSpell(creature, SPELL_SUMMON_VOID_ZONE_VISUAL, true); + 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; + + Milliseconds delay = 1ms; + _currentPoint = pointId + 1; + switch (pointId) + { + case 2: + delay = 8s; + 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(1ms); + return; + case POINT_BRANN_OUTRO: + case POINT_BRANN_OUTRO_END: + return; } - uint32 _summonTimer; + events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, delay); + } - void Reset() override + void UpdateAI(uint32 diff) override + { + UpdateVictim(); + events.Update(diff); + + switch (events.ExecuteEvent()) { - _summonTimer = urand(22000, 24000); + 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()->GetCreature(BOSS_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; } + } +}; - void JustSummoned(Creature* summon) override +struct npc_collapsing_star : public NullCreatureAI +{ + npc_collapsing_star(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()) { - if (TempSummon* summ = me->ToTempSummon()) - { - if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID())) + me->CastSpell(me, SPELL_BLACK_HOLE_SPAWN_VISUAL, true); + me->CastSpell(me, SPELL_SUMMON_BLACK_HOLE, true); + } + } +}; + +struct npc_living_constellation : public ScriptedAI +{ + npc_living_constellation(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)) { - algalon->AI()->JustSummoned(summon); + AttackStart(target); + me->AddThreat(target, 100.0f); } - } + me->SetInCombatWithZone(); + break; + case ACTION_BIG_BANG: + events.SetPhase(PHASE_BIG_BANG); + events.DelayEvents(9500ms); + events.ScheduleEvent(EVENT_RESUME_UPDATING, 9500ms); + break; } + } - 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 + void SpellHit(Unit* caster, SpellInfo const* spell) override { - return GetUlduarAI(creature); + if (spell->Id != SPELL_CONSTELLATION_PHASE_EFFECT || !caster->IsCreature()) + 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(1ms); + me->DespawnOrUnsummon(1ms); + if (Creature* voidZone = caster->FindNearestCreature(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER, 10.0f)) + voidZone->DespawnOrUnsummon(1ms); + } + + 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; + } + } +}; + +struct npc_algalon_worm_hole : public NullCreatureAI +{ + npc_algalon_worm_hole(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; + } } }; @@ -1153,10 +1098,10 @@ public: 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))) + if (GameObject* sigil = instance->GetGameObject(DATA_SIGILDOOR_01)) sigil->SetGoState(GO_STATE_ACTIVE); - if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_DOODAD_UL_SIGILDOOR_02))) + if (GameObject* sigil = instance->GetGameObject(DATA_SIGILDOOR_02)) sigil->SetGoState(GO_STATE_ACTIVE); if (Map* map = player->GetMap()) @@ -1394,11 +1339,11 @@ public: void AddSC_boss_algalon_the_observer() { // NPCs - new boss_algalon_the_observer(); - new npc_brann_bronzebeard_algalon(); - new npc_collapsing_star(); - new npc_living_constellation(); - new npc_algalon_worm_hole(); + RegisterUlduarCreatureAI(boss_algalon_the_observer); + RegisterUlduarCreatureAI(npc_brann_bronzebeard_algalon); + RegisterUlduarCreatureAI(npc_collapsing_star); + RegisterUlduarCreatureAI(npc_living_constellation); + RegisterUlduarCreatureAI(npc_algalon_worm_hole); // GOs new go_celestial_planetarium_access(); 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 8e423166a..fe3493e67 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 @@ -128,11 +128,7 @@ bool IsEncounterComplete(InstanceScript* pInstance, Creature* me) for (uint8 i = 0; i < 3; ++i) { - ObjectGuid guid = pInstance->GetGuidData(DATA_STEELBREAKER + i); - if (!guid) - return false; - - if (Creature* boss = (ObjectAccessor::GetCreature(*me, guid))) + if (Creature* boss = pInstance->GetCreature(DATA_STEELBREAKER + i)) { if (boss->IsAlive()) return false; @@ -151,201 +147,186 @@ void RespawnAssemblyOfIron(InstanceScript* pInstance, Creature* me) for (uint8 i = 0; i < 3; ++i) { - ObjectGuid guid = pInstance->GetGuidData(DATA_STEELBREAKER + i); - if (!guid) - return; - - if (Creature* boss = (ObjectAccessor::GetCreature((*me), guid))) + if (Creature* boss = pInstance->GetCreature(DATA_STEELBREAKER + i)) if (!boss->IsAlive()) boss->Respawn(); } return; } -void RestoreAssemblyHealth(ObjectGuid guid1, ObjectGuid guid2, Creature* me) +void RestoreAssemblyHealth(uint32 dataId1, uint32 dataId2, InstanceScript* pInstance) { - if (Creature* cr = ObjectAccessor::GetCreature(*me, guid1)) + if (Creature* cr = pInstance->GetCreature(dataId1)) if (cr->IsAlive()) cr->SetHealth(cr->GetMaxHealth()); - if (Creature* cr2 = ObjectAccessor::GetCreature(*me, guid2)) + if (Creature* cr2 = pInstance->GetCreature(dataId2)) if (cr2->IsAlive()) cr2->SetHealth(cr2->GetMaxHealth()); } -class boss_steelbreaker : public CreatureScript +struct boss_steelbreaker : public ScriptedAI { -public: - boss_steelbreaker() : CreatureScript("boss_steelbreaker") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_steelbreaker(Creature* c) : ScriptedAI(c) { - return GetUlduarAI(pCreature); + pInstance = c->GetInstanceScript(); } - struct boss_steelbreakerAI : public ScriptedAI + EventMap events; + InstanceScript* pInstance; + uint8 _phase; + + void Reset() override { - boss_steelbreakerAI(Creature* c) : ScriptedAI(c) + me->SetLootMode(0); + RespawnAssemblyOfIron(pInstance, me); + + _phase = 0; + events.Reset(); + if (pInstance) + pInstance->SetBossState(BOSS_ASSEMBLY, NOT_STARTED); + } + + void JustReachedHome() override + { + me->setActive(false); + me->RemoveAllAuras(); + } + + void JustEngagedWith(Unit* who) override + { + if (pInstance) + pInstance->SetBossState(BOSS_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 = pInstance->GetCreature(DATA_STEELBREAKER + urand(0, 2))) { - pInstance = c->GetInstanceScript(); + 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; + } } - EventMap events; - InstanceScript* pInstance; - uint8 _phase; + for (uint8 i = 0; i < 3; ++i) + if (Creature* boss = pInstance->GetCreature(DATA_STEELBREAKER + i)) + if (!boss->IsInCombat()) + boss->AI()->AttackStart(who); + } - void Reset() override + void UpdatePhase() + { + if (_phase >= 3) + return; + + ++_phase; + + switch (_phase) { - me->SetLootMode(0); - RespawnAssemblyOfIron(pInstance, me); - - _phase = 0; - events.Reset(); - if (pInstance) - pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); + 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 JustReachedHome() override + void JustDied(Unit* /*Killer*/) override + { + if (!pInstance) + return; + + if (IsEncounterComplete(pInstance, me)) { - me->setActive(false); - me->RemoveAllAuras(); + pInstance->SetBossState(BOSS_ASSEMBLY, DONE); + me->CastSpell(me, 65195, true); // credit + Talk(SAY_STEELBREAKER_ENCOUNTER_DEFEATED); } - - void JustEngagedWith(Unit* who) override + else { - if (pInstance) - pInstance->SetData(TYPE_ASSEMBLY, IN_PROGRESS); + RestoreAssemblyHealth(DATA_BRUNDIR, DATA_MOLGEIM, pInstance); + me->CastSpell(me, SPELL_SUPERCHARGE, true); + Talk(SAY_STEELBREAKER_DEATH); + } + } - me->setActive(true); - me->SetInCombatWithZone(); - me->CastSpell(me, SPELL_HIGH_VOLTAGE, true); - events.ScheduleEvent(EVENT_ENRAGE, 15min); + void KilledUnit(Unit* who) override + { + if (!who->IsPlayer()) + 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(); + } - if (!pInstance) - return; + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + 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; - } - } + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + 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() + switch (events.ExecuteEvent()) { - if (_phase >= 3) - return; + 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); - ++_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; - } + events.Repeat(20s, 40s); + break; + case EVENT_OVERWHELMING_POWER: + Talk(SAY_STEELBREAKER_POWER); + me->CastSpell(me->GetVictim(), SPELL_OVERWHELMING_POWER, true); + events.Repeat(RAID_MODE(61s, 36s)); + break; + case EVENT_ENRAGE: + Talk(SAY_STEELBREAKER_BERSERK); + me->CastSpell(me, SPELL_BERSERK, true); + 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->IsPlayer()) - 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.Repeat(RAID_MODE(61s, 36s)); - break; - case EVENT_ENRAGE: - Talk(SAY_STEELBREAKER_BERSERK); - me->CastSpell(me, SPELL_BERSERK, true); - break; - } - - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } }; class CastRunesEvent : public BasicEvent @@ -364,464 +345,431 @@ private: Creature& _owner; }; -class boss_runemaster_molgeim : public CreatureScript +struct boss_runemaster_molgeim : public ScriptedAI { -public: - boss_runemaster_molgeim() : CreatureScript("boss_runemaster_molgeim") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_runemaster_molgeim(Creature* c) : ScriptedAI(c), summons(me) { - return GetUlduarAI(pCreature); + pInstance = c->GetInstanceScript(); } - struct boss_runemaster_molgeimAI : public ScriptedAI + InstanceScript* pInstance; + SummonList summons; + EventMap events; + uint8 _phase; + + void Reset() override { - boss_runemaster_molgeimAI(Creature* c) : ScriptedAI(c), summons(me) + me->SetLootMode(0); + RespawnAssemblyOfIron(pInstance, me); + + _phase = 0; + events.Reset(); + summons.DespawnAll(); + + if (pInstance) + pInstance->SetBossState(BOSS_ASSEMBLY, NOT_STARTED); + + me->m_Events.AddEventAtOffset(new CastRunesEvent(*me), 8s); + } + + 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 = pInstance->GetCreature(DATA_STEELBREAKER + i)) + if (!boss->IsInCombat()) + boss->AI()->AttackStart(who); + } + + void UpdatePhase() + { + if (_phase >= 3) + return; + + ++_phase; + + switch (_phase) { - pInstance = c->GetInstanceScript(); + 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; } + } - InstanceScript* pInstance; - SummonList summons; - EventMap events; - uint8 _phase; + void JustDied(Unit* /*killer*/) override + { + if (!pInstance) + return; - void Reset() override + if (IsEncounterComplete(pInstance, me)) { - me->SetLootMode(0); - RespawnAssemblyOfIron(pInstance, me); - - _phase = 0; - events.Reset(); - summons.DespawnAll(); - - if (pInstance) - pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED); - - me->m_Events.AddEventAtOffset(new CastRunesEvent(*me), 8s); + pInstance->SetBossState(BOSS_ASSEMBLY, DONE); + me->CastSpell(me, 65195, true); // credit + Talk(SAY_MOLGEIM_ENCOUNTER_DEFEATED); } - - void JustReachedHome() override + else { - me->setActive(false); - me->RemoveAllAuras(); + RestoreAssemblyHealth(DATA_STEELBREAKER, DATA_BRUNDIR, pInstance); + me->CastSpell(me, SPELL_SUPERCHARGE, true); + Talk(SAY_MOLGEIM_DEATH); } + } - void JustEngagedWith(Unit* who) override - { - me->InterruptNonMeleeSpells(false); - me->setActive(true); - me->SetInCombatWithZone(); - events.ScheduleEvent(EVENT_ENRAGE, 15min); + void KilledUnit(Unit* who) override + { + if (!who->IsPlayer()) + return; + + Talk(SAY_MOLGEIM_SLAY); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_SUPERCHARGE) 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->IsPlayer()) - 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 + void UpdateAI(uint32 diff) override { - npc_assembly_lightningAI(Creature* c) : ScriptedAI(c) + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - _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(1ms); - } - - void MovementInform(uint32 type, uint32 /*id*/) override - { - if (type == FOLLOW_MOTION_TYPE && !_boomed) - { - _boomed = true; - me->CastSpell(me, SPELL_LIGHTNING_BLAST, true); - me->DespawnOrUnsummon(1s); - } - } - }; -}; - -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->IsPlayer() || 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 == sSpellMgr->GetSpellIdForDifficulty(SPELL_CHAIN_LIGHTNING, me) || spellInfo->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_LIGHTNING_WHIRL_TRIGG, me)) - _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) + case EVENT_RUNE_OF_POWER: { - _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); + 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); - 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, SPELL_LIGHTNING_TENDRILS_2, 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->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), FORCED_MOVEMENT_NONE, 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(sSpellMgr->GetSpellIdForDifficulty(SPELL_LIGHTNING_TENDRILS, me)); - me->RemoveAura(SPELL_LIGHTNING_TENDRILS_2); - 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(); + 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(); + } +}; + +struct npc_assembly_lightning : public ScriptedAI +{ + npc_assembly_lightning(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(1ms); + } + + void MovementInform(uint32 type, uint32 /*id*/) override + { + if (type == FOLLOW_MOTION_TYPE && !_boomed) + { + _boomed = true; + me->CastSpell(me, SPELL_LIGHTNING_BLAST, true); + me->DespawnOrUnsummon(1s); + } + } +}; + +struct boss_stormcaller_brundir : public ScriptedAI +{ + boss_stormcaller_brundir(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->SetBossState(BOSS_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 = pInstance->GetCreature(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->SetBossState(BOSS_ASSEMBLY, DONE); + me->CastSpell(me, 65195, true); // credit + Talk(SAY_BRUNDIR_ENCOUNTER_DEFEATED); + } + else + { + RestoreAssemblyHealth(DATA_STEELBREAKER, DATA_MOLGEIM, pInstance); + me->CastSpell(me, SPELL_SUPERCHARGE, true); + Talk(SAY_BRUNDIR_DEATH); + } + } + + void KilledUnit(Unit* who) override + { + if (!who->IsPlayer() || 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 == sSpellMgr->GetSpellIdForDifficulty(SPELL_CHAIN_LIGHTNING, me) || spellInfo->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_LIGHTNING_WHIRL_TRIGG, me)) + _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, SPELL_LIGHTNING_TENDRILS_2, 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->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), FORCED_MOVEMENT_NONE, 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(sSpellMgr->GetSpellIdForDifficulty(SPELL_LIGHTNING_TENDRILS, me)); + me->RemoveAura(SPELL_LIGHTNING_TENDRILS_2); + 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_aura : public AuraScript @@ -853,7 +801,7 @@ class spell_assembly_meltdown : public SpellScript void HandleInstaKill(SpellEffIndex /*effIndex*/) { if (InstanceScript* instance = GetCaster()->GetInstanceScript()) - if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_STEELBREAKER))) + if (Creature* Steelbreaker = instance->GetCreature(DATA_STEELBREAKER)) Steelbreaker->AI()->DoAction(ACTION_ADD_CHARGE); } @@ -921,7 +869,7 @@ public: return false; if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(DATA_BRUNDIR))) + if (Creature* cr = instance->GetCreature(DATA_BRUNDIR)) return cr->AI()->GetData(DATA_BRUNDIR); return false; @@ -930,10 +878,10 @@ public: void AddSC_boss_assembly_of_iron() { - new boss_steelbreaker(); - new boss_runemaster_molgeim(); - new boss_stormcaller_brundir(); - new npc_assembly_lightning(); + RegisterUlduarCreatureAI(boss_steelbreaker); + RegisterUlduarCreatureAI(boss_runemaster_molgeim); + RegisterUlduarCreatureAI(boss_stormcaller_brundir); + RegisterUlduarCreatureAI(npc_assembly_lightning); RegisterSpellScript(spell_shield_of_runes_aura); RegisterSpellScript(spell_assembly_meltdown); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp index b29cf2b26..015436c7a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp @@ -97,7 +97,7 @@ enum Misc struct boss_auriaya : public BossAI { - boss_auriaya(Creature* creature) : BossAI(creature, TYPE_AURIAYA) { } + boss_auriaya(Creature* creature) : BossAI(creature, BOSS_AURIAYA) { } bool _feralDied{false}; bool _nineLives{false}; @@ -230,8 +230,8 @@ struct npc_auriaya_sanctum_sentry : public ScriptedAI void JustEngagedWith(Unit*) override { - if (me->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_AURIAYA))) + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* cr = instance->GetCreature(BOSS_AURIAYA)) cr->SetInCombatWithZone(); events.ScheduleEvent(EVENT_SAVAGE_POUNCE, 5s); @@ -241,7 +241,7 @@ struct npc_auriaya_sanctum_sentry : public ScriptedAI void Reset() override { events.Reset(); - me->CastSpell(me, SPELL_STRENGTH_OF_THE_PACK, true); + DoCastSelf(SPELL_STRENGTH_OF_THE_PACK, true); } void UpdateAI(uint32 diff) override @@ -303,8 +303,8 @@ struct npc_auriaya_feral_defender : public ScriptedAI void JustDied(Unit*) override { - if (me->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_AURIAYA))) + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* cr = instance->GetCreature(BOSS_AURIAYA)) cr->AI()->DoAction(_feralEssenceStack ? ACTION_FERAL_DEATH_WITH_STACK : ACTION_FERAL_DEATH); if (_feralEssenceStack) @@ -357,11 +357,11 @@ struct npc_auriaya_feral_defender : public ScriptedAI DoResetThreatList(); if (!UpdateVictim()) return; - me->CastSpell(me->GetVictim(), SPELL_FERAL_RUSH, true); + DoCastVictim(SPELL_FERAL_RUSH, true); events.Repeat(6s); break; case EVENT_FERAL_POUNCE: - me->CastSpell(me->GetVictim(), SPELL_FERAL_POUNCE, false); + DoCastVictim(SPELL_FERAL_POUNCE); events.Repeat(6s); break; } @@ -394,8 +394,8 @@ public: { if (target) if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_AURIAYA))) - return cr->AI()->GetData(DATA_CRAZY_CAT); + if (Creature* auriaya = instance->GetCreature(BOSS_AURIAYA)) + return auriaya->AI()->GetData(DATA_CRAZY_CAT); return false; } @@ -410,7 +410,7 @@ public: { if (target) if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_AURIAYA))) + if (Creature* cr = instance->GetCreature(BOSS_AURIAYA)) return cr->AI()->GetData(DATA_NINE_LIVES); return false; 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 6946daa78..61aaed9aa 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -193,319 +193,300 @@ enum Misc const Position homePos = {322.39f, -14.5f, 409.8f, 3.14f}; -class boss_flame_leviathan : public CreatureScript +struct boss_flame_leviathan : public BossAI { -public: - boss_flame_leviathan() : CreatureScript("boss_flame_leviathan") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_flame_leviathan(Creature* pCreature) : BossAI(pCreature, BOSS_LEVIATHAN), vehicle(me->GetVehicleKit()) { - return GetUlduarAI(pCreature); + assert(vehicle); } - struct boss_flame_leviathanAI : public ScriptedAI + Vehicle* vehicle; + + 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 { - boss_flame_leviathanAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me) + _JustReachedHome(); + // For achievement + instance->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()) + BossAI::AttackStart(veh); + else + BossAI::AttackStart(who); + } + + void JustEngagedWith(Unit*) override + { + ScheduleEvents(); + Talk(FLAME_LEVIATHAN_SAY_AGGRO); + + me->setActive(true); + me->SetHomePosition(homePos); + TurnHealStations(false); + ActivateTowers(); + instance->SetBossState(BOSS_LEVIATHAN, SPECIAL); + + BindPlayers(); + me->SetInCombatWithZone(); + + if (!_startTimer) { - m_pInstance = pCreature->GetInstanceScript(); - assert(vehicle); + TurnGates(true, false); } + } - 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 + void InitializeAI() override + { + if (instance->GetBossState(BOSS_LEVIATHAN) == SPECIAL) { - // 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); - } + me->UpdatePosition(homePos); + me->StopMovingOnCurrentPos(); } - void InitializeAI() override - { - if (m_pInstance && m_pInstance->GetData(TYPE_LEVIATHAN) == SPECIAL) - { - me->SetHomePosition(homePos); - me->UpdatePosition(homePos); - me->StopMovingOnCurrentPos(); - } + BossAI::InitializeAI(); + } - 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 (instance->GetBossState(BOSS_LEVIATHAN) != SPECIAL) + { + instance->SetBossState(BOSS_LEVIATHAN, NOT_STARTED); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + } + else + { + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + instance->SetData(DATA_VEHICLE_SPAWN, VEHICLE_POS_LEVIATHAN); + _startTimer = 0; } - void Reset() override + 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) { - // 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) + _startTimer += diff; + if (_startTimer >= 4000) { - if (m_pInstance->GetData(TYPE_LEVIATHAN) != SPECIAL) - { - m_pInstance->SetData(TYPE_LEVIATHAN, NOT_STARTED); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - } + // Colossus dead, players in range + if (me->FindNearestCreature(NPC_ULDUAR_COLOSSUS, 250.0f, true) || !SelectTargetFromPlayerList(250.0f)) + _startTimer = 1; else { - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - m_pInstance->SetData(DATA_VEHICLE_SPAWN, VEHICLE_POS_LEVIATHAN); _startTimer = 0; + _speakTimer = 1; } } - - TurnGates(false, false); - TurnHealStations(true); + return; } - uint32 GetData(uint32 param) const override + if (_speakTimer) { - 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) + _speakTimer += diff; + if (_speakTimer <= 10000) { - _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; + _speakTimer = 10000; + RadioSay(BRANN_RADIO_SAY_FL_START_0); } - - if (_speakTimer) + else if (_speakTimer > 16000 && _speakTimer < 20000) { - _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->GetMotionMaster()->MovePoint(0, homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), FORCED_MOVEMENT_NONE, 100.0f); - _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; + _speakTimer = 20000; + RadioSay(BRANN_RADIO_SAY_FL_START_1); } - - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) + else if (_speakTimer > 24000 && _speakTimer < 40000) { - 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); + _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->GetMotionMaster()->MovePoint(0, homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), FORCED_MOVEMENT_NONE, 100.0f); + _speakTimer = 60000; + } + else if (_speakTimer > 63500) + { + me->SetInCombatWithZone(); + if (!me->GetVictim()) + { 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->IsCreature()) - 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(); } + _speakTimer = 0; } + return; } - void DoAction(int32 action) override + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - if (action == ACTION_DESTROYED_TURRET) - { - ++_destroyedTurretCount; - - if (_destroyedTurretCount == RAID_MODE(2, 4)) + case EVENT_POSITION_CHECK: + if (me->GetPositionX() > 450 || me->GetPositionX() < 120) { - _destroyedTurretCount = 0; - me->CastSpell(me, SPELL_SYSTEMS_SHUTDOWN, true); + 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->IsCreature()) + 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() +void boss_flame_leviathan::BindPlayers() { me->GetMap()->ToInstanceMap()->PermBindAllPlayers(); } -void boss_flame_leviathan::boss_flame_leviathanAI::RadioSay(uint8 textid) +void boss_flame_leviathan::RadioSay(uint8 textid) { if (Creature* r = me->SummonCreature(NPC_BRANN_RADIO, me->GetPositionX() - 150, me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 5000)) { @@ -513,13 +494,13 @@ void boss_flame_leviathan::boss_flame_leviathanAI::RadioSay(uint8 textid) } } -void boss_flame_leviathan::boss_flame_leviathanAI::ActivateTowers() +void boss_flame_leviathan::ActivateTowers() { _towersCount = 0; me->ResetLootMode(); for (uint32 i = EVENT_TOWER_OF_LIFE_DESTROYED; i <= EVENT_TOWER_OF_FLAMES_DESTROYED; ++i) { - if (m_pInstance->GetData(i)) + if (instance->GetData(i)) { ++_towersCount; @@ -547,35 +528,35 @@ void boss_flame_leviathan::boss_flame_leviathanAI::ActivateTowers() } } -void boss_flame_leviathan::boss_flame_leviathanAI::TurnGates(bool _start, bool _death) +void boss_flame_leviathan::TurnGates(bool _start, bool _death) { - if (!m_pInstance) + if (!instance) return; if (_start) { // first one is ALWAYS turned on, unless leviathan is beaten GameObject* go = nullptr; - if ((go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(DATA_LIGHTNING_WALL2)))) + if ((go = instance->GetGameObject(DATA_LIGHTNING_WALL2))) go->SetGoState(GO_STATE_READY); - if (m_pInstance->GetData(TYPE_LEVIATHAN) == NOT_STARTED) - if ((go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_LEVIATHAN_DOORS)))) + if (instance->GetBossState(BOSS_LEVIATHAN) == NOT_STARTED) + if ((go = instance->GetGameObject(DATA_LEVIATHAN_DOORS))) go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); } else { GameObject* go = nullptr; if (_death) - if ((go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(DATA_LIGHTNING_WALL1)))) + if ((go = instance->GetGameObject(DATA_LIGHTNING_WALL1))) go->SetGoState(GO_STATE_ACTIVE); - if ((go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(DATA_LIGHTNING_WALL2)))) + if ((go = instance->GetGameObject(DATA_LIGHTNING_WALL2))) go->SetGoState(GO_STATE_ACTIVE); - if ((go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_LEVIATHAN_DOORS)))) + if ((go = instance->GetGameObject(DATA_LEVIATHAN_DOORS))) { - if (m_pInstance->GetData(TYPE_LEVIATHAN) == SPECIAL || m_pInstance->GetData(TYPE_LEVIATHAN) == DONE) + if (instance->GetBossState(BOSS_LEVIATHAN) == SPECIAL || instance->GetBossState(BOSS_LEVIATHAN) == DONE) go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); else go->SetGoState(GO_STATE_READY); @@ -583,29 +564,29 @@ void boss_flame_leviathan::boss_flame_leviathanAI::TurnGates(bool _start, bool _ } } -void boss_flame_leviathan::boss_flame_leviathanAI::TurnHealStations(bool _apply) +void boss_flame_leviathan::TurnHealStations(bool _apply) { - if (!m_pInstance) + if (!instance) return; GameObject* go = nullptr; if (_apply) { - if ((go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(DATA_REPAIR_STATION1)))) + if ((go = instance->GetGameObject(DATA_REPAIR_STATION1))) go->SetLootState(GO_READY); - if ((go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(DATA_REPAIR_STATION2)))) + if ((go = instance->GetGameObject(DATA_REPAIR_STATION2))) go->SetLootState(GO_READY); } else { - if ((go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(DATA_REPAIR_STATION1)))) + if ((go = instance->GetGameObject(DATA_REPAIR_STATION1))) go->SetLootState(GO_ACTIVATED); - if ((go = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(DATA_REPAIR_STATION2)))) + if ((go = instance->GetGameObject(DATA_REPAIR_STATION2))) go->SetLootState(GO_ACTIVATED); } } -void boss_flame_leviathan::boss_flame_leviathanAI::ScheduleEvents() +void boss_flame_leviathan::ScheduleEvents() { events.RescheduleEvent(EVENT_MISSILE, 5s); events.RescheduleEvent(EVENT_VENT, 20s); @@ -617,7 +598,7 @@ void boss_flame_leviathan::boss_flame_leviathanAI::ScheduleEvents() events.RescheduleEvent(EVENT_PURSUE, 0ms); } -void boss_flame_leviathan::boss_flame_leviathanAI::SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) +void boss_flame_leviathan::SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) { if (spellInfo->Id == SPELL_SYSTEMS_SHUTDOWN) { @@ -634,17 +615,14 @@ void boss_flame_leviathan::boss_flame_leviathanAI::SpellHit(Unit* /*caster*/, S me->InterruptNonMeleeSpells(false); } -void boss_flame_leviathan::boss_flame_leviathanAI::JustDied(Unit*) +void boss_flame_leviathan::JustDied(Unit*) { // Despawn Lashers, do before summons clear summons.DoAction(ACTION_DESPAWN_ADDS); summons.DespawnAll(); - if (m_pInstance) - { - m_pInstance->SetData(TYPE_LEVIATHAN, DONE); - m_pInstance->SetData(DATA_VEHICLE_SPAWN, VEHICLE_POS_NONE); - } + instance->SetBossState(BOSS_LEVIATHAN, DONE); + instance->SetData(DATA_VEHICLE_SPAWN, VEHICLE_POS_NONE); Talk(FLAME_LEVIATHAN_SAY_DEATH); @@ -652,7 +630,7 @@ void boss_flame_leviathan::boss_flame_leviathanAI::JustDied(Unit*) BindPlayers(); } -void boss_flame_leviathan::boss_flame_leviathanAI::KilledUnit(Unit* who) +void boss_flame_leviathan::KilledUnit(Unit* who) { if (who == me->GetVictim()) events.RescheduleEvent(EVENT_PURSUE, 0ms); @@ -661,7 +639,7 @@ void boss_flame_leviathan::boss_flame_leviathanAI::KilledUnit(Unit* who) Talk(FLAME_LEVIATHAN_SAY_SLAY); } -void boss_flame_leviathan::boss_flame_leviathanAI::SummonTowerHelpers(uint8 towerId) +void boss_flame_leviathan::SummonTowerHelpers(uint8 towerId) { if (towerId == TOWER_OF_LIFE) { @@ -691,7 +669,7 @@ void boss_flame_leviathan::boss_flame_leviathanAI::SummonTowerHelpers(uint8 towe } } -void boss_flame_leviathan::boss_flame_leviathanAI::SpellHitTarget(Unit* target, SpellInfo const* spell) +void boss_flame_leviathan::SpellHitTarget(Unit* target, SpellInfo const* spell) { if (spell->Id != SPELL_PURSUED) return; @@ -706,729 +684,597 @@ void boss_flame_leviathan::boss_flame_leviathanAI::SpellHitTarget(Unit* target, } } -class boss_flame_leviathan_seat : public CreatureScript +struct boss_flame_leviathan_seat : public VehicleAI { -public: - boss_flame_leviathan_seat() : CreatureScript("boss_flame_leviathan_seat") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_flame_leviathan_seat(Creature* creature) : VehicleAI(creature), vehicle(creature->GetVehicleKit()) { - return GetUlduarAI(pCreature); + ASSERT(vehicle); + me->SetReactState(REACT_PASSIVE); } - struct boss_flame_leviathan_seatAI : public VehicleAI + Vehicle* vehicle; + uint32 _despawnTimer; + + void EnterEvadeMode(EvadeReason /*why*/) override { - 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(1ms); - } - } - - VehicleAI::UpdateAI(diff); - } - - void AttackStart(Unit*) override { } - - void PassengerBoarded(Unit* who, int8 seatId, bool apply) override - { - if (!who->IsPlayer() || !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->IsCreature()) - 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->IsPlayer() || !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); + vehicle->InstallAllAccessories(false); } - struct npc_freya_wardAI : public NullCreatureAI + void Reset() override { - 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); + _despawnTimer = !me->GetMap()->Is25ManRaid(); } - struct npc_hodirs_furyAI : public NullCreatureAI + void UpdateAI(uint32 diff) override { - npc_hodirs_furyAI(Creature* c) : NullCreatureAI(c) + if (_despawnTimer) { - } - - uint32 _timeToHit; - uint32 _switchTargetTimer; - - void Reset() override - { - _timeToHit = 0; - _switchTargetTimer = 30000; - me->SetWalk(true); - - if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_BLUE, me)) + _despawnTimer += diff; + if (_despawnTimer >= 2000) { - aur->SetMaxDuration(-1); - aur->SetDuration(-1); + _despawnTimer = 0; + if (Vehicle* veh = me->GetVehicle()) + if (veh->GetPassenger(0) == me || veh->GetPassenger(1) == me) + me->DespawnOrUnsummon(1ms); } } - void MovementInform(uint32 type, uint32 /*param*/) override - { - if (type == FOLLOW_MOTION_TYPE && !_timeToHit) - { - _timeToHit = 1; - _switchTargetTimer = 0; - me->SetControlled(true, UNIT_STATE_STUNNED); - } - } + VehicleAI::UpdateAI(diff); + } - void UpdateAI(uint32 diff) override + void AttackStart(Unit*) override { } + + void PassengerBoarded(Unit* who, int8 seatId, bool apply) override + { + if (!who->IsPlayer() || !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 (_timeToHit) + if (Unit* turret = me->GetVehicleKit()->GetPassenger(SEAT_TURRET)) { - _timeToHit += diff; - if (_timeToHit >= 5000) + if (apply) { - 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; + turret->ReplaceAllUnitFlags(UNIT_FLAG_NONE); + turret->GetAI()->AttackStart(who); + if (Creature* leviathan = me->GetVehicleCreatureBase()) + leviathan->AI()->Talk(FLAME_LEVIATHAN_SAY_PLAYER_RIDING); } else - _switchTargetTimer = 25000; + { + turret->ReplaceAllUnitFlags(UNIT_FLAG_NOT_SELECTABLE); + turret->SetImmuneToAll(true); + if (turret->IsCreature()) + turret->ToCreature()->AI()->EnterEvadeMode(); + } } } - }; + } }; -class npc_mimirons_inferno : public CreatureScript +struct boss_flame_leviathan_defense_turret : public TurretAI { -public: - npc_mimirons_inferno() : CreatureScript("npc_mimirons_inferno") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_flame_leviathan_defense_turret(Creature* creature) : TurretAI(creature) { - return GetUlduarAI(creature); + _setHealth = false; + _instance = creature->GetInstanceScript(); } - struct npc_mimirons_infernoAI : public npc_escortAI + InstanceScript* _instance; + + bool _setHealth; + void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override { - npc_mimirons_infernoAI(Creature* creature) : npc_escortAI(creature), summons(me) + if (!CanAIAttack(who)) { - me->SetReactState(REACT_PASSIVE); + _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 = _instance->GetCreature(BOSS_LEVIATHAN)) + leviathan->AI()->DoAction(ACTION_DESTROYED_TURRET); + } + + bool CanAIAttack(Unit const* who) const override + { + if (!who || !who->IsPlayer() || !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; } - SummonList summons; - uint32 _spellTimer; - uint32 _recastTimer; + TurretAI::UpdateAI(diff); + } - void AttackStart(Unit*) override { } - void MoveInLineOfSight(Unit*) override { } - void WaypointReached(uint32 /*waypointId*/) override { } + 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(); + } +}; - void DoAction(int32 param) override +struct boss_flame_leviathan_overload_device : public NullCreatureAI +{ + boss_flame_leviathan_overload_device(Creature* creature) : NullCreatureAI(creature) + { + } + + void OnSpellClick(Unit* /*clicker*/, bool& result) override + { + if (!result) + return; + + if (me->GetVehicle()) { - if (param == ACTION_DESPAWN_ADDS) - summons.DespawnAll(); + 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(); + } } + } +}; - void Reset() override - { - summons.DespawnAll(); - _spellTimer = 0; - me->SetWalk(true); - Start(false, ObjectGuid::Empty, nullptr, false, true); - if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_YELLOW, me)) +struct npc_freya_ward : public NullCreatureAI +{ + npc_freya_ward(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 { 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 + void JustSummoned(Creature* cr) override { - npc_thorims_hammerAI(Creature* c) : NullCreatureAI(c) - { - } + _summoned = true; + summons.Summon(cr); + } - uint32 _beamTimer; - uint32 _finishTime; - uint32 _removeTimer; + void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } - void Reset() override + void UpdateAI(uint32 diff) override + { + if (_summoned) { - _finishTime = 5000 + rand() % 15000; - _beamTimer = 1; - _removeTimer = 0; - me->CastSpell(me, SPELL_FREYA_DUMMY_BLUE, true); - } - - void UpdateAI(uint32 diff) override - { - if (_beamTimer) + for (SummonList::const_iterator itr = summons.begin(); itr != summons.end();) { - _beamTimer += diff; - if (_beamTimer >= _finishTime) + Creature* summon = ObjectAccessor::GetCreature(*me, *itr); + ++itr; + if (summon) { - 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(5s); + summon->ToTempSummon()->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN); + if (Unit* target = summon->SelectNearestTarget(200.0f)) + summon->AI()->AttackStart(target); } } - if (_removeTimer) + _summoned = false; + } + + _castTimer += diff; + if (_castTimer >= 29 * IN_MILLISECONDS) + { + if (Creature* cr = me->FindNearestCreature(NPC_FREYA_WARD_TARGET, 60.0f, true)) { - _removeTimer += diff; - if (_removeTimer >= 3 * IN_MILLISECONDS) - { - _removeTimer = 0; - me->RemoveAura(SPELL_FREYA_DUMMY_BLUE); - } + me->CastSpell(cr, SPELL_FREYA_WARD, false); + me->CastSpell(cr, 62947 /*SPELL_FREYA_WARD_SECOND_SUMMON*/, false); } + + _castTimer = 0; } - }; -}; - -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 + void DoAction(int32 param) override { - 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); - } - }; + if (param == ACTION_DESPAWN_ADDS) + summons.DespawnAll(); + } }; -class npc_brann_radio : public CreatureScript +struct npc_hodirs_fury : public NullCreatureAI { -public: - npc_brann_radio() : CreatureScript("npc_brann_radio") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_hodirs_fury(Creature* c) : NullCreatureAI(c) { - return GetUlduarAI(pCreature); } - struct npc_brann_radioAI : public NullCreatureAI + uint32 _timeToHit; + uint32 _switchTargetTimer; + + void Reset() override { - npc_brann_radioAI(Creature* c) : NullCreatureAI(c) + _timeToHit = 0; + _switchTargetTimer = 30000; + me->SetWalk(true); + + if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_BLUE, me)) { - _lock = (me->GetInstanceScript() && me->GetInstanceScript()->GetData(TYPE_LEVIATHAN) > NOT_STARTED); - _helpLock = _lock; + aur->SetMaxDuration(-1); + aur->SetDuration(-1); } + } - bool _lock; - bool _helpLock; - - void Reset() override + void MovementInform(uint32 type, uint32 /*param*/) override + { + if (type == FOLLOW_MOTION_TYPE && !_timeToHit) { - me->SetReactState(REACT_AGGRESSIVE); + _timeToHit = 1; + _switchTargetTimer = 0; + me->SetControlled(true, UNIT_STATE_STUNNED); } + } - void MoveInLineOfSight(Unit* who) override + void UpdateAI(uint32 diff) override + { + if (_timeToHit) { - if (!_lock) + _timeToHit += diff; + if (_timeToHit >= 5000) { - if (!who->IsPlayer() && !who->IsVehicle()) + 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; - - // 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; - } } + me->SetControlled(false, UNIT_STATE_STUNNED); + me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f); + _switchTargetTimer = 0; } + else + _switchTargetTimer = 25000; } - }; + } }; -class npc_storm_beacon_spawn : public CreatureScript +struct npc_mimirons_inferno : public npc_escortAI { -public: - npc_storm_beacon_spawn() : CreatureScript("npc_storm_beacon_spawn") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_mimirons_inferno(Creature* creature) : npc_escortAI(creature), summons(me) { - return GetUlduarAI(pCreature); + me->SetReactState(REACT_PASSIVE); } - struct npc_storm_beacon_spawnAI : public NullCreatureAI + SummonList summons; + uint32 _spellTimer; + uint32 _recastTimer; + + void AttackStart(Unit*) override { } + void MoveInLineOfSight(Unit*) override { } + void WaypointReached(uint32 /*waypointId*/) override { } + + void DoAction(int32 param) override { - npc_storm_beacon_spawnAI(Creature* c) : NullCreatureAI(c) + if (param == ACTION_DESPAWN_ADDS) + summons.DespawnAll(); + } + + void Reset() override + { + summons.DespawnAll(); + _spellTimer = 0; + me->SetWalk(true); + Start(false, ObjectGuid::Empty, nullptr, false, true); + if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_YELLOW, me)) { - _amount = 0; - _checkTimer = 0; + aur->SetMaxDuration(-1); + aur->SetDuration(-1); } + } - uint8 _amount; - uint32 _checkTimer; + void JustSummoned(Creature* cr) override { summons.Summon(cr); } + void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + npc_escortAI::UpdateAI(diff); + + _spellTimer += diff; + if (_spellTimer >= 2000) { - if (_amount < 40) + 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; + } + } +}; + +struct npc_thorims_hammer : public NullCreatureAI +{ + npc_thorims_hammer(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) { - _checkTimer += diff; - if (_checkTimer >= 4000) + 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(5s); + } + } + if (_removeTimer) + { + _removeTimer += diff; + if (_removeTimer >= 3 * IN_MILLISECONDS) + { + _removeTimer = 0; + me->RemoveAura(SPELL_FREYA_DUMMY_BLUE); + } + } + } +}; + +struct npc_pool_of_tar : public NullCreatureAI +{ + npc_pool_of_tar(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); + } +}; + +struct npc_brann_radio : public NullCreatureAI +{ + npc_brann_radio(Creature* c) : NullCreatureAI(c) + { + _lock = (me->GetInstanceScript() && me->GetInstanceScript()->GetBossState(BOSS_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->IsPlayer() && !who->IsVehicle()) + return; + + // MIMIRON + else if (me->GetDistance2d(-81.9207f, 111.432f) < 5.0f) + { + if (me->GetDistance2d(who) <= 60.0f && who->GetPositionZ() > 430.0f) { - _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); - } + 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 boss_flame_leviathan_safety_container : public CreatureScript +struct npc_storm_beacon_spawn : public NullCreatureAI { -public: - boss_flame_leviathan_safety_container() : CreatureScript("boss_flame_leviathan_safety_container") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_storm_beacon_spawn(Creature* c) : NullCreatureAI(c) { - return GetUlduarAI(pCreature); + _amount = 0; + _checkTimer = 0; } - struct boss_flame_leviathan_safety_containerAI : public NullCreatureAI + uint8 _amount; + uint32 _checkTimer; + + void UpdateAI(uint32 diff) override { - boss_flame_leviathan_safety_containerAI(Creature* c) : NullCreatureAI(c) + if (_amount < 40) { - _allowTimer = 0; - } - - uint32 _allowTimer; - - void MovementInform(uint32 /*type*/, uint32 id) override - { - if (id == me->GetEntry()) + _checkTimer += diff; + if (_checkTimer >= 4000) { - if (Creature* liquid = me->SummonCreature(NPC_LIQUID, *me)) + _checkTimer = 0; + if (Unit* target = me->SelectNearbyTarget(nullptr, 80.0f)) { - liquid->CastSpell(liquid, SPELL_LIQUID_PYRITE, true); - liquid->CastSpell(liquid, SPELL_DUST_CLOUD_IMPACT, true); + ++_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); } - - me->DespawnOrUnsummon(1ms); } } - - 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 +struct boss_flame_leviathan_safety_container : public NullCreatureAI { -public: - npc_mechanolift() : CreatureScript("npc_mechanolift") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_flame_leviathan_safety_container(Creature* c) : NullCreatureAI(c) { - return GetUlduarAI(pCreature); + _allowTimer = 0; } - struct npc_mechanoliftAI : public NullCreatureAI + uint32 _allowTimer; + + void MovementInform(uint32 /*type*/, uint32 id) override { - npc_mechanoliftAI(Creature* c) : NullCreatureAI(c) + if (id == me->GetEntry()) { - me->SetSpeed(MOVE_RUN, rand_norm() + 0.5f); + 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(1ms); + } + } + + 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); + } + } +}; + +struct npc_mechanolift : public NullCreatureAI +{ + npc_mechanolift(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()->MoveWaypoint(3000000 + urand(0, 11), true); + _startTimer = 0; + } } - int32 _startTimer; - uint32 _evadeTimer; - - void Reset() override + _evadeTimer += diff; + if (_evadeTimer >= 10000) { - _startTimer = urand(1, 5000); + _EnterEvadeMode(); _evadeTimer = 0; } - - void UpdateAI(uint32 diff) override - { - if (_startTimer) - { - _startTimer -= diff; - if (_startTimer <= 0) - { - me->GetMotionMaster()->MoveWaypoint(3000000 + urand(0, 11), true); - _startTimer = 0; - } - } - - _evadeTimer += diff; - if (_evadeTimer >= 10000) - { - _EnterEvadeMode(); - _evadeTimer = 0; - } - } - }; + } }; class go_ulduar_tower : public GameObjectScript @@ -2018,23 +1864,23 @@ public: void AddSC_boss_flame_leviathan() { - new boss_flame_leviathan(); - new boss_flame_leviathan_seat(); - new boss_flame_leviathan_defense_turret(); - new boss_flame_leviathan_overload_device(); - new npc_pool_of_tar(); + RegisterUlduarCreatureAI(boss_flame_leviathan); + RegisterUlduarCreatureAI(boss_flame_leviathan_seat); + RegisterUlduarCreatureAI(boss_flame_leviathan_defense_turret); + RegisterUlduarCreatureAI(boss_flame_leviathan_overload_device); + RegisterUlduarCreatureAI(npc_pool_of_tar); // Hard Mode - new npc_freya_ward(); - new npc_thorims_hammer(); - new npc_mimirons_inferno(); - new npc_hodirs_fury(); + RegisterUlduarCreatureAI(npc_freya_ward); + RegisterUlduarCreatureAI(npc_thorims_hammer); + RegisterUlduarCreatureAI(npc_mimirons_inferno); + RegisterUlduarCreatureAI(npc_hodirs_fury); // Helpers - new npc_brann_radio(); - new npc_storm_beacon_spawn(); - new boss_flame_leviathan_safety_container(); - new npc_mechanolift(); + RegisterUlduarCreatureAI(npc_brann_radio); + RegisterUlduarCreatureAI(npc_storm_beacon_spawn); + RegisterUlduarCreatureAI(boss_flame_leviathan_safety_container); + RegisterUlduarCreatureAI(npc_mechanolift); // GOs new go_ulduar_tower(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index 61841533b..cb3668d45 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -198,869 +198,763 @@ enum Misc CRITERIA_LUMBERJACKED = 21686, }; -class boss_freya : public CreatureScript +struct boss_freya : public BossAI { -public: - boss_freya() : CreatureScript("boss_freya") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_freya(Creature* pCreature) : BossAI(pCreature, BOSS_FREYA) { - return GetUlduarAI(pCreature); + if (!me->IsAlive()) + instance->SetBossState(BOSS_FREYA, DONE); } - struct boss_freyaAI : public ScriptedAI + uint8 _waveNumber; + uint8 _trioKilled; + uint8 _spawnedAmount; + uint8 _lumberjacked; + bool _respawningTrio; + bool _backToNature; + uint8 _deforestation; + + ObjectGuid _elderGUID[3]; + + void Reset() override { - boss_freyaAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + _Reset(); + + for (uint8 i = 0; i < 3; ++i) { - m_pInstance = pCreature->GetInstanceScript(); - if (!me->IsAlive()) - if (m_pInstance) - m_pInstance->SetData(TYPE_FREYA, DONE); + if (!_elderGUID[i]) + continue; + + if (Creature* elder = ObjectAccessor::GetCreature(*me, _elderGUID[i])) + elder->AI()->EnterEvadeMode(); + + _elderGUID[i].Clear(); } - InstanceScript* m_pInstance; - EventMap events; - SummonList summons; + _lumberjacked = 0; + _spawnedAmount = 0; + _trioKilled = 0; + _waveNumber = urand(1, 3); + _respawningTrio = false; + _backToNature = true; + _deforestation = 0; + } - uint8 _waveNumber; - uint8 _trioKilled; - uint8 _spawnedAmount; - uint8 _lumberjacked; - bool _respawningTrio; - bool _backToNature; - uint8 _deforestation; + void KilledUnit(Unit* victim) override + { + if (!victim->IsPlayer() || urand(0, 2)) + return; - ObjectGuid _elderGUID[3]; + Talk(SAY_SLAY); + } - void Reset() override + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (damage >= me->GetHealth()) { - if (m_pInstance && m_pInstance->GetData(TYPE_FREYA) != DONE) - m_pInstance->SetData(TYPE_FREYA, NOT_STARTED); + damage = 0; + if (instance->GetBossState(BOSS_FREYA) != DONE) + { + Talk(SAY_DEATH); - events.Reset(); - summons.DespawnAll(); + 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 + + 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 + me->CastSpell(me, 65074, true); // credit + instance->SetBossState(BOSS_FREYA, DONE); + + scheduler.Schedule(14s, [this](TaskContext /*context*/) + { + DoCastSelf(SPELL_TELEPORT); + }); + } + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_TELEPORT) + { + me->DespawnOrUnsummon(); + instance->SetData(EVENT_KEEPER_TELEPORTED, 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); + } + BossAI::JustSummoned(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) + { + ++_lumberjacked; + if (_lumberjacked == 1) + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_LUMBERJACKED); + else if (_lumberjacked == 3) + instance->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) + instance->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]) - continue; + if (_elderGUID[i]) + ++_count; - if (Creature* elder = ObjectAccessor::GetCreature(*me, _elderGUID[i])) - elder->AI()->EnterEvadeMode(); + return _count; + } + if (param == DATA_BACK_TO_NATURE) + return _backToNature; - _elderGUID[i].Clear(); - } + return 0; + } - _lumberjacked = 0; - _spawnedAmount = 0; - _trioKilled = 0; - _waveNumber = urand(1, 3); - _respawningTrio = false; - _backToNature = true; - _deforestation = 0; + void JustReachedHome() override { _JustReachedHome(); 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 (instance->GetBossState(BOSS_FREYA) != DONE) + instance->SetBossState(BOSS_FREYA, IN_PROGRESS); + + // HARD MODE CHECKS + Creature* elder = instance->GetCreature(DATA_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(); } - void KilledUnit(Unit* victim) override + elder = instance->GetCreature(DATA_ELDER_IRONBRANCH); + if (elder && elder->IsAlive()) { - if (!victim->IsPlayer() || urand(0, 2)) - return; + elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true); + elder->CastSpell(elder, SPELL_IRONBRANCH_ESSENCE, true); + elder->SetInCombatWithZone(); - Talk(SAY_SLAY); + events.ScheduleEvent(EVENT_FREYA_IRON_ROOT, 20s); + _elderGUID[1] = elder->GetGUID(); } - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + elder = instance->GetCreature(DATA_ELDER_BRIGHTLEAF); + if (elder && elder->IsAlive()) { - 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 - - 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); - } - - scheduler.Schedule(14s, [this](TaskContext /*context*/) - { - DoCastSelf(SPELL_TELEPORT); - }); - } - } - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_TELEPORT) - { - me->DespawnOrUnsummon(); - m_pInstance->SetData(EVENT_KEEPER_TELEPORTED, 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 + 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 + { + scheduler.Update(diff); + 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); - 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 - { - scheduler.Update(diff); - 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)) + _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) { - 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)) { - 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(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; + me->CastSpell(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), SPELL_SUMMON_LIFEBINDER, true); break; - case EVENT_FREYA_NATURE_BOMB: + } + 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) { - 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; + if (me->GetDistance(itr->GetSource()) > 70 || !itr->GetSource()->IsAlive()) + continue; - me->CastSpell(itr->GetSource(), SPELL_NATURE_BOMB_FLIGHT, true); + me->CastSpell(itr->GetSource(), SPELL_NATURE_BOMB_FLIGHT, true); - if (!(--_minCount)) - break; - } - events.Repeat(18s); - break; + if (!(--_minCount)) + break; } - case EVENT_FREYA_BERSERK: - Talk(SAY_BERSERK); - me->CastSpell(me, SPELL_BERSERK, true); + events.Repeat(18s); 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: + } + 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); - 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(); + 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; } - 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); + DoMeleeAttackIfReady(); } - struct boss_freya_elder_stonebarkAI : public ScriptedAI + bool CheckEvadeIfOutOfCombatArea() const override { - 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(); - } - }; + return me->GetPositionX() < 2135.0f; + } }; -class boss_freya_elder_brightleaf : public CreatureScript +struct boss_freya_elder_stonebark : public ScriptedAI { -public: - boss_freya_elder_brightleaf() : CreatureScript("boss_freya_elder_brightleaf") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_freya_elder_stonebark(Creature* pCreature) : ScriptedAI(pCreature) { - return GetUlduarAI(pCreature); } - struct boss_freya_elder_brightleafAI : public ScriptedAI + EventMap events; + uint8 _chargesCount; + + void Reset() override { - boss_freya_elder_brightleafAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) + 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 = me->GetInstanceScript()->GetCreature(BOSS_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; } - 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(); - } - }; + DoMeleeAttackIfReady(); + } }; -class boss_freya_elder_ironbranch : public CreatureScript +struct boss_freya_elder_brightleaf : public ScriptedAI { -public: - boss_freya_elder_ironbranch() : CreatureScript("boss_freya_elder_ironbranch") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_freya_elder_brightleaf(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) { - return GetUlduarAI(pCreature); } - struct boss_freya_elder_ironbranchAI : public ScriptedAI + EventMap events; + SummonList summons; + + void Reset() override { - boss_freya_elder_ironbranchAI(Creature* pCreature) : ScriptedAI(pCreature) + 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 = me->GetInstanceScript()->GetCreature(BOSS_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; } - 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(); - } - }; + DoMeleeAttackIfReady(); + } }; -class boss_freya_iron_root : public CreatureScript +struct boss_freya_elder_ironbranch : public ScriptedAI { -public: - boss_freya_iron_root() : CreatureScript("boss_freya_iron_root") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_freya_elder_ironbranch(Creature* pCreature) : ScriptedAI(pCreature) { - return GetUlduarAI(pCreature); } - struct boss_freya_iron_rootAI : public NullCreatureAI + EventMap events; + + void Reset() override { - boss_freya_iron_rootAI(Creature* pCreature) : NullCreatureAI(pCreature) { } + events.Reset(); + } - void JustDied(Unit* /*killer*/) override + 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 = me->GetInstanceScript()->GetCreature(BOSS_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()) { - 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(sSpellMgr->GetSpellIdForDifficulty(SPELL_IRON_ROOTS_DAMAGE, me)); - else - target->RemoveAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_IRON_ROOTS_FREYA_DAMAGE, me)); - } + 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_lifebinder : public CreatureScript +struct boss_freya_iron_root : public NullCreatureAI { -public: - boss_freya_lifebinder() : CreatureScript("boss_freya_lifebinder") { } + boss_freya_iron_root(Creature* pCreature) : NullCreatureAI(pCreature) { } - CreatureAI* GetAI(Creature* pCreature) const override + 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(sSpellMgr->GetSpellIdForDifficulty(SPELL_IRON_ROOTS_DAMAGE, me)); + else + target->RemoveAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_IRON_ROOTS_FREYA_DAMAGE, me)); + } + } +}; + +struct boss_freya_lifebinder : public NullCreatureAI +{ + boss_freya_lifebinder(Creature* pCreature) : NullCreatureAI(pCreature) { - return GetUlduarAI(pCreature); } - struct boss_freya_lifebinderAI : public NullCreatureAI + uint32 _healTimer; + + void Reset() override { - boss_freya_lifebinderAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - } + me->CastSpell(me, SPELL_LIFEBINDER_VISUAL, true); + me->CastSpell(me, SPELL_LIFEBINDER_PHERONOMES, true); + me->CastSpell(me, SPELL_AUTO_GROW, true); + _healTimer = 0; + } - uint32 _healTimer; - - void Reset() override + void UpdateAI(uint32 diff) override + { + _healTimer += diff; + if (_healTimer >= 12000) { - me->CastSpell(me, SPELL_LIFEBINDER_VISUAL, true); - me->CastSpell(me, SPELL_LIFEBINDER_PHERONOMES, true); - me->CastSpell(me, SPELL_AUTO_GROW, true); + me->RemoveAurasDueToSpell(SPELL_AUTO_GROW); + me->CastSpell(me, SPELL_LIFEBINDER_HEAL, true); + me->DespawnOrUnsummon(2s); _healTimer = 0; } - - void UpdateAI(uint32 diff) override - { - _healTimer += diff; - if (_healTimer >= 12000) - { - me->RemoveAurasDueToSpell(SPELL_AUTO_GROW); - me->CastSpell(me, SPELL_LIFEBINDER_HEAL, true); - me->DespawnOrUnsummon(2s); - _healTimer = 0; - } - } - }; + } }; -class boss_freya_healthy_spore : public CreatureScript +struct boss_freya_healthy_spore : public NullCreatureAI { -public: - boss_freya_healthy_spore() : CreatureScript("boss_freya_healthy_spore") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_freya_healthy_spore(Creature* pCreature) : NullCreatureAI(pCreature) { - return GetUlduarAI(pCreature); } - struct boss_freya_healthy_sporeAI : public NullCreatureAI + uint32 _despawnTimer; + + void Reset() override { - boss_freya_healthy_sporeAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - } + me->CastSpell(me, SPELL_POTENT_PHEROMONES, true); + me->CastSpell(me, SPELL_HEALTHY_SPORE_VISUAL, true); + me->CastSpell(me, SPELL_AUTO_GROW, true); + _despawnTimer = 0; + } - uint32 _despawnTimer; - - void Reset() override + void UpdateAI(uint32 diff) override + { + _despawnTimer += diff; + if (_despawnTimer >= 22000) { - me->CastSpell(me, SPELL_POTENT_PHEROMONES, true); - me->CastSpell(me, SPELL_HEALTHY_SPORE_VISUAL, true); - me->CastSpell(me, SPELL_AUTO_GROW, true); + me->RemoveAurasDueToSpell(SPELL_AUTO_GROW); + me->DespawnOrUnsummon(2200ms); _despawnTimer = 0; } - - void UpdateAI(uint32 diff) override - { - _despawnTimer += diff; - if (_despawnTimer >= 22000) - { - me->RemoveAurasDueToSpell(SPELL_AUTO_GROW); - me->DespawnOrUnsummon(2200ms); - _despawnTimer = 0; - } - } - }; + } }; -class boss_freya_summons : public CreatureScript +struct boss_freya_summons : public ScriptedAI { -public: - boss_freya_summons() : CreatureScript("boss_freya_summons") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_freya_summons(Creature* pCreature) : ScriptedAI(pCreature) { - return GetUlduarAI(pCreature); + _isTrio = me->GetEntry() == NPC_ANCIENT_WATER_SPIRIT || me->GetEntry() == NPC_STORM_LASHER || me->GetEntry() == NPC_SNAPLASHER; + _hasDied = false; } - struct boss_freya_summonsAI : public ScriptedAI + EventMap events; + uint8 _stackCount; + bool _hasDied; + bool _isTrio; + + void Reset() override { - 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; - } + _stackCount = 0; + events.Reset(); + if (Unit* target = SelectTargetFromPlayerList(70)) + AttackStart(target); + } - EventMap events; - ObjectGuid _freyaGUID; - uint8 _stackCount; - bool _hasDied; - bool _isTrio; - - void Reset() override + void JustDied(Unit* /*killer*/) override + { + if (InstanceScript* instance = me->GetInstanceScript()) { - _stackCount = 0; - events.Reset(); - if (Unit* target = SelectTargetFromPlayerList(70)) - AttackStart(target); - } - - void JustDied(Unit* /*killer*/) override - { - if (Creature* freya = ObjectAccessor::GetCreature(*me, _freyaGUID)) + if (Creature* freya = instance->GetCreature(BOSS_FREYA)) { if (!_hasDied) freya->AI()->DoAction(_stackCount); @@ -1071,153 +965,142 @@ public: _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(1ms); - 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); + if (me->GetEntry() == NPC_DETONATING_LASHER) + me->CastSpell(me, SPELL_DETONATE, true); } - struct boss_freya_nature_bombAI : public NullCreatureAI + void DoAction(int32 param) override { - boss_freya_nature_bombAI(Creature* pCreature) : NullCreatureAI(pCreature) + if (_isTrio && param == ACTION_RESPAWN_TRIO) { - _goGUID.Clear(); + 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(1ms); + events.Repeat(10s); + break; } - ObjectGuid _goGUID; - uint32 _explodeTimer; + DoMeleeAttackIfReady(); + } +}; - void Reset() override +struct boss_freya_nature_bomb : public NullCreatureAI +{ + boss_freya_nature_bomb(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->SetObjectScale(0.5f); - me->CastSpell(me, SPELL_GREEN_BANISH_STATE, true); - + me->CastSpell(me, SPELL_NATURE_BOMB_DAMAGE, false); + me->DespawnOrUnsummon(1s); _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 + // Delay explosion a little, visual + if (_explodeTimer >= 5000 && _explodeTimer < 10000) { - _explodeTimer += diff; - if (_explodeTimer >= 11000) - { - me->CastSpell(me, SPELL_NATURE_BOMB_DAMAGE, false); - me->DespawnOrUnsummon(1s); - _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); - } + _explodeTimer = 10000; + if (GameObject* go = me->GetMap()->GetGameObject(_goGUID)) + go->SetGoState(GO_STATE_ACTIVE); } - }; + } }; class achievement_freya_getting_back_to_nature : public AchievementCriteriaScript @@ -1253,15 +1136,15 @@ private: void AddSC_boss_freya() { - new boss_freya(); - new boss_freya_elder_stonebark(); - new boss_freya_elder_brightleaf(); - new boss_freya_elder_ironbranch(); - new boss_freya_iron_root(); - new boss_freya_lifebinder(); - new boss_freya_healthy_spore(); - new boss_freya_summons(); - new boss_freya_nature_bomb(); + RegisterUlduarCreatureAI(boss_freya); + RegisterUlduarCreatureAI(boss_freya_elder_stonebark); + RegisterUlduarCreatureAI(boss_freya_elder_brightleaf); + RegisterUlduarCreatureAI(boss_freya_elder_ironbranch); + RegisterUlduarCreatureAI(boss_freya_iron_root); + RegisterUlduarCreatureAI(boss_freya_lifebinder); + RegisterUlduarCreatureAI(boss_freya_healthy_spore); + RegisterUlduarCreatureAI(boss_freya_summons); + RegisterUlduarCreatureAI(boss_freya_nature_bomb); new achievement_freya_getting_back_to_nature(); new achievement_freya_knock_on_wood("achievement_freya_knock_on_wood", 1); 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 b71b583fe..1fed3825c 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp @@ -15,18 +15,14 @@ * with this program. If not, see . */ -#include "AccountMgr.h" #include "AchievementCriteriaScript.h" #include "AreaDefines.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 @@ -110,367 +106,307 @@ enum VaporsText SAY_EMOTE_VAPORS = 0, }; -class boss_vezax : public CreatureScript +struct boss_vezax : public BossAI { -public: - boss_vezax() : CreatureScript("boss_vezax") { } + boss_vezax(Creature* pCreature) : BossAI(pCreature, BOSS_VEZAX) { } - CreatureAI* GetAI(Creature* pCreature) const override + uint8 vaporsCount; + bool hardmodeAvailable; + bool berserk; + bool bAchievShadowdodger; + + void Reset() override { - return GetUlduarAI(pCreature); + _Reset(); + vaporsCount = 0; + hardmodeAvailable = true; + berserk = false; + bAchievShadowdodger = true; + me->SetLootMode(1); } - struct boss_vezaxAI : public ScriptedAI + void JustReachedHome() override { - boss_vezaxAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + _JustReachedHome(); + me->setActive(false); + } + + void JustEngagedWith(Unit* /*pWho*/) override + { + me->setActive(true); + _JustEngagedWith(); + + 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); + + me->CastSpell(me, SPELL_AURA_OF_DESPAIR_1, true); + } + + void DoAction(int32 param) override + { + switch (param) { - pInstance = pCreature->GetInstanceScript(); + case 1: + hardmodeAvailable = false; + break; + case 2: + me->RemoveAura(SPELL_SARONITE_BARRIER); + me->SetLootMode(3); + break; } + } - EventMap events; - SummonList summons; - uint8 vaporsCount; - bool hardmodeAvailable; - bool berserk; - bool bAchievShadowdodger; - - InstanceScript* pInstance; - - void Reset() override + uint32 GetData(uint32 id) const override + { + switch (id) { - vaporsCount = 0; - hardmodeAvailable = true; - berserk = false; - bAchievShadowdodger = true; - events.Reset(); - summons.DespawnAll(); - me->SetLootMode(1); - - if (pInstance) - pInstance->SetData(TYPE_VEZAX, NOT_STARTED); + case 1: + return (me->GetLootMode() == 3 ? 1 : 0); + case 2: + return (bAchievShadowdodger ? 1 : 0); } + return 0; + } - void JustReachedHome() override + void SpellHitTarget(Unit* target, SpellInfo const* spell) override + { + if (target && spell && target->IsPlayer() && 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()) { - 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->IsPlayer() && 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(10s, 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(12s, 0); - events.DelayEvents(12s, 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 ) + 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: { - door->SetLootState(GO_READY); - door->UseDoorOrButton(0, false); + 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(10s, 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(12s, 0); + events.DelayEvents(12s, 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; } - void KilledUnit(Unit* who) override - { - if (who->IsPlayer()) - 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); + DoMeleeAttackIfReady(); } - struct npc_ulduar_saronite_vaporsAI : public NullCreatureAI + void JustDied(Unit* /*killer*/) override { - npc_ulduar_saronite_vaporsAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - pInstance = pCreature->GetInstanceScript(); - me->GetMotionMaster()->MoveRandom(4.0f); - } + _JustDied(); + Talk(SAY_DEATH); - 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(3s); - - 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) + if (GameObject* door = me->FindNearestGameObject(GO_VEZAX_DOOR, 500.0f)) + if (door->GetGoState() != GO_STATE_ACTIVE) { - me->CastSpell(me, SPELL_PROFOUND_DARKNESS, true); - timer -= 2000; + door->SetLootState(GO_READY); + door->UseDoorOrButton(0, false); } + } - DoMeleeAttackIfReady(); + void KilledUnit(Unit* who) override + { + if (who->IsPlayer()) + Talk(SAY_SLAY); + } + + void MoveInLineOfSight(Unit* /*who*/) override {} +}; + +struct npc_ulduar_saronite_vapors : public NullCreatureAI +{ + npc_ulduar_saronite_vapors(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 = pInstance->GetCreature(BOSS_VEZAX)) + vezax->AI()->DoAction(1); + } + + void IsSummonedBy(WorldObject* /*summoner*/) override + { + Talk(SAY_EMOTE_VAPORS); + } +}; + +struct npc_ulduar_saronite_animus : public ScriptedAI +{ + npc_ulduar_saronite_animus(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = pCreature->GetInstanceScript(); + if (pInstance) + if (Creature* vezax = pInstance->GetCreature(BOSS_VEZAX)) + vezax->AI()->JustSummoned(me); + timer = 0; + me->SetInCombatWithZone(); + } + + InstanceScript* pInstance; + uint16 timer; + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(3s); + + if (pInstance) + if (Creature* vezax = pInstance->GetCreature(BOSS_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_aura : public AuraScript @@ -630,34 +566,11 @@ public: } }; -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(); - new npc_ulduar_saronite_vapors(); - new npc_ulduar_saronite_animus(); + RegisterUlduarCreatureAI(boss_vezax); + RegisterUlduarCreatureAI(npc_ulduar_saronite_vapors); + RegisterUlduarCreatureAI(npc_ulduar_saronite_animus); RegisterSpellScript(spell_aura_of_despair_aura); RegisterSpellScript(spell_mark_of_the_faceless_periodic_aura); @@ -668,5 +581,4 @@ void AddSC_boss_vezax() new achievement_smell_saronite(); new achievement_shadowdodger(); - new go_ulduar_pure_saronite_deposit(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp index ae301a541..391a73146 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp @@ -197,987 +197,879 @@ HodirHelperData hhd[4][4] = } }; -class boss_hodir : public CreatureScript +struct boss_hodir : public BossAI { -public: - boss_hodir() : CreatureScript("boss_hodir") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_hodir(Creature* pCreature) : BossAI(pCreature, BOSS_HODIR) { - return GetUlduarAI(pCreature); + if (!me->IsAlive()) + instance->SetBossState(BOSS_HODIR, DONE); } - struct boss_hodirAI : public ScriptedAI + 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 { - boss_hodirAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + _Reset(); + berserk = false; + bAchievCheese = true; + bAchievGettingCold = true; + bAchievCacheRare = true; + bAchievCoolestFriends = true; + me->SetSheath(SHEATH_STATE_MELEE); + + // Reset the spells cast after wipe + me->RemoveAllAuras(); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA); + + if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 900.0f)) { - pInstance = pCreature->GetInstanceScript(); - if (!me->IsAlive()) - if (pInstance) - pInstance->SetData(TYPE_HODIR, DONE); + go->SetGoState(GO_STATE_ACTIVE); } - 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 }; + // Reset helpers + if (!summons.size()) + SpawnHelpers(); + } - // 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 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); - void Reset() override + if (instance->GetBossState(BOSS_HODIR) != DONE) { - 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(); + instance->SetBossState(BOSS_HODIR, IN_PROGRESS); } - void JustEngagedWith(Unit* /*pWho*/) override + if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 300.0f)) { - 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); - } + go->SetGoState(GO_STATE_READY); } + } - void DoAction(int action) override + GameObject* GetHardmodeChest() + { + if (GameObject* go = instance->GetGameObject(DATA_HODIR_CHEST_HARD)) + return go; + return instance->GetGameObject(DATA_HODIR_CHEST_HARD_HERO); + } + + void DoAction(int action) override + { + if (action) { - if (action) + switch (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: + case EVENT_FAIL_HM: + if (instance) { - 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 + if (GameObject* go = GetHardmodeChest()) + { + go->SetGoState(GO_STATE_ACTIVE); + events.ScheduleEvent(EVENT_DESPAWN_CHEST, 3s); + } } break; } } + } - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + 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) { - if (damage >= me->GetHealth() || me->GetHealth() < 150000) - { - damage = 0; - me->SetReactState(REACT_PASSIVE); - if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE)) + case SPELL_ICICLE_TBBA: + me->CastSpell(target, SPELL_ICICLE_VISUAL_UNPACKED, true); + break; + case SPELL_FLASH_FREEZE_VISUAL: { - if (pInstance) - { - pInstance->SetData(TYPE_HODIR, DONE); - me->CastSpell(me, 64899, true); // credit - pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA); - } - - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetFaction(FACTION_FRIENDLY); - me->GetMotionMaster()->Clear(); - me->AttackStop(); - me->CombatStop(); - me->InterruptNonMeleeSpells(true); - me->RemoveAllAuras(); - - 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); - scheduler.Schedule(14s, [this](TaskContext /*context*/) - { - DoCastSelf(SPELL_TELEPORT); - }); + 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 (instance) + { + instance->SetBossState(BOSS_HODIR, DONE); + me->CastSpell(me, 64899, true); // credit + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA); + } + + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetFaction(FACTION_FRIENDLY); + me->GetMotionMaster()->Clear(); + me->AttackStop(); + me->CombatStop(); + me->InterruptNonMeleeSpells(true); + me->RemoveAllAuras(); + + 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); + scheduler.Schedule(14s, [this](TaskContext /*context*/) + { + DoCastSelf(SPELL_TELEPORT); + }); } } + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + scheduler.Update(diff); + if (me->GetPositionY() <= ENTRANCE_DOOR.GetPositionY() || me->GetPositionY() >= EXIT_DOOR.GetPositionY()) { - scheduler.Update(diff); - if (me->GetPositionY() <= ENTRANCE_DOOR.GetPositionY() || me->GetPositionY() >= EXIT_DOOR.GetPositionY()) - { - boss_hodirAI::EnterEvadeMode(); - return; - } + boss_hodir::EnterEvadeMode(); + return; + } - if (!UpdateVictim()) + if (!UpdateVictim()) + { + if (me->IsInCombat()) { - 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 (instance) + { + if (GameObject* go = GetHardmodeChest()) + me->CastSpell(go, SPELL_SHATTER_CHEST, false); + } + } + break; + case EVENT_DESPAWN_CHEST: + if (instance && instance->GetBossState(BOSS_HODIR) != DONE) + instance->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) - itr->GetSource()->CastSpell(itr->GetSource(), SPELL_FLASH_FREEZE_INSTAKILL, true); - EnterEvadeMode(); - } - return; - } + 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; + } - 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, SPELL_FROZEN_BLOWS, 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); - } + 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; - } - - DoMeleeAttackIfReady(); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_TELEPORT) - { - me->DespawnOrUnsummon(); - pInstance->SetData(EVENT_KEEPER_TELEPORTED, DONE); - } - } - - 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 ) + } + break; + case EVENT_SMALL_ICICLES_ENABLE: { - if ((faction == 'A' && ( k > 1 || (k == 1 && RAID_MODE(1, 0)))) || - (faction == 'H' && ( k < 2 || (k == 3 && RAID_MODE(1, 0))))) + SmallIcicles(true); + } + break; + case EVENT_FROZEN_BLOWS: + { + Talk(TEXT_EMOTE_BLOW); + Talk(TEXT_STALACTITE); + me->CastSpell(me, SPELL_FROZEN_BLOWS, 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(); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_TELEPORT) + { + me->DespawnOrUnsummon(); + instance->SetData(EVENT_KEEPER_TELEPORTED, DONE); + } + } + + 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; - for( uint8 i = 0; i < 4; ++i ) + if (Creature* h_p = me->SummonCreature(hhd[k][i].id, hhd[k][i].x, hhd[k][i].y, 432.69f, M_PI / 2)) { - if (!hhd[k][i].id) - continue; + h_p->SetFaction(1665); + if (cnt < 8) + Helpers[cnt++] = h_p->GetGUID(); - if (Creature* h_p = me->SummonCreature(hhd[k][i].id, hhd[k][i].x, hhd[k][i].y, 432.69f, M_PI / 2)) + 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)) { - 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); - } + c->CastSpell(h_p, SPELL_FLASH_FREEZE_TRAPPED_NPC, true); + JustSummoned(c); } } } - } + } + } - void KilledUnit(Unit* who) override - { - if (who->IsPlayer()) - Talk(TEXT_SLAY); - } + void KilledUnit(Unit* who) override + { + if (who->IsPlayer()) + Talk(TEXT_SLAY); + } - void JustSummoned(Creature* s) override - { - summons.Summon(s); - } + bool CanAIAttack(Unit const* t) const override + { + if (t->IsPlayer()) + return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER); + else if (t->IsCreature()) + return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC); - void SummonedCreatureDespawn(Creature* s) override - { - summons.Despawn(s); - } + return true; + } - bool CanAIAttack(Unit const* t) const override - { - if (t->IsPlayer()) - return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER); - else if (t->IsCreature()) - 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 - { + void SetData(uint32 id, uint32 value) override + { + if (value) switch (id) { case 1: - return (bAchievCheese ? 1 : 0); + bAchievCheese = false; + break; case 2: - return (bAchievGettingCold ? 1 : 0); - case 3: - return (bAchievCacheRare ? 1 : 0); + bAchievGettingCold = false; + break; case 4: - return (bAchievCoolestFriends ? 1 : 0); + bAchievCoolestFriends = false; + break; } - 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 + uint32 GetData(uint32 id) const override { - npc_ulduar_icicleAI(Creature* pCreature) : NullCreatureAI(pCreature) + switch (id) { - timer1 = 2000; - timer2 = 5000; + case 1: + return (bAchievCheese ? 1 : 0); + case 2: + return (bAchievGettingCold ? 1 : 0); + case 3: + return (bAchievCacheRare ? 1 : 0); + case 4: + return (bAchievCoolestFriends ? 1 : 0); } - - 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); + return 0; } - struct npc_ulduar_flash_freezeAI : public NullCreatureAI + void MoveInLineOfSight(Unit* /*who*/) override {} +}; + +struct npc_ulduar_icicle : public NullCreatureAI +{ + npc_ulduar_icicle(Creature* pCreature) : NullCreatureAI(pCreature) { - npc_ulduar_flash_freezeAI(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; + } +}; + +struct npc_ulduar_flash_freeze : public NullCreatureAI +{ + npc_ulduar_flash_freeze(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->GetBossState(BOSS_HODIR) == NOT_STARTED) + if (Creature* hodir = pInstance->GetCreature(BOSS_HODIR)) + hodir->AI()->AttackStart(doneBy); + } + + void UpdateAI(uint32 diff) override + { + if (timer <= diff) { 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) + if (me->IsSummon()) { - timer = 2500; - if (me->IsSummon()) + if (Unit* s = me->ToTempSummon()->GetSummonerUnit()) { - if (Unit* s = me->ToTempSummon()->GetSummonerUnit()) - { - if ((s->IsPlayer() && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER)) || (s->IsCreature() && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC))) - me->DespawnOrUnsummon(2s); - else if (s->IsPlayer()) - if (InstanceScript* instanceScript = me->GetInstanceScript()) - if (instanceScript->GetData(TYPE_HODIR) == NOT_STARTED) - { - s->CastSpell(s, SPELL_FLASH_FREEZE_INSTAKILL, true); - me->DespawnOrUnsummon(2s); - } - } - else - { + if ((s->IsPlayer() && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER)) || (s->IsCreature() && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC))) me->DespawnOrUnsummon(2s); - } - } - } - 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 - { - uint32 spellid = sSpellMgr->GetSpellIdForDifficulty(SPELL_SHAMAN_STORM_CLOUD, me); - if (target && spell->Id == spellid) - if (Aura* a = target->GetAura(spellid, 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: - { - uint32 spellid = sSpellMgr->GetSpellIdForDifficulty(SPELL_SHAMAN_STORM_CLOUD, me); - if (Player* target = ScriptedAI::SelectTargetFromPlayerList(35.0f, spellid)) - me->CastSpell(target, spellid, 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))) + else if (s->IsPlayer()) + if (InstanceScript* instanceScript = me->GetInstanceScript()) + if (instanceScript->GetBossState(BOSS_HODIR) == NOT_STARTED) { - me->CastSpell((*itr), SPELL_MAGE_MELT_ICE, false); - found = true; - break; + s->CastSpell(s, SPELL_FLASH_FREEZE_INSTAKILL, true); + me->DespawnOrUnsummon(2s); } + } + else + { + me->DespawnOrUnsummon(2s); + } + } + } + else + timer -= diff; + } +}; - if (found) +struct npc_ulduar_toasty_fire : public NullCreatureAI +{ + npc_ulduar_toasty_fire(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; + } + } +}; + +struct npc_ulduar_hodir_priest : public ScriptedAI +{ + npc_ulduar_hodir_priest(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 (Creature* hodir = pInstance->GetCreature(BOSS_HODIR)) + { + 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->GetCreature(BOSS_HODIR)) + hodir->AI()->SetData(4, 1); + } +}; + +struct npc_ulduar_hodir_druid : public ScriptedAI +{ + npc_ulduar_hodir_druid(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 (Creature* hodir = pInstance->GetCreature(BOSS_HODIR)) + { + 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->GetCreature(BOSS_HODIR)) + hodir->AI()->SetData(4, 1); + } +}; + +struct npc_ulduar_hodir_shaman : public ScriptedAI +{ + npc_ulduar_hodir_shaman(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 + { + uint32 spellid = sSpellMgr->GetSpellIdForDifficulty(SPELL_SHAMAN_STORM_CLOUD, me); + if (target && spell->Id == spellid) + if (Aura* a = target->GetAura(spellid, 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 (Creature* hodir = pInstance->GetCreature(BOSS_HODIR)) + { + 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: + { + uint32 spellid = sSpellMgr->GetSpellIdForDifficulty(SPELL_SHAMAN_STORM_CLOUD, me); + if (Player* target = ScriptedAI::SelectTargetFromPlayerList(35.0f, spellid)) + me->CastSpell(target, spellid, 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->GetCreature(BOSS_HODIR)) + hodir->AI()->SetData(4, 1); + } +}; + +struct npc_ulduar_hodir_mage : public ScriptedAI +{ + npc_ulduar_hodir_mage(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 (Creature* hodir = pInstance->GetCreature(BOSS_HODIR)) + { + 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))) { - events.DelayEvents(2s); - events.Repeat(2s); + me->CastSpell((*itr), SPELL_MAGE_MELT_ICE, false); + found = true; break; } - events.Repeat(5s); + + if (found) + { + events.DelayEvents(2s); + events.Repeat(2s); + break; } - break; - } + events.Repeat(5s); + } + break; } + } - void MoveInLineOfSight(Unit* /*who*/) override {} + void MoveInLineOfSight(Unit* /*who*/) override {} - void EnterEvadeMode(EvadeReason /*why*/) override {} - bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; } + 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); - } - }; + void JustDied(Unit* /*killer*/) override + { + if (pInstance) + if (Creature* hodir = pInstance->GetCreature(BOSS_HODIR)) + hodir->AI()->SetData(4, 1); + } }; class spell_hodir_shatter_chest : public SpellScript @@ -1271,7 +1163,7 @@ class spell_hodir_biting_cold_player_aura : public AuraScript { 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))) + if (Creature* hodir = pInstance->GetCreature(BOSS_HODIR)) hodir->AI()->SetData(2, 1); ModStackAmount(1); _counter = 0; @@ -1544,15 +1436,15 @@ public: void AddSC_boss_hodir() { - new boss_hodir(); - new npc_ulduar_icicle(); - new npc_ulduar_flash_freeze(); - new npc_ulduar_toasty_fire(); + RegisterUlduarCreatureAI(boss_hodir); + RegisterUlduarCreatureAI(npc_ulduar_icicle); + RegisterUlduarCreatureAI(npc_ulduar_flash_freeze); + RegisterUlduarCreatureAI(npc_ulduar_toasty_fire); - new npc_ulduar_hodir_priest(); - new npc_ulduar_hodir_druid(); - new npc_ulduar_hodir_shaman(); - new npc_ulduar_hodir_mage(); + RegisterUlduarCreatureAI(npc_ulduar_hodir_priest); + RegisterUlduarCreatureAI(npc_ulduar_hodir_druid); + RegisterUlduarCreatureAI(npc_ulduar_hodir_shaman); + RegisterUlduarCreatureAI(npc_ulduar_hodir_mage); RegisterSpellScript(spell_hodir_shatter_chest); RegisterSpellScript(spell_hodir_biting_cold_main_aura); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp index 0b933628f..e0756cbd9 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -48,7 +48,6 @@ enum IgnisSpellData enum IgnisNPCs { - BOSS_IGNIS = 33118, NPC_IRON_CONSTRUCT = 33121, NPC_SCORCHED_GROUND = 33123, NPC_WATER_TRIGGER = 22515, @@ -78,155 +77,130 @@ enum eEvents EVENT_GRAB, }; -class npc_ulduar_iron_construct : public CreatureScript +struct npc_ulduar_iron_construct : public ScriptedAI { -public: - npc_ulduar_iron_construct() : CreatureScript("npc_ulduar_iron_construct") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_ulduar_iron_construct(Creature* pCreature) : ScriptedAI(pCreature) { - return GetUlduarAI(pCreature); + me->CastSpell(me, 38757, true); } - struct npc_ulduar_iron_constructAI : public ScriptedAI + uint16 timer; + + void Reset() override { - npc_ulduar_iron_constructAI(Creature* pCreature) : ScriptedAI(pCreature) - { - me->CastSpell(me, 38757, true); - } + timer = 1000; + me->SetReactState(REACT_PASSIVE); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + } - uint16 timer; + void JustReachedHome() override + { + me->CastSpell(me, 38757, true); + } - void Reset() override + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_ACTIVATE_CONSTRUCT) { - 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)) + me->RemoveAura(38757); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* ignis = instance->GetCreature(BOSS_IGNIS)) { - if (heat->GetStackAmount() >= 10) + 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) { - if (heat->GetStackAmount() > 10) - { - heat->ModStackAmount(-1); - } - me->CastSpell(me, SPELL_MOLTEN, true); - me->GetThreatMgr().ResetAllThreat(); + 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(sSpellMgr->GetSpellIdForDifficulty(SPELL_BRITTLE, me))) - { - 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, SPELL_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 + void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override { - boss_ignisAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - EventMap events; - uint8 counter; - bool bShattered; - uint32 lastShatterMSTime; - - void Reset() override + if (damage >= RAID_MODE(3000U, 5000U) && me->GetAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_BRITTLE, me))) { - events.Reset(); - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - counter = 0; - bShattered = false; - lastShatterMSTime = 0; + me->CastSpell(me, SPELL_SHATTER, true); + Unit::Kill(attacker, me); - 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); - } + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* ignis = instance->GetCreature(BOSS_IGNIS)) + ignis->AI()->SetData(1337, 0); } + } - void JustEngagedWith(Unit* /*who*/) override + void JustDied(Unit* /*killer*/) override + { + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* ignis = instance->GetCreature(BOSS_IGNIS)) + ignis->RemoveAuraFromStack(SPELL_STRENGTH_OF_THE_CREATOR); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (timer <= diff) { - me->setActive(true); + timer = 1000; + if (Aura* a = me->GetAura(SPELL_MOLTEN)) + if (me->FindNearestCreature(NPC_WATER_TRIGGER, 18.0f, true)) + { + me->RemoveAura(a); + me->CastSpell(me, SPELL_BRITTLE, true); + } + } + else + timer -= diff; - std::list icl; - me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT); + DoMeleeAttackIfReady(); + } + + void MoveInLineOfSight(Unit* /*who*/) override {} +}; + +struct boss_ignis : public BossAI +{ + boss_ignis(Creature* pCreature) : BossAI(pCreature, BOSS_IGNIS) { } + + uint8 counter; + bool bShattered; + uint32 lastShatterMSTime; + + void Reset() override + { + _Reset(); + me->SetControlled(false, UNIT_STATE_ROOT); + me->DisableRotate(false); + counter = 0; + bShattered = false; + lastShatterMSTime = 0; + + if (instance) + instance->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()) @@ -240,185 +214,183 @@ public: (*itr)->CastSpell((*itr), 38757, true); } - bShattered = false; - lastShatterMSTime = 0; - events.Reset(); - events.ScheduleEvent(EVENT_ACTIVATE_CONSTRUCT, RAID_MODE(40s, 30s)); - events.ScheduleEvent(EVENT_SPELL_SCORCH, 10s); - events.ScheduleEvent(EVENT_SPELL_FLAME_JETS, 32s); - events.ScheduleEvent(EVENT_GRAB, 25s); + bShattered = false; + lastShatterMSTime = 0; + events.Reset(); + events.ScheduleEvent(EVENT_ACTIVATE_CONSTRUCT, RAID_MODE(40s, 30s)); + events.ScheduleEvent(EVENT_SPELL_SCORCH, 10s); + events.ScheduleEvent(EVENT_SPELL_FLAME_JETS, 32s); + events.ScheduleEvent(EVENT_GRAB, 25s); - Talk(SAY_AGGRO); - DoZoneInCombat(); + 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); - } + if (instance) + { + instance->SetBossState(BOSS_IGNIS, IN_PROGRESS); + instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT); + instance->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 + { + _JustReachedHome(); + me->setActive(false); + } + + void KilledUnit(Unit* victim) override + { + if (victim->IsPlayer()) + Talk(SAY_SLAY); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + _JustDied(); + + 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, SPELL_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; } - void SetData(uint32 id, uint32 /*value*/) override + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - 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->IsPlayer()) - 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, SPELL_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: + 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; - case EVENT_ACTIVATE_CONSTRUCT: - Talk(SAY_SUMMON); - me->CastCustomSpell(SPELL_ACTIVATE_CONSTRUCT, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false); - if (++counter >= 20) + } + events.Repeat(RAID_MODE(40s, 30s)); + break; + case EVENT_SPELL_SCORCH: + Talk(SAY_SCORCH); + me->SetControlled(true, UNIT_STATE_ROOT); + me->DisableRotate(true); + me->SendMovementFlagUpdate(); + me->CastSpell(me->GetVictim(), SPELL_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(), SPELL_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) { - Talk(SAY_BERSERK); - me->CastSpell(me, SPELL_BERSERK, true); - break; - } - events.Repeat(RAID_MODE(40s, 30s)); - break; - case EVENT_SPELL_SCORCH: - Talk(SAY_SCORCH); - me->SetControlled(true, UNIT_STATE_ROOT); - me->DisableRotate(true); - me->SendMovementFlagUpdate(); - me->CastSpell(me->GetVictim(), SPELL_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(), SPELL_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) { - 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()) { - 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); + found = true; + break; } } - events.Repeat(24s); - events.DelayEvents(6s); + if (!found) + playerGUIDs.push_back(temp->GetGUID()); } - break; - } - DoMeleeAttackIfReady(); + 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; } - void EnterEvadeMode(EvadeReason why) override - { - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - ScriptedAI::EnterEvadeMode(why); - } - }; + DoMeleeAttackIfReady(); + } + + void EnterEvadeMode(EvadeReason why) override + { + me->SetControlled(false, UNIT_STATE_ROOT); + me->DisableRotate(false); + BossAI::EnterEvadeMode(why); + } }; class spell_ignis_scorch_aura : public AuraScript @@ -541,8 +513,8 @@ public: void AddSC_boss_ignis() { - new boss_ignis(); - new npc_ulduar_iron_construct(); + RegisterUlduarCreatureAI(boss_ignis); + RegisterUlduarCreatureAI(npc_ulduar_iron_construct); RegisterSpellScript(spell_ignis_scorch_aura); RegisterSpellScript(spell_ignis_grab_initial); RegisterSpellScript(spell_ignis_slag_pot_aura); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp index df8e2ea3e..99e5c4de9 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp @@ -117,34 +117,19 @@ enum Misc DATA_KOLOGARN_ARMS_ACHIEV = 57, }; -class boss_kologarn : public CreatureScript +struct boss_kologarn : public BossAI { -public: - boss_kologarn() : CreatureScript("boss_kologarn") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_kologarn(Creature* creature) : BossAI(creature, BOSS_KOLOGARN), vehicle(me->GetVehicleKit()), breathReady(false) { - return GetUlduarAI(pCreature); + assert(vehicle); + me->SetStandState(UNIT_STAND_STATE_SUBMERGED); } - struct boss_kologarnAI : public ScriptedAI - { - boss_kologarnAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me), breathReady(false) - { - m_pInstance = me->GetInstanceScript(); - assert(vehicle); - me->SetStandState(UNIT_STAND_STATE_SUBMERGED); - } + Vehicle* vehicle; + ObjectGuid _left, _right; - InstanceScript* m_pInstance; - - Vehicle* vehicle; - ObjectGuid _left, _right; - EventMap events; - SummonList summons; - - bool _looksAchievement, breathReady; - uint8 _rubbleAchievement; + bool _looksAchievement, breathReady; + uint8 _rubbleAchievement; void MoveInLineOfSight(Unit* who) override { @@ -158,13 +143,18 @@ public: } if (me->GetExactDist2d(who) < 30.0f) - ScriptedAI::MoveInLineOfSight(who); + BossAI::MoveInLineOfSight(who); } void EnterEvadeMode(EvadeReason why) override { - if (!_EnterEvadeMode(why)) + if (!CreatureAI::_EnterEvadeMode(why)) return; + if (instance && instance->GetBossState(BOSS_KOLOGARN) != DONE) + { + instance->SetBossState(BOSS_KOLOGARN, NOT_STARTED); + instance->SaveToDB(); + } Reset(); me->setActive(false); } @@ -214,15 +204,12 @@ public: me->SetDisableGravity(true); me->DisableRotate(true); - events.Reset(); - summons.DespawnAll(); + _Reset(); - if (m_pInstance) + if (instance) { - 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))) + if (GameObject* door = instance->GetGameObject(DATA_KOLOGARN_DOORS)) door->SetGoState(GO_STATE_ACTIVE); } @@ -240,8 +227,8 @@ public: if (param == DATA_KOLOGARN_RUBBLE_ACHIEV) { // Means arm died - if (m_pInstance && (!_left || !_right)) - m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_DISARMED_CRITERIA); + if (instance && (!_left || !_right)) + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_DISARMED_CRITERIA); ++_rubbleAchievement; } @@ -267,12 +254,12 @@ public: void JustSummoned(Creature* cr) override { if (cr->GetEntry() != NPC_LEFT_ARM && cr->GetEntry() != NPC_RIGHT_ARM) - summons.Summon(cr); + BossAI::JustSummoned(cr); } void SummonedCreatureDespawn(Creature* cr) override { - if (m_pInstance->GetData(TYPE_KOLOGARN) > NOT_STARTED) + if (instance->GetBossState(BOSS_KOLOGARN) > NOT_STARTED) return; if (cr->GetEntry() == NPC_LEFT_ARM) @@ -290,17 +277,15 @@ public: void JustDied(Unit*) override { - summons.DespawnAll(); + _JustDied(); me->StopMoving(); - if (m_pInstance) - m_pInstance->SetData(TYPE_KOLOGARN, DONE); Talk(SAY_DEATH); - if (m_pInstance) + if (instance) { // Open the door inside Kologarn chamber - if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS))) + if (GameObject* door = instance->GetGameObject(DATA_KOLOGARN_DOORS)) door->SetGoState(GO_STATE_ACTIVE); } @@ -333,7 +318,7 @@ public: void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override { - if (!me->IsAlive() || m_pInstance->GetData(TYPE_KOLOGARN) != IN_PROGRESS) + if (!me->IsAlive() || instance->GetBossState(BOSS_KOLOGARN) != IN_PROGRESS) return; if (!apply) @@ -375,8 +360,8 @@ public: void JustEngagedWith(Unit* /*who*/) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_KOLOGARN, IN_PROGRESS); + if (instance) + instance->SetBossState(BOSS_KOLOGARN, IN_PROGRESS); events.ScheduleEvent(EVENT_SMASH, 8s); events.ScheduleEvent(EVENT_SWEEP, 17s); @@ -389,9 +374,9 @@ public: me->setActive(true); // Close the door inside Kologarn chamber - if (m_pInstance) + if (instance) { - if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS))) + if (GameObject* door = instance->GetGameObject(DATA_KOLOGARN_DOORS)) { door->SetGoState(GO_STATE_READY); } @@ -491,173 +476,151 @@ public: me->resetAttackTimer(); } } - }; }; // also used for left arm, all functions except JustDied wont be used by left arm -class boss_kologarn_arms : public CreatureScript +struct boss_kologarn_arms : public ScriptedAI { -public: - boss_kologarn_arms() : CreatureScript("boss_kologarn_arms") { } + boss_kologarn_arms(Creature* c) : ScriptedAI(c) { } - CreatureAI* GetAI(Creature* pCreature) const override + 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 { - return GetUlduarAI(pCreature); + _combatStarted = false; + _damageDone = 0; } - struct boss_kologarn_armsAI : public ScriptedAI + void PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool apply) override { - 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; + 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 = instance->GetCreature(BOSS_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; } - void PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool apply) override + if (Creature* cr = me->SummonTrigger(x, y, z, 0, 5000)) { - 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); - } - } + cr->CastSpell(cr, SPELL_RUBBLE_FALL, true); if (me->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN))) - cr->AI()->DoAction(DATA_KOLOGARN_RUBBLE_ACHIEV); - - me->ExitVehicle(); + if (Creature* kologarn = me->GetInstanceScript()->GetCreature(BOSS_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 = me->GetInstanceScript()->GetCreature(BOSS_KOLOGARN)) + cr->AI()->DoAction(DATA_KOLOGARN_RUBBLE_ACHIEV); + + me->ExitVehicle(); + } }; -class boss_kologarn_eyebeam : public CreatureScript +struct boss_kologarn_eyebeam : public ScriptedAI { -public: - boss_kologarn_eyebeam() : CreatureScript("boss_kologarn_eyebeam") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_kologarn_eyebeam(Creature* c) : ScriptedAI(c), _timer(1), _damaged(false) { - return GetUlduarAI(pCreature); + m_pInstance = (InstanceScript*)c->GetInstanceScript(); } - struct boss_kologarn_eyebeamAI : public ScriptedAI + + InstanceScript* m_pInstance; + uint32 _timer; + bool _damaged; + + void DamageDealt(Unit* /*victim*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override { - boss_kologarn_eyebeamAI(Creature* c) : ScriptedAI(c), _timer(1), _damaged(false) + if (damage > 0 && !_damaged && me->GetInstanceScript()) { - m_pInstance = (InstanceScript*)c->GetInstanceScript(); + _damaged = true; + if (Creature* cr = me->GetInstanceScript()->GetCreature(BOSS_KOLOGARN)) + cr->AI()->DoAction(DATA_KOLOGARN_LOOKS_ACHIEV); + } + } + + void IsSummonedBy(WorldObject* summoner) override + { + if (!summoner) + { + return; } - InstanceScript* m_pInstance; - uint32 _timer; - bool _damaged; - - void DamageDealt(Unit* /*victim*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override + // Should only work on playable characters + if (Player* player = summoner->ToPlayer()) { - if (damage > 0 && !_damaged && me->GetInstanceScript()) + me->Attack(player, false); + me->GetMotionMaster()->MoveChase(player); + + if (Creature* cr = m_pInstance->GetCreature(BOSS_KOLOGARN)) { - _damaged = true; - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN))) - cr->AI()->DoAction(DATA_KOLOGARN_LOOKS_ACHIEV); + me->CastSpell(cr, me->GetEntry() == NPC_EYE_LEFT ? SPELL_FOCUSED_EYEBEAM_LEFT : SPELL_FOCUSED_EYEBEAM_RIGHT, true); } } + } - void IsSummonedBy(WorldObject* summoner) override + void UpdateAI(uint32 diff) override + { + if (_timer) { - if (!summoner) + _timer += diff; + if (_timer >= 2000) { - return; - } - - // Should only work on playable characters - if (Player* player = summoner->ToPlayer()) - { - me->Attack(player, false); - me->GetMotionMaster()->MoveChase(player); - - 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); + _timer = 0; } } - - void UpdateAI(uint32 diff) override - { - if (_timer) - { - _timer += diff; - if (_timer >= 2000) - { - me->CastSpell(me, SPELL_FOCUSED_EYEBEAM, true); - _timer = 0; - } - } - } - }; + } }; class spell_kologarn_focused_eyebeam : public SpellScript @@ -867,7 +830,7 @@ public: { if (target) if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN))) + if (Creature* cr = instance->GetCreature(BOSS_KOLOGARN)) return cr->AI()->GetData(DATA_KOLOGARN_LOOKS_ACHIEV); return false; @@ -883,7 +846,7 @@ public: { if (target) if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN))) + if (Creature* cr = instance->GetCreature(BOSS_KOLOGARN)) return cr->AI()->GetData(DATA_KOLOGARN_RUBBLE_ACHIEV); return false; @@ -899,7 +862,7 @@ public: { if (target) if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN))) + if (Creature* cr = instance->GetCreature(BOSS_KOLOGARN)) return cr->AI()->GetData(DATA_KOLOGARN_ARMS_ACHIEV); return false; @@ -909,9 +872,9 @@ public: void AddSC_boss_kologarn() { // Npcs - new boss_kologarn(); - new boss_kologarn_arms(); - new boss_kologarn_eyebeam(); + RegisterUlduarCreatureAI(boss_kologarn); + RegisterUlduarCreatureAI(boss_kologarn_arms); + RegisterUlduarCreatureAI(boss_kologarn_eyebeam); RegisterUlduarCreatureAI(boss_kologarn_pit_kill_bunny); // Spells diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index f09fc8252..e4c1367f9 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -250,1658 +250,1575 @@ enum Texts 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)) +#define GetMimiron() instance->GetCreature(BOSS_MIMIRON) +#define GetLMK2() instance->GetCreature(DATA_MIMIRON_LEVIATHAN_MKII) +#define GetVX001() instance->GetCreature(DATA_MIMIRON_VX001) +#define GetACU() instance->GetCreature(DATA_MIMIRON_ACU) -class boss_mimiron : public CreatureScript +struct boss_mimiron : public BossAI { -public: - boss_mimiron() : CreatureScript("boss_mimiron") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_mimiron(Creature* pCreature) : BossAI(pCreature, BOSS_MIMIRON) { - return GetUlduarAI(pCreature); + if (!me->IsAlive()) + instance->SetBossState(BOSS_MIMIRON, DONE); + + bIsEvading = false; } - struct boss_mimironAI : public ScriptedAI + bool bIsEvading; + bool hardmode; + bool berserk; + bool bAchievProximityMine; + bool bAchievBombBot; + bool bAchievRocketStrike; + uint32 allowedFlameSpreadTime; + bool changeAllowedFlameSpreadTime; + uint8 minutesTalkNum; + uint32 outofCombatTimer; + + void Reset() override { - boss_mimironAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + hardmode = false; + berserk = false; + bAchievProximityMine = false; + bAchievBombBot = false; + bAchievRocketStrike = false; + allowedFlameSpreadTime = 0; + outofCombatTimer = 0; + changeAllowedFlameSpreadTime = false; + ResetGameObjects(); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + + if (!instance->IsBossDone(BOSS_MIMIRON)) + _Reset(); + } + + void AttackStart(Unit* who) override + { + if (who) + me->Attack(who, true); // skip following + } + + void JustReachedHome() override + { + _JustReachedHome(); + me->setActive(false); + } + + void JustEngagedWith(Unit* /*who*/) override + { + me->setActive(true); + DoZoneInCombat(); + me->RemoveAllAuras(); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + events.Reset(); + + if (Creature* c = GetLMK2()) { - 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 + if (c->IsInEvadeMode()) { EnterEvadeMode(EVADE_REASON_OTHER); return; } - CloseDoorAndButton(); + if (!c->IsAlive()) + c->Respawn(); - if (!hardmode) + 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); + + 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); + + 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, Milliseconds((i + 1) * 60000)); + events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, Milliseconds((TALK_COMPUTER_ZERO - minutesTalkNum) * 60000)); + } + + // ensure LMK2 is at proper position + if (Creature* LMK2 = GetLMK2()) + { + LMK2->UpdatePosition(LMK2->GetHomePosition(), true); + LMK2->StopMovingOnCurrentPos(); + } + + if (!instance->IsBossDone(BOSS_MIMIRON)) + instance->SetBossState(BOSS_MIMIRON, IN_PROGRESS); + } + + void UpdateAI(uint32 diff) override + { + if (!me->IsInCombat()) + { + outofCombatTimer += diff; + if (outofCombatTimer >= 10000) { - Talk(SAY_MKII_ACTIVATE); - events.ScheduleEvent(EVENT_SIT_LMK2, 6s); - events.ScheduleEvent(EVENT_BERSERK, 15min); + 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); } - else - { - events.ScheduleEvent(EVENT_MIMIRON_SAY_HARDMODE, 7s); - events.ScheduleEvent(EVENT_BERSERK, Is25ManRaid() ? 10min : 8min); + return; + } - 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, Milliseconds((i + 1) * 60000)); - events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, Milliseconds((TALK_COMPUTER_ZERO - minutesTalkNum) * 60000)); - } + Position p = me->GetHomePosition(); + if (me->GetExactDist(&p) > 80.0f || !SelectTargetFromPlayerList(150.0f)) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } - // ensure LMK2 is at proper position - if (pInstance) + events.Update(diff); + + switch (events.ExecuteEvent()) + { + case 0: + 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()) { - LMK2->UpdatePosition(LMK2->GetHomePosition(), true); - LMK2->StopMovingOnCurrentPos(); + me->EnterVehicle(LMK2, 6); + events.ScheduleEvent(EVENT_SIT_LMK2_INTERVAL, 2s); + break; } - - 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); + break; + case EVENT_SIT_LMK2_INTERVAL: + if (Creature* LMK2 = GetLMK2()) + { 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); + 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; - case EVENT_SIT_LMK2: - if (Creature* LMK2 = GetLMK2()) - { - me->EnterVehicle(LMK2, 6); - events.ScheduleEvent(EVENT_SIT_LMK2_INTERVAL, 2s); - break; - } - EnterEvadeMode(EVADE_REASON_OTHER); + } + 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; - 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: + } + 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, false); + elevator->UseDoorOrButton(0, true); elevator->EnableCollision(false); } - events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_1, 6s); + events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_2, 18s); 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->GetMotionMaster()->MovePoint(0, 2737.75f, 2574.22f, 381.34f, FORCED_MOVEMENT_NONE, 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(7s); - LMK2->SetReactState(REACT_PASSIVE); - VX001->InterruptNonMeleeSpells(false); - VX001->AttackStop(); - VX001->AI()->SetData(1, 0); - VX001->DespawnOrUnsummon(7s); - VX001->SetReactState(REACT_PASSIVE); - ACU->InterruptNonMeleeSpells(false); - ACU->AttackStop(); - ACU->AI()->SetData(1, 0); - ACU->DespawnOrUnsummon(7s); - ACU->SetReactState(REACT_PASSIVE); - - Position exitPos = me->GetPosition(); - me->_ExitVehicle(&exitPos); - me->AttackStop(); - me->GetMotionMaster()->Clear(); - summons.DoAction(1337); // despawn summons of summons - summons.DespawnEntry(NPC_FLAMES_INITIAL); - summons.DespawnEntry(33576); - - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - - 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); - - DoCastSelf(SPELL_SLEEP_VISUAL_1); - - 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_STAND_UP_FRIENDLY, 6s); - } - break; - case EVENT_STAND_UP_FRIENDLY: - me->RemoveAurasDueToSpell(SPELL_SLEEP_VISUAL_1); - DoCastSelf(SPELL_SLEEP_VISUAL_2); - me->SetFaction(FACTION_FRIENDLY); - events.ScheduleEvent(EVENT_SAY_VOLTRON_DEAD, 4s); - break; - case EVENT_SAY_VOLTRON_DEAD: - Talk(SAY_V07TRON_DEATH); - me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); - if (pInstance) - pInstance->SetData(TYPE_MIMIRON, DONE); - // 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, 9s); - break; - case EVENT_DISAPPEAR: - DoCastSelf(SPELL_TELEPORT); - summons.DespawnAll(); - break; - } - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_TELEPORT) - { - me->DespawnOrUnsummon(); - pInstance->SetData(EVENT_KEEPER_TELEPORTED, DONE); - } - } - - 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 ) + EnterEvadeMode(EVADE_REASON_OTHER); + break; + case EVENT_ELEVATOR_INTERVAL_2: + if (Creature* VX001 = GetVX001()) { - button->SetLootState(GO_READY); - button->UseDoorOrButton(0, false); - button->RemoveGameObjectFlag(GO_FLAG_IN_USE); + 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->GetMotionMaster()->MovePoint(0, 2737.75f, 2574.22f, 381.34f, FORCED_MOVEMENT_NONE, 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(7s); + LMK2->SetReactState(REACT_PASSIVE); + VX001->InterruptNonMeleeSpells(false); + VX001->AttackStop(); + VX001->AI()->SetData(1, 0); + VX001->DespawnOrUnsummon(7s); + VX001->SetReactState(REACT_PASSIVE); + ACU->InterruptNonMeleeSpells(false); + ACU->AttackStop(); + ACU->AI()->SetData(1, 0); + ACU->DespawnOrUnsummon(7s); + ACU->SetReactState(REACT_PASSIVE); + + Position exitPos = me->GetPosition(); + me->_ExitVehicle(&exitPos); + me->AttackStop(); + me->GetMotionMaster()->Clear(); + summons.DoAction(1337); // despawn summons of summons + summons.DespawnEntry(NPC_FLAMES_INITIAL); + summons.DespawnEntry(33576); + + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + + 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); + + DoCastSelf(SPELL_SLEEP_VISUAL_1); + + if (instance) + for( uint16 i = 0; i < 3; ++i ) + if (GameObject* door = instance->GetGameObject(DATA_GO_MIMIRON_DOOR_1 + i)) + if (door->GetGoState() != GO_STATE_ACTIVE ) + { + door->SetLootState(GO_READY); + door->UseDoorOrButton(0, false); + } + + instance->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_STAND_UP_FRIENDLY, 6s); + } + break; + case EVENT_STAND_UP_FRIENDLY: + me->RemoveAurasDueToSpell(SPELL_SLEEP_VISUAL_1); + DoCastSelf(SPELL_SLEEP_VISUAL_2); + me->SetFaction(FACTION_FRIENDLY); + events.ScheduleEvent(EVENT_SAY_VOLTRON_DEAD, 4s); + break; + case EVENT_SAY_VOLTRON_DEAD: + Talk(SAY_V07TRON_DEATH); + me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + instance->SetBossState(BOSS_MIMIRON, DONE); + // 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, 9s); + break; + case EVENT_DISAPPEAR: + DoCastSelf(SPELL_TELEPORT); + summons.DespawnAll(); + break; + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_TELEPORT) + { + me->DespawnOrUnsummon(); + instance->SetData(EVENT_KEEPER_TELEPORTED, DONE); + } + } + + 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(); } - 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); - } + summons.DoAction(1337); // despawn summons of summons - if (GameObject* button = me->FindNearestGameObject(GO_BUTTON, 200.0f)) - if (button->GetGoState() != GO_STATE_ACTIVE ) - { - button->SetLootState(GO_READY); - button->UseDoorOrButton(0, false); - } - } + me->RemoveAllAuras(); + me->ExitVehicle(); + BossAI::EnterEvadeMode(why); - void SetData(uint32 /*id*/, uint32 value) override + bIsEvading = false; + } + + void ResetGameObjects() + { + for (uint16 i = 0; i < 3; ++i) + if (GameObject* door = instance->GetGameObject(DATA_GO_MIMIRON_DOOR_1 + i)) + if (door->GetGoState() != GO_STATE_ACTIVE) + { + door->SetLootState(GO_READY); + door->UseDoorOrButton(0, false); + } + + if (GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 200.0f)) { - switch (value) // end of phase 1-3, 4-6 for voltron + 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() + { + for (uint16 i = 0; i < 3; ++i) + if (GameObject* door = instance->GetGameObject(DATA_GO_MIMIRON_DOOR_1 + i)) + 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; + } +}; + +struct npc_ulduar_leviathan_mkii : public ScriptedAI +{ + npc_ulduar_leviathan_mkii(Creature* pCreature) : ScriptedAI(pCreature) + { + instance = me->GetInstanceScript(); + bIsEvading = false; + } + + InstanceScript* instance; + 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: - 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); + 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: - 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; + 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; } } - - 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 + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { - npc_ulduar_leviathan_mkiiAI(Creature* pCreature) : ScriptedAI(pCreature) + if (damage >= me->GetHealth() || me->GetHealth() < 15000) { - 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 + damage = 0; + if (me->GetReactState() == REACT_PASSIVE) + return; + me->SetReactState(REACT_PASSIVE); + if (Phase == 1) { - switch (value) + if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) { - 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; + 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 DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + 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->HasSilenceAura()) + return; + + switch (events.ExecuteEvent()) { - if (damage >= me->GetHealth() || me->GetHealth() < 15000) + 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->IsPlayer()) + if (Creature* c = GetMimiron()) { - 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->HasSilenceAura()) - 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->IsPlayer()) - 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(6s); - } - } - - 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->IsCreature()) - r->ToCreature()->DespawnOrUnsummon(1ms); - } - - 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; + c->AI()->Talk(SAY_MKII_SLAY); } 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->IsCreature()) - 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->IsPlayer()) - if (Creature* c = GetMimiron()) { - if (Phase == 2) - { - c->AI()->Talk(SAY_VX001_SLAY); - } - else - { - c->AI()->Talk(SAY_V07TRON_SLAY); - } + 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(8s); - } - - 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 + void EnterEvadeMode(EvadeReason why) override { - npc_ulduar_aerial_command_unitAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + 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) { - pInstance = me->GetInstanceScript(); - bIsEvading = false; - immobilized = false; - me->SetDisableGravity(true); + Unit::Kill(p, p); + p->ToCreature()->DespawnOrUnsummon(6s); } + } - InstanceScript* pInstance; - EventMap events; - SummonList summons; - bool bIsEvading; - uint8 Phase; - bool immobilized; + Unit* GetS3() + { + if (Vehicle* vk = me->GetVehicleKit()) + if (Unit* cannon = vk->GetPassenger(3)) + return cannon; - void Reset() override + return 0; + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_SELF_REPAIR) { - Phase = 0; - events.Reset(); - summons.DespawnAll(); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); } + } +}; - void AttackStart(Unit* who) override +struct npc_ulduar_vx001 : public ScriptedAI +{ + npc_ulduar_vx001(Creature* pCreature) : ScriptedAI(pCreature) + { + instance = me->GetInstanceScript(); + bIsEvading = false; + } + + InstanceScript* instance; + 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 { - 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->GetMotionMaster()->MovePoint(0, 2744.65f, 2569.46f, 381.34f); - - 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->GetMotionMaster()->MovePoint(0, x, y, 381.34f, FORCED_MOVEMENT_NONE, speed); - if (mc) - { - mc->AI()->SetData(0, 0); - SetData(2, 1); - } - } - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) + switch (value) { case 0: + Phase = 0; + fighting = false; + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); + events.Reset(); break; - case EVENT_SPELL_PLASMA_BALL: - if (!immobilized) - DoCastVictim(SPELL_PLASMA_BALL); - events.Repeat(3s); + 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 EVENT_SUMMON_BOMB_BOT: - if (!immobilized) - me->CastSpell(me, SPELL_SUMMON_BOMB_BOT, false); - events.Repeat(15s); + 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; - 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 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->IsCreature()) + r->ToCreature()->DespawnOrUnsummon(1ms); + } + + 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()) { - 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); + 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); } - break; - case EVENT_MAGNETIC_CORE_PULL_DOWN: - me->CastSpell(me, SPELL_MAGNETIC_CORE, true); - me->CastSpell(me, SPELL_SPINNING, true); - me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), 365.34f, FORCED_MOVEMENT_NONE, me->GetExactDist(me->GetPositionX(), me->GetPositionY(), 365.34f)); - events.ScheduleEvent(EVENT_MAGNETIC_CORE_FREE, 20s); - break; - case EVENT_MAGNETIC_CORE_FREE: - me->RemoveAura(SPELL_SPINNING); - me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), 381.34f, FORCED_MOVEMENT_NONE, me->GetDistance(me->GetPositionX(), me->GetPositionY(), 381.34f)); - events.ScheduleEvent(EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE, 1s); - break; - case EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE: + } + } + } + } + + 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->IsCreature()) + 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->IsPlayer()) + 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(8s); + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_SELF_REPAIR) + { + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetReactState(REACT_AGGRESSIVE); + } + } +}; + +struct npc_ulduar_aerial_command_unit : public ScriptedAI +{ + npc_ulduar_aerial_command_unit(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + { + instance = me->GetInstanceScript(); + bIsEvading = false; + immobilized = false; + me->SetDisableGravity(true); + } + + InstanceScript* instance; + 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); } } - - void MoveInLineOfSight(Unit* /*mover*/) override {} - - void KilledUnit(Unit* who) override + else if (id == 2 && !immobilized && Phase == 3) // magnetic core { - if (who->IsPlayer()) - if (Creature* c = GetMimiron()) - { - if (Phase == 3) - { - c->AI()->Talk(SAY_AERIAL_SLAY); - } - else - { - c->AI()->Talk(SAY_V07TRON_SLAY); - } - } + immobilized = true; + events.ScheduleEvent(EVENT_MAGNETIC_CORE_PULL_DOWN, 2s); } - - 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 + void DoAction(int32 param) override { - npc_ulduar_proximity_mineAI(Creature* pCreature) : ScriptedAI(pCreature) + 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->GetMotionMaster()->MovePoint(0, 2744.65f, 2569.46f, 381.34f); + + 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->GetMotionMaster()->MovePoint(0, x, y, 381.34f, FORCED_MOVEMENT_NONE, speed); + 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) + DoCastVictim(SPELL_PLASMA_BALL); + 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->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), 365.34f, FORCED_MOVEMENT_NONE, me->GetExactDist(me->GetPositionX(), me->GetPositionY(), 365.34f)); + events.ScheduleEvent(EVENT_MAGNETIC_CORE_FREE, 20s); + break; + case EVENT_MAGNETIC_CORE_FREE: + me->RemoveAura(SPELL_SPINNING); + me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), 381.34f, FORCED_MOVEMENT_NONE, me->GetDistance(me->GetPositionX(), me->GetPositionY(), 381.34f)); + 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->IsPlayer()) + 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); + } + } +}; + +struct npc_ulduar_proximity_mine : public ScriptedAI +{ + npc_ulduar_proximity_mine(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; } + + // MoveInLineOfSight is checked every few yards, can't use it + void UpdateAI(uint32 diff) override + { + if (timer2 <= diff) { - exploded = false; - timer = 2500; timer2 = 35000; + if (!exploded) + { + exploded = true; + me->CastSpell(me, SPELL_MINE_EXPLOSION, false); + } } + else + timer2 -= diff; - 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; } - - // MoveInLineOfSight is checked every few yards, can't use it - void UpdateAI(uint32 diff) override + if (timer <= diff) { - if (timer2 <= diff) + timer = 500; + if (!exploded && SelectTargetFromPlayerList(1.9f)) { - timer2 = 35000; - if (!exploded) - { - exploded = true; - me->CastSpell(me, SPELL_MINE_EXPLOSION, false); - } + 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; } - }; + else + timer -= diff; + } }; class spell_ulduar_mimiron_mine_explosion : public SpellScript @@ -1911,8 +1828,8 @@ class spell_ulduar_mimiron_mine_explosion : public SpellScript void HandleDamage(SpellEffIndex /*effIndex*/) { if (GetHitPlayer()) - if (InstanceScript* pInstance = GetCaster()->GetInstanceScript()) - if (Creature* mimi = pInstance->GetCreature(TYPE_MIMIRON)) + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* mimi = instance->GetCreature(BOSS_MIMIRON)) mimi->AI()->SetData(0, 11); } @@ -1922,163 +1839,130 @@ class spell_ulduar_mimiron_mine_explosion : public SpellScript } }; -class npc_ulduar_mimiron_rocket : public CreatureScript +struct npc_ulduar_mimiron_rocket : public NullCreatureAI { -public: - npc_ulduar_mimiron_rocket() : CreatureScript("npc_ulduar_mimiron_rocket") { } + npc_ulduar_mimiron_rocket(Creature* pCreature) : NullCreatureAI(pCreature) {} - CreatureAI* GetAI(Creature* pCreature) const override + void InitializeAI() override { - return GetUlduarAI(pCreature); + if (!me->isDead()) + Reset(); } - struct npc_ulduar_mimiron_rocketAI : public NullCreatureAI + void Reset() override { - npc_ulduar_mimiron_rocketAI(Creature* pCreature) : NullCreatureAI(pCreature) {} + me->SetCanFly(true); + me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING); + me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); + } - void InitializeAI() override - { - if (!me->isDead()) - Reset(); - } + void SetData(uint32 /*id*/, uint32 /*value*/) override + { + me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 100.0f, FORCED_MOVEMENT_NONE, 0.f, false, true); + } - void Reset() override + void UpdateAI(uint32 /*diff*/) override + { + if (!me->GetVehicle()) { - me->SetCanFly(true); - me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING); - me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD); + me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN) + 0.4f, false); + me->SetSpeed(MOVE_FLIGHT, me->GetSpeedRate(MOVE_RUN), false); } - - void SetData(uint32 /*id*/, uint32 /*value*/) override - { - me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 100.0f, FORCED_MOVEMENT_NONE, 0.f, 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 +struct npc_ulduar_magnetic_core : public NullCreatureAI { -public: - npc_ulduar_magnetic_core() : CreatureScript("npc_ulduar_magnetic_core") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_ulduar_magnetic_core(Creature* pCreature) : NullCreatureAI(pCreature) { - return GetUlduarAI(pCreature); + instance = 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; } - struct npc_ulduar_magnetic_coreAI : public NullCreatureAI + InstanceScript* instance; + uint16 despawnTimer; + + void SetData(uint32 /*id*/, uint32 /*value*/) override { - npc_ulduar_magnetic_coreAI(Creature* pCreature) : NullCreatureAI(pCreature) + despawnTimer = 20000; + } + + void UpdateAI(uint32 diff) override + { + if (despawnTimer <= diff) { - 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; + me->DespawnOrUnsummon(1ms); } - - 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(1ms); - } - else - despawnTimer -= diff; - } - }; + else + despawnTimer -= diff; + } }; -class npc_ulduar_bot_summon_trigger : public CreatureScript +struct npc_ulduar_bot_summon_trigger : public NullCreatureAI { -public: - npc_ulduar_bot_summon_trigger() : CreatureScript("npc_ulduar_bot_summon_trigger") { } + npc_ulduar_bot_summon_trigger(Creature* pCreature) : NullCreatureAI(pCreature) { } - CreatureAI* GetAI(Creature* pCreature) const override + uint32 timer; + uint8 option; + + void Reset() override { - return GetUlduarAI(pCreature); + timer = 8000; + option = 0; } - struct npc_ulduar_bot_summon_triggerAI : public NullCreatureAI + void DoAction(int32 param) override { - npc_ulduar_bot_summon_triggerAI(Creature* pCreature) : NullCreatureAI(pCreature) { } - - uint32 timer; - uint8 option; - - void Reset() override + switch (param) { - timer = 8000; - option = 0; + 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 DoAction(int32 param) override + void UpdateAI(uint32 diff) override + { + if (timer <= diff) { - 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; - } - } + uint32 option_npcid[3] = {NPC_JUNK_BOT, NPC_ASSAULT_BOT, NPC_EMERGENCY_FIRE_BOT}; + InstanceScript* instance = 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); + } - 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(500ms); - timer = 99999; - } - else - timer -= diff; + me->DespawnOrUnsummon(500ms); + timer = 99999; } - }; + else + timer -= diff; + } }; class spell_mimiron_rapid_burst_aura : public AuraScript @@ -2170,10 +2054,10 @@ public: if (InstanceScript* instance = go->GetInstanceScript()) { - if (instance->GetData(TYPE_MIMIRON) != NOT_STARTED) + if (instance->GetBossState(BOSS_MIMIRON) != NOT_STARTED) return false; - if (Creature* c = ObjectAccessor::GetCreature(*go, instance->GetGuidData(TYPE_MIMIRON))) + if (Creature* c = instance->GetCreature(BOSS_MIMIRON)) { c->AI()->SetData(0, 7); c->AI()->AttackStart(player); @@ -2184,254 +2068,208 @@ public: } }; -class npc_ulduar_flames_initial : public CreatureScript +struct npc_ulduar_flames_initial : public NullCreatureAI { -public: - npc_ulduar_flames_initial() : CreatureScript("npc_ulduar_flames_initial") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_ulduar_flames_initial(Creature* pCreature) : NullCreatureAI(pCreature) { - return GetUlduarAI(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); + } } - struct npc_ulduar_flames_initialAI : public NullCreatureAI + GuidList FlameList; + EventMap events; + uint32 CreateTime; + + void DoAction(int32 action) override { - 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); - } - } + if (action == 1337) + RemoveAll(); + } - GuidList FlameList; - EventMap events; - uint32 CreateTime; - - void DoAction(int32 action) override + void SpreadFlame(float x, float y) + { + if (Creature* flame = me->SummonCreature(NPC_FLAMES_SPREAD, x, y, 364.32f, 0.0f)) { - 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(); + 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); + } + } - events.Update(diff); + void RemoveFlame(ObjectGuid guid) + { + FlameList.remove(guid); + } - switch (events.ExecuteEvent()) + 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* instance = me->GetInstanceScript()) + if (instance->GetBossState(BOSS_MIMIRON) != IN_PROGRESS) { - case 0: - break; - case EVENT_FLAMES_SPREAD: - { - if (FlameList.empty()) - { - me->DespawnOrUnsummon(); - return; - } + RemoveAll(); + return; + } - if (InstanceScript* pInstance = me->GetInstanceScript()) - if (Creature* mimiron = GetMimiron()) - if (CreateTime < mimiron->AI()->GetData(10)) + events.Update(diff); + + switch (events.ExecuteEvent()) + { + case 0: + break; + case EVENT_FLAMES_SPREAD: + { + if (FlameList.empty()) + { + me->DespawnOrUnsummon(); + return; + } + + if (InstanceScript* instance = 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()) { - break; + target = plr; + prevdist = plr->GetExactDist2d(last); } - Creature* last = ObjectAccessor::GetCreature(*me, FlameList.back()); - if (last) + if (target && prevdist >= 4.0f) // no need to spread when player is standing in fire, check distance { - 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)); - } + 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; - } + + events.Repeat(5750ms); + } + break; } - }; + } }; -class npc_ulduar_flames_spread : public CreatureScript +struct npc_ulduar_flames_spread : public NullCreatureAI { -public: - npc_ulduar_flames_spread() : CreatureScript("npc_ulduar_flames_spread") { } + npc_ulduar_flames_spread(Creature* pCreature) : NullCreatureAI(pCreature) {} - CreatureAI* GetAI(Creature* pCreature) const override + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) 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) { - 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()); + 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, c->AI())->RemoveFlame(me->GetGUID()); - me->RemoveAllAuras(); - me->DespawnOrUnsummon(2500ms); - } - break; - case SPELL_VX001_FROST_BOMB: - me->CastSpell(me, SPELL_SUMMON_FROST_BOMB, true); - break; - } + me->RemoveAllAuras(); + me->DespawnOrUnsummon(2500ms); + } + break; + case SPELL_VX001_FROST_BOMB: + me->CastSpell(me, SPELL_SUMMON_FROST_BOMB, true); + break; } - }; + } }; -class npc_ulduar_emergency_fire_bot : public CreatureScript +struct npc_ulduar_emergency_fire_bot : public ScriptedAI { -public: - npc_ulduar_emergency_fire_bot() : CreatureScript("npc_ulduar_emergency_fire_bot") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_ulduar_emergency_fire_bot(Creature* pCreature) : ScriptedAI(pCreature) { - return GetUlduarAI(pCreature); + events.Reset(); + events.ScheduleEvent(EVENT_EMERGENCY_BOT_CHECK, 1s); } - struct npc_ulduar_emergency_fire_botAI : public ScriptedAI + EventMap events; + + void MoveInLineOfSight(Unit*) override {} + void AttackStart(Unit*) override {} + + void MovementInform(uint32 type, uint32 id) override { - npc_ulduar_emergency_fire_botAI(Creature* pCreature) : ScriptedAI(pCreature) + 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()) { - events.Reset(); - events.ScheduleEvent(EVENT_EMERGENCY_BOT_CHECK, 1s); + 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; } - - 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 +struct npc_ulduar_rocket_strike_trigger : public NullCreatureAI { -public: - npc_ulduar_rocket_strike_trigger() : CreatureScript("npc_ulduar_rocket_strike_trigger") { } + npc_ulduar_rocket_strike_trigger(Creature* pCreature) : NullCreatureAI(pCreature) {} - CreatureAI* GetAI(Creature* pCreature) const override + void SpellHitTarget(Unit* target, SpellInfo const* spell) 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 || !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->IsPlayer()) - if (InstanceScript* pInstance = me->GetInstanceScript()) - if (Creature* c = GetMimiron()) - c->AI()->SetData(0, 13); - } + if (target->GetEntry() == NPC_ASSAULT_BOT) + me->CastSpell(me, 65040, true); // achievement Not-So-Friendly Fire + else if (target->IsPlayer()) + if (InstanceScript* instance = me->GetInstanceScript()) + if (Creature* c = GetMimiron()) + c->AI()->SetData(0, 13); } - }; + } }; class achievement_mimiron_firefighter : public AchievementCriteriaScript @@ -2480,23 +2318,23 @@ public: void AddSC_boss_mimiron() { - new boss_mimiron(); - new npc_ulduar_leviathan_mkii(); - new npc_ulduar_vx001(); - new npc_ulduar_aerial_command_unit(); + RegisterUlduarCreatureAI(boss_mimiron); + RegisterUlduarCreatureAI(npc_ulduar_leviathan_mkii); + RegisterUlduarCreatureAI(npc_ulduar_vx001); + RegisterUlduarCreatureAI(npc_ulduar_aerial_command_unit); - new npc_ulduar_proximity_mine(); - new npc_ulduar_mimiron_rocket(); - new npc_ulduar_magnetic_core(); - new npc_ulduar_bot_summon_trigger(); + RegisterUlduarCreatureAI(npc_ulduar_proximity_mine); + RegisterUlduarCreatureAI(npc_ulduar_mimiron_rocket); + RegisterUlduarCreatureAI(npc_ulduar_magnetic_core); + RegisterUlduarCreatureAI(npc_ulduar_bot_summon_trigger); RegisterSpellScript(spell_mimiron_rapid_burst_aura); RegisterSpellScript(spell_mimiron_p3wx2_laser_barrage_aura); RegisterSpellScript(spell_ulduar_mimiron_mine_explosion); new go_ulduar_do_not_push_this_button(); - new npc_ulduar_flames_initial(); - new npc_ulduar_flames_spread(); - new npc_ulduar_emergency_fire_bot(); - new npc_ulduar_rocket_strike_trigger(); + RegisterUlduarCreatureAI(npc_ulduar_flames_initial); + RegisterUlduarCreatureAI(npc_ulduar_flames_spread); + RegisterUlduarCreatureAI(npc_ulduar_emergency_fire_bot); + RegisterUlduarCreatureAI(npc_ulduar_rocket_strike_trigger); new achievement_mimiron_firefighter(); new achievement_mimiron_set_up_us_the_bomb_11(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index 6a3682d78..2a2efb95c 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -135,480 +135,446 @@ enum Misc 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 +struct boss_razorscale : public BossAI { -public: - boss_razorscale() : CreatureScript("boss_razorscale") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_razorscale(Creature* creature) : BossAI(creature, BOSS_RAZORSCALE) { - return GetUlduarAI(pCreature); + startPath = true; } - struct boss_razorscaleAI : public ScriptedAI + ObjectGuid ExpeditionEngineerGUIDs[3]; + ObjectGuid CommanderGUID; + float cords[4][2]; + bool bGroundPhase; + bool startPath; + uint8 flyTimes; + + void InitializeAI() override { - boss_razorscaleAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + me->SetDisableGravity(true); + me->setActive(true); + Reset(); + } + + void Reset() override + { + _Reset(); + + 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; + } + + void AttackStart(Unit* who) override + { + if (who && me->Attack(who, true) && bGroundPhase) + me->GetMotionMaster()->MoveChase(who); + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + 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 ) { - pInstance = me->GetInstanceScript(); - startPath = true; + 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(); + } - InstanceScript* pInstance; - EventMap events; - SummonList summons; - ObjectGuid ExpeditionEngineerGUIDs[3]; - ObjectGuid CommanderGUID; - float cords[4][2]; - bool bGroundPhase; - bool startPath; - uint8 flyTimes; + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + if (!caster || !instance) + return; - void InitializeAI() override + switch (spell->Id) { - me->SetDisableGravity(true); - me->setActive(true); - Reset(); - } + case SPELL_LAUNCH_CHAIN: + { + uint32 spellId = SPELL_CHAIN_4; - 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: + if (caster->GetGUID() == instance->GetGuidData(DATA_HARPOON_FIRE_STATE_1)) { - 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); + spellId = SPELL_CHAIN_1; } - break; - case SPELL_CHAIN_1: - case SPELL_CHAIN_2: - case SPELL_CHAIN_3: - case SPELL_CHAIN_4: + else if (caster->GetGUID() == instance->GetGuidData(DATA_HARPOON_FIRE_STATE_2)) { - 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); - } + spellId = SPELL_CHAIN_2; } - 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; - me->GetMotionMaster()->MovePath(me->GetWaypointPath(), FORCED_MOVEMENT_NONE, PathSource::WAYPOINT_MGR); - } - - 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: + else if (caster->GetGUID() == instance->GetGuidData(DATA_HARPOON_FIRE_STATE_3)) { - 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); + spellId = SPELL_CHAIN_3; } - 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); + 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)) { - me->RemoveAura(SPELL_CHAIN_2); - me->RemoveAura(SPELL_CHAIN_4); + if (me->HasAura(SPELL_CHAIN_2)) + count++; + if (me->HasAura(SPELL_CHAIN_4)) + count++; } - me->CastSpell(me, SPELL_WINGBUFFET, true); - - if ((me->GetHealth() * 100) / me->GetMaxHealth() < 50 ) // start phase 3 + if (count >= REQ_CHAIN_COUNT) { - 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; + 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); - - 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->SetTarget(); 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); + me->GetMotionMaster()->MoveLand(0, CORDS_GROUND, 25.0f); } - - 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(); + } + break; } + } - void MoveInLineOfSight(Unit* /*who*/) override {} + void DamageTaken(Unit* attacker, 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 JustReachedHome() override + BossAI::DamageTaken(attacker, damage, damagetype, damageSchoolMask); + } + + 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; } - void JustSummoned(Creature* s) override + if (type != EFFECT_MOTION_TYPE) + return; + if (id == 0) // landed { - summons.Summon(s); + 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; + me->GetMotionMaster()->MovePath(me->GetWaypointPath(), FORCED_MOVEMENT_NONE, PathSource::WAYPOINT_MGR); } - uint32 GetData(uint32 id) const override + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - if (id == 1) - return (flyTimes <= 1 ? 1 : 0); - return 0; + 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 (instance) + for( int i = 0; i < 4; ++i ) + if (Creature* hfs = instance->GetCreature(DATA_HARPOON_FIRE_STATE_1 + i)) + { + 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; } - 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); - } + if (bGroundPhase) + DoMeleeAttackIfReady(); + } - void EnterEvadeMode(EvadeReason why) override - { - me->SetDisableGravity(true); - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - ScriptedAI::EnterEvadeMode(why); - } - }; + void MoveInLineOfSight(Unit* /*who*/) override {} + + void JustReachedHome() override + { + _JustReachedHome(); + startPath = true; + } + + 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 (instance) + instance->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); + BossAI::EnterEvadeMode(why); + } }; class npc_ulduar_expedition_commander : public CreatureScript @@ -625,10 +591,10 @@ public: if (!instance) return true; - if (instance->GetData(TYPE_RAZORSCALE) == DONE) + if (instance->GetBossState(BOSS_RAZORSCALE) == DONE) return true; - Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE)); + Creature* razorscale = instance->GetCreature(BOSS_RAZORSCALE); if (!razorscale || razorscale->IsInCombat()) return true; @@ -645,10 +611,10 @@ public: if (uiAction == GOSSIP_ACTION_INFO_DEF + 1) { InstanceScript* instance = creature->GetInstanceScript(); - if (!instance || instance->GetData(TYPE_RAZORSCALE) == DONE) + if (!instance || instance->GetBossState(BOSS_RAZORSCALE) == DONE) return true; - Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE)); + Creature* razorscale = instance->GetCreature(BOSS_RAZORSCALE); if (razorscale && !razorscale->IsInCombat()) { // Do not show gossip icon if encounter is in progress @@ -656,7 +622,7 @@ public: // 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))) + if (Creature* hfs = instance->GetCreature(DATA_HARPOON_FIRE_STATE_1 + i)) hfs->AI()->SetData(1, 0); if (razorscale->AI()) @@ -682,7 +648,7 @@ public: npc_ulduar_expedition_commanderAI(Creature* creature) : NullCreatureAI(creature) { _instance = creature->GetInstanceScript(); - _introSpoken = _instance->GetData(TYPE_RAZORSCALE) == DONE; + _introSpoken = _instance->GetBossState(BOSS_RAZORSCALE) == DONE; me->SetReactState(REACT_AGGRESSIVE); } @@ -704,213 +670,188 @@ public: }; }; -class npc_ulduar_harpoonfirestate : public CreatureScript +struct npc_ulduar_harpoonfirestate : public NullCreatureAI { -public: - npc_ulduar_harpoonfirestate() : CreatureScript("npc_ulduar_harpoonfirestate") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_ulduar_harpoonfirestate(Creature* pCreature) : NullCreatureAI(pCreature) { - return GetUlduarAI(pCreature); + pInstance = me->GetInstanceScript(); } - struct npc_ulduar_harpoonfirestateAI : public NullCreatureAI + InstanceScript* pInstance; + uint8 repairPoints; + + void Reset() override { - 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); + repairPoints = 0; } - struct npc_ulduar_expedition_engineerAI : public NullCreatureAI + uint32 GetHarpoonGunIdForThisHFS() { - npc_ulduar_expedition_engineerAI(Creature* pCreature) : NullCreatureAI(pCreature) + if (pInstance) { - pInstance = me->GetInstanceScript(); + 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; + } - InstanceScript* pInstance; - bool working; - uint16 timer; - ObjectGuid fixingGUID; - - void Reset() override + void SetData(uint32 id, uint32 value) override + { + switch (id) { - 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) + case 1: // cleanup at the start of the fight + if (pInstance) { - timer = 3000; - - if (fixingGUID) + uint32 h_entry = GetHarpoonGunIdForThisHFS(); + if (GameObject* wh = me->FindNearestGameObject(h_entry, 5.0f)) { - 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(); - } + wh->SetRespawnTime(0); + wh->Delete(); } - - if (!fixingGUID) + 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) { - Creature* razorscale = nullptr; - if (ObjectGuid rsGUID = pInstance->GetGuidData(TYPE_RAZORSCALE)) - razorscale = ObjectAccessor::GetCreature(*me, rsGUID); - - if (!razorscale || !razorscale->IsInCombat()) + 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)) { - Reset(); - me->GetMotionMaster()->MoveTargetedHome(); - return; + 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); } - - 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); + break; + case 3: // shoot + if (pInstance) + { + Creature* razorscale = pInstance->GetCreature(BOSS_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; + } +}; + +struct npc_ulduar_expedition_engineer : public NullCreatureAI +{ + npc_ulduar_expedition_engineer(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 = pInstance->GetCreature(BOSS_RAZORSCALE); + + if (!razorscale || !razorscale->IsInCombat()) + { + Reset(); + me->GetMotionMaster()->MoveTargetedHome(); + return; + } + + for( int i = 0; i < 4; ++i ) + if (Creature* fs = pInstance->GetCreature(DATA_HARPOON_FIRE_STATE_1 + i)) + 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 @@ -927,9 +868,7 @@ public: if (!pInstance) return true; - Creature* rs = nullptr; - if (ObjectGuid rsGUID = pInstance->GetGuidData(TYPE_RAZORSCALE)) - rs = ObjectAccessor::GetCreature(*go, rsGUID); + Creature* rs = pInstance->GetCreature(BOSS_RAZORSCALE); if (!rs || !rs->IsInCombat()) { @@ -960,8 +899,7 @@ public: break; } - if (ObjectGuid g = pInstance->GetGuidData(npc)) - if (Creature* hfs = ObjectAccessor::GetCreature(*go, g)) + if (Creature* hfs = pInstance->GetCreature(npc)) hfs->AI()->SetData(3, spell); go->SetLootState(GO_JUST_DEACTIVATED); @@ -969,161 +907,128 @@ public: } }; -class npc_ulduar_dark_rune_guardian : public CreatureScript +struct npc_ulduar_dark_rune_guardian : public ScriptedAI { -public: - npc_ulduar_dark_rune_guardian() : CreatureScript("npc_ulduar_dark_rune_guardian") { } + npc_ulduar_dark_rune_guardian(Creature* pCreature) : ScriptedAI(pCreature) { } - CreatureAI* GetAI(Creature* pCreature) const override + uint32 timer2; + + void Reset() override { - return GetUlduarAI(pCreature); + timer2 = 6000; } - struct npc_ulduar_dark_rune_guardianAI : public ScriptedAI + bool CanAIAttack(Unit const* target) const override { - npc_ulduar_dark_rune_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) { } + return target && target->GetEntry() != NPC_RAZORSCALE; + } - uint32 timer2; + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void Reset() override + if (timer2 <= diff) timer2 = 0; + else timer2 -= diff; + if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim())) { - timer2 = 6000; + 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; } - 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(); - } - }; + DoMeleeAttackIfReady(); + } }; -class npc_ulduar_dark_rune_watcher : public CreatureScript +struct npc_ulduar_dark_rune_watcher : public ScriptedAI { -public: - npc_ulduar_dark_rune_watcher() : CreatureScript("npc_ulduar_dark_rune_watcher") { } + npc_ulduar_dark_rune_watcher(Creature* pCreature) : ScriptedAI(pCreature) { } - CreatureAI* GetAI(Creature* pCreature) const override + uint32 timer1; + uint32 timer2; + + void Reset() override { - return GetUlduarAI(pCreature); + timer1 = 6000; + timer2 = 2000; } - struct npc_ulduar_dark_rune_watcherAI : public ScriptedAI + bool CanAIAttack(Unit const* target) const override { - npc_ulduar_dark_rune_watcherAI(Creature* pCreature) : ScriptedAI(pCreature) { } + return target && target->GetEntry() != NPC_RAZORSCALE; + } - uint32 timer1; - uint32 timer2; + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void Reset() override + if (timer1 <= diff) { - timer1 = 6000; - timer2 = 2000; + me->CastSpell(me->GetVictim(), SPELL_CHAINLIGHTNING, false); + timer1 = urand(10000, 12000); + return; } + else + timer1 -= diff; - bool CanAIAttack(Unit const* target) const override + if (timer2 <= diff) { - return target && target->GetEntry() != NPC_RAZORSCALE; + me->CastSpell(me->GetVictim(), SPELL_LIGHTINGBOLT, false); + timer2 = 4000; + return; } + else + timer2 -= diff; - 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(); - } - }; + DoMeleeAttackIfReady(); + } }; -class npc_ulduar_dark_rune_sentinel : public CreatureScript +struct npc_ulduar_dark_rune_sentinel : public ScriptedAI { -public: - npc_ulduar_dark_rune_sentinel() : CreatureScript("npc_ulduar_dark_rune_sentinel") { } + npc_ulduar_dark_rune_sentinel(Creature* pCreature) : ScriptedAI(pCreature) { } - CreatureAI* GetAI(Creature* pCreature) const override + uint32 timer1; + uint32 timer2; + + void Reset() override { - return GetUlduarAI(pCreature); + timer1 = urand(1000, 2000); + timer2 = 6000; } - struct npc_ulduar_dark_rune_sentinelAI : public ScriptedAI + bool CanAIAttack(Unit const* target) const override { - npc_ulduar_dark_rune_sentinelAI(Creature* pCreature) : ScriptedAI(pCreature) { } + return target && target->GetEntry() != NPC_RAZORSCALE; + } - uint32 timer1; - uint32 timer2; + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void Reset() override + if (timer1 <= diff) { - timer1 = urand(1000, 2000); - timer2 = 6000; + 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); } - 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(); - } - }; + DoMeleeAttackIfReady(); + } }; class achievement_quick_shave : public AchievementCriteriaScript @@ -1150,14 +1055,14 @@ public: void AddSC_boss_razorscale() { - new boss_razorscale(); + RegisterUlduarCreatureAI(boss_razorscale); new npc_ulduar_expedition_commander(); - new npc_ulduar_harpoonfirestate(); - new npc_ulduar_expedition_engineer(); + RegisterUlduarCreatureAI(npc_ulduar_harpoonfirestate); + RegisterUlduarCreatureAI(npc_ulduar_expedition_engineer); new go_ulduar_working_harpoon(); - new npc_ulduar_dark_rune_guardian(); - new npc_ulduar_dark_rune_watcher(); - new npc_ulduar_dark_rune_sentinel(); + RegisterUlduarCreatureAI(npc_ulduar_dark_rune_guardian); + RegisterUlduarCreatureAI(npc_ulduar_dark_rune_watcher); + RegisterUlduarCreatureAI(npc_ulduar_dark_rune_sentinel); new achievement_quick_shave(); new achievement_iron_dwarf_medium_rare(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp index b3e9a9633..6b94236bd 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp @@ -299,503 +299,468 @@ enum Misc const Position Middle = {2134.68f, -263.13f, 419.44f, M_PI * 1.5f}; -class boss_thorim : public CreatureScript +struct boss_thorim : public BossAI { -public: - boss_thorim() : CreatureScript("boss_thorim") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_thorim(Creature* creature) : BossAI(creature, BOSS_THORIM) { - return GetUlduarAI(pCreature); + _encounterFinished = !me->IsAlive(); + if (_encounterFinished) + instance->SetBossState(BOSS_THORIM, DONE); } - struct boss_thorimAI : public ScriptedAI + bool _isArenaEmpty; + bool _encounterFinished; + bool _spawnCommoners; + bool _hardMode; + bool _isHitAllowed; + bool _isAlly; + uint8 _trashCounter; + + bool _hitByLightning; + + void DisableThorim(bool apply) { - boss_thorimAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + if (apply) { - m_pInstance = pCreature->GetInstanceScript(); - if ((_encounterFinished = (!me->IsAlive()))) - if (m_pInstance) - m_pInstance->SetData(TYPE_THORIM, DONE); + me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED); + me->DisableRotate(true); + me->AddUnitState(UNIT_STATE_ROOT); } - - 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) + else { - if (apply) + 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) + { + return instance->GetGameObject(entry); + } + + 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); + BossAI::EnterEvadeMode(why); + } + + void Reset() override + { + if (!_encounterFinished) + _Reset(); + + _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) { - 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); + 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; + } - GameObject* GetThorimObject(uint32 entry) + void KilledUnit(Unit* victim) override + { + if (victim->IsPlayer()) + Talk(SAY_SLAY); + } + + void JustReachedHome() override + { + _JustReachedHome(); + me->setActive(false); + } + + void JustEngagedWith(Unit*) override + { + if (!_encounterFinished) + instance->SetBossState(BOSS_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->IsPlayer()) { - 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; + 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); - return 0; - } + me->GetMotionMaster()->MoveChase(me->GetVictim()); + me->GetMotionMaster()->MoveJump(Middle.GetPositionX(), Middle.GetPositionY(), Middle.GetPositionZ(), 20, 20); + me->RemoveAura(SPELL_SHEATH_OF_LIGHTNING); - void DoAction(int32 param) override - { - if (param == ACTION_START_TRASH_DIED) + Talk(SAY_JUMPDOWN); + + // Hard Mode + if (!me->HasAura(62565 /*TOUCH OF DOMINION TRIGGER*/)) { - _trashCounter++; - // activate levar - if (_trashCounter >= 6) - { - if (GameObject* go = GetThorimObject(DATA_THORIM_LEVER)) - go->RemoveGameObjectFlag((GameObjectFlags)48); + instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 64980 /*SIFFED ACHIEVEMENT*/); - 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->IsPlayer()) - 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->IsPlayer()) - { - _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); + _hardMode = true; + EntryCheckPredicate pred(NPC_SIF); + summons.DoAction(ACTION_SIF_JOIN_FIGHT, pred); } - if (damage >= me->GetHealth()|| me->GetHealth()<2) - { - 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); - } - } - } + DoResetThreatList(); + if (Player* player = GetArenaPlayer()) + me->AddThreat(player, 1000.0f); } - void SpawnAnArenaNPC(uint32 arenaNpc) + if (damage >= me->GetHealth()|| me->GetHealth()<2) { - Creature* cr; - uint8 rnd = urand(0,13); - if ((cr = me->SummonCreature(arenaNpc, 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 SpawnCommoners() - { - uint8 rnd = urand(6,7); - for (uint8 i = 0; i < rnd; ++i) - SpawnAnArenaNPC(NPC_DARK_RUNE_COMMONER); - } - - 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); - } - else if (spellInfo->Id == SPELL_TELEPORT) - { - me->DespawnOrUnsummon(); - m_pInstance->SetData(EVENT_KEEPER_TELEPORTED, DONE); - } - } - - void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_LIGHTNING_CHARGE_DAMAGE && target->IsPlayer()) - _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_ARENA_SPAWN_WARBRINGER, 0ms, 0, EVENT_PHASE_START); - events.ScheduleEvent(EVENT_THORIM_ARENA_SPAWN_EVOKER, 5s, 0, EVENT_PHASE_START); - events.ScheduleEvent(EVENT_THORIM_ARENA_SPAWN_COMMONER, 7s, 0, EVENT_PHASE_START); - events.ScheduleEvent(EVENT_THORIM_ARENA_SPAWN_CHAMPION, 10s, 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_ARENA_SPAWN_WARBRINGER: - SpawnAnArenaNPC(NPC_DARK_RUNE_WARBRINGER); - events.Repeat(15s); - break; - case EVENT_THORIM_ARENA_SPAWN_EVOKER: - SpawnAnArenaNPC(NPC_DARK_RUNE_EVOKER); - events.Repeat(20s); - break; - case EVENT_THORIM_ARENA_SPAWN_COMMONER: - SpawnCommoners(); - events.Repeat(21s); - break; - case EVENT_THORIM_ARENA_SPAWN_CHAMPION: - SpawnAnArenaNPC(NPC_DARK_RUNE_CHAMPION); - events.Repeat(25s); - 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); - events.ScheduleEvent(EVENT_THORIM_OUTRO4, 14s, 0, 3); - break; - case EVENT_THORIM_OUTRO4: - DoCastSelf(SPELL_TELEPORT); - break; - } - + damage = 0; if (!_encounterFinished) - DoMeleeAttackIfReady(); + { + _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 + me->CastSpell(me, 64985, true); // credit + instance->SetBossState(BOSS_THORIM, DONE); + } } - }; + } + + void SpawnAnArenaNPC(uint32 arenaNpc) + { + Creature* cr; + uint8 rnd = urand(0,13); + if ((cr = me->SummonCreature(arenaNpc, 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 SpawnCommoners() + { + uint8 rnd = urand(6,7); + for (uint8 i = 0; i < rnd; ++i) + SpawnAnArenaNPC(NPC_DARK_RUNE_COMMONER); + } + + 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); + } + else if (spellInfo->Id == SPELL_TELEPORT) + { + me->DespawnOrUnsummon(); + instance->SetData(EVENT_KEEPER_TELEPORTED, DONE); + } + } + + void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_LIGHTNING_CHARGE_DAMAGE && target->IsPlayer()) + _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_ARENA_SPAWN_WARBRINGER, 0ms, 0, EVENT_PHASE_START); + events.ScheduleEvent(EVENT_THORIM_ARENA_SPAWN_EVOKER, 5s, 0, EVENT_PHASE_START); + events.ScheduleEvent(EVENT_THORIM_ARENA_SPAWN_COMMONER, 7s, 0, EVENT_PHASE_START); + events.ScheduleEvent(EVENT_THORIM_ARENA_SPAWN_CHAMPION, 10s, 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_ARENA_SPAWN_WARBRINGER: + SpawnAnArenaNPC(NPC_DARK_RUNE_WARBRINGER); + events.Repeat(15s); + break; + case EVENT_THORIM_ARENA_SPAWN_EVOKER: + SpawnAnArenaNPC(NPC_DARK_RUNE_EVOKER); + events.Repeat(20s); + break; + case EVENT_THORIM_ARENA_SPAWN_COMMONER: + SpawnCommoners(); + events.Repeat(21s); + break; + case EVENT_THORIM_ARENA_SPAWN_CHAMPION: + SpawnAnArenaNPC(NPC_DARK_RUNE_CHAMPION); + events.Repeat(25s); + 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 + instance->SetBossState(BOSS_THORIM, DONE); + events.ScheduleEvent(EVENT_THORIM_OUTRO4, 14s, 0, 3); + break; + case EVENT_THORIM_OUTRO4: + DoCastSelf(SPELL_TELEPORT); + break; + } + + if (!_encounterFinished) + DoMeleeAttackIfReady(); + } }; -class boss_thorim_sif : public CreatureScript +struct boss_thorim_sif : public ScriptedAI { -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) { } + boss_thorim_sif(Creature* creature) : ScriptedAI(creature) { } void MoveInLineOfSight(Unit*) override {} void AttackStart(Unit*) override {} @@ -817,7 +782,7 @@ public: else if (param == ACTION_SIF_START_DOMINION) { if (me->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) + if (Creature* cr = me->GetInstanceScript()->GetCreature(BOSS_THORIM)) me->CastSpell(cr, SPELL_TOUCH_OF_DOMINION, false); events.ScheduleEvent(EVENT_SIF_FINISH_DOMINION, 150s); @@ -888,22 +853,11 @@ public: me->StopMoving(); } } - }; }; -class boss_thorim_lightning_orb : public CreatureScript +struct boss_thorim_lightning_orb : public npc_escortAI { -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) + boss_thorim_lightning_orb(Creature* creature) : npc_escortAI(creature) { InitWaypoint(); Reset(); @@ -936,22 +890,11 @@ public: void WaypointReached(uint32 /*point*/) override { } - }; }; -class boss_thorim_trap : public CreatureScript +struct boss_thorim_trap : public NullCreatureAI { -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) { } + boss_thorim_trap(Creature* creature) : NullCreatureAI(creature) { } uint32 _checkTimer; @@ -974,22 +917,11 @@ public: } } } - }; }; -class boss_thorim_sif_blizzard : public CreatureScript +struct boss_thorim_sif_blizzard : public npc_escortAI { -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) + boss_thorim_sif_blizzard(Creature* creature) : npc_escortAI(creature) { InitWaypoint(); Reset(); @@ -1023,22 +955,11 @@ public: void WaypointReached(uint32 /*point*/) override { } - }; }; -class boss_thorim_pillar : public CreatureScript +struct boss_thorim_pillar : public NullCreatureAI { -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) { } + boss_thorim_pillar(Creature* pCreature) : NullCreatureAI(pCreature) { } uint32 _resetTimer; @@ -1066,22 +987,11 @@ public: if (_resetTimer >= 10000) Reset(); // _resetTimer set to 0 } - }; }; -class boss_thorim_start_npcs : public CreatureScript +struct boss_thorim_start_npcs : public ScriptedAI { -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) { } + boss_thorim_start_npcs(Creature* pCreature) : ScriptedAI(pCreature) { } EventMap events; bool _isCaster; @@ -1102,7 +1012,7 @@ public: if (!_playerAttack && who && (who->IsPlayer() || who->GetOwnerGUID().IsPlayer())) { if (me->GetInstanceScript()) - if (Creature* thorim = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) + if (Creature* thorim = me->GetInstanceScript()->GetCreature(BOSS_THORIM)) { if (!thorim->IsInCombat()) { @@ -1123,7 +1033,7 @@ public: void JustDied(Unit*) override { if (me->GetInstanceScript()) - if (Creature* thorim = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) + if (Creature* thorim = me->GetInstanceScript()->GetCreature(BOSS_THORIM)) thorim->AI()->DoAction(ACTION_START_TRASH_DIED); } @@ -1220,22 +1130,11 @@ public: if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10)) DoMeleeAttackIfReady(); } - }; }; -class boss_thorim_gauntlet_npcs : public CreatureScript +struct boss_thorim_gauntlet_npcs : public ScriptedAI { -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) { } + boss_thorim_gauntlet_npcs(Creature* pCreature) : ScriptedAI(pCreature) { } EventMap events; bool _isCaster; @@ -1327,22 +1226,11 @@ public: if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10)) DoMeleeAttackIfReady(); } - }; }; -class boss_thorim_runic_colossus : public CreatureScript +struct boss_thorim_runic_colossus : public ScriptedAI { -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) { } + boss_thorim_runic_colossus(Creature* pCreature) : ScriptedAI(pCreature) { } EventMap events; bool _leftHand; @@ -1374,10 +1262,10 @@ public: { if (me->GetInstanceScript()) { - if (GameObject* go = ObjectAccessor::GetGameObject(*me, me->GetInstanceScript()->GetGuidData(DATA_THORIM_FIRST_DOORS))) + if (GameObject* go = me->GetInstanceScript()->GetGameObject(DATA_THORIM_FIRST_DOORS)) go->SetGoState(GO_STATE_ACTIVE); - if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM))) + if (Creature* cr = me->GetInstanceScript()->GetCreature(BOSS_THORIM)) cr->AI()->Talk(SAY_SPECIAL_2); } } @@ -1468,238 +1356,215 @@ public: DoMeleeAttackIfReady(); } - }; }; -class boss_thorim_ancient_rune_giant : public CreatureScript +struct boss_thorim_ancient_rune_giant : public ScriptedAI { -public: - boss_thorim_ancient_rune_giant() : CreatureScript("boss_thorim_ancient_rune_giant") { } + boss_thorim_ancient_rune_giant(Creature* pCreature) : ScriptedAI(pCreature) { } - CreatureAI* GetAI(Creature* pCreature) const override + EventMap events; + bool _isInCombat; + + void Reset() override { - return GetUlduarAI(pCreature); + _isInCombat = false; + events.Reset(); } - struct boss_thorim_ancient_rune_giantAI : public ScriptedAI + void JustEngagedWith(Unit*) override { - boss_thorim_ancient_rune_giantAI(Creature* pCreature) : ScriptedAI(pCreature) { } + _isInCombat = true; + events.CancelEvent(EVENT_ARG_SPAWN); + events.ScheduleEvent(EVENT_ARG_RD, 12s); + events.ScheduleEvent(EVENT_ARG_STOMP, 8s); - EventMap events; - bool _isInCombat; + me->CastSpell(me, SPELL_RUNIC_FORTIFICATION, false); + Talk(SAY_GIANT_RUNIC_MIGHT); + } - void Reset() override + void JustDied(Unit*) override + { + if (InstanceScript* pInstance = me->GetInstanceScript()) { - _isInCombat = false; - events.Reset(); + if (GameObject* go = pInstance->GetGameObject(DATA_THORIM_SECOND_DOORS)) + go->SetGoState(GO_STATE_ACTIVE); + + if (Creature* thorim = pInstance->GetCreature(BOSS_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; } - 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(); - } - }; + DoMeleeAttackIfReady(); + } }; -class boss_thorim_arena_npcs : public CreatureScript +struct boss_thorim_arena_npcs : public ScriptedAI { -public: - boss_thorim_arena_npcs() : CreatureScript("boss_thorim_arena_npcs") { } + boss_thorim_arena_npcs(Creature* pCreature) : ScriptedAI(pCreature) { } - CreatureAI* GetAI(Creature* pCreature) const override + EventMap events; + bool _isCaster; + + void Reset() override { - return GetUlduarAI(pCreature); + _isCaster = (me->GetEntry() == NPC_DARK_RUNE_EVOKER); + events.Reset(); + if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER) + me->CastSpell(me, SPELL_AURA_OF_CELERITY, true); } - struct boss_thorim_arena_npcsAI : public ScriptedAI + void JustEngagedWith(Unit*) override { - boss_thorim_arena_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - EventMap events; - bool _isCaster; - - void Reset() override + if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER) { - _isCaster = (me->GetEntry() == NPC_DARK_RUNE_EVOKER); - events.Reset(); - if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER) - me->CastSpell(me, SPELL_AURA_OF_CELERITY, true); + 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; } - void JustEngagedWith(Unit*) override + if (target) { - 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); - } + 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; + } - bool CanAIAttack(Unit const* target) const override + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !SelectT()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - 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(); + 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 - 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(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); - return true; - } - return 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; } - 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(); - } - }; + if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10)) + DoMeleeAttackIfReady(); + } }; class go_thorim_lever : public GameObjectScript @@ -1759,7 +1624,7 @@ public: bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override { if (InstanceScript* instance = player->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*player, instance->GetGuidData(TYPE_THORIM))) + if (Creature* cr = instance->GetCreature(BOSS_THORIM)) return cr->AI()->GetData(DATA_HIT_BY_LIGHTNING); return false; @@ -1774,7 +1639,7 @@ public: bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override { if (InstanceScript* instance = player->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*player, instance->GetGuidData(TYPE_THORIM))) + if (Creature* cr = instance->GetCreature(BOSS_THORIM)) return cr->AI()->GetData(DATA_LOSE_YOUR_ILLUSION); return false; @@ -1784,21 +1649,21 @@ public: void AddSC_boss_thorim() { // Main encounter - new boss_thorim(); - new boss_thorim_sif(); - new boss_thorim_lightning_orb(); - new boss_thorim_trap(); - new boss_thorim_pillar(); - new boss_thorim_sif_blizzard(); + RegisterUlduarCreatureAI(boss_thorim); + RegisterUlduarCreatureAI(boss_thorim_sif); + RegisterUlduarCreatureAI(boss_thorim_lightning_orb); + RegisterUlduarCreatureAI(boss_thorim_trap); + RegisterUlduarCreatureAI(boss_thorim_pillar); + RegisterUlduarCreatureAI(boss_thorim_sif_blizzard); // Trash - new boss_thorim_start_npcs(); - new boss_thorim_gauntlet_npcs(); - new boss_thorim_arena_npcs(); + RegisterUlduarCreatureAI(boss_thorim_start_npcs); + RegisterUlduarCreatureAI(boss_thorim_gauntlet_npcs); + RegisterUlduarCreatureAI(boss_thorim_arena_npcs); // Mini bosses - new boss_thorim_runic_colossus(); - new boss_thorim_ancient_rune_giant(); + RegisterUlduarCreatureAI(boss_thorim_runic_colossus); + RegisterUlduarCreatureAI(boss_thorim_ancient_rune_giant); // GOs new go_thorim_lever(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp index c4ce68597..8bb4fded8 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -112,574 +112,520 @@ enum Misc DATA_XT002_GRAVITY_ACHIEV = 51, }; -class boss_xt002 : public CreatureScript +struct boss_xt002 : public BossAI { -public: - boss_xt002() : CreatureScript("boss_xt002") { } + boss_xt002(Creature* pCreature) : BossAI(pCreature, BOSS_XT002) { } - CreatureAI* GetAI(Creature* pCreature) const override + uint8 _healthCheck; + bool _hardMode; + bool _nerfAchievement; + bool _gravityAchievement; + + void RescheduleEvents() { - return GetUlduarAI(pCreature); + events.RescheduleEvent(EVENT_GRAVITY_BOMB, 1s, 1); + events.RescheduleEvent(EVENT_TYMPANIC_TANTARUM, 1min, 1); + if (!_hardMode) + events.RescheduleEvent(EVENT_HEALTH_CHECK, 2s, 1); } - struct boss_xt002AI : public ScriptedAI + void Reset() override { - boss_xt002AI(Creature* pCreature) : ScriptedAI(pCreature), summons(me) + _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 (instance) { - m_pInstance = pCreature->GetInstanceScript(); + instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_MUST_DECONSTRUCT_FASTER); + if (GameObject* pGo = instance->GetGameObject(DATA_XT002_DOORS)) + pGo->SetGoState(GO_STATE_ACTIVE); + } + } + + 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 + { + _JustReachedHome(); + 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 (instance) + { + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_MUST_DECONSTRUCT_FASTER); + instance->SetBossState(BOSS_XT002, IN_PROGRESS); + if (GameObject* pGo = instance->GetGameObject(DATA_XT002_DOORS)) + pGo->SetGoState(GO_STATE_READY); } - InstanceScript* m_pInstance; - uint8 _healthCheck; - bool _hardMode; - bool _nerfAchievement; - bool _gravityAchievement; - EventMap events; - SummonList summons; + me->CallForHelp(175); + me->SetInCombatWithZone(); + AttachHeart(); + } - void RescheduleEvents() + void KilledUnit(Unit* victim) override + { + if (victim->IsPlayer() && !urand(0, 2)) { - events.RescheduleEvent(EVENT_GRAVITY_BOMB, 1s, 1); - events.RescheduleEvent(EVENT_TYMPANIC_TANTARUM, 1min, 1); - if (!_hardMode) - events.RescheduleEvent(EVENT_HEALTH_CHECK, 2s, 1); + Talk(SAY_SLAY); + } + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + _JustDied(); + + if (instance) + { + if (GameObject* pGo = instance->GetGameObject(DATA_XT002_DOORS)) + pGo->SetGoState(GO_STATE_ACTIVE); + } + } + + void DoAction(int32 param) override + { + if (param == DATA_XT002_NERF_ENGINEERING) + { + _nerfAchievement = false; + return; + } + if (param == DATA_XT002_GRAVITY_ACHIEV) + { + _gravityAchievement = false; + return; } - void Reset() override + if (!me->IsAlive() || _hardMode) + return; + + // heart destory + if (param == ACTION_HEART_BROKEN) { - summons.DespawnAll(); - events.Reset(); - - me->ResetLootMode(); - me->RemoveAllAuras(); - - // first heart expose - _healthCheck = 75; - _hardMode = false; - _nerfAchievement = true; - _gravityAchievement = true; - + _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->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); - } + me->CastSpell(me, SPELL_HEARTBREAK, true); + + Talk(EMOTE_HEART_CLOSED); + events.ScheduleEvent(EVENT_REMOVE_EMOTE, 4s); + return; } - void JustSummoned(Creature* cr) override { summons.Summon(cr); } - void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } - - void AttachHeart() + // damage from heart + if (param > 0) { - 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(); - } + // avoid reducing health under 1 + int32 _final = std::min(param, int32(me->GetHealth() - 1)); + + me->ModifyHealth(-_final); + me->LowerPlayerDamageReq(_final); } + } - void JustReachedHome() override { me->setActive(false); } + uint32 GetData(uint32 param) const override + { + if (param == DATA_XT002_NERF_ENGINEERING) + return _nerfAchievement; + else if (param == DATA_XT002_GRAVITY_ACHIEV) + return _gravityAchievement; - void JustEngagedWith(Unit*) override + return 0; + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - 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 + // Control events + case EVENT_HEALTH_CHECK: + if (_hardMode) + { + return; + } - me->setActive(true); - Talk(SAY_AGGRO); + 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 - 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); - } + Talk(SAY_HEART_OPENED); - me->CallForHelp(175); - me->SetInCombatWithZone(); - AttachHeart(); - } + 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(); - void KilledUnit(Unit* victim) override - { - if (victim->IsPlayer() && !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()); + // 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); - me->CastSpell(me, SPELL_HEARTBREAK, true); - - Talk(EMOTE_HEART_CLOSED); 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); - // 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()) + RescheduleEvents(); 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(); } - }; + + // Disabled by stunned state + DoMeleeAttackIfReady(); + } }; -class npc_xt002_heart : public CreatureScript +struct npc_xt002_heart : public PassiveAI { -public: - npc_xt002_heart() : CreatureScript("npc_xt002_heart") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_xt002_heart(Creature* pCreature) : PassiveAI(pCreature), summons(me) { - return GetUlduarAI(pCreature); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); } - struct npc_xt002_heartAI : public PassiveAI + SummonList summons; + uint32 _damageDone; + uint32 _timerSpawn; + + uint8 _spawnSelection; + uint8 _pummelerCount; + + void MoveInLineOfSight(Unit*) override { } + void AttackStart(Unit*) override { } + void JustSummoned(Creature* cr) override { - npc_xt002_heartAI(Creature* pCreature) : PassiveAI(pCreature), summons(me) + summons.Summon(cr); + if (Unit* owner = me->GetVehicleBase()) + if (owner->IsCreature()) + 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 = me->GetInstanceScript()->GetCreature(BOSS_XT002)) + if (pXT002->AI()) + { + pXT002->AI()->DoAction(_damageDone); + _damageDone = 0; + } 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->IsCreature()) - 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 + void SendEnergyToCorner() { - 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))) + 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) { - 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; + pile = summon; + if ((--num) == 0) + break; } - } - 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(1ms); - } - } - - 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); + if (pile) + me->CastSpell(pile, SPELL_ENERGY_ORB, true); } - struct npc_xt002_pummellerAI : public ScriptedAI + void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override { - npc_xt002_pummellerAI(Creature* pCreature) : ScriptedAI(pCreature) { } + // 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); - int32 _arcingSmashTimer; - int32 _trampleTimer; - int32 _uppercutTimer; + _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 Reset() override + void JustDied(Unit* /*killer*/) override + { + me->SetVisible(false); + if (me->GetInstanceScript()) + if (Creature* XT002 = me->GetInstanceScript()->GetCreature(BOSS_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; + } + } + } +}; + +struct npc_xt002_scrapbot : public PassiveAI +{ + npc_xt002_scrapbot(Creature* pCreature) : PassiveAI(pCreature) { } + + bool _locked; + void Reset() override + { + me->StopMoving(); + _locked = true; + me->SetWalk(true); + + if (me->GetInstanceScript()) + if (Creature* pXT002 = me->GetInstanceScript()->GetCreature(BOSS_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 = me->GetInstanceScript()->GetCreature(BOSS_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(1ms); + } + } + + void UpdateAI(uint32 /*diff*/) override + { + if (!_locked) + { + if (me->GetInstanceScript()) + if (Creature* pXT002 = me->GetInstanceScript()->GetCreature(BOSS_XT002)) + { + me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); + _locked = true; + } + } + } +}; + +struct npc_xt002_pummeller : public ScriptedAI +{ + npc_xt002_pummeller(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(500ms); + } + + 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; - _trampleTimer = 0; - _uppercutTimer = 0; - - if (Unit* target = SelectTargetFromPlayerList(200)) - AttackStart(target); - else - me->DespawnOrUnsummon(500ms); + return; } - - void UpdateAI(uint32 diff) override + if (_trampleTimer >= 11000) { - 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(); + 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 @@ -705,144 +651,122 @@ private: Creature* _me; }; -class npc_xt002_boombot : public CreatureScript +struct npc_xt002_boombot : public PassiveAI { -public: - npc_xt002_boombot() : CreatureScript("npc_xt002_boombot") { } + npc_xt002_boombot(Creature* pCreature) : PassiveAI(pCreature) { } - CreatureAI* GetAI(Creature* pCreature) const override + bool _locked; + bool _boomed; + void Reset() override { - return GetUlduarAI(pCreature); + me->StopMoving(); + _locked = true; + _boomed = false; + me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); + + if (me->GetInstanceScript()) + if (Creature* pXT002 = me->GetInstanceScript()->GetCreature(BOSS_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; + } } - struct npc_xt002_boombotAI : public PassiveAI + void Explode() { - npc_xt002_boombotAI(Creature* pCreature) : PassiveAI(pCreature) { } + if (_boomed) + return; - bool _locked; - bool _boomed; - void Reset() override + _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.AddEventAtOffset(new BoomEvent(me), 1s); + } + + void JustDied(Unit* /*killer*/) override + { + me->m_Events.AddEventAtOffset(new BoomEvent(me), 1s); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (_boomed) + damage = 0; + + if (me->HealthBelowPctDamaged(50, damage) && !_boomed) { - me->StopMoving(); - _locked = true; - _boomed = false; - me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); + 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))) + if (Creature* pXT002 = me->GetInstanceScript()->GetCreature(BOSS_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; + me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); + _locked = true; } } - - 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.AddEventAtOffset(new BoomEvent(me), 1s); - } - - void JustDied(Unit* /*killer*/) override - { - me->m_Events.AddEventAtOffset(new BoomEvent(me), 1s); - } - - 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 +struct npc_xt002_life_spark : public ScriptedAI { -public: - npc_xt002_life_spark() : CreatureScript("npc_xt002_life_spark") { } - - CreatureAI* GetAI(Creature* pCreature) const override + npc_xt002_life_spark(Creature* pCreature) : ScriptedAI(pCreature) { - return GetUlduarAI(pCreature); + me->SetMaxHealth(RAID_MODE(54000, 172000)); + me->SetHealth(me->GetMaxHealth()); + me->CastSpell(me, SPELL_SPARK_DAMAGE, true); } - struct npc_xt002_life_sparkAI : public ScriptedAI + uint32 _attackTimer; + void Reset() override { - 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); - } + if (Unit* target = SelectTargetFromPlayerList(200)) + AttackStart(target); + else + me->DespawnOrUnsummon(); + } - uint32 _attackTimer; - void Reset() override - { - if (Unit* target = SelectTargetFromPlayerList(200)) - AttackStart(target); - else - me->DespawnOrUnsummon(); - } + void UpdateAI(uint32 /*diff*/) override + { + if (!UpdateVictim()) + return; - void UpdateAI(uint32 /*diff*/) override - { - if (!UpdateVictim()) - return; - - me->CastSpell(me->GetVictim(), SPELL_SPARK_MELEE, false); - DoMeleeAttackIfReady(); - } - }; + me->CastSpell(me->GetVictim(), SPELL_SPARK_MELEE, false); + DoMeleeAttackIfReady(); + } }; // 62775 - Tympanic Tantrum @@ -999,7 +923,7 @@ public: { if (target) if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_XT002))) + if (Creature* cr = instance->GetCreature(BOSS_XT002)) return cr->AI()->GetData(DATA_XT002_NERF_ENGINEERING); return false; @@ -1015,7 +939,7 @@ public: { if (target) if (InstanceScript* instance = target->GetInstanceScript()) - if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_XT002))) + if (Creature* cr = instance->GetCreature(BOSS_XT002)) return cr->AI()->GetData(DATA_XT002_GRAVITY_ACHIEV); return false; @@ -1025,12 +949,12 @@ public: void AddSC_boss_xt002() { // Npcs - new boss_xt002(); - new npc_xt002_heart(); - new npc_xt002_scrapbot(); - new npc_xt002_pummeller(); - new npc_xt002_boombot(); - new npc_xt002_life_spark(); + RegisterUlduarCreatureAI(boss_xt002); + RegisterUlduarCreatureAI(npc_xt002_heart); + RegisterUlduarCreatureAI(npc_xt002_scrapbot); + RegisterUlduarCreatureAI(npc_xt002_pummeller); + RegisterUlduarCreatureAI(npc_xt002_boombot); + RegisterUlduarCreatureAI(npc_xt002_life_spark); // Spells RegisterSpellScript(spell_xt002_tympanic_tantrum); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp index 1b4ce7bf5..3e458823e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yoggsaron.cpp @@ -285,7 +285,7 @@ const Position KeepersPos[4] = const uint32 TABLE_KEEPER_ENTRY[4] = {NPC_FREYA_KEEPER, NPC_HODIR_KEEPER, NPC_MIMIRON_KEEPER, NPC_THORIM_KEEPER}; const uint32 TABLE_GOSSIP_ENTRY[4] = {NPC_FREYA_GOSSIP, NPC_HODIR_GOSSIP, NPC_MIMIRON_GOSSIP, NPC_THORIM_GOSSIP}; -const uint32 TABLE_KEEPER_TYPE[4] = {TYPE_FREYA, TYPE_HODIR, TYPE_MIMIRON, TYPE_THORIM}; +const uint32 TABLE_KEEPER_TYPE[4] = {BOSS_FREYA, BOSS_HODIR, BOSS_MIMIRON, BOSS_THORIM}; static LocationsXY yoggPortalLoc[] = { @@ -364,1361 +364,1262 @@ enum Texts const Position Middle = {1980.28f, -25.5868f, 329.397f, M_PI * 1.5f}; -class boss_yoggsaron_sara : public CreatureScript +struct boss_yoggsaron_sara : public ScriptedAI { -public: - boss_yoggsaron_sara() : CreatureScript("boss_yoggsaron_sara") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_yoggsaron_sara(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) { - return GetUlduarAI(pCreature); + m_pInstance = pCreature->GetInstanceScript(); } - struct boss_yoggsaron_saraAI : public ScriptedAI + InstanceScript* m_pInstance; + EventMap events; + SummonList summons; + + uint32 _initFight; + uint8 _summonedGuardiansCount; + uint32 _p2TalkTimer; + bool _secondPhase; + float _summonSpeed; + uint8 _currentIllusion; + bool _isIllusionReversed; + + void AttackStart(Unit*) override { } + void MoveInLineOfSight(Unit*) override { } + + void JustSummoned(Creature* summon) override { - boss_yoggsaron_saraAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) + summons.Summon(summon); + } + + void SpawnClouds() + { + for (uint8 i = 0; i < 6; ++i) { - m_pInstance = pCreature->GetInstanceScript(); - } - - InstanceScript* m_pInstance; - EventMap events; - SummonList summons; - - uint32 _initFight; - uint8 _summonedGuardiansCount; - uint32 _p2TalkTimer; - bool _secondPhase; - float _summonSpeed; - uint8 _currentIllusion; - bool _isIllusionReversed; - - void AttackStart(Unit*) override { } - void MoveInLineOfSight(Unit*) override { } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - } - - 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 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); - } + 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->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); - me->DisableRotate(true); - me->AddUnitState(UNIT_STATE_ROOT); - } + me->SummonCreature(NPC_OMINOUS_CLOUD, me->GetPositionX() - 8 - i * 7, me->GetPositionY() - 8 - i * 7, 326 + Zplus, 0); } - - 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; - - UpdateKeeperSpawns(); - _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); - - DespawnGossipKeepers(); - // Engage Keepers - summons.DoZoneInCombat(); - - me->CastSpell(me, SPELL_SANITY_BASE, true); - - 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 DespawnGossipKeepers() - { - for (uint8 i = KEEPER_FREYA; i <= KEEPER_THORIM; i++) - summons.DespawnEntry(TABLE_GOSSIP_ENTRY[i]); - } - - void UpdateKeeperSpawns() - { - for (uint8 i = KEEPER_FREYA; i <= KEEPER_THORIM; i++) - { - if (m_pInstance->GetData(TYPE_WATCHERS) & (1 << i)) - { - if (!summons.HasEntry(TABLE_KEEPER_ENTRY[i])) - me->SummonCreature(TABLE_KEEPER_ENTRY[i], KeepersPos[i]); - } - else if (m_pInstance->GetData(TABLE_KEEPER_TYPE[i]) == DONE) - { - if (!summons.HasEntry(TABLE_GOSSIP_ENTRY[i])) - me->SummonCreature(TABLE_GOSSIP_ENTRY[i], GossipKeepersPos[i]); - } - } - } - - 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 spawnX = me->GetPositionX() + dist * cos(o); - float spawnY = me->GetPositionY() + dist * std::sin(o); - float spawnZ = me->GetMap()->GetHeight(me->GetPhaseMask(), spawnX, spawnY, 330.0f); - if (Creature* cr = me->SummonCreature(entry, spawnX, spawnY, spawnZ, 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 (m_pInstance->GetData(TYPE_WATCHERS) & (1 << 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_SARA_UPDATE_SUMMON_KEEPERS) - { - UpdateKeeperSpawns(); - } - else 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 (me->GetMap()->Is25ManRaid() && (GetData(DATA_GET_KEEPERS_COUNT) > 0)) - 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) - { - // Despawn everything but Yogg-Saron's corpse - summons.DoAction(ACTION_DESPAWN_ADDS); - summons.DespawnEntry(NPC_CRUSHER_TENTACLE); - summons.DespawnEntry(NPC_CONSTRICTOR_TENTACLE); - summons.DespawnEntry(NPC_CORRUPTOR_TENTACLE); - summons.DespawnEntry(NPC_VOICE_OF_YOGG_SARON); - summons.DespawnEntry(NPC_BRAIN_OF_YOGG_SARON); - summons.DespawnEntry(NPC_MIMIRON_GOSSIP); - summons.DespawnEntry(NPC_HODIR_GOSSIP); - summons.DespawnEntry(NPC_FREYA_GOSSIP); - summons.DespawnEntry(NPC_THORIM_GOSSIP); - 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); - } - - Milliseconds timer = events.GetTimeUntilEvent(EVENT_SARA_P2_OPEN_PORTALS); - Milliseconds portalTime = (timer > 0ms ? timer : 0ms); - events.DelayEvents(Milliseconds(param + 100)); - events.RescheduleEvent(EVENT_SARA_P2_OPEN_PORTALS, portalTime, 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_REMOVE_STUN, Milliseconds(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.Repeat(Milliseconds(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.Repeat(me->GetMap()->Is25ManRaid() ? randtime(0ms, 3s) : randtime(4s, 6s)); - 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, 500ms, 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_SARA_PSYCHOSIS_10, 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.Repeat(Milliseconds(uint32((50000 + urand(0, 10000)) * _summonSpeed))); - break; - case EVENT_SARA_P2_SUMMON_T2: // CONSTRICTOR - SpawnTentacle(NPC_CONSTRICTOR_TENTACLE); - events.Repeat(Milliseconds(uint32((15000 + urand(0, 5000))* _summonSpeed))); - break; - case EVENT_SARA_P2_SUMMON_T3: // CORRUPTOR - SpawnTentacle(NPC_CORRUPTOR_TENTACLE); - events.Repeat(Milliseconds(uint32((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, 30s + randtime(0ms, 10s), 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_BRAIN_LINK, 0ms, 0, EVENT_PHASE_TWO); - events.ScheduleEvent(EVENT_SARA_P2_OPEN_PORTALS, 60s, 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 + void EnterEvadeMode(EvadeReason why) override { - boss_yoggsaron_cloudAI(Creature* pCreature) : npc_escortAI(pCreature) - { - InitWaypoint(); - Reset(); - Start(false, ObjectGuid::Empty, nullptr, false, true); - } + if (!_EnterEvadeMode(why)) + return; - 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); + Position pos; + pos = me->GetHomePosition(); + me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); + Reset(); + me->setActive(false); } - struct boss_yoggsaron_guardian_of_ysAI : public ScriptedAI + void EnableSara(bool apply) { - boss_yoggsaron_guardian_of_ysAI(Creature* pCreature) : ScriptedAI(pCreature) { } - - uint32 _spellTimer; - - void Reset() override + if (apply) { - _spellTimer = 0; - me->SetInCombatWithZone(); + me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); + me->DisableRotate(false); + me->ClearUnitState(UNIT_STATE_ROOT); } - - void JustDied(Unit*) override + else { - me->CastSpell((Unit*)nullptr, SPELL_SHADOW_NOVA, true); + me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); + me->DisableRotate(true); + me->AddUnitState(UNIT_STATE_ROOT); } - - 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 + void Reset() override { - boss_yoggsaronAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) + if (!_secondPhase) // Phase 1 wipe { - 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) + me->GetMap()->DoForAllPlayers([&](Player* player) { - for (uint8 i = 0; i < 4; ++i) - if (m_pInstance->GetData(TYPE_WATCHERS) & (1 << i)) - { - me->RemoveLootMode(1 << _count); - --_count; - } - } + if (Creature* voice = me->FindNearestCreature(NPC_VOICE_OF_YOGG_SARON, 10.0f)) + { + voice->AI()->Talk(WHISPER_VOICE_PHASE_1_WIPE, player); + } + }); } - InstanceScript* m_pInstance; - EventMap events; - SummonList summons; - bool _thirdPhase; - bool _usedInsane; + summons.DoAction(ACTION_DESPAWN_ADDS); + events.Reset(); + summons.DespawnAll(); - void AttackStart(Unit*) override { } + me->SetVisible(true); + me->SetDisplayId(me->GetNativeDisplayId()); + me->SetDisableGravity(true); + EnableSara(false); + SpawnClouds(); - void JustSummoned(Creature* cr) override { summons.Summon(cr); } + _initFight = 1; - void SummonImmortalGuardian() + UpdateKeeperSpawns(); + _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(BOSS_YOGGSARON, NOT_STARTED); + if (GameObject* go = m_pInstance->GetGameObject(DATA_YOGG_SARON_DOORS)) + go->SetGoState(GO_STATE_ACTIVE); + } + } + + void InitFight(Unit* target) + { + if (!m_pInstance) + return; + + // some simple hack checks + if (m_pInstance->GetBossState(BOSS_VEZAX) != DONE || m_pInstance->GetBossState(BOSS_XT002) != DONE) + return; + + m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_NOT_GETTING_OLDER); + m_pInstance->SetData(BOSS_YOGGSARON, IN_PROGRESS); + me->SetInCombatWithZone(); + AttackStart(target); + + DespawnGossipKeepers(); + // Engage Keepers + summons.DoZoneInCombat(); + + me->CastSpell(me, SPELL_SANITY_BASE, true); + + 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 DespawnGossipKeepers() + { + for (uint8 i = KEEPER_FREYA; i <= KEEPER_THORIM; i++) + summons.DespawnEntry(TABLE_GOSSIP_ENTRY[i]); + } + + void UpdateKeeperSpawns() + { + for (uint8 i = KEEPER_FREYA; i <= KEEPER_THORIM; i++) + { + if (m_pInstance->GetData(TYPE_WATCHERS) & (1 << i)) + { + if (!summons.HasEntry(TABLE_KEEPER_ENTRY[i])) + me->SummonCreature(TABLE_KEEPER_ENTRY[i], KeepersPos[i]); + } + else if (m_pInstance->GetData(TABLE_KEEPER_TYPE[i]) == DONE) + { + if (!summons.HasEntry(TABLE_GOSSIP_ENTRY[i])) + me->SummonCreature(TABLE_GOSSIP_ENTRY[i], GossipKeepersPos[i]); + } + } + } + + 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 spawnX = me->GetPositionX() + dist * cos(o); + float spawnY = me->GetPositionY() + dist * std::sin(o); + float spawnZ = me->GetMap()->GetHeight(me->GetPhaseMask(), spawnX, spawnY, 330.0f); + if (Creature* cr = me->SummonCreature(entry, spawnX, spawnY, spawnZ, 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_IMMORTAL_GUARDIAN, me->GetPositionX() + dist * cos(o), me->GetPositionY() + dist * std::sin(o), 327.2 + Zplus, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + 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 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, 7s); - events.ScheduleEvent(EVENT_YS_SHADOW_BEACON, 20s); - events.ScheduleEvent(EVENT_YS_SUMMON_GUARDIAN, 0ms); - _thirdPhase = true; - - Talk(SAY_YOGG_SARON_PHASE_3); - } - else if (param == ACTION_YOGG_SARON_HARD_MODE) - { - events.ScheduleEvent(EVENT_YS_DEAFENING_ROAR, 50s); - } - else if (param == ACTION_YOGG_SARON_SHADOW_BEACON) - { - events.RescheduleEvent(EVENT_YS_SHADOW_BEACON, 40s); - } - 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 + void AddPortals() { - boss_yoggsaron_brainAI(Creature* pCreature) : NullCreatureAI(pCreature), summons(pCreature) - { - me->SetDisableGravity(true); - _tentacleCount = 0; - _activeIllusion = 0; - _induceTimer = 0; - _brainDamaged = false; - me->SetRegeneratingHealth(false); - } + _summonSpeed -= 0.1f; + Creature* cr = nullptr; - bool _brainDamaged; - uint8 _tentacleCount; - uint8 _activeIllusion; - uint32 _induceTimer; - SummonList summons; - - void Reset() override { } - void JustSummoned(Creature* cr) override + // Spawn Portals + for (uint8 i = 0; i < RAID_MODE(4, 10); ++i) { - if (cr->GetEntry() == NPC_INFLUENCE_TENTACLE) + if ((cr = me->SummonCreature(NPC_DESCEND_INTO_MADNESS, yoggPortalLoc[i].x, yoggPortalLoc[i].y, yoggPortalLoc[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 25000))) { - // 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); + cr->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE); + cr->SetArmor(_currentIllusion); } - else if (cr->GetEntry() == NPC_LICH_KING) - cr->CastSpell(cr, SPELL_DEATHGRASP, false); - - summons.Summon(cr); } - void PrepareChamberIllusion() + 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()) { - 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); + Talk(SAY_SARA_KILL); + } + } - // 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); + void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_SANITY) + if (Aura* aur = target->GetAura(SPELL_SANITY)) + aur->SetStackAmount(100); + } - 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); + uint32 GetData(uint32 param) const override + { + if (param == DATA_GET_KEEPERS_COUNT) + { + uint8 _count = 0; + for (uint8 i = 0; i < 4; ++i) + if (m_pInstance->GetData(TYPE_WATCHERS) & (1 << i)) + ++_count; + return _count; + } + else if (param == DATA_GET_SARA_PHASE) + return _secondPhase; - // 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); + return 4; // just to be sure, return max numer of keepers + } - // Yogg Vision - me->SummonCreature(NPC_YOGG_SARON_VISION, 2109.695f, -25.09549f, 222.3250f, 0); + void DoAction(int32 param) override + { + if (param == ACTION_SARA_UPDATE_SUMMON_KEEPERS) + { + UpdateKeeperSpawns(); + } + else 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 (me->GetMap()->Is25ManRaid() && (GetData(DATA_GET_KEEPERS_COUNT) > 0)) + 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) + { + // Despawn everything but Yogg-Saron's corpse + summons.DoAction(ACTION_DESPAWN_ADDS); + summons.DespawnEntry(NPC_CRUSHER_TENTACLE); + summons.DespawnEntry(NPC_CONSTRICTOR_TENTACLE); + summons.DespawnEntry(NPC_CORRUPTOR_TENTACLE); + summons.DespawnEntry(NPC_VOICE_OF_YOGG_SARON); + summons.DespawnEntry(NPC_BRAIN_OF_YOGG_SARON); + summons.DespawnEntry(NPC_MIMIRON_GOSSIP); + summons.DespawnEntry(NPC_HODIR_GOSSIP); + summons.DespawnEntry(NPC_FREYA_GOSSIP); + summons.DespawnEntry(NPC_THORIM_GOSSIP); + 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; } - void PrepareIceCrownIllusion() + // Determine shatter duration + if (param <= 0) + return; + + // Illusion shatters (param - stun time) + if (Creature* yoggb = me->GetInstanceScript()->GetCreature(DATA_BRAIN_OF_YOGG_SARON)) { - // 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); + yoggb->AI()->Talk(EMOTE_YOGG_SARON_BRAIN_SHATTERED); } - void PrepareStormwindIllusion() + Milliseconds timer = events.GetTimeUntilEvent(EVENT_SARA_P2_OPEN_PORTALS); + Milliseconds portalTime = (timer > 0ms ? timer : 0ms); + events.DelayEvents(Milliseconds(param + 100)); + events.RescheduleEvent(EVENT_SARA_P2_OPEN_PORTALS, portalTime, 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_REMOVE_STUN, Milliseconds(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) { - // 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); + damage = 25000; - // 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 + // START PHASE 2 + if (me->GetHealth() <= damage) { + _secondPhase = true; damage = 0; - if (who) - Unit::Kill(who, who); - return; + + 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; + } - if (!_brainDamaged) + damage = 0; + } + + void UpdateAI(uint32 diff) override + { + if (_initFight) + { + _initFight += diff; + if (_initFight > 5000) { - // START PHASE 3 - if (me->HealthBelowPctDamaged(30, damage)) + if (Unit* target = SelectTargetFromPlayerList(90)) { - 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); + _initFight = 0; + InitFight(target); } - } - } - - 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; + _initFight = 1; } - - return target; + return; } - void UpdateAI(uint32 /*diff*/) override + if (!SelectTargetFromPlayerList(90, SPELL_INSANE1)) { - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + m_pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_INSANE1); + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } - if (Unit* target = SelectCorruptionTarget()) + if (_p2TalkTimer) + { + _p2TalkTimer += diff; + if (_p2TalkTimer >= 4000 && _p2TalkTimer < 20000) { - uint32 spellid = RAND(SPELL_APATHY, SPELL_BLACK_PLAGUE, SPELL_DRAINING_POISON, SPELL_CURSE_OF_DOOM); - me->CastSpell(target, spellid, false); + EntryCheckPredicate pred(NPC_OMINOUS_CLOUD); + summons.DoAction(ACTION_UNSUMMON_CLOUDS, pred); + Talk(SAY_SARA_TRANSFORM_2); + _p2TalkTimer = 20000; } - } - }; -}; - -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) + else if (_p2TalkTimer >= 25000 && _p2TalkTimer < 40000) { - if (me->GetDistance(itr->GetSource()) > 10 || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster()) - continue; - if (itr->GetSource()->HasAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_SQUEEZE, me)) || itr->GetSource()->HasAura(SPELL_INSANE1)) - continue; - - if (count <= num || !target) - target = itr->GetSource(); - else - break; + summons.DespawnEntry(NPC_OMINOUS_CLOUD); + Talk(SAY_SARA_TRANSFORM_3); + _p2TalkTimer = 40000; } - - return target; + 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; } - void UpdateAI(uint32 diff) override + events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - if (_checkTimer) - { - _checkTimer += diff; - if (_checkTimer >= 1000 && !me->HasUnitState(UNIT_STATE_STUNNED)) + 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 = m_pInstance->GetGameObject(DATA_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.Repeat(Milliseconds(20000 - (std::min(_summonedGuardiansCount, (uint8)5) * 2000))); + ++_summonedGuardiansCount; + InformCloud(); + break; + case EVENT_SARA_P1_SPELLS: { - if (Unit* target = SelectConstrictTarget()) + uint32 spell = RAND(SPELL_SARAS_ANGER_TARGET_SELECTOR, SPELL_SARAS_BLESSING_TARGET_SELECTOR, SPELL_SARAS_FAVOR_TARGET_SELECTOR); + if (urand(0, 2)) { - target->CastSpell(me, SPELL_LUNGE, true); - target->CastSpell(target, SPELL_SQUEEZE, true); - _playerGUID = target->GetGUID(); - _checkTimer = 0; - return; + if (spell == SPELL_SARAS_ANGER_TARGET_SELECTOR) + { + Talk(SAY_SARA_ANGER); + } + else if (spell == SPELL_SARAS_FAVOR_TARGET_SELECTOR) + { + Talk(SAY_SARA_FERVOR_HIT); + } } - _checkTimer = 1; + me->CastCustomSpell(spell, SPELLVALUE_MAX_TARGETS, 1, nullptr, false); + events.Repeat(me->GetMap()->Is25ManRaid() ? randtime(0ms, 3s) : randtime(4s, 6s)); + 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, 500ms, 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_SARA_PSYCHOSIS_10, 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.Repeat(Milliseconds(uint32((50000 + urand(0, 10000)) * _summonSpeed))); + break; + case EVENT_SARA_P2_SUMMON_T2: // CONSTRICTOR + SpawnTentacle(NPC_CONSTRICTOR_TENTACLE); + events.Repeat(Milliseconds(uint32((15000 + urand(0, 5000))* _summonSpeed))); + break; + case EVENT_SARA_P2_SUMMON_T3: // CORRUPTOR + SpawnTentacle(NPC_CORRUPTOR_TENTACLE); + events.Repeat(Milliseconds(uint32((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, 30s + randtime(0ms, 10s), 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_BRAIN_LINK, 0ms, 0, EVENT_PHASE_TWO); + events.ScheduleEvent(EVENT_SARA_P2_OPEN_PORTALS, 60s, 0, EVENT_PHASE_TWO); + break; + case EVENT_SARA_P1_BERSERK: + if (me->GetInstanceScript()) + { + if (Creature* yogg = me->GetInstanceScript()->GetCreature(BOSS_YOGGSARON)) + { + yogg->AI()->Talk(EMOTE_YOGG_SARON_BERSERK); + } + } + me->CastSpell(me, SPELL_EXTINGUISH_ALL_LIFE, true); + events.Repeat(5s); + break; + } + } +}; + +struct boss_yoggsaron_cloud : public npc_escortAI +{ + boss_yoggsaron_cloud(Creature* pCreature) : npc_escortAI(pCreature) + { + InitWaypoint(); + Reset(); + Start(false, 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 = me->GetInstanceScript()->GetCreature(DATA_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); } } - - void DoAction(int32 param) override + else { - if (param == ACTION_REMOVE_STUN) - me->RemoveAura(SPELL_SHATTERED_ILLUSION); + 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; + } + } +}; + +struct boss_yoggsaron_guardian_of_ys : public ScriptedAI +{ + boss_yoggsaron_guardian_of_ys(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; } - void JustDied(Unit*) override + DoMeleeAttackIfReady(); + } +}; + +struct boss_yoggsaron : public ScriptedAI +{ + boss_yoggsaron(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) { - if (Unit* player = ObjectAccessor::GetUnit(*me, _playerGUID)) - player->RemoveAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_SQUEEZE, me)); + 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(BOSS_YOGGSARON, DONE); + if (Creature* sara = m_pInstance->GetCreature(DATA_SARA)) + sara->AI()->DoAction(ACTION_YOGG_SARON_DEATH); + if (GameObject* go = m_pInstance->GetGameObject(DATA_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, 7s); + events.ScheduleEvent(EVENT_YS_SHADOW_BEACON, 20s); + events.ScheduleEvent(EVENT_YS_SUMMON_GUARDIAN, 0ms); + _thirdPhase = true; + + Talk(SAY_YOGG_SARON_PHASE_3); + } + else if (param == ACTION_YOGG_SARON_HARD_MODE) + { + events.ScheduleEvent(EVENT_YS_DEAFENING_ROAR, 50s); + } + else if (param == ACTION_YOGG_SARON_SHADOW_BEACON) + { + events.RescheduleEvent(EVENT_YS_SHADOW_BEACON, 40s); + } + 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; + } + } +}; + +struct boss_yoggsaron_brain : public NullCreatureAI +{ + boss_yoggsaron_brain(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 = me->GetInstanceScript()->GetCreature(DATA_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 = me->GetInstanceScript()->GetCreature(DATA_SARA)) + sara->AI()->DoAction(ACTION_BRAIN_DAMAGED); + } + } + } + + void UpdateAI(uint32 diff) override + { + if (_induceTimer) + _induceTimer += diff; + } +}; + +struct boss_yoggsaron_death_orb : public NullCreatureAI +{ + boss_yoggsaron_death_orb(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); + } + } + } +}; + +struct boss_yoggsaron_crusher_tentacle : public ScriptedAI +{ + boss_yoggsaron_crusher_tentacle(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(); + } +}; + +struct boss_yoggsaron_corruptor_tentacle : public ScriptedAI +{ + boss_yoggsaron_corruptor_tentacle(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); + } + } +}; + +struct boss_yoggsaron_constrictor_tentacle : public ScriptedAI +{ + boss_yoggsaron_constrictor_tentacle(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(sSpellMgr->GetSpellIdForDifficulty(SPELL_SQUEEZE, me)) || 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(sSpellMgr->GetSpellIdForDifficulty(SPELL_SQUEEZE, me)); + } }; struct boss_yoggsaron_keeper : public NullCreatureAI @@ -1773,495 +1674,418 @@ private: SummonList _summons; }; -class boss_yoggsaron_descend_portal : public CreatureScript +struct boss_yoggsaron_descend_portal : public PassiveAI { -public: - boss_yoggsaron_descend_portal() : CreatureScript("boss_yoggsaron_descend_portal") { } + boss_yoggsaron_descend_portal(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) {} - struct boss_yoggsaron_descend_portalAI : public PassiveAI + void OnSpellClick(Unit* clicker, bool& spellClickHandled) override { - boss_yoggsaron_descend_portalAI(Creature* creature) : PassiveAI(creature), _instance(creature->GetInstanceScript()) {} + if (!spellClickHandled) + return; - void OnSpellClick(Unit* clicker, bool& spellClickHandled) override + if (!me->GetNpcFlags()) + return; + + switch (me->GetArmor()) { - if (!spellClickHandled) - return; - - if (!me->GetNpcFlags()) - 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->ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE); - me->DespawnOrUnsummon(1s); + 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; } - private: - InstanceScript* _instance; - }; + me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE); + me->DespawnOrUnsummon(1s); + } - CreatureAI* GetAI(Creature* creature) const override +private: + InstanceScript* _instance; +}; + +struct boss_yoggsaron_influence_tentacle : public NullCreatureAI +{ + boss_yoggsaron_influence_tentacle(Creature* pCreature) : NullCreatureAI(pCreature) { - return GetUlduarAI(creature); + 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_influence_tentacle : public CreatureScript +struct boss_yoggsaron_immortal_guardian : public ScriptedAI { -public: - boss_yoggsaron_influence_tentacle() : CreatureScript("boss_yoggsaron_influence_tentacle") { } - - CreatureAI* GetAI(Creature* pCreature) const override + boss_yoggsaron_immortal_guardian(Creature* pCreature) : ScriptedAI(pCreature) { - return GetUlduarAI(pCreature); + Reset(); } - struct boss_yoggsaron_influence_tentacleAI : public NullCreatureAI + uint32 _visualTimer; + uint32 _spellTimer; + + void Reset() override { - boss_yoggsaron_influence_tentacleAI(Creature* pCreature) : NullCreatureAI(pCreature) - { - me->CastSpell(me, SPELL_GRIM_REPRISAL, true); - } + 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); - 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); + _spellTimer = 0; + _visualTimer = 1; + me->SetControlled(true, UNIT_STATE_ROOT); + me->SetInCombatWithZone(); } - struct boss_yoggsaron_immortal_guardianAI : public ScriptedAI + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { - boss_yoggsaron_immortal_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) + 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) { - 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) { - _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(me, SPELL_SIMPLE_TELEPORT, false); - _visualTimer = 10000; - } - else if (_visualTimer >= 11000) - { - me->SetControlled(false, UNIT_STATE_ROOT); - _visualTimer = 0; + me->CastSpell(target, SPELL_DRAIN_LIFE, false); + _spellTimer = 0; } } + else + _spellTimer = 7500; + } - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + DoMeleeAttackIfReady(); + } +}; - _spellTimer += diff; - if (_spellTimer >= 9500) +struct boss_yoggsaron_lich_king : public NullCreatureAI +{ + boss_yoggsaron_lich_king(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) { - if (me->HealthBelowPct(85)) + 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; + } + } +}; + +struct boss_yoggsaron_llane : public NullCreatureAI +{ + boss_yoggsaron_llane(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; + } + } +}; + +struct boss_yoggsaron_neltharion : public ScriptedAI +{ + boss_yoggsaron_neltharion(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; + } + } +}; + +struct boss_yoggsaron_voice : public NullCreatureAI +{ + boss_yoggsaron_voice(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 = me->GetInstanceScript()->GetCreature(BOSS_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: { - if (Unit* target = SelectTargetFromPlayerList(40.0f)) + ObjectGuid _guid = _targets.at(_current); + ++_current; + + if (Player* player = ObjectAccessor::GetPlayer(*me, _guid)) { - me->CastSpell(target, SPELL_DRAIN_LIFE, false); - _spellTimer = 0; + Talk(WHISPER_VOICE_INSANE, player); } - } - 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; + 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 @@ -2894,7 +2718,7 @@ public: 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))) + if (Creature* sara = player->GetInstanceScript()->GetCreature(DATA_SARA)) return sara->GetAI()->GetData(DATA_GET_KEEPERS_COUNT) <= _keepersCount; return false; @@ -2915,7 +2739,7 @@ public: 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))) + if (Creature* sara = player->GetInstanceScript()->GetCreature(DATA_BRAIN_OF_YOGG_SARON)) return sara->GetAI()->GetData(DATA_GET_CURRENT_ILLUSION) == _requiredIllusion; return false; @@ -2938,23 +2762,23 @@ public: void AddSC_boss_yoggsaron() { - new boss_yoggsaron(); - new boss_yoggsaron_sara(); - new boss_yoggsaron_cloud(); - new boss_yoggsaron_guardian_of_ys(); - new boss_yoggsaron_brain(); - new boss_yoggsaron_death_orb(); - new boss_yoggsaron_crusher_tentacle(); - new boss_yoggsaron_corruptor_tentacle(); - new boss_yoggsaron_constrictor_tentacle(); + RegisterUlduarCreatureAI(boss_yoggsaron); + RegisterUlduarCreatureAI(boss_yoggsaron_sara); + RegisterUlduarCreatureAI(boss_yoggsaron_cloud); + RegisterUlduarCreatureAI(boss_yoggsaron_guardian_of_ys); + RegisterUlduarCreatureAI(boss_yoggsaron_brain); + RegisterUlduarCreatureAI(boss_yoggsaron_death_orb); + RegisterUlduarCreatureAI(boss_yoggsaron_crusher_tentacle); + RegisterUlduarCreatureAI(boss_yoggsaron_corruptor_tentacle); + RegisterUlduarCreatureAI(boss_yoggsaron_constrictor_tentacle); RegisterUlduarCreatureAI(boss_yoggsaron_keeper); - new boss_yoggsaron_descend_portal(); - new boss_yoggsaron_influence_tentacle(); - new boss_yoggsaron_immortal_guardian(); - new boss_yoggsaron_lich_king(); - new boss_yoggsaron_llane(); - new boss_yoggsaron_neltharion(); - new boss_yoggsaron_voice(); + RegisterUlduarCreatureAI(boss_yoggsaron_descend_portal); + RegisterUlduarCreatureAI(boss_yoggsaron_influence_tentacle); + RegisterUlduarCreatureAI(boss_yoggsaron_immortal_guardian); + RegisterUlduarCreatureAI(boss_yoggsaron_lich_king); + RegisterUlduarCreatureAI(boss_yoggsaron_llane); + RegisterUlduarCreatureAI(boss_yoggsaron_neltharion); + RegisterUlduarCreatureAI(boss_yoggsaron_voice); // SPELLS RegisterSpellScript(spell_yogg_saron_malady_of_the_mind_aura); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 0db04db30..3d179883c 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -19,6 +19,7 @@ #include "CreatureScript.h" #include "GameTime.h" #include "InstanceMapScript.h" +#include "InstanceScript.h" #include "Player.h" #include "ScriptedCreature.h" #include "Transport.h" @@ -27,6 +28,94 @@ #include "WorldStatePackets.h" #include "ulduar.h" +DoorData const doorData[] = +{ + { GO_LEVIATHAN_DOORS, BOSS_LEVIATHAN, DOOR_TYPE_ROOM }, + { GO_XT002_DOORS, BOSS_XT002, DOOR_TYPE_ROOM }, + { GO_KOLOGARN_DOORS, BOSS_KOLOGARN, DOOR_TYPE_ROOM }, + { GO_ASSEMBLY_DOORS, BOSS_ASSEMBLY, DOOR_TYPE_ROOM }, + { GO_ARCHIVUM_DOORS, BOSS_ASSEMBLY, DOOR_TYPE_PASSAGE }, + { GO_YOGG_SARON_DOORS, BOSS_YOGGSARON, DOOR_TYPE_ROOM }, + { 0, 0, DOOR_TYPE_ROOM } +}; + +ObjectData const creatureData[] = +{ + { NPC_LEVIATHAN, BOSS_LEVIATHAN }, + { NPC_IGNIS, BOSS_IGNIS }, + { NPC_RAZORSCALE, BOSS_RAZORSCALE }, + { NPC_XT002, BOSS_XT002 }, + { NPC_KOLOGARN, BOSS_KOLOGARN }, + { NPC_AURIAYA, BOSS_AURIAYA }, + { NPC_MIMIRON, BOSS_MIMIRON }, + { NPC_HODIR, BOSS_HODIR }, + { NPC_THORIM, BOSS_THORIM }, + { NPC_FREYA, BOSS_FREYA }, + { NPC_VEZAX, BOSS_VEZAX }, + { NPC_YOGGSARON, BOSS_YOGGSARON }, + { NPC_ALGALON, BOSS_ALGALON }, + // Assembly of Iron members + { NPC_STEELBREAKER, DATA_STEELBREAKER }, + { NPC_MOLGEIM, DATA_MOLGEIM }, + { NPC_BRUNDIR, DATA_BRUNDIR }, + // Mimiron vehicles + { NPC_MIMIRON_LEVIATHAN_MKII, DATA_MIMIRON_LEVIATHAN_MKII }, + { NPC_MIMIRON_VX001, DATA_MIMIRON_VX001 }, + { NPC_MIMIRON_ACU, DATA_MIMIRON_ACU }, + // Freya elders + { NPC_ELDER_IRONBRANCH, DATA_ELDER_IRONBRANCH }, + { NPC_ELDER_STONEBARK, DATA_ELDER_STONEBARK }, + { NPC_ELDER_BRIGHTLEAF, DATA_ELDER_BRIGHTLEAF }, + // Yogg-Saron helpers + { NPC_SARA, DATA_SARA }, + { NPC_BRAIN_OF_YOGG_SARON, DATA_BRAIN_OF_YOGG_SARON }, + // Algalon helpers + { NPC_BRANN_BRONZBEARD_ALG, DATA_BRANN_BRONZEBEARD_ALG }, + { NPC_BRANN_BASE_CAMP, DATA_BRANN_BASE_CAMP }, + { 0, 0 } +}; + +ObjectData const gameobjectData[] = +{ + { GO_LEVIATHAN_DOORS, DATA_LEVIATHAN_DOORS }, + { GO_LIGHTNING_WALL1, DATA_LIGHTNING_WALL1 }, + { GO_LIGHTNING_WALL2, DATA_LIGHTNING_WALL2 }, + { GO_XT002_DOORS, DATA_XT002_DOORS }, + { GO_KOLOGARN_DOORS, DATA_KOLOGARN_DOORS }, + { GO_ASSEMBLY_DOORS, DATA_ASSEMBLY_DOORS }, + { GO_ARCHIVUM_DOORS, DATA_ARCHIVUM_DOORS }, + { GO_MIMIRON_DOOR_1, DATA_GO_MIMIRON_DOOR_1 }, + { GO_MIMIRON_DOOR_2, DATA_GO_MIMIRON_DOOR_2 }, + { GO_MIMIRON_DOOR_3, DATA_GO_MIMIRON_DOOR_3 }, + { GO_ARENA_LEVER_GATE, DATA_THORIM_LEVER_GATE }, + { GO_ARENA_LEVER, DATA_THORIM_LEVER }, + { GO_ARENA_FENCE, DATA_THORIM_FENCE }, + { GO_FIRST_COLOSSUS_DOORS, DATA_THORIM_FIRST_DOORS }, + { GO_SECOND_COLOSSUS_DOORS, DATA_THORIM_SECOND_DOORS }, + { GO_YOGG_SARON_DOORS, DATA_YOGG_SARON_DOORS }, + { GO_KEEPERS_GATE, DATA_KEEPERS_GATE }, + { GO_DOODAD_UL_SIGILDOOR_01, DATA_SIGILDOOR_01 }, + { GO_DOODAD_UL_SIGILDOOR_02, DATA_SIGILDOOR_02 }, + { GO_DOODAD_UL_SIGILDOOR_03, DATA_SIGILDOOR_03 }, + { GO_DOODAD_UL_UNIVERSEFLOOR_01, DATA_UNIVERSE_FLOOR_01 }, + { GO_DOODAD_UL_UNIVERSEFLOOR_02, DATA_UNIVERSE_FLOOR_02 }, + { GO_DOODAD_UL_UNIVERSEGLOBE01, DATA_UNIVERSE_GLOBE }, + { GO_DOODAD_UL_ULDUAR_TRAPDOOR_03, DATA_ALGALON_TRAPDOOR }, + { GO_MIMIRON_TRAM, DATA_MIMIRON_TRAM }, + { GO_MIMIRON_ACTIVATE_TRAM, DATA_MIMIRON_ACTIVATE_TRAM }, + { GO_MIMIRON_TRAM_ROCKET_BOOSTER, DATA_MIMIRON_TRAM_ROCKET_BOOSTER}, + { GO_MIMIRON_CALL_TRAM_CENTER, DATA_MIMIRON_CALL_TRAM_CENTER }, + { GO_MIMIRON_CALL_TRAM_MIMIRON, DATA_MIMIRON_CALL_TRAM_MIMIRON }, + { GO_DOODAD_UL_TRAIN_TURNAROUND01, DATA_MIMIRON_TRAM_TURNAROUND_1 }, + { GO_DOODAD_UL_TRAIN_TURNAROUND02, DATA_MIMIRON_TRAM_TURNAROUND_2 }, + // Hodir chests (dynamically spawned, one per difficulty) + { GO_HODIR_CHEST_NORMAL, DATA_HODIR_CHEST_NORMAL }, + { GO_HODIR_CHEST_NORMAL_HERO, DATA_HODIR_CHEST_NORMAL_HERO }, + { GO_HODIR_CHEST_HARD, DATA_HODIR_CHEST_HARD }, + { GO_HODIR_CHEST_HARD_HERO, DATA_HODIR_CHEST_HARD_HERO }, + { 0, 0 } +}; + class instance_ulduar : public InstanceMapScript { public: @@ -41,39 +130,25 @@ public: { instance_ulduar_InstanceMapScript(Map* pMap) : InstanceScript(pMap) { - Initialize(); SetHeaders(DataHeader); + SetBossNumber(MAX_ENCOUNTER); + LoadDoorData(doorData); + LoadObjectData(creatureData, gameobjectData); + Initialize(); // 0: 10 man difficulty // 1: 25 man difficulty m_difficulty = (pMap->Is25ManRaid() ? 0 : 1); }; - uint32 m_auiEncounter[MAX_ENCOUNTER]; + // Only used for TYPE_WATCHERS bitmask + uint32 m_watchersMask; uint32 C_of_Ulduar_MASK; int m_difficulty; - // Bosses - ObjectGuid m_uiLeviathanGUID; - ObjectGuid m_uiIgnisGUID; - ObjectGuid m_uiRazorscaleGUID; - ObjectGuid m_uiXT002GUID; - ObjectGuid m_auiAssemblyGUIDs[3]; - ObjectGuid m_uiKologarnGUID; - ObjectGuid m_uiAuriayaGUID; - ObjectGuid m_uiMimironGUID; - ObjectGuid m_uiHodirGUID; - ObjectGuid m_uiThorimGUID; - ObjectGuid m_uiFreyaGUID; - ObjectGuid m_uiVezaxGUID; - ObjectGuid m_uiYoggSaronGUID; - ObjectGuid m_uiAlgalonGUID; - // Flame Leviathan - ObjectGuid m_leviathanDoorsGUID; ObjectGuid m_leviathanVisualTowers[4][2]; ObjectGuid m_RepairSGUID[2]; - ObjectGuid m_lightningWalls[2]; bool m_leviathanTowers[4]; GuidList _leviathanVehicles; uint32 m_unbrokenAchievement; @@ -82,57 +157,17 @@ public: // Razorscale ObjectGuid m_RazorscaleHarpoonFireStateGUID[4]; - // XT-002 - ObjectGuid m_xt002DoorsGUID; - - // Kologarn - ObjectGuid KologarnDoorGUID; - - // Assembly of Iron - ObjectGuid m_assemblyDoorsGUID; - ObjectGuid m_archivumDoorsGUID; - - // Thorim - ObjectGuid m_thorimGameobjectsGUID[5]; - - // Hodir's chests + // Hodir bool hmHodir; - ObjectGuid m_hodirNormalChest; - ObjectGuid m_hodirHardmodeChest; Position normalChestPosition = { 1967.152588f, -204.188461f, 432.686951f, 5.50957f }; Position hardChestPosition = { 2035.94600f, -202.084885f, 432.686859f, 3.164077f }; - // Mimiron Tram - ObjectGuid m_mimironTramGUID; - ObjectGuid m_mimironActivateTramGUID; - ObjectGuid m_mimironTramRocketBoosterGUID; - ObjectGuid m_mimironTramTurnaround1GUID; - ObjectGuid m_mimironTramTurnaround2GUID; - ObjectGuid m_mimironCallTramCenterGUID; - ObjectGuid m_mimironCallTramMimironGUID; - - // Mimiron - ObjectGuid m_MimironDoor[3]; - ObjectGuid m_MimironLeviathanMKIIguid; - ObjectGuid m_MimironVX001guid; - ObjectGuid m_MimironACUguid; - // Freya - ObjectGuid m_FreyaElder[3]; uint32 m_conspeedatoryAttempt; // Yogg-Saron - ObjectGuid m_saraGUID; - ObjectGuid m_yoggsaronBrainGUID; - ObjectGuid m_yoggsaronDoorsGUID; // Algalon - ObjectGuid m_algalonSigilDoorGUID[3]; - ObjectGuid m_algalonFloorGUID[2]; - ObjectGuid m_algalonUniverseGUID; - ObjectGuid m_algalonTrapdoorGUID; - ObjectGuid m_brannBronzebeardAlgGUID; - ObjectGuid m_brannBronzebeardBaseCamp; uint32 m_algalonTimer; // Ancient Gate @@ -141,13 +176,12 @@ public: // Shared EventMap _events; bool m_mimironTramUsed; - ObjectGuid m_keepersgateGUID; ObjectGuid m_keepersGossipGUID[4]; void Initialize() override { // Bosses - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + m_watchersMask = 0; C_of_Ulduar_MASK = 0; // Flame Leviathan @@ -182,21 +216,21 @@ public: void OnPlayerEnter(Player* player) override { // mimiron tram: - if (GameObject* MimironTram = instance->GetGameObject(m_mimironTramGUID)) + if (GameObject* MimironTram = GetGameObject(DATA_MIMIRON_TRAM)) { player->UpdateVisibilityOf(MimironTram); if (StaticTransport* t = MimironTram->ToStaticTransport()) { - if (GameObject* go = instance->GetGameObject(m_mimironTramRocketBoosterGUID)) + if (GameObject* go = GetGameObject(DATA_MIMIRON_TRAM_ROCKET_BOOSTER)) if (!go->GetTransport()) t->AddPassenger(go, true); - if (GameObject* go = instance->GetGameObject(m_mimironActivateTramGUID)) + if (GameObject* go = GetGameObject(DATA_MIMIRON_ACTIVATE_TRAM)) if (!go->GetTransport()) t->AddPassenger(go, true); } } - if (!m_uiAlgalonGUID && m_algalonTimer && (m_algalonTimer <= 60 || m_algalonTimer == TIMER_ALGALON_TO_SUMMON)) + if (!GetObjectGuid(BOSS_ALGALON) && m_algalonTimer && (m_algalonTimer <= 60 || m_algalonTimer == TIMER_ALGALON_TO_SUMMON)) { TempSummon* algalon = instance->SummonCreature(NPC_ALGALON, AlgalonLandPos); if (!algalon) @@ -217,15 +251,15 @@ public: bool IsEncounterInProgress() const override { - for (uint8 i = 0; i < (MAX_ENCOUNTER - 1); ++i) + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) { - if (m_auiEncounter[i] == IN_PROGRESS) + if (GetBossState(i) == IN_PROGRESS) return true; } // Leviathan does not use IN_PROGRESS type, instead SPECIAL is set and never reset, // Check if he is in combat. - if (Unit* l = instance->GetCreature(m_uiLeviathanGUID)) + if (Creature* l = instance->GetCreature(GetObjectGuid(BOSS_LEVIATHAN))) if (l->IsInCombat()) return true; @@ -239,13 +273,120 @@ public: SetData(eventId, 0); } + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) + { + case BOSS_LEVIATHAN: + if (state == DONE) + { + instance->DoForAllPlayers([&](Player* player) + { + if (Creature* vehicleCreature = player->GetVehicleCreatureBase()) + vehicleCreature->DespawnOrUnsummon(); + }); + + if (GameObject* go = GetGameObject(DATA_LEVIATHAN_DOORS)) + go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + } + break; + case BOSS_ASSEMBLY: + // Assembly doors handled by DoorData, archivum + // doors stay open only after DONE + if (GameObject* go = GetGameObject(DATA_ARCHIVUM_DOORS)) + go->SetGoState(state == DONE ? GO_STATE_ACTIVE : GO_STATE_READY); + break; + case BOSS_MIMIRON: + if (state == IN_PROGRESS) + m_mimironTramUsed = true; + [[fallthrough]]; + case BOSS_HODIR: + case BOSS_THORIM: + case BOSS_FREYA: + if (GetBossState(BOSS_MIMIRON) == DONE && GetBossState(BOSS_FREYA) == DONE && GetBossState(BOSS_HODIR) == DONE && GetBossState(BOSS_THORIM) == DONE) + { + scheduler.Schedule(45s, [this](TaskContext /*context*/) + { + if (GameObject* go = GetGameObject(DATA_KEEPERS_GATE)) + { + go->RemoveGameObjectFlag(GO_FLAG_LOCKED); + if (Creature* trigger = instance->SummonCreature(NPC_ANCIENT_GATE_WORLD_TRIGGER, triggerAncientGatePosition, nullptr, 10 * IN_MILLISECONDS)) + trigger->AI()->Talk(EMOTE_ANCIENT_GATE_UNLOCKED); + } + }); + } + if (type == BOSS_HODIR && state == DONE) + setChestsLootable(BOSS_HODIR); + break; + case BOSS_ALGALON: + if (GameObject* go = GetGameObject(DATA_SIGILDOOR_03)) + { + go->SetGoState(state != IN_PROGRESS ? GO_STATE_ACTIVE : GO_STATE_READY); + go->EnableCollision(false); + } + if (GameObject* go = GetGameObject(DATA_UNIVERSE_FLOOR_01)) + { + go->SetGoState(state != IN_PROGRESS ? GO_STATE_ACTIVE : GO_STATE_READY); + go->EnableCollision(false); + } + if (GameObject* go = GetGameObject(DATA_UNIVERSE_FLOOR_02)) + { + go->SetGoState(state == IN_PROGRESS ? GO_STATE_ACTIVE : GO_STATE_READY); + go->EnableCollision(false); + } + if (GameObject* go = GetGameObject(DATA_UNIVERSE_GLOBE)) + { + go->SetGoState(state == IN_PROGRESS ? GO_STATE_ACTIVE : GO_STATE_READY); + go->EnableCollision(false); + } + if (GameObject* go = GetGameObject(DATA_ALGALON_TRAPDOOR)) + { + go->SetGoState(state == IN_PROGRESS ? GO_STATE_ACTIVE : GO_STATE_READY); + go->EnableCollision(false); + } + break; + default: + break; + } + + // take care of herbs + if (type == BOSS_FREYA && state == DONE) + { + std::list goList; + if (Creature* freya = GetCreature(BOSS_FREYA)) + { + freya->GetGameObjectListWithEntryInGrid(goList, { 191019, 190176, 190171, 190170, 189973 }, 333.0f); + + for (GameObject* herb : goList) + herb->SetRespawnTime(7 * DAY); + } + } + + if (state == DONE) + SaveToDB(); + + if (type > BOSS_LEVIATHAN && type < MAX_ENCOUNTER && state == IN_PROGRESS) + { + instance->DoForAllPlayers([&](Player* player) + { + if (Creature* vehicleCreature = player->GetVehicleCreatureBase()) + vehicleCreature->DespawnOrUnsummon(); + }); + } + + return true; + } + void SpawnHodirChests(Difficulty diff, Creature* hodir) { switch (diff) { case RAID_DIFFICULTY_10MAN_NORMAL: // 10 man chest { - if (!m_hodirNormalChest) + if (!GetObjectGuid(DATA_HODIR_CHEST_NORMAL)) { if (GameObject* go = hodir->SummonGameObject( GO_HODIR_CHEST_NORMAL, @@ -254,11 +395,10 @@ public: normalChestPosition.GetPositionZ(), normalChestPosition.GetOrientation(), 0, 0, 0, 0, 0)) { - m_hodirNormalChest = go->GetGUID(); go->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); } } - if (!m_hodirHardmodeChest) + if (!GetObjectGuid(DATA_HODIR_CHEST_HARD)) { if (GameObject* go = hodir->SummonGameObject( GO_HODIR_CHEST_HARD, @@ -267,7 +407,6 @@ public: hardChestPosition.GetPositionZ(), hardChestPosition.GetOrientation(), 0, 0, 0, 0, 0)) { - m_hodirHardmodeChest = go->GetGUID(); go->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); hmHodir = true; } @@ -276,7 +415,7 @@ public: } case RAID_DIFFICULTY_25MAN_NORMAL: // 25 man chest { - if (!m_hodirNormalChest) + if (!GetObjectGuid(DATA_HODIR_CHEST_NORMAL_HERO)) { if (GameObject* go = hodir->SummonGameObject( GO_HODIR_CHEST_NORMAL_HERO, @@ -285,11 +424,10 @@ public: normalChestPosition.GetPositionZ(), normalChestPosition.GetOrientation(), 0, 0, 0, 0, 0)) { - m_hodirNormalChest = go->GetGUID(); go->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); } } - if (!m_hodirHardmodeChest) + if (!GetObjectGuid(DATA_HODIR_CHEST_HARD_HERO)) { if (GameObject* go = hodir->SummonGameObject( GO_HODIR_CHEST_HARD_HERO, @@ -298,7 +436,6 @@ public: hardChestPosition.GetPositionZ(), hardChestPosition.GetOrientation(), 0, 0, 0, 0, 0)) { - m_hodirHardmodeChest = go->GetGUID(); go->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); hmHodir = true; } @@ -312,32 +449,12 @@ public: void OnCreatureCreate(Creature* creature) override { + InstanceScript::OnCreatureCreate(creature); + switch (creature->GetEntry()) { - case NPC_LEVIATHAN: - m_uiLeviathanGUID = creature->GetGUID(); - break; - case NPC_IGNIS: - m_uiIgnisGUID = creature->GetGUID(); - break; - case NPC_RAZORSCALE: - m_uiRazorscaleGUID = creature->GetGUID(); - break; - case NPC_XT002: - m_uiXT002GUID = creature->GetGUID(); - break; - case NPC_STEELBREAKER: - m_auiAssemblyGUIDs[0] = creature->GetGUID(); - break; - case NPC_MOLGEIM: - m_auiAssemblyGUIDs[1] = creature->GetGUID(); - break; - case NPC_BRUNDIR: - m_auiAssemblyGUIDs[2] = creature->GetGUID(); - break; case NPC_KOLOGARN: - m_uiKologarnGUID = creature->GetGUID(); - if (GetData(TYPE_KOLOGARN) == DONE) + if (GetBossState(BOSS_KOLOGARN) == DONE) { creature->SetDisableGravity(true); creature->SetPosition(creature->GetHomePosition()); @@ -345,34 +462,13 @@ public: creature->StopMovingOnCurrentPos(); } break; - case NPC_AURIAYA: - m_uiAuriayaGUID = creature->GetGUID(); - break; - case NPC_MIMIRON: - m_uiMimironGUID = creature->GetGUID(); - break; case NPC_HODIR: - m_uiHodirGUID = creature->GetGUID(); - if (m_auiEncounter[TYPE_HODIR] != DONE) + if (GetBossState(BOSS_HODIR) != DONE) { SpawnHodirChests(instance->GetDifficulty(), creature); } break; - case NPC_THORIM: - m_uiThorimGUID = creature->GetGUID(); - break; - case NPC_FREYA: - m_uiFreyaGUID = creature->GetGUID(); - break; - case NPC_VEZAX: - m_uiVezaxGUID = creature->GetGUID(); - break; - case NPC_YOGGSARON: - m_uiYoggSaronGUID = creature->GetGUID(); - break; case NPC_ALGALON: - m_uiAlgalonGUID = creature->GetGUID(); - if (!m_algalonTimer) creature->DespawnOrUnsummon(); break; @@ -388,32 +484,6 @@ public: m_RazorscaleHarpoonFireStateGUID[0] = creature->GetGUID(); } break; - case NPC_MIMIRON_LEVIATHAN_MKII: - m_MimironLeviathanMKIIguid = creature->GetGUID(); - break; - case NPC_MIMIRON_VX001: - m_MimironVX001guid = creature->GetGUID(); - break; - case NPC_MIMIRON_ACU: - m_MimironACUguid = creature->GetGUID(); - break; - case NPC_ELDER_IRONBRANCH: - case NPC_ELDER_STONEBARK: - case NPC_ELDER_BRIGHTLEAF: - m_FreyaElder[creature->GetEntry() - NPC_ELDER_IRONBRANCH] = creature->GetGUID(); - break; - case NPC_SARA: - m_saraGUID = creature->GetGUID(); - break; - case NPC_BRAIN_OF_YOGG_SARON: - m_yoggsaronBrainGUID = creature->GetGUID(); - break; - case NPC_BRANN_BRONZBEARD_ALG: - m_brannBronzebeardAlgGUID = creature->GetGUID(); - break; - case NPC_BRANN_BASE_CAMP: - m_brannBronzebeardBaseCamp = creature->GetGUID(); - break; //! These creatures are summoned by something else than Algalon //! but need to be controlled/despawned by him - so they need to be //! registered in his summon list @@ -421,31 +491,36 @@ public: case NPC_ALGALON_STALKER_ASTEROID_TARGET_01: case NPC_ALGALON_STALKER_ASTEROID_TARGET_02: case NPC_UNLEASHED_DARK_MATTER: - if (Creature* algalon = instance->GetCreature(m_uiAlgalonGUID)) + if (Creature* algalon = GetCreature(BOSS_ALGALON)) algalon->AI()->JustSummoned(creature); break; } } - void OnCreatureRemove(Creature* creature) override - { - switch (creature->GetEntry()) - { - case NPC_BRANN_BRONZBEARD_ALG: - if (m_brannBronzebeardAlgGUID == creature->GetGUID()) - m_brannBronzebeardAlgGUID.Clear(); - break; - } - } - void OpenIfDone(uint32 encounter, GameObject* go, GOState state) { - if (GetData(encounter) == DONE) + if (GetBossState(encounter) == DONE) go->SetGoState(state); } + GameObject* GetHodirChest(bool hardmode) + { + if (hardmode) + { + if (GameObject* go = GetGameObject(DATA_HODIR_CHEST_HARD)) + return go; + return GetGameObject(DATA_HODIR_CHEST_HARD_HERO); + } + + if (GameObject* go = GetGameObject(DATA_HODIR_CHEST_NORMAL)) + return go; + return GetGameObject(DATA_HODIR_CHEST_NORMAL_HERO); + } + void OnGameObjectCreate(GameObject* gameObject) override { + InstanceScript::OnGameObjectCreate(gameObject); + switch (gameObject->GetEntry()) { // Flame Leviathan @@ -458,108 +533,61 @@ public: break; } case GO_LIGHTNING_WALL1: - m_lightningWalls[0] = gameObject->GetGUID(); - OpenIfDone(TYPE_LEVIATHAN, gameObject, GO_STATE_ACTIVE); - break; - case GO_LIGHTNING_WALL2: - m_lightningWalls[1] = gameObject->GetGUID(); + OpenIfDone(BOSS_LEVIATHAN, gameObject, GO_STATE_ACTIVE); break; case GO_MIMIRONS_TARGETTING_CRYSTAL: - OpenIfDone(TYPE_LEVIATHAN, gameObject, GO_STATE_ACTIVE); + OpenIfDone(BOSS_LEVIATHAN, gameObject, GO_STATE_ACTIVE); m_leviathanVisualTowers[3][0] = gameObject->GetGUID(); break; case GO_FREYAS_TARGETTING_CRYSTAL: - OpenIfDone(TYPE_LEVIATHAN, gameObject, GO_STATE_ACTIVE); + OpenIfDone(BOSS_LEVIATHAN, gameObject, GO_STATE_ACTIVE); m_leviathanVisualTowers[0][0] = gameObject->GetGUID(); break; case GO_HODIRS_TARGETTING_CRYSTAL: - OpenIfDone(TYPE_LEVIATHAN, gameObject, GO_STATE_ACTIVE); + OpenIfDone(BOSS_LEVIATHAN, gameObject, GO_STATE_ACTIVE); m_leviathanVisualTowers[2][0] = gameObject->GetGUID(); break; case GO_THORIMS_TARGETTING_CRYSTAL: - OpenIfDone(TYPE_LEVIATHAN, gameObject, GO_STATE_ACTIVE); + OpenIfDone(BOSS_LEVIATHAN, gameObject, GO_STATE_ACTIVE); m_leviathanVisualTowers[1][0] = gameObject->GetGUID(); break; case GO_MIMIRONS_GENERATOR: - OpenIfDone(TYPE_LEVIATHAN, gameObject, GO_STATE_ACTIVE); + OpenIfDone(BOSS_LEVIATHAN, gameObject, GO_STATE_ACTIVE); m_leviathanVisualTowers[3][1] = gameObject->GetGUID(); break; case GO_FREYAS_GENERATOR: - OpenIfDone(TYPE_LEVIATHAN, gameObject, GO_STATE_ACTIVE); + OpenIfDone(BOSS_LEVIATHAN, gameObject, GO_STATE_ACTIVE); m_leviathanVisualTowers[0][1] = gameObject->GetGUID(); break; case GO_HODIRS_GENERATOR: - OpenIfDone(TYPE_LEVIATHAN, gameObject, GO_STATE_ACTIVE); + OpenIfDone(BOSS_LEVIATHAN, gameObject, GO_STATE_ACTIVE); m_leviathanVisualTowers[2][1] = gameObject->GetGUID(); break; case GO_THORIMS_GENERATOR: - OpenIfDone(TYPE_LEVIATHAN, gameObject, GO_STATE_ACTIVE); + OpenIfDone(BOSS_LEVIATHAN, gameObject, GO_STATE_ACTIVE); m_leviathanVisualTowers[1][1] = gameObject->GetGUID(); break; case GO_LEVIATHAN_DOORS: - if (GetData(TYPE_LEVIATHAN) >= DONE) + if (GetBossState(BOSS_LEVIATHAN) >= DONE) gameObject->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); - m_leviathanDoorsGUID = gameObject->GetGUID(); - break; - // XT-002, Kologarn, Assembly of Iron - case GO_XT002_DOORS: - m_xt002DoorsGUID = gameObject->GetGUID(); - break; - case GO_KOLOGARN_DOORS: - KologarnDoorGUID = gameObject->GetGUID(); break; case GO_KOLOGARN_BRIDGE: - OpenIfDone(TYPE_KOLOGARN, gameObject, GO_STATE_READY); - break; - case GO_ASSEMBLY_DOORS: - m_assemblyDoorsGUID = gameObject->GetGUID(); + OpenIfDone(BOSS_KOLOGARN, gameObject, GO_STATE_READY); break; case GO_ARCHIVUM_DOORS: - m_archivumDoorsGUID = gameObject->GetGUID(); - OpenIfDone(TYPE_ASSEMBLY, gameObject, GO_STATE_ACTIVE); - break; - // Thorim - case GO_ARENA_LEVER_GATE: - m_thorimGameobjectsGUID[DATA_THORIM_LEVER_GATE - DATA_THORIM_LEVER_GATE] = gameObject->GetGUID(); - break; - case GO_ARENA_LEVER: - m_thorimGameobjectsGUID[DATA_THORIM_LEVER - DATA_THORIM_LEVER_GATE] = gameObject->GetGUID(); - break; - case GO_ARENA_FENCE: - m_thorimGameobjectsGUID[DATA_THORIM_FENCE - DATA_THORIM_LEVER_GATE] = gameObject->GetGUID(); - break; - case GO_FIRST_COLOSSUS_DOORS: - m_thorimGameobjectsGUID[DATA_THORIM_FIRST_DOORS - DATA_THORIM_LEVER_GATE] = gameObject->GetGUID(); - break; - case GO_SECOND_COLOSSUS_DOORS: - m_thorimGameobjectsGUID[DATA_THORIM_SECOND_DOORS - DATA_THORIM_LEVER_GATE] = gameObject->GetGUID(); - break; - // Yogg-Saron - case GO_YOGG_SARON_DOORS: - m_yoggsaronDoorsGUID = gameObject->GetGUID(); + OpenIfDone(BOSS_ASSEMBLY, gameObject, GO_STATE_ACTIVE); break; case GO_KEEPERS_GATE: - if (GetData(TYPE_MIMIRON) == DONE && GetData(TYPE_FREYA) == DONE && GetData(TYPE_HODIR) == DONE && GetData(TYPE_THORIM) == DONE) + if (GetBossState(BOSS_MIMIRON) == DONE && GetBossState(BOSS_FREYA) == DONE && GetBossState(BOSS_HODIR) == DONE && GetBossState(BOSS_THORIM) == DONE) gameObject->RemoveGameObjectFlag(GO_FLAG_LOCKED); - - m_keepersgateGUID = gameObject->GetGUID(); break; // Mimiron, Hodir, Vezax case GO_MIMIRON_ELEVATOR: gameObject->EnableCollision(false); break; - case GO_MIMIRON_DOOR_1: - m_MimironDoor[0] = gameObject->GetGUID(); - break; - case GO_MIMIRON_DOOR_2: - m_MimironDoor[1] = gameObject->GetGUID(); - break; - case GO_MIMIRON_DOOR_3: - m_MimironDoor[2] = gameObject->GetGUID(); - break; case GO_HODIR_FROZEN_DOOR: case GO_HODIR_DOOR: - if (GetData(TYPE_HODIR) == DONE) + if (GetBossState(BOSS_HODIR) == DONE) if (gameObject->GetGoState() != GO_STATE_ACTIVE ) { gameObject->SetLootState(GO_READY); @@ -567,7 +595,7 @@ public: } break; case GO_VEZAX_DOOR: - if (GetData(TYPE_VEZAX) == DONE ) + if (GetBossState(BOSS_VEZAX) == DONE ) if (gameObject->GetGoState() != GO_STATE_ACTIVE ) { gameObject->SetLootState(GO_READY); @@ -579,27 +607,8 @@ public: break; // Mimiron Tram case GO_MIMIRON_TRAM: - if (GetData(TYPE_MIMIRON) == DONE) + if (GetBossState(BOSS_MIMIRON) == DONE) m_mimironTramUsed = true; - m_mimironTramGUID = gameObject->GetGUID(); - break; - case GO_MIMIRON_TRAM_ROCKET_BOOSTER: - m_mimironTramRocketBoosterGUID = gameObject->GetGUID(); - break; - case GO_MIMIRON_ACTIVATE_TRAM: - m_mimironActivateTramGUID = gameObject->GetGUID(); - break; - case GO_MIMIRON_CALL_TRAM_CENTER: - m_mimironCallTramCenterGUID = gameObject->GetGUID(); - break; - case GO_MIMIRON_CALL_TRAM_MIMIRON: - m_mimironCallTramMimironGUID = gameObject->GetGUID(); - break; - case GO_DOODAD_UL_TRAIN_TURNAROUND01: - m_mimironTramTurnaround1GUID = gameObject->GetGUID(); - break; - case GO_DOODAD_UL_TRAIN_TURNAROUND02: - m_mimironTramTurnaround2GUID = gameObject->GetGUID(); break; // Algalon the Observer case GO_CELESTIAL_PLANETARIUM_ACCESS_10: @@ -608,37 +617,20 @@ public: gameObject->SetGameObjectFlag(GO_FLAG_IN_USE); break; case GO_DOODAD_UL_SIGILDOOR_01: - m_algalonSigilDoorGUID[0] = gameObject->GetGUID(); if (m_algalonTimer) gameObject->SetGoState(GO_STATE_ACTIVE); break; case GO_DOODAD_UL_SIGILDOOR_02: - m_algalonSigilDoorGUID[1] = gameObject->GetGUID(); if (m_algalonTimer) gameObject->SetGoState(GO_STATE_ACTIVE); break; - case GO_DOODAD_UL_SIGILDOOR_03: - m_algalonSigilDoorGUID[2] = gameObject->GetGUID(); - break; - case GO_DOODAD_UL_UNIVERSEFLOOR_01: - m_algalonFloorGUID[0] = gameObject->GetGUID(); - break; - case GO_DOODAD_UL_UNIVERSEFLOOR_02: - m_algalonFloorGUID[1] = gameObject->GetGUID(); - break; - case GO_DOODAD_UL_UNIVERSEGLOBE01: - m_algalonUniverseGUID = gameObject->GetGUID(); - break; - case GO_DOODAD_UL_ULDUAR_TRAPDOOR_03: - m_algalonTrapdoorGUID = gameObject->GetGUID(); - break; // Herbs case 191019: // Adder's Tongue case 190176: // Frost Lotus case 190171: // Lichbloom case 190170: // Talandra's Rose case 189973: // Goldclover - if (GetData(TYPE_FREYA) == DONE) + if (GetBossState(BOSS_FREYA) == DONE) gameObject->SetRespawnTime(7 * DAY); break; } @@ -650,16 +642,16 @@ public: { switch (boss) { - case TYPE_HODIR: + case BOSS_HODIR: if (hmHodir) { - if (GameObject* go = instance->GetGameObject(m_hodirHardmodeChest)) + if (GameObject* go = GetHodirChest(true)) { go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); go->SetLootRecipient(instance); } } - if (GameObject* go = instance->GetGameObject(m_hodirNormalChest)) + if (GameObject* go = GetHodirChest(false)) { go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); go->SetLootRecipient(instance); @@ -673,74 +665,18 @@ public: { switch (type) { - case TYPE_LEVIATHAN: - m_auiEncounter[type] = data; - if (data == DONE) - { - Map::PlayerList const& pList = instance->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) - { - if (Creature* vehicleCreature = itr->GetSource()->GetVehicleCreatureBase()) - { - vehicleCreature->DespawnOrUnsummon(); - } - } - } - break; - case TYPE_IGNIS: - case TYPE_RAZORSCALE: - case TYPE_XT002: - case TYPE_AURIAYA: - case TYPE_VEZAX: - case TYPE_YOGGSARON: - case TYPE_KOLOGARN: - m_auiEncounter[type] = data; - break; - case TYPE_ASSEMBLY: - if (GameObject* go = instance->GetGameObject(m_assemblyDoorsGUID)) - go->SetGoState(data == IN_PROGRESS ? GO_STATE_READY : GO_STATE_ACTIVE); - if (GameObject* go = instance->GetGameObject(m_archivumDoorsGUID)) - go->SetGoState(data == DONE ? GO_STATE_ACTIVE : GO_STATE_READY); - - m_auiEncounter[type] = data; - break; - case TYPE_MIMIRON: - case TYPE_HODIR: - case TYPE_THORIM: - case TYPE_FREYA: - m_auiEncounter[type] = data; - if (GetData(TYPE_MIMIRON) == DONE && GetData(TYPE_FREYA) == DONE && GetData(TYPE_HODIR) == DONE && GetData(TYPE_THORIM) == DONE) - { - scheduler.Schedule(45s, [this](TaskContext /*context*/) - { - if (GameObject* go = instance->GetGameObject(m_keepersgateGUID)) - { - go->RemoveGameObjectFlag(GO_FLAG_LOCKED); - if (Creature* trigger = instance->SummonCreature(NPC_ANCIENT_GATE_WORLD_TRIGGER, triggerAncientGatePosition, nullptr, 10*IN_MILLISECONDS)) - { - trigger->AI()->Talk(EMOTE_ANCIENT_GATE_UNLOCKED); - } - } - }); - } - if (type == TYPE_MIMIRON && data == IN_PROGRESS) // after reaching him without tram and starting the fight - m_mimironTramUsed = true; - if (GetData(TYPE_HODIR) == DONE) - setChestsLootable(TYPE_HODIR); - break; case TYPE_HODIR_HM_FAIL: - if (GameObject* go = instance->GetGameObject(m_hodirHardmodeChest)) + if (GameObject* go = GetHodirChest(true)) { hmHodir = false; go->Delete(); - m_hodirHardmodeChest.Clear(); } break; case TYPE_WATCHERS: - m_auiEncounter[type] |= 1 << data; + m_watchersMask |= 1 << data; [[fallthrough]]; case EVENT_KEEPER_TELEPORTED: - if (Creature* sara = instance->GetCreature(m_saraGUID)) + if (Creature* sara = GetCreature(DATA_SARA)) sara->AI()->DoAction(ACTION_SARA_UPDATE_SUMMON_KEEPERS); break; case DATA_MAGE_BARRIER: @@ -784,98 +720,66 @@ public: _events.CancelEvent(EVENT_UPDATE_ALGALON_TIMER); SaveToDB(); return; - case TYPE_ALGALON: - m_auiEncounter[type] = data; - if (GameObject* go = instance->GetGameObject(GetGuidData(GO_DOODAD_UL_SIGILDOOR_03))) - { - go->SetGoState(data != IN_PROGRESS ? GO_STATE_ACTIVE : GO_STATE_READY); - go->EnableCollision(false); - } - if (GameObject* go = instance->GetGameObject(GetGuidData(GO_DOODAD_UL_UNIVERSEFLOOR_01))) - { - go->SetGoState(data != IN_PROGRESS ? GO_STATE_ACTIVE : GO_STATE_READY); - go->EnableCollision(false); - } - if (GameObject* go = instance->GetGameObject(GetGuidData(GO_DOODAD_UL_UNIVERSEFLOOR_02))) - { - go->SetGoState(data == IN_PROGRESS ? GO_STATE_ACTIVE : GO_STATE_READY); - go->EnableCollision(false); - } - if (GameObject* go = instance->GetGameObject(GetGuidData(GO_DOODAD_UL_UNIVERSEGLOBE01))) - { - go->SetGoState(data == IN_PROGRESS ? GO_STATE_ACTIVE : GO_STATE_READY); - go->EnableCollision(false); - } - if (GameObject* go = instance->GetGameObject(GetGuidData(GO_DOODAD_UL_ULDUAR_TRAPDOOR_03))) - { - go->SetGoState(data == IN_PROGRESS ? GO_STATE_ACTIVE : GO_STATE_READY); - go->EnableCollision(false); - } - - break; - // Achievement case DATA_DWARFAGEDDON: DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, SPELL_DWARFAGEDDON); DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_DWARFAGEDDON); return; case DATA_CALL_TRAM: - if (GameObject* MimironTram = instance->GetGameObject(m_mimironTramGUID)) + if (GameObject* MimironTram = GetGameObject(DATA_MIMIRON_TRAM)) if (StaticTransport* t = MimironTram->ToStaticTransport()) { if (data == 0 && t->GetGoState() == GO_STATE_ACTIVE && t->GetPathProgress() == t->GetPauseTime()) { MimironTram->SetGoState(GO_STATE_READY); - if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID)) + if (GameObject* rocketBooster = GetGameObject(DATA_MIMIRON_TRAM_ROCKET_BOOSTER)) rocketBooster->SetGoState(GO_STATE_ACTIVE); - if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID)) + if (GameObject* activateTramButton = GetGameObject(DATA_MIMIRON_ACTIVATE_TRAM)) activateTramButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - if (GameObject* callTramCenterButton = instance->GetGameObject(m_mimironCallTramCenterGUID)) + if (GameObject* callTramCenterButton = GetGameObject(DATA_MIMIRON_CALL_TRAM_CENTER)) callTramCenterButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); scheduler.Schedule(30s, [this](TaskContext /*context*/) { - if (GameObject* turnaround1 = instance->GetGameObject(m_mimironTramTurnaround1GUID)) + if (GameObject* turnaround1 = GetGameObject(DATA_MIMIRON_TRAM_TURNAROUND_1)) turnaround1->UseDoorOrButton(); - if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID)) + if (GameObject* rocketBooster = GetGameObject(DATA_MIMIRON_TRAM_ROCKET_BOOSTER)) rocketBooster->SetGoState(GO_STATE_READY); }).Schedule(60s, [this](TaskContext /*context*/) { - if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID)) + if (GameObject* activateTramButton = GetGameObject(DATA_MIMIRON_ACTIVATE_TRAM)) activateTramButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - if (GameObject* callTramMimironButton = instance->GetGameObject(m_mimironCallTramMimironGUID)) + if (GameObject* callTramMimironButton = GetGameObject(DATA_MIMIRON_CALL_TRAM_MIMIRON)) callTramMimironButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); }); } if (data == 1 && t->GetGoState() == GO_STATE_READY && t->GetPathProgress() == 0) { MimironTram->SetGoState(GO_STATE_ACTIVE); - if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID)) + if (GameObject* rocketBooster = GetGameObject(DATA_MIMIRON_TRAM_ROCKET_BOOSTER)) rocketBooster->SetGoState(GO_STATE_ACTIVE); - if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID)) + if (GameObject* activateTramButton = GetGameObject(DATA_MIMIRON_ACTIVATE_TRAM)) activateTramButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - if (GameObject* callTramMimironButton = instance->GetGameObject(m_mimironCallTramMimironGUID)) + if (GameObject* callTramMimironButton = GetGameObject(DATA_MIMIRON_CALL_TRAM_MIMIRON)) callTramMimironButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); scheduler.Schedule(33s, [this](TaskContext /*context*/) { - if (GameObject* turnaround2 = instance->GetGameObject(m_mimironTramTurnaround2GUID)) + if (GameObject* turnaround2 = GetGameObject(DATA_MIMIRON_TRAM_TURNAROUND_2)) turnaround2->UseDoorOrButton(); - if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID)) + if (GameObject* rocketBooster = GetGameObject(DATA_MIMIRON_TRAM_ROCKET_BOOSTER)) rocketBooster->SetGoState(GO_STATE_READY); }).Schedule(63s, [this](TaskContext /*context*/) { - if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID)) + if (GameObject* activateTramButton = GetGameObject(DATA_MIMIRON_ACTIVATE_TRAM)) activateTramButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); - if (GameObject* callTramCenterButton = instance->GetGameObject(m_mimironCallTramCenterGUID)) + if (GameObject* callTramCenterButton = GetGameObject(DATA_MIMIRON_CALL_TRAM_CENTER)) callTramCenterButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); }); } } break; case DATA_BRANN_MEMOTESAY: - if (Creature* cr = instance->GetCreature(m_brannBronzebeardBaseCamp)) - { + if (Creature* cr = GetCreature(DATA_BRANN_BASE_CAMP)) cr->TextEmote("Go to your vehicles!", nullptr, true); - } break; case DATA_BRANN_EASY_MODE: ProcessEvent(nullptr, EVENT_TOWER_OF_STORM_DESTROYED); @@ -885,88 +789,19 @@ public: break; } - // take care of herbs - if (type == TYPE_FREYA && data == DONE) - { - std::list goList; - if (Creature* freya = instance->GetCreature(GetGuidData(TYPE_FREYA))) - { - freya->GetGameObjectListWithEntryInGrid(goList, 191019 /*Adder's Tongue*/, 333.0f); - freya->GetGameObjectListWithEntryInGrid(goList, 190176 /*Frost Lotus*/, 333.0f); - freya->GetGameObjectListWithEntryInGrid(goList, 190171 /*Lichbloom*/, 333.0f); - freya->GetGameObjectListWithEntryInGrid(goList, 190170 /*Talandra's Rose*/, 333.0f); - freya->GetGameObjectListWithEntryInGrid(goList, 189973 /*Goldclover*/, 333.0f); - - for (std::list::const_iterator itr = goList.begin(); itr != goList.end(); ++itr) - (*itr)->SetRespawnTime(7 * DAY); - } - } - - if (data == DONE || type == TYPE_LEVIATHAN || type == TYPE_WATCHERS) + if (type == TYPE_WATCHERS) SaveToDB(); - - if (type > TYPE_LEVIATHAN && type < TYPE_WATCHERS && data == IN_PROGRESS) - { - Map::PlayerList const& pList = instance->GetPlayers(); - for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) - { - if (Creature* vehicleCreature = itr->GetSource()->GetVehicleCreatureBase()) - { - vehicleCreature->DespawnOrUnsummon(); - } - } - } } ObjectGuid GetGuidData(uint32 data) const override { switch (data) { - // Bosses - case TYPE_LEVIATHAN: - return m_uiLeviathanGUID; - case TYPE_IGNIS: - return m_uiIgnisGUID; - case TYPE_RAZORSCALE: - return m_uiRazorscaleGUID; - case TYPE_XT002: - return m_uiXT002GUID; - case TYPE_KOLOGARN: - return m_uiKologarnGUID; - case TYPE_AURIAYA: - return m_uiAuriayaGUID; - case TYPE_MIMIRON: - return m_uiMimironGUID; - case TYPE_HODIR: - return m_uiHodirGUID; - case TYPE_THORIM: - return m_uiThorimGUID; - case TYPE_FREYA: - return m_uiFreyaGUID; - case TYPE_VEZAX: - return m_uiVezaxGUID; - case TYPE_YOGGSARON: - return m_uiYoggSaronGUID; - case TYPE_ALGALON: - return m_uiAlgalonGUID; - case DATA_STEELBREAKER: - return m_auiAssemblyGUIDs[0]; - case DATA_MOLGEIM: - return m_auiAssemblyGUIDs[1]; - case DATA_BRUNDIR: - return m_auiAssemblyGUIDs[2]; - // Flame Leviathan case DATA_REPAIR_STATION1: return m_RepairSGUID[0]; case DATA_REPAIR_STATION2: return m_RepairSGUID[1]; - case DATA_LIGHTNING_WALL1: - return m_lightningWalls[0]; - case DATA_LIGHTNING_WALL2: - return m_lightningWalls[1]; - case GO_LEVIATHAN_DOORS: - return m_leviathanDoorsGUID; // Razorscales Harpoon Fire State GUIDs case DATA_HARPOON_FIRE_STATE_1: @@ -974,95 +809,17 @@ public: case DATA_HARPOON_FIRE_STATE_3: case DATA_HARPOON_FIRE_STATE_4: return m_RazorscaleHarpoonFireStateGUID[data - 200]; - - // XT-002 - case GO_XT002_DOORS: - return m_xt002DoorsGUID; - // XT-002 - case GO_KOLOGARN_DOORS: - return KologarnDoorGUID; - // Thorim - case DATA_THORIM_LEVER_GATE: - case DATA_THORIM_LEVER: - case DATA_THORIM_FENCE: - case DATA_THORIM_FIRST_DOORS: - case DATA_THORIM_SECOND_DOORS: - return m_thorimGameobjectsGUID[data - DATA_THORIM_LEVER_GATE]; - - // Hodir chests - case GO_HODIR_CHEST_HARD: - return m_hodirHardmodeChest; - case GO_HODIR_CHEST_NORMAL: - return m_hodirNormalChest; - - // Freya Elders - case NPC_ELDER_IRONBRANCH: - case NPC_ELDER_STONEBARK: - case NPC_ELDER_BRIGHTLEAF: - return m_FreyaElder[data - NPC_ELDER_IRONBRANCH]; - - // Mimiron's first vehicle (spawned by default) - case DATA_MIMIRON_LEVIATHAN_MKII: - return m_MimironLeviathanMKIIguid; - case DATA_MIMIRON_VX001: - return m_MimironVX001guid; - case DATA_MIMIRON_ACU: - return m_MimironACUguid; - case DATA_GO_MIMIRON_DOOR_1: - case DATA_GO_MIMIRON_DOOR_2: - case DATA_GO_MIMIRON_DOOR_3: - return m_MimironDoor[data - 311]; - - // Yogg-Saron - case GO_YOGG_SARON_DOORS: - return m_yoggsaronDoorsGUID; - case NPC_SARA: - return m_saraGUID; - case NPC_BRAIN_OF_YOGG_SARON: - return m_yoggsaronBrainGUID; - - // Algalon the Observer - case GO_DOODAD_UL_SIGILDOOR_01: - return m_algalonSigilDoorGUID[0]; - case GO_DOODAD_UL_SIGILDOOR_02: - return m_algalonSigilDoorGUID[1]; - case GO_DOODAD_UL_SIGILDOOR_03: - return m_algalonSigilDoorGUID[2]; - case GO_DOODAD_UL_UNIVERSEFLOOR_01: - return m_algalonFloorGUID[0]; - case GO_DOODAD_UL_UNIVERSEFLOOR_02: - return m_algalonFloorGUID[1]; - case GO_DOODAD_UL_UNIVERSEGLOBE01: - return m_algalonUniverseGUID; - case GO_DOODAD_UL_ULDUAR_TRAPDOOR_03: - return m_algalonTrapdoorGUID; - case NPC_BRANN_BRONZBEARD_ALG: - return m_brannBronzebeardAlgGUID; } - return ObjectGuid::Empty; + return GetObjectGuid(data); } uint32 GetData(uint32 type) const override { switch (type) { - case TYPE_LEVIATHAN: - case TYPE_IGNIS: - case TYPE_RAZORSCALE: - case TYPE_XT002: - case TYPE_ASSEMBLY: - case TYPE_KOLOGARN: - case TYPE_AURIAYA: - case TYPE_MIMIRON: - case TYPE_HODIR: - case TYPE_THORIM: - case TYPE_FREYA: - case TYPE_VEZAX: - case TYPE_YOGGSARON: - case TYPE_ALGALON: case TYPE_WATCHERS: - return m_auiEncounter[type]; + return m_watchersMask; case EVENT_TOWER_OF_LIFE_DESTROYED: case EVENT_TOWER_OF_STORM_DESTROYED: @@ -1088,8 +845,8 @@ public: // Feeds on Tears achievement if (unit->IsPlayer()) { - if (GetData(TYPE_ALGALON) == IN_PROGRESS) - if (Creature* algalon = instance->GetCreature(m_uiAlgalonGUID)) + if (GetBossState(BOSS_ALGALON) == IN_PROGRESS) + if (Creature* algalon = GetCreature(BOSS_ALGALON)) algalon->AI()->DoAction(ACTION_FEEDS_ON_TEARS_FAILED); } else if (unit->IsCreature() && unit->GetAreaId() == AREA_THE_CONSERVATORY_OF_LIFE) @@ -1107,14 +864,14 @@ public: for (uint8 i = 0; i <= 12; ++i) { bool go = false; - if (i == TYPE_LEVIATHAN) + if (i == BOSS_LEVIATHAN) { - if (Creature* c = instance->GetCreature(m_uiLeviathanGUID)) + if (Creature* c = GetCreature(BOSS_LEVIATHAN)) if (c->IsInCombat()) go = true; } else - go = (m_auiEncounter[i] == IN_PROGRESS); + go = (GetBossState(i) == IN_PROGRESS); if (go && (C_of_Ulduar_MASK & (1 << i)) == 0) { @@ -1126,21 +883,8 @@ public: void ReadSaveDataMore(std::istringstream& data) override { - data >> m_auiEncounter[0]; - data >> m_auiEncounter[1]; - data >> m_auiEncounter[2]; - data >> m_auiEncounter[3]; - data >> m_auiEncounter[4]; - data >> m_auiEncounter[5]; - data >> m_auiEncounter[6]; - data >> m_auiEncounter[7]; - data >> m_auiEncounter[8]; - data >> m_auiEncounter[9]; - data >> m_auiEncounter[10]; - data >> m_auiEncounter[11]; - data >> m_auiEncounter[12]; - data >> m_auiEncounter[13]; - data >> m_auiEncounter[14]; + // Boss states 0-13 are read by base InstanceScript. + data >> m_watchersMask; data >> m_conspeedatoryAttempt; data >> m_unbrokenAchievement; data >> m_algalonTimer; @@ -1148,7 +892,7 @@ public: if (m_algalonTimer == TIMER_ALGALON_SUMMONED) m_algalonTimer = TIMER_ALGALON_TO_SUMMON; - if (m_algalonTimer && m_algalonTimer <= 60 && GetData(TYPE_ALGALON) != DONE) + if (m_algalonTimer && m_algalonTimer <= 60 && GetBossState(BOSS_ALGALON) != DONE) { DoUpdateWorldState(WORLD_STATE_ULDUAR_ALGALON_TIMER_ENABLED, 1); DoUpdateWorldState(WORLD_STATE_ULDUAR_ALGALON_DESPAWN_TIMER, m_algalonTimer); @@ -1156,23 +900,18 @@ public: data >> C_of_Ulduar_MASK; data >> m_mageBarrier; - - for (uint8 i = 0; i < (MAX_ENCOUNTER - 1); ++i) - { - if (m_auiEncounter[i] == IN_PROGRESS) - { - m_auiEncounter[i] = NOT_STARTED; - } - } } void WriteSaveDataMore(std::ostringstream& data) override { - data << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' ' << m_auiEncounter[3] << ' ' - << m_auiEncounter[4] << ' ' << m_auiEncounter[5] << ' ' << m_auiEncounter[6] << ' ' << m_auiEncounter[7] << ' ' - << m_auiEncounter[8] << ' ' << m_auiEncounter[9] << ' ' << m_auiEncounter[10] << ' ' << m_auiEncounter[11] << ' ' - << m_auiEncounter[12] << ' ' << m_auiEncounter[13] << ' ' << m_auiEncounter[14] << ' ' << m_conspeedatoryAttempt << ' ' - << m_unbrokenAchievement << ' ' << m_algalonTimer << ' ' << C_of_Ulduar_MASK << ' ' << m_mageBarrier; + // Boss states 0-13 are written by base InstanceScript. + // Only write extra non-boss data here. + data << m_watchersMask << ' ' + << m_conspeedatoryAttempt << ' ' + << m_unbrokenAchievement << ' ' + << m_algalonTimer << ' ' + << C_of_Ulduar_MASK << ' ' + << m_mageBarrier; } void Update(uint32 diff) override @@ -1187,9 +926,7 @@ public: { case EVENT_UPDATE_ALGALON_TIMER: if (m_algalonTimer == TIMER_ALGALON_DEFEATED) - { return; - } SaveToDB(); DoUpdateWorldState(WORLD_STATE_ULDUAR_ALGALON_DESPAWN_TIMER, --m_algalonTimer); @@ -1200,7 +937,7 @@ public: } SetData(DATA_ALGALON_DEFEATED, 1); - if (Creature* algalon = instance->GetCreature(m_uiAlgalonGUID)) + if (Creature* algalon = GetCreature(BOSS_ALGALON)) algalon->AI()->DoAction(ACTION_DESPAWN_ALGALON); } } @@ -1213,43 +950,43 @@ public: { case 10042: case 10352: - return (C_of_Ulduar_MASK & (1 << TYPE_LEVIATHAN)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_LEVIATHAN)) == 0; case 10342: case 10355: - return (C_of_Ulduar_MASK & (1 << TYPE_IGNIS)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_IGNIS)) == 0; case 10340: case 10353: - return (C_of_Ulduar_MASK & (1 << TYPE_RAZORSCALE)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_RAZORSCALE)) == 0; case 10341: case 10354: - return (C_of_Ulduar_MASK & (1 << TYPE_XT002)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_XT002)) == 0; case 10598: case 10599: - return (C_of_Ulduar_MASK & (1 << TYPE_ASSEMBLY)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_ASSEMBLY)) == 0; case 10348: case 10357: - return (C_of_Ulduar_MASK & (1 << TYPE_KOLOGARN)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_KOLOGARN)) == 0; case 10351: case 10363: - return (C_of_Ulduar_MASK & (1 << TYPE_AURIAYA)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_AURIAYA)) == 0; case 10439: case 10719: - return (C_of_Ulduar_MASK & (1 << TYPE_HODIR)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_HODIR)) == 0; case 10403: case 10404: - return (C_of_Ulduar_MASK & (1 << TYPE_THORIM)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_THORIM)) == 0; case 10582: case 10583: - return (C_of_Ulduar_MASK & (1 << TYPE_FREYA)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_FREYA)) == 0; case 10347: case 10361: - return (C_of_Ulduar_MASK & (1 << TYPE_MIMIRON)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_MIMIRON)) == 0; case 10349: case 10362: - return (C_of_Ulduar_MASK & (1 << TYPE_VEZAX)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_VEZAX)) == 0; case 10350: case 10364: - return (C_of_Ulduar_MASK & (1 << TYPE_YOGGSARON)) == 0; + return (C_of_Ulduar_MASK & (1 << BOSS_YOGGSARON)) == 0; } return false; } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.cpp index f38f49e2b..4a72bf5ab 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.cpp @@ -300,56 +300,148 @@ private: uint8 _counter; }; -class npc_ulduar_storm_tempered_keeper : public CreatureScript +struct npc_ulduar_storm_tempered_keeper : public ScriptedAI { -public: - npc_ulduar_storm_tempered_keeper() : CreatureScript("npc_ulduar_storm_tempered_keeper") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_ulduar_storm_tempered_keeper(Creature* creature) : ScriptedAI(creature) { - return GetUlduarAI(creature); + otherGUID.Clear(); } - struct npc_ulduar_storm_tempered_keeperAI : public ScriptedAI + EventMap events; + ObjectGuid otherGUID; + + void Reset() override { - npc_ulduar_storm_tempered_keeperAI(Creature* creature) : ScriptedAI(creature) + events.Reset(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + events.Reset(); + events.ScheduleEvent(1, 2s); // checking Separation Anxiety, Charged Sphere + events.ScheduleEvent(2, 5s, 8s); // Forked Lightning + events.ScheduleEvent(3, (me->GetEntry() == 33722 ? 20s : 50s)); // Summon Charged Sphere + if (Creature* c = me->FindNearestCreature((me->GetEntry() == 33722 ? 33699 : 33722), 30.0f, true)) + otherGUID = c->GetGUID(); + else + me->CastSpell(me, 63630, true); // Vengeful Surge + } + + void JustDied(Unit* /*killer*/) override + { + if (Creature* c = ObjectAccessor::GetCreature(*me, otherGUID)) + c->CastSpell(c, 63630, true); // Vengeful Surge + } + + void JustSummoned(Creature* s) override + { + if (Creature* c = ObjectAccessor::GetCreature(*me, otherGUID)) + s->GetMotionMaster()->MoveFollow(c, 0.0f, 0.0f); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) { - otherGUID.Clear(); + case 0: + break; + case 1: + if (Creature* c = ObjectAccessor::GetCreature(*me, otherGUID)) + if (c->IsAlive() && me->GetExactDist2d(c) > 45.0f) + me->CastSpell(me, 63539, true); + if (Creature* c = me->FindNearestCreature(33715, 2.0f, true)) + if (c->IsSummon()) + if (c->ToTempSummon()->GetSummonerGUID() != me->GetGUID()) + me->CastSpell(me, 63528, true); + events.Repeat(2s); + break; + case 2: + me->CastSpell(me->GetVictim(), 63541, false); + events.Repeat(10s, 14s); + break; + case 3: + if (!me->HasAura(63630)) + me->CastSpell(me, 63527, false); + events.Repeat(1min); + break; } - EventMap events; - ObjectGuid otherGUID; + DoMeleeAttackIfReady(); + } +}; - void Reset() override +struct npc_ulduar_arachnopod_destroyer : public ScriptedAI +{ + npc_ulduar_arachnopod_destroyer(Creature* creature) : ScriptedAI(creature) + { + _spawnedMechanic = false; + me->ApplySpellImmune(0, IMMUNITY_ID, 64919, true); // Ice Nova from Ice Turret + } + + EventMap events; + bool _spawnedMechanic; + + void Reset() override + { + events.Reset(); + events.ScheduleEvent(1, 5s, 8s); // Flame Spray + events.ScheduleEvent(2, 3s, 6s); // Machine Gun + events.ScheduleEvent(3, 1s); // Charged Leap + } + + void PassengerBoarded(Unit* p, int8 /*seat*/, bool /*apply*/) override + { + me->SetFaction(p->GetFaction()); + me->SetReactState(REACT_PASSIVE); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (!_spawnedMechanic && me->HealthBelowPctDamaged(20, damage)) { - events.Reset(); + _spawnedMechanic = true; + if (Creature* c = me->SummonCreature(34184, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_MANUAL_DESPAWN, 0)) + c->AI()->AttackStart(me->GetVictim()); + me->InterruptNonMeleeSpells(false); + me->CombatStop(true); + me->SetReactState(REACT_PASSIVE); + me->SetRegeneratingHealth(false); + me->SetFaction(FACTION_PREY); + me->SetNpcFlag(UNIT_NPC_FLAG_SPELLCLICK); + me->CastSpell(me, 64770, true); } + } - void JustEngagedWith(Unit* /*who*/) override + void AttackStart(Unit* who) override + { + if (me->GetFaction() == FACTION_MONSTER_2) + ScriptedAI::AttackStart(who); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (me->GetFaction() == FACTION_MONSTER_2) + ScriptedAI::EnterEvadeMode(why); + } + + void OnCharmed(bool /*apply*/) override {} + + void UpdateAI(uint32 diff) override + { + if (me->GetFaction() != FACTION_MONSTER_2) { - events.Reset(); - events.ScheduleEvent(1, 2s); // checking Separation Anxiety, Charged Sphere - events.ScheduleEvent(2, 5s, 8s); // Forked Lightning - events.ScheduleEvent(3, (me->GetEntry() == 33722 ? 20s : 50s)); // Summon Charged Sphere - if (Creature* c = me->FindNearestCreature((me->GetEntry() == 33722 ? 33699 : 33722), 30.0f, true)) - otherGUID = c->GetGUID(); - else - me->CastSpell(me, 63630, true); // Vengeful Surge + if (me->IsAlive() && (me->GetExactDist2dSq(2058.0f, 42.0f) < 25.0f * 25.0f || me->GetExactDist2dSq(2203.0f, 292.0f) < 25.0f * 25.0f || me->GetExactDist2dSq(2125.0f, 170.0f) > 160.0f * 160.0f)) + Unit::Kill(me, me, false); } - - void JustDied(Unit* /*killer*/) override - { - if (Creature* c = ObjectAccessor::GetCreature(*me, otherGUID)) - c->CastSpell(c, 63630, true); // Vengeful Surge - } - - void JustSummoned(Creature* s) override - { - if (Creature* c = ObjectAccessor::GetCreature(*me, otherGUID)) - s->GetMotionMaster()->MoveFollow(c, 0.0f, 0.0f); - } - - void UpdateAI(uint32 diff) override + else { if (!UpdateVictim()) return; @@ -364,144 +456,30 @@ public: case 0: break; case 1: - if (Creature* c = ObjectAccessor::GetCreature(*me, otherGUID)) - if (c->IsAlive() && me->GetExactDist2d(c) > 45.0f) - me->CastSpell(me, 63539, true); - if (Creature* c = me->FindNearestCreature(33715, 2.0f, true)) - if (c->IsSummon()) - if (c->ToTempSummon()->GetSummonerGUID() != me->GetGUID()) - me->CastSpell(me, 63528, true); - events.Repeat(2s); + me->CastSpell(me->GetVictim(), SPELL_FLAME_SPRAY, false); + events.Repeat(15s, 25s); break; case 2: - me->CastSpell(me->GetVictim(), 63541, false); - events.Repeat(10s, 14s); + me->CastSpell(me->GetVictim(), SPELL_MACHINE_GUN, false); + events.Repeat(10s, 15s); break; case 3: - if (!me->HasAura(63630)) - me->CastSpell(me, 63527, false); - events.Repeat(1min); + { + float dist = me->GetDistance(me->GetVictim()); + if (dist > 10.0f && dist < 40.0f) + { + me->CastSpell(me->GetVictim(), 64779, false); + events.Repeat(25s); + } + else + events.Repeat(3s); + } break; } DoMeleeAttackIfReady(); } - }; -}; - -class npc_ulduar_arachnopod_destroyer : public CreatureScript -{ -public: - npc_ulduar_arachnopod_destroyer() : CreatureScript("npc_ulduar_arachnopod_destroyer") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI(creature); } - - struct npc_ulduar_arachnopod_destroyerAI : public ScriptedAI - { - npc_ulduar_arachnopod_destroyerAI(Creature* creature) : ScriptedAI(creature) - { - _spawnedMechanic = false; - me->ApplySpellImmune(0, IMMUNITY_ID, 64919, true); // Ice Nova from Ice Turret - } - - EventMap events; - bool _spawnedMechanic; - - void Reset() override - { - events.Reset(); - events.ScheduleEvent(1, 5s, 8s); // Flame Spray - events.ScheduleEvent(2, 3s, 6s); // Machine Gun - events.ScheduleEvent(3, 1s); // Charged Leap - } - - void PassengerBoarded(Unit* p, int8 /*seat*/, bool /*apply*/) override - { - me->SetFaction(p->GetFaction()); - me->SetReactState(REACT_PASSIVE); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (!_spawnedMechanic && me->HealthBelowPctDamaged(20, damage)) - { - _spawnedMechanic = true; - if (Creature* c = me->SummonCreature(34184, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_MANUAL_DESPAWN, 0)) - c->AI()->AttackStart(me->GetVictim()); - me->InterruptNonMeleeSpells(false); - me->CombatStop(true); - me->SetReactState(REACT_PASSIVE); - me->SetRegeneratingHealth(false); - me->SetFaction(FACTION_PREY); - me->SetNpcFlag(UNIT_NPC_FLAG_SPELLCLICK); - me->CastSpell(me, 64770, true); - } - } - - void AttackStart(Unit* who) override - { - if (me->GetFaction() == FACTION_MONSTER_2) - ScriptedAI::AttackStart(who); - } - - void EnterEvadeMode(EvadeReason why) override - { - if (me->GetFaction() == FACTION_MONSTER_2) - ScriptedAI::EnterEvadeMode(why); - } - - void OnCharmed(bool /*apply*/) override {} - - void UpdateAI(uint32 diff) override - { - if (me->GetFaction() != FACTION_MONSTER_2) - { - if (me->IsAlive() && (me->GetExactDist2dSq(2058.0f, 42.0f) < 25.0f * 25.0f || me->GetExactDist2dSq(2203.0f, 292.0f) < 25.0f * 25.0f || me->GetExactDist2dSq(2125.0f, 170.0f) > 160.0f * 160.0f)) - Unit::Kill(me, me, false); - } - else - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case 1: - me->CastSpell(me->GetVictim(), SPELL_FLAME_SPRAY, false); - events.Repeat(15s, 25s); - break; - case 2: - me->CastSpell(me->GetVictim(), SPELL_MACHINE_GUN, false); - events.Repeat(10s, 15s); - break; - case 3: - { - float dist = me->GetDistance(me->GetVictim()); - if (dist > 10.0f && dist < 40.0f) - { - me->CastSpell(me->GetVictim(), 64779, false); - events.Repeat(25s); - } - else - events.Repeat(3s); - } - break; - } - - DoMeleeAttackIfReady(); - } - } - }; }; class spell_ulduar_arachnopod_damaged_aura : public AuraScript @@ -571,8 +549,8 @@ void AddSC_ulduar() new npc_ulduar_keeper(); RegisterSpellScript(spell_ulduar_energy_sap_aura); RegisterUlduarCreatureAI(npc_ulduar_snow_mound); - new npc_ulduar_storm_tempered_keeper(); - new npc_ulduar_arachnopod_destroyer(); + RegisterUlduarCreatureAI(npc_ulduar_storm_tempered_keeper); + RegisterUlduarCreatureAI(npc_ulduar_arachnopod_destroyer); RegisterSpellScript(spell_ulduar_arachnopod_damaged_aura); new AreaTrigger_at_celestial_planetarium_enterance(); RegisterCreatureAI(npc_salvaged_siege_engine); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 797f6b61f..f443536ea 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -25,31 +25,38 @@ #define UlduarScriptName "instance_ulduar" -enum UlduarEncounters +enum UlduarBossIds { - MAX_ENCOUNTER = 15, - - TYPE_LEVIATHAN = 0, - TYPE_IGNIS = 1, - TYPE_RAZORSCALE = 2, - TYPE_XT002 = 3, - TYPE_ASSEMBLY = 4, - TYPE_KOLOGARN = 5, - TYPE_AURIAYA = 6, - TYPE_FREYA = 7, - TYPE_HODIR = 8, - TYPE_MIMIRON = 9, - TYPE_THORIM = 10, - TYPE_VEZAX = 11, - TYPE_YOGGSARON = 12, - TYPE_ALGALON = 13, - TYPE_WATCHERS = 14, - TYPE_HODIR_HM_FAIL = 15, - TYPE_WINTER_CACHE = 16 + // Boss IDs used by SetBossNumber/SetBossState (0-indexed) + BOSS_LEVIATHAN = 0, + BOSS_IGNIS = 1, + BOSS_RAZORSCALE = 2, + BOSS_XT002 = 3, + BOSS_ASSEMBLY = 4, + BOSS_KOLOGARN = 5, + BOSS_AURIAYA = 6, + BOSS_FREYA = 7, + BOSS_HODIR = 8, + BOSS_MIMIRON = 9, + BOSS_THORIM = 10, + BOSS_VEZAX = 11, + BOSS_YOGGSARON = 12, + BOSS_ALGALON = 13, + MAX_ENCOUNTER = 14 }; enum UlduarData { + // Non-boss encounter data + TYPE_WATCHERS = 14, + TYPE_HODIR_HM_FAIL = 15, + TYPE_WINTER_CACHE = 16, + + // Assembly of Iron + DATA_STEELBREAKER = 20, + DATA_MOLGEIM = 21, + DATA_BRUNDIR = 22, + // Flame Leviathan DATA_VEHICLE_SPAWN = 100, DATA_LIGHTNING_WALL1 = 101, @@ -57,6 +64,7 @@ enum UlduarData DATA_REPAIR_STATION1 = 103, DATA_REPAIR_STATION2 = 104, DATA_UNBROKEN_ACHIEVEMENT = 105, + DATA_LEVIATHAN_DOORS = 106, // Razorscales Harpoon Fire State GUIDs DATA_HARPOON_FIRE_STATE_1 = 200, @@ -64,16 +72,31 @@ enum UlduarData DATA_HARPOON_FIRE_STATE_3 = 202, DATA_HARPOON_FIRE_STATE_4 = 203, - // Mimiron's first vehicle (spawned by default) + // Mimiron creatures DATA_MIMIRON_LEVIATHAN_MKII = 301, DATA_MIMIRON_VX001 = 302, DATA_MIMIRON_ACU = 303, - // Mimiron's Doors + // Mimiron doors DATA_GO_MIMIRON_DOOR_1 = 311, DATA_GO_MIMIRON_DOOR_2 = 312, DATA_GO_MIMIRON_DOOR_3 = 313, + // Mimiron tram + DATA_MIMIRON_TRAM = 320, + DATA_MIMIRON_ACTIVATE_TRAM = 321, + DATA_MIMIRON_TRAM_ROCKET_BOOSTER = 322, + DATA_MIMIRON_CALL_TRAM_CENTER = 323, + DATA_MIMIRON_CALL_TRAM_MIMIRON = 324, + DATA_MIMIRON_TRAM_TURNAROUND_1 = 325, + DATA_MIMIRON_TRAM_TURNAROUND_2 = 326, + + // XT-002 + DATA_XT002_DOORS = 400, + + // Kologarn + DATA_KOLOGARN_DOORS = 410, + // Thorim DATA_THORIM_LEVER_GATE = 500, DATA_THORIM_LEVER = 501, @@ -81,15 +104,18 @@ enum UlduarData DATA_THORIM_FIRST_DOORS = 503, DATA_THORIM_SECOND_DOORS = 504, - // Assembly of Iron - DATA_STEELBREAKER = 20, - DATA_MOLGEIM = 21, - DATA_BRUNDIR = 22, - // Algalon the Observer DATA_ALGALON_SUMMON_STATE = 600, DATA_DESPAWN_ALGALON = 601, DATA_ALGALON_DEFEATED = 602, + DATA_SIGILDOOR_01 = 603, + DATA_SIGILDOOR_02 = 604, + DATA_SIGILDOOR_03 = 605, + DATA_UNIVERSE_FLOOR_01 = 606, + DATA_UNIVERSE_FLOOR_02 = 607, + DATA_UNIVERSE_GLOBE = 608, + DATA_ALGALON_TRAPDOOR = 609, + DATA_BRANN_BRONZEBEARD_ALG = 610, // Achievements DATA_DWARFAGEDDON = 700, @@ -97,10 +123,32 @@ enum UlduarData // Tram DATA_CALL_TRAM = 710, + // Freya elders + DATA_ELDER_IRONBRANCH = 750, + DATA_ELDER_STONEBARK = 751, + DATA_ELDER_BRIGHTLEAF = 752, + + // Yogg-Saron + DATA_SARA = 760, + DATA_BRAIN_OF_YOGG_SARON = 761, + DATA_YOGG_SARON_DOORS = 762, + + // Middle section + DATA_ASSEMBLY_DOORS = 770, + DATA_ARCHIVUM_DOORS = 771, + DATA_KEEPERS_GATE = 772, + + // Hodir chests (dynamically spawned) + DATA_HODIR_CHEST_NORMAL = 780, + DATA_HODIR_CHEST_HARD = 781, + DATA_HODIR_CHEST_NORMAL_HERO = 782, + DATA_HODIR_CHEST_HARD_HERO = 783, + // Mage Barrier DATA_MAGE_BARRIER = 800, DATA_BRANN_MEMOTESAY = 801, DATA_BRANN_EASY_MODE = 802, + DATA_BRANN_BASE_CAMP = 803, }; enum UlduarNPCs