diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
index 98b1784802b412..0eb2bcab4b3816 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_algalon_the_observer.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "GameObjectAI.h"
@@ -29,1435 +30,6 @@
#include "SpellScriptLoader.h"
#include "ulduar.h"
-enum Spells
-{
- // Algalon the Observer
- SPELL_ARRIVAL = 64997,
- SPELL_RIDE_THE_LIGHTNING = 64986,
- SPELL_SUMMON_AZEROTH = 64994,
- SPELL_REORIGINATION = 64996,
- SPELL_SUPERMASSIVE_FAIL = 65311,
- SPELL_QUANTUM_STRIKE = 64395,
- SPELL_PHASE_PUNCH = 64412,
- SPELL_BIG_BANG = 64443,
- SPELL_ASCEND_TO_THE_HEAVENS = 64487,
- SPELL_COSMIC_SMASH = 62301,
- SPELL_COSMIC_SMASH_TRIGGERED = 62304,
- SPELL_COSMIC_SMASH_VISUAL_STATE = 62300,
- SPELL_SELF_STUN = 65256,
- SPELL_KILL_CREDIT = 65184,
- SPELL_TELEPORT = 62940,
- SPELL_DUAL_WIELD = 42459,
-
- // Algalon Stalker
- SPELL_TRIGGER_3_ADDS = 62266, // Triggers Living Constellation
-
- // Living Constellation
- SPELL_ARCANE_BARRAGE = 64599,
-
- // Collapsing Star
- SPELL_COLLAPSE = 62018,
- SPELL_BLACK_HOLE_SPAWN_VISUAL = 62003,
- SPELL_SUMMON_BLACK_HOLE = 62189,
-
- // Black Hole
- SPELL_BLACK_HOLE_TRIGGER = 62185,
- SPELL_CONSTELLATION_PHASE_TRIGGER = 65508,
- SPELL_CONSTELLATION_PHASE_EFFECT = 65509,
- SPELL_BLACK_HOLE_EXPLOSION = 64122,
- SPELL_SUMMON_VOID_ZONE_VISUAL = 64470,
- SPELL_VOID_ZONE_VISUAL = 64469,
- SPELL_BLACK_HOLE_CREDIT = 65312,
- SPELL_BLACK_HOLE_DAMAGE = 62169,
-
- // Worm Hole
- SPELL_WORM_HOLE_TRIGGER = 65251,
- SPELL_SUMMON_UNLEASHED_DARK_MATTER = 64450,
-};
-
-enum Actions
-{
- //ACTION_INIT_ALGALON = 1, defined in ulduar.h
- //ACTION_DESPAWN_ALGALON = 2, defined in ulduar.h
- ACTION_START_INTRO = 3,
- ACTION_FINISH_INTRO = 4,
- ACTION_ACTIVATE_STAR = 5,
- ACTION_BIG_BANG = 6,
- ACTION_ASCEND = 7,
- ACTION_OUTRO = 8,
-};
-
-enum Misc
-{
- POINT_BRANN_INTRO = 0,
- MAX_BRANN_WAYPOINTS_INTRO = 11,
- POINT_BRANN_OUTRO = 11,
- POINT_BRANN_OUTRO_END = 12,
-
- POINT_ALGALON_LAND = 1,
- POINT_ALGALON_OUTRO = 2,
-
- EVENT_ID_SUPERMASSIVE_START = 21697,
-
- DATA_HAS_FED_ON_TEARS = 1,
- DATA_HERALD_OF_THE_TITANS = 2,
-};
-
-enum Events
-{
- // Celestial Planetarium Access
- EVENT_DESPAWN_CONSOLE = 1,
-
- // Brann Bronzebeard
- EVENT_BRANN_MOVE_INTRO = 2,
- EVENT_SUMMON_ALGALON = 3,
- EVENT_BRANN_OUTRO_1 = 4,
- EVENT_BRANN_OUTRO_2 = 5,
-
- // Algalon the Observer
- EVENT_INTRO_1 = 6,
- EVENT_INTRO_2 = 7,
- EVENT_INTRO_3 = 8,
- EVENT_INTRO_FINISH = 9,
- EVENT_START_COMBAT = 10,
- EVENT_INTRO_TIMER_DONE = 11,
- EVENT_QUANTUM_STRIKE = 12,
- EVENT_PHASE_PUNCH = 13,
- EVENT_SUMMON_COLLAPSING_STAR = 14,
- EVENT_BIG_BANG = 15,
- EVENT_RESUME_UPDATING = 16,
- EVENT_ASCEND_TO_THE_HEAVENS = 17,
- EVENT_EVADE = 18,
- EVENT_COSMIC_SMASH = 19,
- EVENT_UNLOCK_YELL = 20,
- EVENT_OUTRO_START = 21,
- EVENT_OUTRO_1 = 22,
- EVENT_OUTRO_2 = 23,
- EVENT_OUTRO_3 = 24,
- EVENT_OUTRO_4 = 25,
- EVENT_OUTRO_5 = 26,
- EVENT_OUTRO_6 = 27,
- EVENT_OUTRO_7 = 28,
- EVENT_OUTRO_8 = 29,
- EVENT_OUTRO_9 = 30,
- EVENT_OUTRO_10 = 31,
- EVENT_OUTRO_11 = 32,
- EVENT_ACTIVATE_LIVING_CONSTELLATION = 33,
- EVENT_CHECK_HERALD_ITEMS = 34,
- EVENT_REMOVE_UNNATTACKABLE = 35,
- EVENT_DESPAWN_ALGALON_1 = 36,
- EVENT_DESPAWN_ALGALON_2 = 37,
- EVENT_DESPAWN_ALGALON_3 = 38,
- EVENT_DESPAWN_ALGALON_4 = 39,
- EVENT_DESPAWN_ALGALON_5 = 40,
-
- // Living Constellation
- EVENT_ARCANE_BARRAGE = 41,
-};
-
-enum EncounterPhases
-{
- PHASE_NORMAL = 0,
- PHASE_ROLE_PLAY = 1,
- PHASE_BIG_BANG = 2,
-
- PHASE_MASK_NO_UPDATE = (1 << (PHASE_ROLE_PLAY - 1)) | (1 << (PHASE_BIG_BANG - 1)),
- PHASE_MASK_NO_CAST_CHECK = 1 << (PHASE_ROLE_PLAY - 1),
-};
-
-enum Texts
-{
- SAY_BRANN_ALGALON_INTRO_1 = 0,
- SAY_BRANN_ALGALON_INTRO_2 = 1,
- SAY_BRANN_ALGALON_OUTRO = 2,
-
- SAY_ALGALON_INTRO_1 = 0,
- SAY_ALGALON_INTRO_2 = 1,
- SAY_ALGALON_INTRO_3 = 2,
- SAY_ALGALON_START_TIMER = 3,
- SAY_ALGALON_AGGRO = 4,
- SAY_ALGALON_COLLAPSING_STAR = 5,
- EMOTE_ALGALON_COLLAPSING_STAR = 6,
- SAY_ALGALON_BIG_BANG = 7,
- EMOTE_ALGALON_BIG_BANG = 8,
- SAY_ALGALON_ASCEND = 9,
- EMOTE_ALGALON_COSMIC_SMASH = 10,
- SAY_ALGALON_PHASE_TWO = 11,
- SAY_ALGALON_OUTRO_1 = 12,
- SAY_ALGALON_OUTRO_2 = 13,
- SAY_ALGALON_OUTRO_3 = 14,
- SAY_ALGALON_OUTRO_4 = 15,
- SAY_ALGALON_OUTRO_5 = 16,
- SAY_ALGALON_DESPAWN_1 = 17,
- SAY_ALGALON_DESPAWN_2 = 18,
- SAY_ALGALON_DESPAWN_3 = 19,
- SAY_ALGALON_KILL = 20,
-};
-
-uint32 const PhasePunchAlphaId[5] = {64435, 64434, 64428, 64421, 64417};
-
-Position const BrannIntroSpawnPos = {1676.277f, -162.5308f, 427.3326f, 3.235537f};
-Position const BrannIntroWaypoint[MAX_BRANN_WAYPOINTS_INTRO] =
-{
- {1642.482f, -164.0812f, 427.2602f, 0.0f},
- {1635.000f, -169.5145f, 427.2523f, 0.0f},
- {1632.814f, -173.9334f, 427.2621f, 0.0f},
- {1632.676f, -190.5927f, 427.2631f, 0.0f},
- {1631.497f, -214.2221f, 418.1152f, 0.0f},
- {1636.455f, -263.6647f, 417.3213f, 0.0f},
- {1629.586f, -267.9792f, 417.3219f, 0.0f},
- {1631.497f, -214.2221f, 418.1152f, 0.0f},
- {1632.676f, -190.5927f, 425.8831f, 0.0f},
- {1632.814f, -173.9334f, 427.2621f, 0.0f},
- {1635.000f, -169.5145f, 427.2523f, 0.0f},
-};
-
-#define LIVING_CONSTELLATION_COUNT 11
-Position const ConstellationPos[LIVING_CONSTELLATION_COUNT] =
-{
- {1625.208f, -267.2771f, 446.4296f, 5.044002f},
- {1593.389f, -299.4325f, 432.4636f, 6.073746f},
- {1668.317f, -324.7676f, 457.9394f, 3.211406f},
- {1685.613f, -300.1219f, 443.2366f, 3.385939f},
- {1592.242f, -325.5323f, 446.9508f, 0.226893f},
- {1658.279f, -262.5490f, 441.9073f, 4.188790f},
- {1635.821f, -363.3442f, 424.3459f, 1.466077f},
- {1591.706f, -263.8201f, 441.4153f, 5.253441f},
- {1672.188f, -357.2484f, 436.7337f, 2.338741f},
- {1678.677f, -276.3280f, 427.7531f, 3.979351f},
- {1615.800f, -348.0065f, 442.9586f, 1.134464f},
-};
-
-#define COLLAPSING_STAR_COUNT 4
-Position const CollapsingStarPos[COLLAPSING_STAR_COUNT] =
-{
- {1649.438f, -319.8127f, 418.3941f, 1.082104f},
- {1647.005f, -288.6790f, 417.3955f, 3.490659f},
- {1622.451f, -321.1563f, 417.6188f, 4.677482f},
- {1615.060f, -291.6816f, 417.7796f, 3.490659f},
-};
-Position const AlgalonOutroPos = {1633.64f, -317.78f, 417.3211f, 0.0f};
-Position const BrannOutroPos[3] =
-{
- {1632.023f, -243.7434f, 417.9118f, 0.0f},
- {1631.986f, -297.7831f, 417.3210f, 0.0f},
- {1633.832f, -216.2948f, 417.0463f, 0.0f},
-};
-
-class CosmicSmashDamageEvent : public BasicEvent
-{
-public:
- CosmicSmashDamageEvent(Unit* caster) : _caster(caster)
- {
- }
-
- bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
- {
- _caster->CastSpell(_caster, SPELL_COSMIC_SMASH_TRIGGERED, true);
- return true;
- }
-
-private:
- Unit* _caster;
-};
-
-class boss_algalon_the_observer : public CreatureScript
-{
-public:
- boss_algalon_the_observer() : CreatureScript("boss_algalon_the_observer") {}
-
- struct boss_algalon_the_observerAI : public ScriptedAI
- {
- boss_algalon_the_observerAI(Creature* creature) : ScriptedAI(creature), summons(me)
- {
- _fedOnTears = true;
- _firstPull = true;
- _fightWon = false;
- m_pInstance = me->GetInstanceScript();
- }
-
- EventMap events;
- SummonList summons;
- InstanceScript* m_pInstance;
-
- bool _firstPull;
- bool _fightWon;
- bool _phaseTwo;
- bool _fedOnTears;
- bool _heraldOfTheTitans;
-
- bool IsValidHeraldItem(ItemTemplate const* item)
- {
- if (!item) // should not happen, but checked in GetAverageItemLevel()
- return true;
- if (item->ItemLevel <= 226 || (item->ItemLevel <= 232 && (
- item->InventoryType == INVTYPE_SHIELD ||
- item->Class == ITEM_CLASS_WEAPON ||
- (item->Class == ITEM_CLASS_ARMOR && (item->InventoryType == INVTYPE_RELIC || item->InventoryType == INVTYPE_HOLDABLE))
- )))
- return true;
- return false;
- }
-
- bool DoCheckHeraldOfTheTitans()
- {
- if (!_heraldOfTheTitans)
- return true;
-
- Map::PlayerList const& pl = me->GetMap()->GetPlayers();
- for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
- if (Player* plr = itr->GetSource())
- if (!plr->IsGameMaster() && plr->IsInCombat() /*performance*/)
- {
- for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) // loop through equipped items
- if (Item* item = plr->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
- if (!IsValidHeraldItem(item->GetTemplate()))
- {
- _heraldOfTheTitans = false;
- return true;
- }
- }
-
- return false;
- }
-
- void AttackStart(Unit* who) override
- {
- if (_fightWon)
- return;
- ScriptedAI::AttackStart(who);
- }
-
- uint32 GetData(uint32 param) const override
- {
- if (param == DATA_HAS_FED_ON_TEARS)
- return _fedOnTears;
- if (param == DATA_HERALD_OF_THE_TITANS)
- return _heraldOfTheTitans;
- return 0;
- }
-
- void CallConstellations()
- {
- uint8 _count = 0;
- for (SummonList::const_iterator i = summons.begin(); i != summons.end(); )
- {
- Creature* summon = ObjectAccessor::GetCreature(*me, *i++);
- if (summon && summon->GetEntry() == NPC_LIVING_CONSTELLATION && !summon->AI()->GetData(0))
- {
- ++_count;
- summon->AI()->DoAction(ACTION_ACTIVATE_STAR);
- if (_count >= 3)
- break;
- }
- }
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- if (_fightWon)
- return;
-
- if (SelectTargetFromPlayerList(120.0f))
- {
- me->SetInCombatWithZone();
- return;
- }
- else if (events.GetPhaseMask() & PHASE_NORMAL)
- {
- DoAction(ACTION_ASCEND);
- return;
- }
-
- if (m_pInstance)
- m_pInstance->SetData(TYPE_ALGALON, FAIL);
-
- ScriptedAI::EnterEvadeMode(why);
- }
-
- void Reset() override
- {
- if (_fightWon)
- return;
-
- events.Reset();
- summons.DespawnAll();
- me->SetReactState(REACT_PASSIVE);
- me->SetImmuneToPC(false);
- me->SetSheath(SHEATH_STATE_UNARMED);
- me->SetFaction(190);
- me->CastSpell(me, SPELL_DUAL_WIELD, true);
-
- _phaseTwo = false;
- _heraldOfTheTitans = true;
-
- if (m_pInstance->GetData(TYPE_ALGALON) == FAIL)
- {
- _firstPull = false;
- }
-
- if (m_pInstance)
- m_pInstance->SetData(TYPE_ALGALON, NOT_STARTED);
- }
-
- void KilledUnit(Unit* victim) override
- {
- if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
- return;
-
- Talk(SAY_ALGALON_KILL);
- }
-
- void DoAction(int32 action) override
- {
- switch (action)
- {
- case ACTION_START_INTRO:
- {
- me->SetImmuneToPC(true);
- me->SetUnitFlag2(UNIT_FLAG2_DO_NOT_FADE_IN);
- me->SetDisableGravity(true);
- me->CastSpell(me, SPELL_ARRIVAL, true);
- me->CastSpell(me, SPELL_RIDE_THE_LIGHTNING, true);
- me->GetMotionMaster()->MovePoint(POINT_ALGALON_LAND, AlgalonLandPos);
- me->SetHomePosition(AlgalonLandPos);
- Movement::MoveSplineInit init(me);
- init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ());
- init.SetOrientationFixed(true);
- init.Launch();
- events.Reset();
- events.SetPhase(PHASE_ROLE_PLAY);
- events.ScheduleEvent(EVENT_INTRO_1, 5s, 0, PHASE_ROLE_PLAY);
- events.ScheduleEvent(EVENT_INTRO_2, 15s, 0, PHASE_ROLE_PLAY);
- events.ScheduleEvent(EVENT_INTRO_3, 23s, 0, PHASE_ROLE_PLAY);
- events.ScheduleEvent(EVENT_INTRO_FINISH, 36s, 0, PHASE_ROLE_PLAY);
- break;
- }
- case ACTION_DESPAWN_ALGALON:
- _fightWon = true;
- events.Reset();
- summons.DespawnAll();
- events.SetPhase(PHASE_ROLE_PLAY);
- events.ScheduleEvent(EVENT_DESPAWN_ALGALON_1, 5s);
- events.ScheduleEvent(EVENT_DESPAWN_ALGALON_2, 17s);
- events.ScheduleEvent(EVENT_DESPAWN_ALGALON_3, 26s);
- if (me->IsInCombat())
- events.ScheduleEvent(EVENT_DESPAWN_ALGALON_4, 26s);
- events.ScheduleEvent(EVENT_DESPAWN_ALGALON_5, 32s);
- me->DespawnOrUnsummon(39000);
-
- me->SetReactState(REACT_PASSIVE);
- me->AttackStop();
- me->SetFaction(FACTION_FRIENDLY);
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->InterruptNonMeleeSpells(false);
- if (m_pInstance)
- m_pInstance->SetData(TYPE_ALGALON, NOT_STARTED);
- break;
- case ACTION_INIT_ALGALON:
- _firstPull = false;
- _fedOnTears = false;
- me->SetImmuneToPC(false);
- break;
- case ACTION_ASCEND:
- summons.DespawnAll();
- events.SetPhase(PHASE_BIG_BANG);
- events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 1500ms);
- break;
- case ACTION_FEEDS_ON_TEARS_FAILED:
- _fedOnTears = false;
- }
- }
-
- void JustReachedHome() override
- {
- me->setActive(false);
- }
-
- void JustEngagedWith(Unit*) override
- {
- if (_fightWon)
- return;
-
- if (!m_pInstance)
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
-
- uint32 introDelay = 0;
- me->setActive(true);
- me->SetInCombatWithZone();
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->SetImmuneToNPC(true);
- events.Reset();
- events.SetPhase(PHASE_ROLE_PLAY);
-
- if (!_firstPull)
- {
- events.ScheduleEvent(EVENT_START_COMBAT, 0ms);
- introDelay = 8000;
- }
- else
- {
- summons.DespawnEntry(NPC_AZEROTH);
- _firstPull = false;
- Talk(SAY_ALGALON_START_TIMER);
- introDelay = 22000;
- events.ScheduleEvent(EVENT_START_COMBAT, 14s);
- m_pInstance->SetData(DATA_DESPAWN_ALGALON, 0);
- }
-
- events.ScheduleEvent(EVENT_REMOVE_UNNATTACKABLE, introDelay - 500);
- events.ScheduleEvent(EVENT_INTRO_TIMER_DONE, introDelay);
- events.ScheduleEvent(EVENT_QUANTUM_STRIKE, 3500 + introDelay);
- events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500 + introDelay);
- events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 16500 + introDelay);
- events.ScheduleEvent(EVENT_COSMIC_SMASH, 25000 + introDelay);
- events.ScheduleEvent(EVENT_ACTIVATE_LIVING_CONSTELLATION, 50500 + introDelay);
- events.ScheduleEvent(EVENT_BIG_BANG, 90000 + introDelay);
- events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 360000 + introDelay);
-
- events.ScheduleEvent(EVENT_CHECK_HERALD_ITEMS, 5s);
- DoCheckHeraldOfTheTitans();
- }
-
- void MovementInform(uint32 movementType, uint32 pointId) override
- {
- if (movementType != POINT_MOTION_TYPE)
- return;
-
- if (pointId == POINT_ALGALON_LAND)
- me->SetDisableGravity(false);
- else if (pointId == POINT_ALGALON_OUTRO)
- {
- me->SetFacingTo(1.605703f);
- events.ScheduleEvent(EVENT_OUTRO_3, 1200ms);
- events.ScheduleEvent(EVENT_OUTRO_4, 2400ms);
- events.ScheduleEvent(EVENT_OUTRO_5, 8500ms);
- events.ScheduleEvent(EVENT_OUTRO_6, 15s + 500ms);
- events.ScheduleEvent(EVENT_OUTRO_7, 55s + 500ms);
- events.ScheduleEvent(EVENT_OUTRO_8, 73s + 500ms);
- events.ScheduleEvent(EVENT_OUTRO_9, 85s + 500ms);
- events.ScheduleEvent(EVENT_OUTRO_10, 101s + 500ms);
- events.ScheduleEvent(EVENT_OUTRO_11, 117s + 500ms);
- }
- }
-
- void JustSummoned(Creature* summon) override
- {
- summons.Summon(summon);
- switch (summon->GetEntry())
- {
- case NPC_AZEROTH:
- me->CastSpell(summon, SPELL_REORIGINATION, true);
- break;
- case NPC_BLACK_HOLE:
- summon->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_TRIGGER, true);
- summon->CastSpell(summon, SPELL_CONSTELLATION_PHASE_TRIGGER, true);
- summon->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_EXPLOSION, false);
- summon->CastSpell(summon, SPELL_SUMMON_VOID_ZONE_VISUAL, true);
- break;
- case NPC_ALGALON_VOID_ZONE_VISUAL_STALKER:
- summon->CastSpell(summon, SPELL_VOID_ZONE_VISUAL, true);
- break;
- case NPC_ALGALON_STALKER_ASTEROID_TARGET_01:
- summon->CastSpell(summon, SPELL_COSMIC_SMASH_VISUAL_STATE, true);
- break;
- case NPC_ALGALON_STALKER_ASTEROID_TARGET_02:
- {
- float x = summon->GetPositionX();
- float y = summon->GetPositionY();
- float z = summon->GetPositionZ() + 35.0f;
- float o = summon->GetOrientation();
-
- summon->GetMotionMaster()->Clear();
- summon->SetHomePosition(x, y, z, o);
- summon->UpdatePosition(x, y, z, o, true);
- summon->StopMovingOnCurrentPos();
- summon->m_Events.AddEvent(new CosmicSmashDamageEvent(summon), summon->m_Events.CalculateTime(4000));
- break;
- }
- case NPC_UNLEASHED_DARK_MATTER:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
- if (summon->Attack(target, true))
- summon->GetMotionMaster()->MoveChase(target);
- break;
- }
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (_fightWon)
- {
- damage = 0;
- return;
- }
-
- if (!_phaseTwo && me->HealthBelowPctDamaged(20, damage))
- {
- _phaseTwo = true;
- Talk(SAY_ALGALON_PHASE_TWO);
- summons.DespawnEntry(NPC_LIVING_CONSTELLATION);
- summons.DespawnEntry(NPC_COLLAPSING_STAR);
- summons.DespawnEntry(NPC_BLACK_HOLE);
- summons.DespawnEntry(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER);
- events.CancelEvent(EVENT_SUMMON_COLLAPSING_STAR);
- events.CancelEvent(EVENT_ACTIVATE_LIVING_CONSTELLATION);
-
- for (uint32 i = 0; i < COLLAPSING_STAR_COUNT; ++i)
- me->SummonCreature(NPC_WORM_HOLE, CollapsingStarPos[i], TEMPSUMMON_MANUAL_DESPAWN);
- }
- else if (me->HealthBelowPctDamaged(2, damage) && !_fightWon)
- {
- _fightWon = true;
- damage = 0;
- me->SetReactState(REACT_PASSIVE);
- me->AttackStop();
- me->SetFaction(FACTION_FRIENDLY);
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- events.Reset();
- summons.DespawnAll();
- me->InterruptNonMeleeSpells(false);
- events.SetPhase(PHASE_ROLE_PLAY);
- events.ScheduleEvent(EVENT_OUTRO_START, 1500ms);
- events.ScheduleEvent(EVENT_OUTRO_1, 7200ms);
- events.ScheduleEvent(EVENT_OUTRO_2, 8700ms);
- }
- }
-
- bool IsInRoom()
- {
- if (me->GetExactDist2d(&me->GetHomePosition()) > 45.f || me->GetPositionZ() < 410.f)
- {
- DoAction(ACTION_ASCEND);
- return false;
- }
-
- return true;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && (!UpdateVictim() || !IsInRoom()))
- return;
-
- events.Update(diff);
- if (!(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK) && me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_INTRO_1:
- me->RemoveAurasDueToSpell(SPELL_RIDE_THE_LIGHTNING);
- Talk(SAY_ALGALON_INTRO_1);
- break;
- case EVENT_INTRO_2:
- me->CastSpell((Unit*)nullptr, SPELL_SUMMON_AZEROTH, true);
- Talk(SAY_ALGALON_INTRO_2);
- break;
- case EVENT_INTRO_3:
- Talk(SAY_ALGALON_INTRO_3);
- break;
- case EVENT_INTRO_FINISH:
- events.Reset();
- me->SetImmuneToPC(false);
- if (Creature* brann = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_BRANN_BRONZBEARD_ALG)))
- brann->AI()->DoAction(ACTION_FINISH_INTRO);
- break;
- case EVENT_START_COMBAT:
- m_pInstance->SetData(TYPE_ALGALON, IN_PROGRESS);
- Talk(SAY_ALGALON_AGGRO);
- break;
- case EVENT_REMOVE_UNNATTACKABLE:
- me->SetSheath(SHEATH_STATE_MELEE);
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->SetImmuneToNPC(false);
- break;
- case EVENT_INTRO_TIMER_DONE:
- events.SetPhase(PHASE_NORMAL);
- me->CastSpell((Unit*)nullptr, SPELL_SUPERMASSIVE_FAIL, true);
- // Hack: _IsValidTarget failed earlier due to flags, call AttackStart again
- me->SetReactState(REACT_AGGRESSIVE);
- me->SetFaction(FACTION_MONSTER);
- if (Player* target = SelectTargetFromPlayerList(150.0f))
- AttackStart(target);
- me->SetInCombatWithZone();
-
- for (uint32 i = 0; i < LIVING_CONSTELLATION_COUNT; ++i)
- me->SummonCreature(NPC_LIVING_CONSTELLATION, ConstellationPos[i], TEMPSUMMON_DEAD_DESPAWN);
- break;
- case EVENT_QUANTUM_STRIKE:
- me->CastSpell(me->GetVictim(), SPELL_QUANTUM_STRIKE, false);
- events.Repeat(3000ms, 4500ms);
- break;
- case EVENT_PHASE_PUNCH:
- me->CastSpell(me->GetVictim(), SPELL_PHASE_PUNCH, false);
- events.Repeat(15s + 500ms);
- break;
- case EVENT_SUMMON_COLLAPSING_STAR:
- Talk(SAY_ALGALON_COLLAPSING_STAR);
- Talk(EMOTE_ALGALON_COLLAPSING_STAR);
- for (uint8 i = 0; i < COLLAPSING_STAR_COUNT; ++i)
- me->SummonCreature(NPC_COLLAPSING_STAR, CollapsingStarPos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);
- events.Repeat(1min);
- break;
- case EVENT_COSMIC_SMASH:
- Talk(EMOTE_ALGALON_COSMIC_SMASH);
- me->CastCustomSpell(SPELL_COSMIC_SMASH, SPELLVALUE_MAX_TARGETS, RAID_MODE(1, 3), (Unit*)nullptr);
- events.Repeat(25s + 500ms);
- break;
- case EVENT_ACTIVATE_LIVING_CONSTELLATION:
- {
- if (events.GetPhaseMask() & PHASE_MASK_NO_UPDATE)
- {
- events.Repeat(4s);
- break;
- }
- CallConstellations();
- //me->CastSpell(me, SPELL_TRIGGER_3_ADDS, true);
- events.Repeat(50s);
- break;
- }
- case EVENT_BIG_BANG:
- {
- Talk(SAY_ALGALON_BIG_BANG);
- Talk(EMOTE_ALGALON_BIG_BANG);
-
- EntryCheckPredicate pred(NPC_LIVING_CONSTELLATION);
- summons.DoAction(ACTION_BIG_BANG, pred);
-
- me->CastSpell((Unit*)nullptr, SPELL_BIG_BANG, false);
- events.Repeat(90s + 500ms);
- break;
- }
- case EVENT_ASCEND_TO_THE_HEAVENS:
- Talk(SAY_ALGALON_ASCEND);
- me->CastSpell((Unit*)nullptr, SPELL_ASCEND_TO_THE_HEAVENS, false);
- events.ScheduleEvent(EVENT_EVADE, 2500ms);
- break;
- case EVENT_EVADE:
- events.Reset();
- ScriptedAI::EnterEvadeMode();
- return;
- case EVENT_OUTRO_START:
- if (m_pInstance)
- {
- m_pInstance->SetData(TYPE_ALGALON, DONE);
- m_pInstance->SetData(DATA_ALGALON_DEFEATED, 1);
- }
- break;
- case EVENT_OUTRO_1:
- me->RemoveAllAuras();
- me->SetUnitFlag(UNIT_FLAG_RENAME);
- break;
- case EVENT_OUTRO_2:
- {
- Player* lootRecipent = me->GetLootRecipient();
- _EnterEvadeMode();
- // LootRecipent is cleared in _EnterEvadeMode, restore it
- me->SetLootRecipient(lootRecipent);
- me->GetMotionMaster()->MovePoint(POINT_ALGALON_OUTRO, AlgalonOutroPos);
- break;
- }
- case EVENT_OUTRO_3:
- me->CastSpell((Unit*)nullptr, SPELL_KILL_CREDIT);
- // Summon Chest
- if (GameObject* go = me->SummonGameObject(RAID_MODE(GO_ALGALON_CHEST, GO_ALGALON_CHEST_HERO), 1632.1f, -306.561f, 417.321f, 4.69494f, 0, 0, 0, 1, 0))
- {
- go->ReplaceAllGameObjectFlags((GameObjectFlags)0);
- go->SetLootRecipient(me);
- }
- break;
- case EVENT_OUTRO_4:
- me->CastSpell((Unit*)nullptr, SPELL_SUPERMASSIVE_FAIL);
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- break;
- case EVENT_OUTRO_5:
- if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannOutroPos[0], TEMPSUMMON_TIMED_DESPAWN, 131500))
- brann->AI()->DoAction(ACTION_OUTRO);
- break;
- case EVENT_OUTRO_6:
- Talk(SAY_ALGALON_OUTRO_1);
- me->SetStandState(UNIT_STAND_STATE_KNEEL);
- break;
- case EVENT_OUTRO_7:
- Talk(SAY_ALGALON_OUTRO_2);
- break;
- case EVENT_OUTRO_8:
- Talk(SAY_ALGALON_OUTRO_3);
- break;
- case EVENT_OUTRO_9:
- Talk(SAY_ALGALON_OUTRO_4);
- break;
- case EVENT_OUTRO_10:
- Talk(SAY_ALGALON_OUTRO_5);
- break;
- case EVENT_OUTRO_11:
- me->SetStandState(UNIT_STAND_STATE_STAND);
- me->CastSpell(me, SPELL_TELEPORT, false);
- me->DespawnOrUnsummon(3000);
- break;
- case EVENT_DESPAWN_ALGALON_1:
- Talk(SAY_ALGALON_DESPAWN_1);
- break;
- case EVENT_DESPAWN_ALGALON_2:
- Talk(SAY_ALGALON_DESPAWN_2);
- break;
- case EVENT_DESPAWN_ALGALON_3:
- Talk(SAY_ALGALON_DESPAWN_3);
- break;
- case EVENT_DESPAWN_ALGALON_4:
- me->CastSpell((Unit*)nullptr, SPELL_ASCEND_TO_THE_HEAVENS, false);
- break;
- case EVENT_DESPAWN_ALGALON_5:
- me->SetStandState(UNIT_STAND_STATE_STAND);
- me->CastSpell(me, SPELL_TELEPORT, false);
- me->DespawnOrUnsummon(3000);
- break;
- case EVENT_CHECK_HERALD_ITEMS:
- if (!DoCheckHeraldOfTheTitans())
- events.Repeat(5s);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetUlduarAI(creature);
- }
-};
-
-class npc_brann_bronzebeard_algalon : public CreatureScript
-{
-public:
- npc_brann_bronzebeard_algalon() : CreatureScript("npc_brann_bronzebeard_algalon") { }
-
- struct npc_brann_bronzebeard_algalonAI : public CreatureAI
- {
- npc_brann_bronzebeard_algalonAI(Creature* creature) : CreatureAI(creature)
- {
- }
-
- EventMap events;
- uint32 _currentPoint;
-
- void DoAction(int32 action) override
- {
- switch (action)
- {
- case ACTION_START_INTRO:
- me->SetWalk(false);
- _currentPoint = 0;
- events.Reset();
- events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1ms);
- break;
- case ACTION_FINISH_INTRO:
- Talk(SAY_BRANN_ALGALON_INTRO_2);
- events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1ms);
- break;
- case ACTION_OUTRO:
- me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO, BrannOutroPos[1]);
- events.ScheduleEvent(EVENT_BRANN_OUTRO_1, 87s + 500ms);
- events.ScheduleEvent(EVENT_BRANN_OUTRO_2, 116s + 500ms);
- break;
- }
- }
-
- void MovementInform(uint32 movementType, uint32 pointId) override
- {
- if (movementType != POINT_MOTION_TYPE)
- return;
-
- uint32 delay = 1;
- _currentPoint = pointId + 1;
- switch (pointId)
- {
- case 2:
- delay = 8000;
- me->SetWalk(true);
- break;
- case 6:
- me->SetFacingTo(4.6156f);
- me->SetWalk(false);
- Talk(SAY_BRANN_ALGALON_INTRO_1);
- events.ScheduleEvent(EVENT_SUMMON_ALGALON, 7500ms);
- return;
- case 10:
- me->DespawnOrUnsummon(1);
- return;
- case POINT_BRANN_OUTRO:
- case POINT_BRANN_OUTRO_END:
- return;
- }
-
- events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, delay);
- }
-
- void UpdateAI(uint32 diff) override
- {
- UpdateVictim();
- events.Update(diff);
-
- switch (events.ExecuteEvent())
- {
- case EVENT_BRANN_MOVE_INTRO:
- if (_currentPoint < MAX_BRANN_WAYPOINTS_INTRO)
- me->GetMotionMaster()->MovePoint(_currentPoint, BrannIntroWaypoint[_currentPoint]);
- break;
- case EVENT_SUMMON_ALGALON:
- if (me->GetInstanceScript() && !me->GetInstanceScript()->GetGuidData(TYPE_ALGALON))
- if (Creature* algalon = me->GetMap()->SummonCreature(NPC_ALGALON, AlgalonSummonPos))
- algalon->AI()->DoAction(ACTION_START_INTRO);
- break;
- case EVENT_BRANN_OUTRO_1:
- Talk(SAY_BRANN_ALGALON_OUTRO);
- break;
- case EVENT_BRANN_OUTRO_2:
- me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO_END, BrannOutroPos[2]);
- break;
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetUlduarAI(creature);
- }
-};
-
-class npc_collapsing_star : public CreatureScript
-{
-public:
- npc_collapsing_star() : CreatureScript("npc_collapsing_star") { }
-
- struct npc_collapsing_starAI : public NullCreatureAI
- {
- npc_collapsing_starAI(Creature* creature) : NullCreatureAI(creature)
- {
- creature->GetMotionMaster()->MoveRandom(25.0f);
- creature->CastSpell(creature, SPELL_COLLAPSE, true);
- }
-
- void JustSummoned(Creature* summon) override
- {
- if (TempSummon* summ = me->ToTempSummon())
- if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID()))
- algalon->AI()->JustSummoned(summon);
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (damage >= me->GetHealth())
- {
- me->CastSpell(me, SPELL_BLACK_HOLE_SPAWN_VISUAL, true);
- me->CastSpell(me, SPELL_SUMMON_BLACK_HOLE, true);
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetUlduarAI(creature);
- }
-};
-
-class npc_living_constellation : public CreatureScript
-{
-public:
- npc_living_constellation() : CreatureScript("npc_living_constellation") { }
-
- struct npc_living_constellationAI : public ScriptedAI
- {
- npc_living_constellationAI(Creature* creature) : ScriptedAI(creature)
- {
- me->SetReactState(REACT_PASSIVE);
- }
-
- EventMap events;
- bool _isActive;
-
- void Reset() override
- {
- events.Reset();
- events.ScheduleEvent(EVENT_ARCANE_BARRAGE, 2500ms);
- _isActive = false;
- }
-
- uint32 GetData(uint32 /*param*/) const override
- {
- return _isActive;
- }
-
- void DoAction(int32 action) override
- {
- switch (action)
- {
- case ACTION_ACTIVATE_STAR:
- me->SetReactState(REACT_AGGRESSIVE);
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->SetImmuneToAll(false);
- _isActive = true;
-
- if (Player* target = SelectTargetFromPlayerList(250.0f))
- {
- AttackStart(target);
- me->AddThreat(target, 100.0f);
- }
- me->SetInCombatWithZone();
- break;
- case ACTION_BIG_BANG:
- events.SetPhase(PHASE_BIG_BANG);
- events.DelayEvents(9500);
- events.ScheduleEvent(EVENT_RESUME_UPDATING, 9500ms);
- break;
- }
- }
-
- void SpellHit(Unit* caster, SpellInfo const* spell) override
- {
- if (spell->Id != SPELL_CONSTELLATION_PHASE_EFFECT || caster->GetTypeId() != TYPEID_UNIT)
- return;
-
- if (InstanceScript* instance = me->GetInstanceScript())
- instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_ID_SUPERMASSIVE_START);
-
- caster->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_CREDIT, TRIGGERED_FULL_MASK);
- caster->ToCreature()->DespawnOrUnsummon(1);
- me->DespawnOrUnsummon(1);
- if (Creature* voidZone = caster->FindNearestCreature(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER, 10.0f))
- voidZone->DespawnOrUnsummon(1);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && !UpdateVictim())
- return;
-
- events.Update(diff);
- switch (events.ExecuteEvent())
- {
- case EVENT_ARCANE_BARRAGE:
- me->CastCustomSpell(SPELL_ARCANE_BARRAGE, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, true);
- events.Repeat(2500ms);
- break;
- case EVENT_RESUME_UPDATING:
- events.SetPhase(0);
- break;
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetUlduarAI(creature);
- }
-};
-
-class npc_algalon_worm_hole : public CreatureScript
-{
-public:
- npc_algalon_worm_hole() : CreatureScript("npc_algalon_worm_hole") { }
-
- struct npc_algalon_worm_holeAI : public NullCreatureAI
- {
- npc_algalon_worm_holeAI(Creature* creature) : NullCreatureAI(creature)
- {
- creature->CastSpell(creature, SPELL_WORM_HOLE_TRIGGER, true);
- creature->CastSpell(creature, SPELL_SUMMON_VOID_ZONE_VISUAL, true);
- }
-
- uint32 _summonTimer;
-
- void Reset() override
- {
- _summonTimer = urand(22000, 24000);
- }
-
- void JustSummoned(Creature* summon) override
- {
- if (TempSummon* summ = me->ToTempSummon())
- {
- if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID()))
- {
- algalon->AI()->JustSummoned(summon);
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- _summonTimer += diff;
- if (_summonTimer >= 30000)
- {
- me->CastSpell((Unit*)nullptr, SPELL_SUMMON_UNLEASHED_DARK_MATTER, true);
- _summonTimer = 0;
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetUlduarAI(creature);
- }
-};
-
-class go_celestial_planetarium_access : public GameObjectScript
-{
-public:
- go_celestial_planetarium_access() : GameObjectScript("go_celestial_planetarium_access") {}
-
- struct go_celestial_planetarium_accessAI : public GameObjectAI
- {
- go_celestial_planetarium_accessAI(GameObject* go) : GameObjectAI(go)
- {
- _locked = false;
- }
-
- EventMap events;
- bool _locked;
-
- bool GossipHello(Player* player, bool /*reportUse*/) override
- {
- bool hasKey = true;
- if (LockEntry const* lock = sLockStore.LookupEntry(me->GetGOInfo()->goober.lockId))
- {
- hasKey = false;
- for (uint32 i = 0; i < MAX_LOCK_CASE; ++i)
- {
- if (!lock->Index[i])
- continue;
-
- if (player->HasItemCount(lock->Index[i]))
- {
- hasKey = true;
- break;
- }
- }
- }
-
- if (!hasKey)
- return false;
-
- if (_locked)
- return false;
- _locked = true;
- // Start Algalon event
- me->SetGameObjectFlag(GO_FLAG_IN_USE);
- events.ScheduleEvent(EVENT_DESPAWN_CONSOLE, 5000ms);
- if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannIntroSpawnPos))
- brann->AI()->DoAction(ACTION_START_INTRO);
-
- if (InstanceScript* instance = me->GetInstanceScript())
- {
- instance->SetData(DATA_ALGALON_SUMMON_STATE, 1);
- if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_DOODAD_UL_SIGILDOOR_01)))
- sigil->SetGoState(GO_STATE_ACTIVE);
-
- if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_DOODAD_UL_SIGILDOOR_02)))
- sigil->SetGoState(GO_STATE_ACTIVE);
-
- if (Map* map = player->GetMap())
- {
- if (InstanceMap* instanceMap = map->ToInstanceMap())
- {
- instanceMap->PermBindAllPlayers();
- }
- }
- }
-
- return false;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (events.Empty())
- return;
-
- events.Update(diff);
- switch (events.ExecuteEvent())
- {
- case EVENT_DESPAWN_CONSOLE:
- me->Delete();
- break;
- }
- }
- };
-
- GameObjectAI* GetAI(GameObject* go) const override
- {
- return new go_celestial_planetarium_accessAI(go);
- }
-};
-
-class spell_algalon_phase_punch : public SpellScriptLoader
-{
-public:
- spell_algalon_phase_punch() : SpellScriptLoader("spell_algalon_phase_punch") { }
-
- class spell_algalon_phase_punch_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_algalon_phase_punch_AuraScript);
-
- void HandlePeriodic(AuraEffect const* /*aurEff*/)
- {
- PreventDefaultAction();
- if (GetStackAmount() != 1)
- GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 2]);
- GetTarget()->CastSpell(GetTarget(), PhasePunchAlphaId[GetStackAmount() - 1], TRIGGERED_FULL_MASK);
- if (GetStackAmount() == 5)
- Remove(AURA_REMOVE_BY_DEFAULT);
- }
-
- void OnRemove(AuraEffect const*, AuraEffectHandleModes)
- {
- if (GetStackAmount() != 5)
- GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 1]);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_phase_punch_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
- OnEffectRemove += AuraEffectRemoveFn(spell_algalon_phase_punch_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_algalon_phase_punch_AuraScript();
- }
-};
-
-class spell_algalon_collapse : public SpellScriptLoader
-{
-public:
- spell_algalon_collapse() : SpellScriptLoader("spell_algalon_collapse") { }
-
- class spell_algalon_collapse_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_algalon_collapse_AuraScript);
-
- void HandlePeriodic(AuraEffect const* /*aurEff*/)
- {
- PreventDefaultAction();
- Unit::DealDamage(GetTarget(), GetTarget(), GetTarget()->CountPctFromMaxHealth(1), nullptr, NODAMAGE);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_collapse_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_algalon_collapse_AuraScript();
- }
-};
-
-class ActiveConstellationFilter
-{
-public:
- bool operator()(WorldObject* object) const
- {
- return object->ToUnit()->GetAI()->GetData(0);
- }
-};
-
-class spell_algalon_trigger_3_adds : public SpellScriptLoader
-{
-public:
- spell_algalon_trigger_3_adds() : SpellScriptLoader("spell_algalon_trigger_3_adds") { }
-
- class spell_algalon_trigger_3_adds_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_algalon_trigger_3_adds_SpellScript);
-
- void SelectTarget(std::list& targets)
- {
- targets.remove_if(ActiveConstellationFilter());
- }
-
- void HandleDummyEffect(SpellEffIndex effIndex)
- {
- PreventHitDefaultEffect(effIndex);
- Creature* target = GetHitCreature();
- if (!target)
- return;
-
- target->AI()->DoAction(ACTION_ACTIVATE_STAR);
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_trigger_3_adds_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
- OnEffectHitTarget += SpellEffectFn(spell_algalon_trigger_3_adds_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_algalon_trigger_3_adds_SpellScript();
- }
-};
-
-class spell_algalon_cosmic_smash_damage : public SpellScriptLoader
-{
-public:
- spell_algalon_cosmic_smash_damage() : SpellScriptLoader("spell_algalon_cosmic_smash_damage") { }
-
- class spell_algalon_cosmic_smash_damage_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_algalon_cosmic_smash_damage_SpellScript);
-
- void RecalculateDamage()
- {
- if (!GetExplTargetDest() || !GetHitUnit())
- return;
-
- float distance = GetHitUnit()->GetDistance2d(GetExplTargetDest()->GetPositionX(), GetExplTargetDest()->GetPositionY());
- if (distance >= 10.0f)
- SetHitDamage(int32(float(GetHitDamage()) / distance));
- else if (distance > 6.0f)
- SetHitDamage(int32(float(GetHitDamage()) / distance) * 2);
- }
-
- void Register() override
- {
- OnHit += SpellHitFn(spell_algalon_cosmic_smash_damage_SpellScript::RecalculateDamage);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_algalon_cosmic_smash_damage_SpellScript();
- }
-};
-
-class spell_algalon_big_bang : public SpellScriptLoader
-{
-public:
- spell_algalon_big_bang() : SpellScriptLoader("spell_algalon_big_bang") { }
-
- class spell_algalon_big_bang_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_algalon_big_bang_SpellScript);
-
- bool Load() override
- {
- _targetCount = 0;
- return true;
- }
-
- void CountTargets(std::list& targets)
- {
- _targetCount = targets.size();
- }
-
- void CheckTargets()
- {
- Unit* caster = GetCaster();
- if (!_targetCount && caster && caster->GetAI())
- caster->GetAI()->DoAction(ACTION_ASCEND);
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_big_bang_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
- AfterCast += SpellCastFn(spell_algalon_big_bang_SpellScript::CheckTargets);
- }
-
- uint32 _targetCount;
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_algalon_big_bang_SpellScript();
- }
-};
-
-class spell_algalon_remove_phase : public SpellScriptLoader
-{
-public:
- spell_algalon_remove_phase() : SpellScriptLoader("spell_algalon_remove_phase") { }
-
- class spell_algalon_remove_phase_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_algalon_remove_phase_AuraScript);
-
- void HandlePeriodic(AuraEffect const* /*aurEff*/)
- {
- PreventDefaultAction();
- GetTarget()->RemoveAurasByType(SPELL_AURA_PHASE);
- GetTarget()->RemoveAurasDueToSpell(SPELL_BLACK_HOLE_DAMAGE);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_remove_phase_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_algalon_remove_phase_AuraScript();
- }
-};
-
-class spell_algalon_supermassive_fail : public SpellScriptLoader
-{
-public:
- spell_algalon_supermassive_fail() : SpellScriptLoader("spell_algalon_supermassive_fail") { }
-
- class spell_algalon_supermassive_fail_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_algalon_supermassive_fail_SpellScript);
-
- void RecalculateDamage()
- {
- if (!GetHitPlayer())
- return;
-
- GetHitPlayer()->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_NO_SPELL_HIT, GetSpellInfo()->Id, true);
- }
-
- void Register() override
- {
- OnHit += SpellHitFn(spell_algalon_supermassive_fail_SpellScript::RecalculateDamage);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_algalon_supermassive_fail_SpellScript();
- }
-};
-
-class achievement_algalon_he_feeds_on_your_tears : public AchievementCriteriaScript
-{
-public:
- achievement_algalon_he_feeds_on_your_tears() : AchievementCriteriaScript("achievement_algalon_he_feeds_on_your_tears") { }
-
- bool OnCheck(Player*, Unit* target /*Algalon*/, uint32 /*criteria_id*/) override
- {
- return target && target->GetAI()->GetData(DATA_HAS_FED_ON_TEARS);
- }
-};
-
-class achievement_algalon_herald_of_the_titans : public AchievementCriteriaScript
-{
-public:
- achievement_algalon_herald_of_the_titans() : AchievementCriteriaScript("achievement_algalon_herald_of_the_titans") { }
-
- bool OnCheck(Player*, Unit* target /*Algalon*/, uint32 /*criteria_id*/) override
- {
- return target && target->GetAI()->GetData(DATA_HERALD_OF_THE_TITANS);
- }
-};
-
void AddSC_boss_algalon_the_observer()
{
// NPCs
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.h
new file mode 100644
index 00000000000000..bd5ead4a5c7c91
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.h
@@ -0,0 +1,1447 @@
+#ifndef BOSS_ALGALON_THE_OBSERVER_H_
+#define BOSS_ALGALON_THE_OBSERVER_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "GameObjectAI.h"
+#include "GameObjectScript.h"
+#include "MapMgr.h"
+#include "MoveSplineInit.h"
+#include "ObjectMgr.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "ulduar.h"
+
+enum Spells
+{
+ // Algalon the Observer
+ SPELL_ARRIVAL = 64997,
+ SPELL_RIDE_THE_LIGHTNING = 64986,
+ SPELL_SUMMON_AZEROTH = 64994,
+ SPELL_REORIGINATION = 64996,
+ SPELL_SUPERMASSIVE_FAIL = 65311,
+ SPELL_QUANTUM_STRIKE = 64395,
+ SPELL_PHASE_PUNCH = 64412,
+ SPELL_BIG_BANG = 64443,
+ SPELL_ASCEND_TO_THE_HEAVENS = 64487,
+ SPELL_COSMIC_SMASH = 62301,
+ SPELL_COSMIC_SMASH_TRIGGERED = 62304,
+ SPELL_COSMIC_SMASH_VISUAL_STATE = 62300,
+ SPELL_SELF_STUN = 65256,
+ SPELL_KILL_CREDIT = 65184,
+ SPELL_TELEPORT = 62940,
+ SPELL_DUAL_WIELD = 42459,
+
+ // Algalon Stalker
+ SPELL_TRIGGER_3_ADDS = 62266, // Triggers Living Constellation
+
+ // Living Constellation
+ SPELL_ARCANE_BARRAGE = 64599,
+
+ // Collapsing Star
+ SPELL_COLLAPSE = 62018,
+ SPELL_BLACK_HOLE_SPAWN_VISUAL = 62003,
+ SPELL_SUMMON_BLACK_HOLE = 62189,
+
+ // Black Hole
+ SPELL_BLACK_HOLE_TRIGGER = 62185,
+ SPELL_CONSTELLATION_PHASE_TRIGGER = 65508,
+ SPELL_CONSTELLATION_PHASE_EFFECT = 65509,
+ SPELL_BLACK_HOLE_EXPLOSION = 64122,
+ SPELL_SUMMON_VOID_ZONE_VISUAL = 64470,
+ SPELL_VOID_ZONE_VISUAL = 64469,
+ SPELL_BLACK_HOLE_CREDIT = 65312,
+ SPELL_BLACK_HOLE_DAMAGE = 62169,
+
+ // Worm Hole
+ SPELL_WORM_HOLE_TRIGGER = 65251,
+ SPELL_SUMMON_UNLEASHED_DARK_MATTER = 64450,
+};
+
+enum Actions
+{
+ //ACTION_INIT_ALGALON = 1, defined in ulduar.h
+ //ACTION_DESPAWN_ALGALON = 2, defined in ulduar.h
+ ACTION_START_INTRO = 3,
+ ACTION_FINISH_INTRO = 4,
+ ACTION_ACTIVATE_STAR = 5,
+ ACTION_BIG_BANG = 6,
+ ACTION_ASCEND = 7,
+ ACTION_OUTRO = 8,
+};
+
+enum Misc
+{
+ POINT_BRANN_INTRO = 0,
+ MAX_BRANN_WAYPOINTS_INTRO = 11,
+ POINT_BRANN_OUTRO = 11,
+ POINT_BRANN_OUTRO_END = 12,
+
+ POINT_ALGALON_LAND = 1,
+ POINT_ALGALON_OUTRO = 2,
+
+ EVENT_ID_SUPERMASSIVE_START = 21697,
+
+ DATA_HAS_FED_ON_TEARS = 1,
+ DATA_HERALD_OF_THE_TITANS = 2,
+};
+
+enum Events
+{
+ // Celestial Planetarium Access
+ EVENT_DESPAWN_CONSOLE = 1,
+
+ // Brann Bronzebeard
+ EVENT_BRANN_MOVE_INTRO = 2,
+ EVENT_SUMMON_ALGALON = 3,
+ EVENT_BRANN_OUTRO_1 = 4,
+ EVENT_BRANN_OUTRO_2 = 5,
+
+ // Algalon the Observer
+ EVENT_INTRO_1 = 6,
+ EVENT_INTRO_2 = 7,
+ EVENT_INTRO_3 = 8,
+ EVENT_INTRO_FINISH = 9,
+ EVENT_START_COMBAT = 10,
+ EVENT_INTRO_TIMER_DONE = 11,
+ EVENT_QUANTUM_STRIKE = 12,
+ EVENT_PHASE_PUNCH = 13,
+ EVENT_SUMMON_COLLAPSING_STAR = 14,
+ EVENT_BIG_BANG = 15,
+ EVENT_RESUME_UPDATING = 16,
+ EVENT_ASCEND_TO_THE_HEAVENS = 17,
+ EVENT_EVADE = 18,
+ EVENT_COSMIC_SMASH = 19,
+ EVENT_UNLOCK_YELL = 20,
+ EVENT_OUTRO_START = 21,
+ EVENT_OUTRO_1 = 22,
+ EVENT_OUTRO_2 = 23,
+ EVENT_OUTRO_3 = 24,
+ EVENT_OUTRO_4 = 25,
+ EVENT_OUTRO_5 = 26,
+ EVENT_OUTRO_6 = 27,
+ EVENT_OUTRO_7 = 28,
+ EVENT_OUTRO_8 = 29,
+ EVENT_OUTRO_9 = 30,
+ EVENT_OUTRO_10 = 31,
+ EVENT_OUTRO_11 = 32,
+ EVENT_ACTIVATE_LIVING_CONSTELLATION = 33,
+ EVENT_CHECK_HERALD_ITEMS = 34,
+ EVENT_REMOVE_UNNATTACKABLE = 35,
+ EVENT_DESPAWN_ALGALON_1 = 36,
+ EVENT_DESPAWN_ALGALON_2 = 37,
+ EVENT_DESPAWN_ALGALON_3 = 38,
+ EVENT_DESPAWN_ALGALON_4 = 39,
+ EVENT_DESPAWN_ALGALON_5 = 40,
+
+ // Living Constellation
+ EVENT_ARCANE_BARRAGE = 41,
+};
+
+enum EncounterPhases
+{
+ PHASE_NORMAL = 0,
+ PHASE_ROLE_PLAY = 1,
+ PHASE_BIG_BANG = 2,
+
+ PHASE_MASK_NO_UPDATE = (1 << (PHASE_ROLE_PLAY - 1)) | (1 << (PHASE_BIG_BANG - 1)),
+ PHASE_MASK_NO_CAST_CHECK = 1 << (PHASE_ROLE_PLAY - 1),
+};
+
+enum Texts
+{
+ SAY_BRANN_ALGALON_INTRO_1 = 0,
+ SAY_BRANN_ALGALON_INTRO_2 = 1,
+ SAY_BRANN_ALGALON_OUTRO = 2,
+
+ SAY_ALGALON_INTRO_1 = 0,
+ SAY_ALGALON_INTRO_2 = 1,
+ SAY_ALGALON_INTRO_3 = 2,
+ SAY_ALGALON_START_TIMER = 3,
+ SAY_ALGALON_AGGRO = 4,
+ SAY_ALGALON_COLLAPSING_STAR = 5,
+ EMOTE_ALGALON_COLLAPSING_STAR = 6,
+ SAY_ALGALON_BIG_BANG = 7,
+ EMOTE_ALGALON_BIG_BANG = 8,
+ SAY_ALGALON_ASCEND = 9,
+ EMOTE_ALGALON_COSMIC_SMASH = 10,
+ SAY_ALGALON_PHASE_TWO = 11,
+ SAY_ALGALON_OUTRO_1 = 12,
+ SAY_ALGALON_OUTRO_2 = 13,
+ SAY_ALGALON_OUTRO_3 = 14,
+ SAY_ALGALON_OUTRO_4 = 15,
+ SAY_ALGALON_OUTRO_5 = 16,
+ SAY_ALGALON_DESPAWN_1 = 17,
+ SAY_ALGALON_DESPAWN_2 = 18,
+ SAY_ALGALON_DESPAWN_3 = 19,
+ SAY_ALGALON_KILL = 20,
+};
+
+uint32 const PhasePunchAlphaId[5] = {64435, 64434, 64428, 64421, 64417};
+
+Position const BrannIntroSpawnPos = {1676.277f, -162.5308f, 427.3326f, 3.235537f};
+Position const BrannIntroWaypoint[MAX_BRANN_WAYPOINTS_INTRO] =
+{
+ {1642.482f, -164.0812f, 427.2602f, 0.0f},
+ {1635.000f, -169.5145f, 427.2523f, 0.0f},
+ {1632.814f, -173.9334f, 427.2621f, 0.0f},
+ {1632.676f, -190.5927f, 427.2631f, 0.0f},
+ {1631.497f, -214.2221f, 418.1152f, 0.0f},
+ {1636.455f, -263.6647f, 417.3213f, 0.0f},
+ {1629.586f, -267.9792f, 417.3219f, 0.0f},
+ {1631.497f, -214.2221f, 418.1152f, 0.0f},
+ {1632.676f, -190.5927f, 425.8831f, 0.0f},
+ {1632.814f, -173.9334f, 427.2621f, 0.0f},
+ {1635.000f, -169.5145f, 427.2523f, 0.0f},
+};
+
+#define LIVING_CONSTELLATION_COUNT 11
+Position const ConstellationPos[LIVING_CONSTELLATION_COUNT] =
+{
+ {1625.208f, -267.2771f, 446.4296f, 5.044002f},
+ {1593.389f, -299.4325f, 432.4636f, 6.073746f},
+ {1668.317f, -324.7676f, 457.9394f, 3.211406f},
+ {1685.613f, -300.1219f, 443.2366f, 3.385939f},
+ {1592.242f, -325.5323f, 446.9508f, 0.226893f},
+ {1658.279f, -262.5490f, 441.9073f, 4.188790f},
+ {1635.821f, -363.3442f, 424.3459f, 1.466077f},
+ {1591.706f, -263.8201f, 441.4153f, 5.253441f},
+ {1672.188f, -357.2484f, 436.7337f, 2.338741f},
+ {1678.677f, -276.3280f, 427.7531f, 3.979351f},
+ {1615.800f, -348.0065f, 442.9586f, 1.134464f},
+};
+
+#define COLLAPSING_STAR_COUNT 4
+Position const CollapsingStarPos[COLLAPSING_STAR_COUNT] =
+{
+ {1649.438f, -319.8127f, 418.3941f, 1.082104f},
+ {1647.005f, -288.6790f, 417.3955f, 3.490659f},
+ {1622.451f, -321.1563f, 417.6188f, 4.677482f},
+ {1615.060f, -291.6816f, 417.7796f, 3.490659f},
+};
+Position const AlgalonOutroPos = {1633.64f, -317.78f, 417.3211f, 0.0f};
+Position const BrannOutroPos[3] =
+{
+ {1632.023f, -243.7434f, 417.9118f, 0.0f},
+ {1631.986f, -297.7831f, 417.3210f, 0.0f},
+ {1633.832f, -216.2948f, 417.0463f, 0.0f},
+};
+
+class CosmicSmashDamageEvent : public BasicEvent
+{
+public:
+ CosmicSmashDamageEvent(Unit* caster) : _caster(caster)
+ {
+ }
+
+ bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
+ {
+ _caster->CastSpell(_caster, SPELL_COSMIC_SMASH_TRIGGERED, true);
+ return true;
+ }
+
+private:
+ Unit* _caster;
+};
+
+class boss_algalon_the_observer : public CreatureScript
+{
+public:
+ boss_algalon_the_observer() : CreatureScript("boss_algalon_the_observer") {}
+
+ struct boss_algalon_the_observerAI : public ScriptedAI
+ {
+ boss_algalon_the_observerAI(Creature* creature) : ScriptedAI(creature), summons(me)
+ {
+ _fedOnTears = true;
+ _firstPull = true;
+ _fightWon = false;
+ m_pInstance = me->GetInstanceScript();
+ }
+
+ EventMap events;
+ SummonList summons;
+ InstanceScript* m_pInstance;
+
+ bool _firstPull;
+ bool _fightWon;
+ bool _phaseTwo;
+ bool _fedOnTears;
+ bool _heraldOfTheTitans;
+
+ bool IsValidHeraldItem(ItemTemplate const* item)
+ {
+ if (!item) // should not happen, but checked in GetAverageItemLevel()
+ return true;
+ if (item->ItemLevel <= 226 || (item->ItemLevel <= 232 && (
+ item->InventoryType == INVTYPE_SHIELD ||
+ item->Class == ITEM_CLASS_WEAPON ||
+ (item->Class == ITEM_CLASS_ARMOR && (item->InventoryType == INVTYPE_RELIC || item->InventoryType == INVTYPE_HOLDABLE))
+ )))
+ return true;
+ return false;
+ }
+
+ bool DoCheckHeraldOfTheTitans()
+ {
+ if (!_heraldOfTheTitans)
+ return true;
+
+ Map::PlayerList const& pl = me->GetMap()->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
+ if (Player* plr = itr->GetSource())
+ if (!plr->IsGameMaster() && plr->IsInCombat() /*performance*/)
+ {
+ for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) // loop through equipped items
+ if (Item* item = plr->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
+ if (!IsValidHeraldItem(item->GetTemplate()))
+ {
+ _heraldOfTheTitans = false;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ if (_fightWon)
+ return;
+ ScriptedAI::AttackStart(who);
+ }
+
+ uint32 GetData(uint32 param) const override
+ {
+ if (param == DATA_HAS_FED_ON_TEARS)
+ return _fedOnTears;
+ if (param == DATA_HERALD_OF_THE_TITANS)
+ return _heraldOfTheTitans;
+ return 0;
+ }
+
+ void CallConstellations()
+ {
+ uint8 _count = 0;
+ for (SummonList::const_iterator i = summons.begin(); i != summons.end(); )
+ {
+ Creature* summon = ObjectAccessor::GetCreature(*me, *i++);
+ if (summon && summon->GetEntry() == NPC_LIVING_CONSTELLATION && !summon->AI()->GetData(0))
+ {
+ ++_count;
+ summon->AI()->DoAction(ACTION_ACTIVATE_STAR);
+ if (_count >= 3)
+ break;
+ }
+ }
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ if (_fightWon)
+ return;
+
+ if (SelectTargetFromPlayerList(120.0f))
+ {
+ me->SetInCombatWithZone();
+ return;
+ }
+ else if (events.GetPhaseMask() & PHASE_NORMAL)
+ {
+ DoAction(ACTION_ASCEND);
+ return;
+ }
+
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_ALGALON, FAIL);
+
+ ScriptedAI::EnterEvadeMode(why);
+ }
+
+ void Reset() override
+ {
+ if (_fightWon)
+ return;
+
+ events.Reset();
+ summons.DespawnAll();
+ me->SetReactState(REACT_PASSIVE);
+ me->SetImmuneToPC(false);
+ me->SetSheath(SHEATH_STATE_UNARMED);
+ me->SetFaction(190);
+ me->CastSpell(me, SPELL_DUAL_WIELD, true);
+
+ _phaseTwo = false;
+ _heraldOfTheTitans = true;
+
+ if (m_pInstance->GetData(TYPE_ALGALON) == FAIL)
+ {
+ _firstPull = false;
+ }
+
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_ALGALON, NOT_STARTED);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
+ return;
+
+ Talk(SAY_ALGALON_KILL);
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_START_INTRO:
+ {
+ me->SetImmuneToPC(true);
+ me->SetUnitFlag2(UNIT_FLAG2_DO_NOT_FADE_IN);
+ me->SetDisableGravity(true);
+ me->CastSpell(me, SPELL_ARRIVAL, true);
+ me->CastSpell(me, SPELL_RIDE_THE_LIGHTNING, true);
+ me->GetMotionMaster()->MovePoint(POINT_ALGALON_LAND, AlgalonLandPos);
+ me->SetHomePosition(AlgalonLandPos);
+ Movement::MoveSplineInit init(me);
+ init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ());
+ init.SetOrientationFixed(true);
+ init.Launch();
+ events.Reset();
+ events.SetPhase(PHASE_ROLE_PLAY);
+ events.ScheduleEvent(EVENT_INTRO_1, 5s, 0, PHASE_ROLE_PLAY);
+ events.ScheduleEvent(EVENT_INTRO_2, 15s, 0, PHASE_ROLE_PLAY);
+ events.ScheduleEvent(EVENT_INTRO_3, 23s, 0, PHASE_ROLE_PLAY);
+ events.ScheduleEvent(EVENT_INTRO_FINISH, 36s, 0, PHASE_ROLE_PLAY);
+ break;
+ }
+ case ACTION_DESPAWN_ALGALON:
+ _fightWon = true;
+ events.Reset();
+ summons.DespawnAll();
+ events.SetPhase(PHASE_ROLE_PLAY);
+ events.ScheduleEvent(EVENT_DESPAWN_ALGALON_1, 5s);
+ events.ScheduleEvent(EVENT_DESPAWN_ALGALON_2, 17s);
+ events.ScheduleEvent(EVENT_DESPAWN_ALGALON_3, 26s);
+ if (me->IsInCombat())
+ events.ScheduleEvent(EVENT_DESPAWN_ALGALON_4, 26s);
+ events.ScheduleEvent(EVENT_DESPAWN_ALGALON_5, 32s);
+ me->DespawnOrUnsummon(39000);
+
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->SetFaction(FACTION_FRIENDLY);
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ me->InterruptNonMeleeSpells(false);
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_ALGALON, NOT_STARTED);
+ break;
+ case ACTION_INIT_ALGALON:
+ _firstPull = false;
+ _fedOnTears = false;
+ me->SetImmuneToPC(false);
+ break;
+ case ACTION_ASCEND:
+ summons.DespawnAll();
+ events.SetPhase(PHASE_BIG_BANG);
+ events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 1500ms);
+ break;
+ case ACTION_FEEDS_ON_TEARS_FAILED:
+ _fedOnTears = false;
+ }
+ }
+
+ void JustReachedHome() override
+ {
+ me->setActive(false);
+ }
+
+ void JustEngagedWith(Unit*) override
+ {
+ if (_fightWon)
+ return;
+
+ if (!m_pInstance)
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+
+ uint32 introDelay = 0;
+ me->setActive(true);
+ me->SetInCombatWithZone();
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ me->SetImmuneToNPC(true);
+ events.Reset();
+ events.SetPhase(PHASE_ROLE_PLAY);
+
+ if (!_firstPull)
+ {
+ events.ScheduleEvent(EVENT_START_COMBAT, 0ms);
+ introDelay = 8000;
+ }
+ else
+ {
+ summons.DespawnEntry(NPC_AZEROTH);
+ _firstPull = false;
+ Talk(SAY_ALGALON_START_TIMER);
+ introDelay = 22000;
+ events.ScheduleEvent(EVENT_START_COMBAT, 14s);
+ m_pInstance->SetData(DATA_DESPAWN_ALGALON, 0);
+ }
+
+ events.ScheduleEvent(EVENT_REMOVE_UNNATTACKABLE, introDelay - 500);
+ events.ScheduleEvent(EVENT_INTRO_TIMER_DONE, introDelay);
+ events.ScheduleEvent(EVENT_QUANTUM_STRIKE, 3500 + introDelay);
+ events.ScheduleEvent(EVENT_PHASE_PUNCH, 15500 + introDelay);
+ events.ScheduleEvent(EVENT_SUMMON_COLLAPSING_STAR, 16500 + introDelay);
+ events.ScheduleEvent(EVENT_COSMIC_SMASH, 25000 + introDelay);
+ events.ScheduleEvent(EVENT_ACTIVATE_LIVING_CONSTELLATION, 50500 + introDelay);
+ events.ScheduleEvent(EVENT_BIG_BANG, 90000 + introDelay);
+ events.ScheduleEvent(EVENT_ASCEND_TO_THE_HEAVENS, 360000 + introDelay);
+
+ events.ScheduleEvent(EVENT_CHECK_HERALD_ITEMS, 5s);
+ DoCheckHeraldOfTheTitans();
+ }
+
+ void MovementInform(uint32 movementType, uint32 pointId) override
+ {
+ if (movementType != POINT_MOTION_TYPE)
+ return;
+
+ if (pointId == POINT_ALGALON_LAND)
+ me->SetDisableGravity(false);
+ else if (pointId == POINT_ALGALON_OUTRO)
+ {
+ me->SetFacingTo(1.605703f);
+ events.ScheduleEvent(EVENT_OUTRO_3, 1200ms);
+ events.ScheduleEvent(EVENT_OUTRO_4, 2400ms);
+ events.ScheduleEvent(EVENT_OUTRO_5, 8500ms);
+ events.ScheduleEvent(EVENT_OUTRO_6, 15s + 500ms);
+ events.ScheduleEvent(EVENT_OUTRO_7, 55s + 500ms);
+ events.ScheduleEvent(EVENT_OUTRO_8, 73s + 500ms);
+ events.ScheduleEvent(EVENT_OUTRO_9, 85s + 500ms);
+ events.ScheduleEvent(EVENT_OUTRO_10, 101s + 500ms);
+ events.ScheduleEvent(EVENT_OUTRO_11, 117s + 500ms);
+ }
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ summons.Summon(summon);
+ switch (summon->GetEntry())
+ {
+ case NPC_AZEROTH:
+ me->CastSpell(summon, SPELL_REORIGINATION, true);
+ break;
+ case NPC_BLACK_HOLE:
+ summon->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_TRIGGER, true);
+ summon->CastSpell(summon, SPELL_CONSTELLATION_PHASE_TRIGGER, true);
+ summon->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_EXPLOSION, false);
+ summon->CastSpell(summon, SPELL_SUMMON_VOID_ZONE_VISUAL, true);
+ break;
+ case NPC_ALGALON_VOID_ZONE_VISUAL_STALKER:
+ summon->CastSpell(summon, SPELL_VOID_ZONE_VISUAL, true);
+ break;
+ case NPC_ALGALON_STALKER_ASTEROID_TARGET_01:
+ summon->CastSpell(summon, SPELL_COSMIC_SMASH_VISUAL_STATE, true);
+ break;
+ case NPC_ALGALON_STALKER_ASTEROID_TARGET_02:
+ {
+ float x = summon->GetPositionX();
+ float y = summon->GetPositionY();
+ float z = summon->GetPositionZ() + 35.0f;
+ float o = summon->GetOrientation();
+
+ summon->GetMotionMaster()->Clear();
+ summon->SetHomePosition(x, y, z, o);
+ summon->UpdatePosition(x, y, z, o, true);
+ summon->StopMovingOnCurrentPos();
+ summon->m_Events.AddEvent(new CosmicSmashDamageEvent(summon), summon->m_Events.CalculateTime(4000));
+ break;
+ }
+ case NPC_UNLEASHED_DARK_MATTER:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
+ if (summon->Attack(target, true))
+ summon->GetMotionMaster()->MoveChase(target);
+ break;
+ }
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (_fightWon)
+ {
+ damage = 0;
+ return;
+ }
+
+ if (!_phaseTwo && me->HealthBelowPctDamaged(20, damage))
+ {
+ _phaseTwo = true;
+ Talk(SAY_ALGALON_PHASE_TWO);
+ summons.DespawnEntry(NPC_LIVING_CONSTELLATION);
+ summons.DespawnEntry(NPC_COLLAPSING_STAR);
+ summons.DespawnEntry(NPC_BLACK_HOLE);
+ summons.DespawnEntry(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER);
+ events.CancelEvent(EVENT_SUMMON_COLLAPSING_STAR);
+ events.CancelEvent(EVENT_ACTIVATE_LIVING_CONSTELLATION);
+
+ for (uint32 i = 0; i < COLLAPSING_STAR_COUNT; ++i)
+ me->SummonCreature(NPC_WORM_HOLE, CollapsingStarPos[i], TEMPSUMMON_MANUAL_DESPAWN);
+ }
+ else if (me->HealthBelowPctDamaged(2, damage) && !_fightWon)
+ {
+ _fightWon = true;
+ damage = 0;
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->SetFaction(FACTION_FRIENDLY);
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ events.Reset();
+ summons.DespawnAll();
+ me->InterruptNonMeleeSpells(false);
+ events.SetPhase(PHASE_ROLE_PLAY);
+ events.ScheduleEvent(EVENT_OUTRO_START, 1500ms);
+ events.ScheduleEvent(EVENT_OUTRO_1, 7200ms);
+ events.ScheduleEvent(EVENT_OUTRO_2, 8700ms);
+ }
+ }
+
+ bool IsInRoom()
+ {
+ if (me->GetExactDist2d(&me->GetHomePosition()) > 45.f || me->GetPositionZ() < 410.f)
+ {
+ DoAction(ACTION_ASCEND);
+ return false;
+ }
+
+ return true;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && (!UpdateVictim() || !IsInRoom()))
+ return;
+
+ events.Update(diff);
+ if (!(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK) && me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_INTRO_1:
+ me->RemoveAurasDueToSpell(SPELL_RIDE_THE_LIGHTNING);
+ Talk(SAY_ALGALON_INTRO_1);
+ break;
+ case EVENT_INTRO_2:
+ me->CastSpell((Unit*)nullptr, SPELL_SUMMON_AZEROTH, true);
+ Talk(SAY_ALGALON_INTRO_2);
+ break;
+ case EVENT_INTRO_3:
+ Talk(SAY_ALGALON_INTRO_3);
+ break;
+ case EVENT_INTRO_FINISH:
+ events.Reset();
+ me->SetImmuneToPC(false);
+ if (Creature* brann = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_BRANN_BRONZBEARD_ALG)))
+ brann->AI()->DoAction(ACTION_FINISH_INTRO);
+ break;
+ case EVENT_START_COMBAT:
+ m_pInstance->SetData(TYPE_ALGALON, IN_PROGRESS);
+ Talk(SAY_ALGALON_AGGRO);
+ break;
+ case EVENT_REMOVE_UNNATTACKABLE:
+ me->SetSheath(SHEATH_STATE_MELEE);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ me->SetImmuneToNPC(false);
+ break;
+ case EVENT_INTRO_TIMER_DONE:
+ events.SetPhase(PHASE_NORMAL);
+ me->CastSpell((Unit*)nullptr, SPELL_SUPERMASSIVE_FAIL, true);
+ // Hack: _IsValidTarget failed earlier due to flags, call AttackStart again
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->SetFaction(FACTION_MONSTER);
+ if (Player* target = SelectTargetFromPlayerList(150.0f))
+ AttackStart(target);
+ me->SetInCombatWithZone();
+
+ for (uint32 i = 0; i < LIVING_CONSTELLATION_COUNT; ++i)
+ me->SummonCreature(NPC_LIVING_CONSTELLATION, ConstellationPos[i], TEMPSUMMON_DEAD_DESPAWN);
+ break;
+ case EVENT_QUANTUM_STRIKE:
+ me->CastSpell(me->GetVictim(), SPELL_QUANTUM_STRIKE, false);
+ events.Repeat(3000ms, 4500ms);
+ break;
+ case EVENT_PHASE_PUNCH:
+ me->CastSpell(me->GetVictim(), SPELL_PHASE_PUNCH, false);
+ events.Repeat(15s + 500ms);
+ break;
+ case EVENT_SUMMON_COLLAPSING_STAR:
+ Talk(SAY_ALGALON_COLLAPSING_STAR);
+ Talk(EMOTE_ALGALON_COLLAPSING_STAR);
+ for (uint8 i = 0; i < COLLAPSING_STAR_COUNT; ++i)
+ me->SummonCreature(NPC_COLLAPSING_STAR, CollapsingStarPos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);
+ events.Repeat(1min);
+ break;
+ case EVENT_COSMIC_SMASH:
+ Talk(EMOTE_ALGALON_COSMIC_SMASH);
+ me->CastCustomSpell(SPELL_COSMIC_SMASH, SPELLVALUE_MAX_TARGETS, RAID_MODE(1, 3), (Unit*)nullptr);
+ events.Repeat(25s + 500ms);
+ break;
+ case EVENT_ACTIVATE_LIVING_CONSTELLATION:
+ {
+ if (events.GetPhaseMask() & PHASE_MASK_NO_UPDATE)
+ {
+ events.Repeat(4s);
+ break;
+ }
+ CallConstellations();
+ //me->CastSpell(me, SPELL_TRIGGER_3_ADDS, true);
+ events.Repeat(50s);
+ break;
+ }
+ case EVENT_BIG_BANG:
+ {
+ Talk(SAY_ALGALON_BIG_BANG);
+ Talk(EMOTE_ALGALON_BIG_BANG);
+
+ EntryCheckPredicate pred(NPC_LIVING_CONSTELLATION);
+ summons.DoAction(ACTION_BIG_BANG, pred);
+
+ me->CastSpell((Unit*)nullptr, SPELL_BIG_BANG, false);
+ events.Repeat(90s + 500ms);
+ break;
+ }
+ case EVENT_ASCEND_TO_THE_HEAVENS:
+ Talk(SAY_ALGALON_ASCEND);
+ me->CastSpell((Unit*)nullptr, SPELL_ASCEND_TO_THE_HEAVENS, false);
+ events.ScheduleEvent(EVENT_EVADE, 2500ms);
+ break;
+ case EVENT_EVADE:
+ events.Reset();
+ ScriptedAI::EnterEvadeMode();
+ return;
+ case EVENT_OUTRO_START:
+ if (m_pInstance)
+ {
+ m_pInstance->SetData(TYPE_ALGALON, DONE);
+ m_pInstance->SetData(DATA_ALGALON_DEFEATED, 1);
+ }
+ break;
+ case EVENT_OUTRO_1:
+ me->RemoveAllAuras();
+ me->SetUnitFlag(UNIT_FLAG_RENAME);
+ break;
+ case EVENT_OUTRO_2:
+ {
+ Player* lootRecipent = me->GetLootRecipient();
+ _EnterEvadeMode();
+ // LootRecipent is cleared in _EnterEvadeMode, restore it
+ me->SetLootRecipient(lootRecipent);
+ me->GetMotionMaster()->MovePoint(POINT_ALGALON_OUTRO, AlgalonOutroPos);
+ break;
+ }
+ case EVENT_OUTRO_3:
+ me->CastSpell((Unit*)nullptr, SPELL_KILL_CREDIT);
+ // Summon Chest
+ if (GameObject* go = me->SummonGameObject(RAID_MODE(GO_ALGALON_CHEST, GO_ALGALON_CHEST_HERO), 1632.1f, -306.561f, 417.321f, 4.69494f, 0, 0, 0, 1, 0))
+ {
+ go->ReplaceAllGameObjectFlags((GameObjectFlags)0);
+ go->SetLootRecipient(me);
+ }
+ break;
+ case EVENT_OUTRO_4:
+ me->CastSpell((Unit*)nullptr, SPELL_SUPERMASSIVE_FAIL);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ break;
+ case EVENT_OUTRO_5:
+ if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannOutroPos[0], TEMPSUMMON_TIMED_DESPAWN, 131500))
+ brann->AI()->DoAction(ACTION_OUTRO);
+ break;
+ case EVENT_OUTRO_6:
+ Talk(SAY_ALGALON_OUTRO_1);
+ me->SetStandState(UNIT_STAND_STATE_KNEEL);
+ break;
+ case EVENT_OUTRO_7:
+ Talk(SAY_ALGALON_OUTRO_2);
+ break;
+ case EVENT_OUTRO_8:
+ Talk(SAY_ALGALON_OUTRO_3);
+ break;
+ case EVENT_OUTRO_9:
+ Talk(SAY_ALGALON_OUTRO_4);
+ break;
+ case EVENT_OUTRO_10:
+ Talk(SAY_ALGALON_OUTRO_5);
+ break;
+ case EVENT_OUTRO_11:
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ me->CastSpell(me, SPELL_TELEPORT, false);
+ me->DespawnOrUnsummon(3000);
+ break;
+ case EVENT_DESPAWN_ALGALON_1:
+ Talk(SAY_ALGALON_DESPAWN_1);
+ break;
+ case EVENT_DESPAWN_ALGALON_2:
+ Talk(SAY_ALGALON_DESPAWN_2);
+ break;
+ case EVENT_DESPAWN_ALGALON_3:
+ Talk(SAY_ALGALON_DESPAWN_3);
+ break;
+ case EVENT_DESPAWN_ALGALON_4:
+ me->CastSpell((Unit*)nullptr, SPELL_ASCEND_TO_THE_HEAVENS, false);
+ break;
+ case EVENT_DESPAWN_ALGALON_5:
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ me->CastSpell(me, SPELL_TELEPORT, false);
+ me->DespawnOrUnsummon(3000);
+ break;
+ case EVENT_CHECK_HERALD_ITEMS:
+ if (!DoCheckHeraldOfTheTitans())
+ events.Repeat(5s);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI(creature);
+ }
+};
+
+class npc_brann_bronzebeard_algalon : public CreatureScript
+{
+public:
+ npc_brann_bronzebeard_algalon() : CreatureScript("npc_brann_bronzebeard_algalon") { }
+
+ struct npc_brann_bronzebeard_algalonAI : public CreatureAI
+ {
+ npc_brann_bronzebeard_algalonAI(Creature* creature) : CreatureAI(creature)
+ {
+ }
+
+ EventMap events;
+ uint32 _currentPoint;
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_START_INTRO:
+ me->SetWalk(false);
+ _currentPoint = 0;
+ events.Reset();
+ events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1ms);
+ break;
+ case ACTION_FINISH_INTRO:
+ Talk(SAY_BRANN_ALGALON_INTRO_2);
+ events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, 1ms);
+ break;
+ case ACTION_OUTRO:
+ me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO, BrannOutroPos[1]);
+ events.ScheduleEvent(EVENT_BRANN_OUTRO_1, 87s + 500ms);
+ events.ScheduleEvent(EVENT_BRANN_OUTRO_2, 116s + 500ms);
+ break;
+ }
+ }
+
+ void MovementInform(uint32 movementType, uint32 pointId) override
+ {
+ if (movementType != POINT_MOTION_TYPE)
+ return;
+
+ uint32 delay = 1;
+ _currentPoint = pointId + 1;
+ switch (pointId)
+ {
+ case 2:
+ delay = 8000;
+ me->SetWalk(true);
+ break;
+ case 6:
+ me->SetFacingTo(4.6156f);
+ me->SetWalk(false);
+ Talk(SAY_BRANN_ALGALON_INTRO_1);
+ events.ScheduleEvent(EVENT_SUMMON_ALGALON, 7500ms);
+ return;
+ case 10:
+ me->DespawnOrUnsummon(1);
+ return;
+ case POINT_BRANN_OUTRO:
+ case POINT_BRANN_OUTRO_END:
+ return;
+ }
+
+ events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, delay);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ UpdateVictim();
+ events.Update(diff);
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_BRANN_MOVE_INTRO:
+ if (_currentPoint < MAX_BRANN_WAYPOINTS_INTRO)
+ me->GetMotionMaster()->MovePoint(_currentPoint, BrannIntroWaypoint[_currentPoint]);
+ break;
+ case EVENT_SUMMON_ALGALON:
+ if (me->GetInstanceScript() && !me->GetInstanceScript()->GetGuidData(TYPE_ALGALON))
+ if (Creature* algalon = me->GetMap()->SummonCreature(NPC_ALGALON, AlgalonSummonPos))
+ algalon->AI()->DoAction(ACTION_START_INTRO);
+ break;
+ case EVENT_BRANN_OUTRO_1:
+ Talk(SAY_BRANN_ALGALON_OUTRO);
+ break;
+ case EVENT_BRANN_OUTRO_2:
+ me->GetMotionMaster()->MovePoint(POINT_BRANN_OUTRO_END, BrannOutroPos[2]);
+ break;
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI(creature);
+ }
+};
+
+class npc_collapsing_star : public CreatureScript
+{
+public:
+ npc_collapsing_star() : CreatureScript("npc_collapsing_star") { }
+
+ struct npc_collapsing_starAI : public NullCreatureAI
+ {
+ npc_collapsing_starAI(Creature* creature) : NullCreatureAI(creature)
+ {
+ creature->GetMotionMaster()->MoveRandom(25.0f);
+ creature->CastSpell(creature, SPELL_COLLAPSE, true);
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ if (TempSummon* summ = me->ToTempSummon())
+ if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID()))
+ algalon->AI()->JustSummoned(summon);
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (damage >= me->GetHealth())
+ {
+ me->CastSpell(me, SPELL_BLACK_HOLE_SPAWN_VISUAL, true);
+ me->CastSpell(me, SPELL_SUMMON_BLACK_HOLE, true);
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI(creature);
+ }
+};
+
+class npc_living_constellation : public CreatureScript
+{
+public:
+ npc_living_constellation() : CreatureScript("npc_living_constellation") { }
+
+ struct npc_living_constellationAI : public ScriptedAI
+ {
+ npc_living_constellationAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ EventMap events;
+ bool _isActive;
+
+ void Reset() override
+ {
+ events.Reset();
+ events.ScheduleEvent(EVENT_ARCANE_BARRAGE, 2500ms);
+ _isActive = false;
+ }
+
+ uint32 GetData(uint32 /*param*/) const override
+ {
+ return _isActive;
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_ACTIVATE_STAR:
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ me->SetImmuneToAll(false);
+ _isActive = true;
+
+ if (Player* target = SelectTargetFromPlayerList(250.0f))
+ {
+ AttackStart(target);
+ me->AddThreat(target, 100.0f);
+ }
+ me->SetInCombatWithZone();
+ break;
+ case ACTION_BIG_BANG:
+ events.SetPhase(PHASE_BIG_BANG);
+ events.DelayEvents(9500);
+ events.ScheduleEvent(EVENT_RESUME_UPDATING, 9500ms);
+ break;
+ }
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ if (spell->Id != SPELL_CONSTELLATION_PHASE_EFFECT || caster->GetTypeId() != TYPEID_UNIT)
+ return;
+
+ if (InstanceScript* instance = me->GetInstanceScript())
+ instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, EVENT_ID_SUPERMASSIVE_START);
+
+ caster->CastSpell((Unit*)nullptr, SPELL_BLACK_HOLE_CREDIT, TRIGGERED_FULL_MASK);
+ caster->ToCreature()->DespawnOrUnsummon(1);
+ me->DespawnOrUnsummon(1);
+ if (Creature* voidZone = caster->FindNearestCreature(NPC_ALGALON_VOID_ZONE_VISUAL_STALKER, 10.0f))
+ voidZone->DespawnOrUnsummon(1);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && !UpdateVictim())
+ return;
+
+ events.Update(diff);
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_ARCANE_BARRAGE:
+ me->CastCustomSpell(SPELL_ARCANE_BARRAGE, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, true);
+ events.Repeat(2500ms);
+ break;
+ case EVENT_RESUME_UPDATING:
+ events.SetPhase(0);
+ break;
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI(creature);
+ }
+};
+
+class npc_algalon_worm_hole : public CreatureScript
+{
+public:
+ npc_algalon_worm_hole() : CreatureScript("npc_algalon_worm_hole") { }
+
+ struct npc_algalon_worm_holeAI : public NullCreatureAI
+ {
+ npc_algalon_worm_holeAI(Creature* creature) : NullCreatureAI(creature)
+ {
+ creature->CastSpell(creature, SPELL_WORM_HOLE_TRIGGER, true);
+ creature->CastSpell(creature, SPELL_SUMMON_VOID_ZONE_VISUAL, true);
+ }
+
+ uint32 _summonTimer;
+
+ void Reset() override
+ {
+ _summonTimer = urand(22000, 24000);
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ if (TempSummon* summ = me->ToTempSummon())
+ {
+ if (Creature* algalon = ObjectAccessor::GetCreature(*me, summ->GetSummonerGUID()))
+ {
+ algalon->AI()->JustSummoned(summon);
+ }
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _summonTimer += diff;
+ if (_summonTimer >= 30000)
+ {
+ me->CastSpell((Unit*)nullptr, SPELL_SUMMON_UNLEASHED_DARK_MATTER, true);
+ _summonTimer = 0;
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI(creature);
+ }
+};
+
+class go_celestial_planetarium_access : public GameObjectScript
+{
+public:
+ go_celestial_planetarium_access() : GameObjectScript("go_celestial_planetarium_access") {}
+
+ struct go_celestial_planetarium_accessAI : public GameObjectAI
+ {
+ go_celestial_planetarium_accessAI(GameObject* go) : GameObjectAI(go)
+ {
+ _locked = false;
+ }
+
+ EventMap events;
+ bool _locked;
+
+ bool GossipHello(Player* player, bool /*reportUse*/) override
+ {
+ bool hasKey = true;
+ if (LockEntry const* lock = sLockStore.LookupEntry(me->GetGOInfo()->goober.lockId))
+ {
+ hasKey = false;
+ for (uint32 i = 0; i < MAX_LOCK_CASE; ++i)
+ {
+ if (!lock->Index[i])
+ continue;
+
+ if (player->HasItemCount(lock->Index[i]))
+ {
+ hasKey = true;
+ break;
+ }
+ }
+ }
+
+ if (!hasKey)
+ return false;
+
+ if (_locked)
+ return false;
+ _locked = true;
+ // Start Algalon event
+ me->SetGameObjectFlag(GO_FLAG_IN_USE);
+ events.ScheduleEvent(EVENT_DESPAWN_CONSOLE, 5000ms);
+ if (Creature* brann = me->SummonCreature(NPC_BRANN_BRONZBEARD_ALG, BrannIntroSpawnPos))
+ brann->AI()->DoAction(ACTION_START_INTRO);
+
+ if (InstanceScript* instance = me->GetInstanceScript())
+ {
+ instance->SetData(DATA_ALGALON_SUMMON_STATE, 1);
+ if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_DOODAD_UL_SIGILDOOR_01)))
+ sigil->SetGoState(GO_STATE_ACTIVE);
+
+ if (GameObject* sigil = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_DOODAD_UL_SIGILDOOR_02)))
+ sigil->SetGoState(GO_STATE_ACTIVE);
+
+ if (Map* map = player->GetMap())
+ {
+ if (InstanceMap* instanceMap = map->ToInstanceMap())
+ {
+ instanceMap->PermBindAllPlayers();
+ }
+ }
+ }
+
+ return false;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (events.Empty())
+ return;
+
+ events.Update(diff);
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_DESPAWN_CONSOLE:
+ me->Delete();
+ break;
+ }
+ }
+ };
+
+ GameObjectAI* GetAI(GameObject* go) const override
+ {
+ return new go_celestial_planetarium_accessAI(go);
+ }
+};
+
+class spell_algalon_phase_punch : public SpellScriptLoader
+{
+public:
+ spell_algalon_phase_punch() : SpellScriptLoader("spell_algalon_phase_punch") { }
+
+ class spell_algalon_phase_punch_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_algalon_phase_punch_AuraScript);
+
+ void HandlePeriodic(AuraEffect const* /*aurEff*/)
+ {
+ PreventDefaultAction();
+ if (GetStackAmount() != 1)
+ GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 2]);
+ GetTarget()->CastSpell(GetTarget(), PhasePunchAlphaId[GetStackAmount() - 1], TRIGGERED_FULL_MASK);
+ if (GetStackAmount() == 5)
+ Remove(AURA_REMOVE_BY_DEFAULT);
+ }
+
+ void OnRemove(AuraEffect const*, AuraEffectHandleModes)
+ {
+ if (GetStackAmount() != 5)
+ GetTarget()->RemoveAurasDueToSpell(PhasePunchAlphaId[GetStackAmount() - 1]);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_phase_punch_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ OnEffectRemove += AuraEffectRemoveFn(spell_algalon_phase_punch_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_algalon_phase_punch_AuraScript();
+ }
+};
+
+class spell_algalon_collapse : public SpellScriptLoader
+{
+public:
+ spell_algalon_collapse() : SpellScriptLoader("spell_algalon_collapse") { }
+
+ class spell_algalon_collapse_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_algalon_collapse_AuraScript);
+
+ void HandlePeriodic(AuraEffect const* /*aurEff*/)
+ {
+ PreventDefaultAction();
+ Unit::DealDamage(GetTarget(), GetTarget(), GetTarget()->CountPctFromMaxHealth(1), nullptr, NODAMAGE);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_collapse_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_algalon_collapse_AuraScript();
+ }
+};
+
+class ActiveConstellationFilter
+{
+public:
+ bool operator()(WorldObject* object) const
+ {
+ return object->ToUnit()->GetAI()->GetData(0);
+ }
+};
+
+class spell_algalon_trigger_3_adds : public SpellScriptLoader
+{
+public:
+ spell_algalon_trigger_3_adds() : SpellScriptLoader("spell_algalon_trigger_3_adds") { }
+
+ class spell_algalon_trigger_3_adds_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_algalon_trigger_3_adds_SpellScript);
+
+ void SelectTarget(std::list& targets)
+ {
+ targets.remove_if(ActiveConstellationFilter());
+ }
+
+ void HandleDummyEffect(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ Creature* target = GetHitCreature();
+ if (!target)
+ return;
+
+ target->AI()->DoAction(ACTION_ACTIVATE_STAR);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_trigger_3_adds_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ OnEffectHitTarget += SpellEffectFn(spell_algalon_trigger_3_adds_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_algalon_trigger_3_adds_SpellScript();
+ }
+};
+
+class spell_algalon_cosmic_smash_damage : public SpellScriptLoader
+{
+public:
+ spell_algalon_cosmic_smash_damage() : SpellScriptLoader("spell_algalon_cosmic_smash_damage") { }
+
+ class spell_algalon_cosmic_smash_damage_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_algalon_cosmic_smash_damage_SpellScript);
+
+ void RecalculateDamage()
+ {
+ if (!GetExplTargetDest() || !GetHitUnit())
+ return;
+
+ float distance = GetHitUnit()->GetDistance2d(GetExplTargetDest()->GetPositionX(), GetExplTargetDest()->GetPositionY());
+ if (distance >= 10.0f)
+ SetHitDamage(int32(float(GetHitDamage()) / distance));
+ else if (distance > 6.0f)
+ SetHitDamage(int32(float(GetHitDamage()) / distance) * 2);
+ }
+
+ void Register() override
+ {
+ OnHit += SpellHitFn(spell_algalon_cosmic_smash_damage_SpellScript::RecalculateDamage);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_algalon_cosmic_smash_damage_SpellScript();
+ }
+};
+
+class spell_algalon_big_bang : public SpellScriptLoader
+{
+public:
+ spell_algalon_big_bang() : SpellScriptLoader("spell_algalon_big_bang") { }
+
+ class spell_algalon_big_bang_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_algalon_big_bang_SpellScript);
+
+ bool Load() override
+ {
+ _targetCount = 0;
+ return true;
+ }
+
+ void CountTargets(std::list& targets)
+ {
+ _targetCount = targets.size();
+ }
+
+ void CheckTargets()
+ {
+ Unit* caster = GetCaster();
+ if (!_targetCount && caster && caster->GetAI())
+ caster->GetAI()->DoAction(ACTION_ASCEND);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_algalon_big_bang_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ AfterCast += SpellCastFn(spell_algalon_big_bang_SpellScript::CheckTargets);
+ }
+
+ uint32 _targetCount;
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_algalon_big_bang_SpellScript();
+ }
+};
+
+class spell_algalon_remove_phase : public SpellScriptLoader
+{
+public:
+ spell_algalon_remove_phase() : SpellScriptLoader("spell_algalon_remove_phase") { }
+
+ class spell_algalon_remove_phase_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_algalon_remove_phase_AuraScript);
+
+ void HandlePeriodic(AuraEffect const* /*aurEff*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->RemoveAurasByType(SPELL_AURA_PHASE);
+ GetTarget()->RemoveAurasDueToSpell(SPELL_BLACK_HOLE_DAMAGE);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_algalon_remove_phase_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_algalon_remove_phase_AuraScript();
+ }
+};
+
+class spell_algalon_supermassive_fail : public SpellScriptLoader
+{
+public:
+ spell_algalon_supermassive_fail() : SpellScriptLoader("spell_algalon_supermassive_fail") { }
+
+ class spell_algalon_supermassive_fail_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_algalon_supermassive_fail_SpellScript);
+
+ void RecalculateDamage()
+ {
+ if (!GetHitPlayer())
+ return;
+
+ GetHitPlayer()->ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_CONDITION_NO_SPELL_HIT, GetSpellInfo()->Id, true);
+ }
+
+ void Register() override
+ {
+ OnHit += SpellHitFn(spell_algalon_supermassive_fail_SpellScript::RecalculateDamage);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_algalon_supermassive_fail_SpellScript();
+ }
+};
+
+class achievement_algalon_he_feeds_on_your_tears : public AchievementCriteriaScript
+{
+public:
+ achievement_algalon_he_feeds_on_your_tears() : AchievementCriteriaScript("achievement_algalon_he_feeds_on_your_tears") { }
+
+ bool OnCheck(Player*, Unit* target /*Algalon*/, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetAI()->GetData(DATA_HAS_FED_ON_TEARS);
+ }
+};
+
+class achievement_algalon_herald_of_the_titans : public AchievementCriteriaScript
+{
+public:
+ achievement_algalon_herald_of_the_titans() : AchievementCriteriaScript("achievement_algalon_herald_of_the_titans") { }
+
+ bool OnCheck(Player*, Unit* target /*Algalon*/, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetAI()->GetData(DATA_HERALD_OF_THE_TITANS);
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp
index c8f049a5039dc2..4c159fa8eb365c 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_assembly_of_iron.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "Player.h"
@@ -24,123 +25,6 @@
#include "SpellScriptLoader.h"
#include "ulduar.h"
-enum AssemblySpells
-{
- // Any boss
- SPELL_SUPERCHARGE = 61920,
- SPELL_BERSERK = 47008,
-
- // Steelbreaker
- SPELL_HIGH_VOLTAGE_10 = 61890,
- SPELL_HIGH_VOLTAGE_25 = 63498,
- SPELL_FUSION_PUNCH_10 = 61903,
- SPELL_FUSION_PUNCH_25 = 63493,
- SPELL_STATIC_DISRUPTION_10 = 61911,
- SPELL_STATIC_DISRUPTION_25 = 63495,
- SPELL_OVERWHELMING_POWER_10 = 64637,
- SPELL_OVERWHELMING_POWER_25 = 61888,
- SPELL_ELECTRICAL_CHARGE = 61902,
-
- // Runemaster Molgeim
- SPELL_SHIELD_OF_RUNES_BUFF = 62277,
- SPELL_SHIELD_OF_RUNES_10 = 62274,
- SPELL_SHIELD_OF_RUNES_25 = 63489,
- SPELL_RUNE_OF_POWER = 61973,
- SPELL_RUNE_OF_DEATH_10 = 62269,
- SPELL_RUNE_OF_DEATH_25 = 63490,
- SPELL_RUNE_OF_SUMMONING = 62273,
- SPELL_RUNE_OF_SUMMONING_SUMMON = 62020,
- SPELL_LIGHTNING_BLAST_10 = 62054,
- SPELL_LIGHTNING_BLAST_25 = 63491,
- CREATURE_LIGHTNING_ELEMENTAL = 32958,
- CREATURE_RUNE_OF_SUMMONING = 33051,
- SPELL_RUNE_OF_POWER_OOC_CHANNEL = 61975,
-
- // Stormcaller Brundir
- SPELL_CHAIN_LIGHTNING_10 = 61879,
- SPELL_CHAIN_LIGHTNING_25 = 63479,
- SPELL_OVERLOAD_10 = 61869,
- SPELL_OVERLOAD_25 = 63481,
- SPELL_LIGHTNING_WHIRL_10 = 61915,
- SPELL_LIGHTNING_WHIRL_25 = 63483,
- SPELL_LIGHTNING_TENDRILS_10 = 61887,
- SPELL_LIGHTNING_TENDRILS_25 = 63486,
- SPELL_STORMSHIELD = 64187,
- SPELL_LIGHTNING_CHANNEL_PRE = 61942,
-};
-
-#define SPELL_HIGH_VOLTAGE RAID_MODE(SPELL_HIGH_VOLTAGE_10, SPELL_HIGH_VOLTAGE_25)
-#define SPELL_FUSION_PUNCH RAID_MODE(SPELL_FUSION_PUNCH_10, SPELL_FUSION_PUNCH_25)
-#define SPELL_STATIC_DISRUPTION RAID_MODE(SPELL_STATIC_DISRUPTION_10, SPELL_STATIC_DISRUPTION_25)
-#define SPELL_OVERWHELMING_POWER RAID_MODE(SPELL_OVERWHELMING_POWER_10, SPELL_OVERWHELMING_POWER_25)
-#define SPELL_SHIELD_OF_RUNES RAID_MODE(SPELL_SHIELD_OF_RUNES_10, SPELL_SHIELD_OF_RUNES_25)
-#define SPELL_RUNE_OF_DEATH RAID_MODE(SPELL_RUNE_OF_DEATH_10, SPELL_RUNE_OF_DEATH_25)
-#define SPELL_LIGHTNING_BLAST RAID_MODE(SPELL_LIGHTNING_BLAST_10, SPELL_LIGHTNING_BLAST_25)
-#define SPELL_CHAIN_LIGHTNING RAID_MODE(SPELL_CHAIN_LIGHTNING_10, SPELL_CHAIN_LIGHTNING_25)
-#define SPELL_OVERLOAD RAID_MODE(SPELL_OVERLOAD_10, SPELL_OVERLOAD_25)
-#define SPELL_LIGHTNING_WHIRL RAID_MODE(SPELL_LIGHTNING_WHIRL_10, SPELL_LIGHTNING_WHIRL_25)
-#define SPELL_LIGHTNING_TENDRILS RAID_MODE(SPELL_LIGHTNING_TENDRILS_10, SPELL_LIGHTNING_TENDRILS_25)
-
-enum eEnums
-{
- // Steelbreaker
- EVENT_FUSION_PUNCH = 1,
- EVENT_STATIC_DISRUPTION = 2,
- EVENT_OVERWHELMING_POWER = 3,
- //EVENT_CHECK_MAIN_TANK = 4,
-
- // Molgeim
- EVENT_RUNE_OF_POWER = 11,
- EVENT_SHIELD_OF_RUNES = 12,
- EVENT_RUNE_OF_DEATH = 13,
- EVENT_RUNE_OF_SUMMONING = 14,
- EVENT_LIGHTNING_BLAST = 15,
-
- // Brundir
- EVENT_CHAIN_LIGHTNING = 21,
- EVENT_OVERLOAD = 22,
- EVENT_LIGHTNING_WHIRL = 23,
- EVENT_LIGHTNING_TENDRILS = 24,
- EVENT_LIGHTNING_LAND = 25,
- EVENT_LAND_LAND = 26,
- EVENT_LIGHTNING_FLIGHT = 27,
-
- EVENT_ENRAGE = 30
-};
-
-enum AssemblyYells
-{
- SAY_STEELBREAKER_AGGRO = 0,
- SAY_STEELBREAKER_SLAY = 1,
- SAY_STEELBREAKER_POWER = 2,
- SAY_STEELBREAKER_DEATH = 3,
- SAY_STEELBREAKER_ENCOUNTER_DEFEATED = 4,
- SAY_STEELBREAKER_BERSERK = 5,
-
- SAY_MOLGEIM_AGGRO = 0,
- SAY_MOLGEIM_SLAY = 1,
- SAY_MOLGEIM_RUNE_DEATH = 2,
- SAY_MOLGEIM_SUMMON = 3,
- SAY_MOLGEIM_DEATH = 4,
- SAY_MOLGEIM_ENCOUNTER_DEFEATED = 5,
- SAY_MOLGEIM_BERSERK = 6,
-
- SAY_BRUNDIR_AGGRO = 0,
- SAY_BRUNDIR_SLAY = 1,
- SAY_BRUNDIR_SPECIAL = 2,
- SAY_BRUNDIR_FLIGHT = 3,
- SAY_BRUNDIR_DEATH = 4,
- SAY_BRUNDIR_ENCOUNTER_DEFEATED = 5,
- SAY_BRUNDIR_BERSERK = 6,
- EMOTE_BRUNDIR_OVERLOAD = 7
-};
-
-enum Misc
-{
- ACTION_ADD_CHARGE = 1,
- POINT_CHANNEL_STEELBREAKER = 1
-};
-
bool IsEncounterComplete(InstanceScript* pInstance, Creature* me)
{
if (!pInstance || !me)
@@ -193,783 +77,6 @@ void RestoreAssemblyHealth(ObjectGuid guid1, ObjectGuid guid2, Creature* me)
cr2->SetHealth(cr2->GetMaxHealth());
}
-class boss_steelbreaker : public CreatureScript
-{
-public:
- boss_steelbreaker() : CreatureScript("boss_steelbreaker") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_steelbreakerAI : public ScriptedAI
- {
- boss_steelbreakerAI(Creature* c) : ScriptedAI(c)
- {
- pInstance = c->GetInstanceScript();
- }
-
- EventMap events;
- InstanceScript* pInstance;
- uint8 _phase;
-
- void Reset() override
- {
- me->SetLootMode(0);
- RespawnAssemblyOfIron(pInstance, me);
-
- _phase = 0;
- events.Reset();
- if (pInstance)
- pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED);
- }
-
- void JustReachedHome() override
- {
- me->setActive(false);
- me->RemoveAllAuras();
- }
-
- void JustEngagedWith(Unit* who) override
- {
- if (pInstance)
- pInstance->SetData(TYPE_ASSEMBLY, IN_PROGRESS);
-
- me->setActive(true);
- me->SetInCombatWithZone();
- me->CastSpell(me, SPELL_HIGH_VOLTAGE, true);
- events.ScheduleEvent(EVENT_ENRAGE, 15min);
- UpdatePhase();
-
- if (!pInstance)
- return;
-
- if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + urand(0, 2))))
- {
- switch (boss->GetEntry())
- {
- case NPC_STEELBREAKER:
- boss->AI()->Talk(SAY_STEELBREAKER_AGGRO);
- break;
- case NPC_MOLGEIM:
- boss->AI()->Talk(SAY_MOLGEIM_AGGRO);
- break;
- case NPC_BRUNDIR:
- boss->AI()->Talk(SAY_BRUNDIR_AGGRO);
- break;
- }
- }
-
- for (uint8 i = 0; i < 3; ++i)
- if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i)))
- if (!boss->IsInCombat())
- boss->AI()->AttackStart(who);
- }
-
- void UpdatePhase()
- {
- if (_phase >= 3)
- return;
-
- ++_phase;
-
- switch (_phase)
- {
- case 1:
- events.RescheduleEvent(EVENT_FUSION_PUNCH, 15s);
- break;
- case 2:
- events.RescheduleEvent(EVENT_STATIC_DISRUPTION, 20s);
- break;
- case 3:
- me->ResetLootMode();
- events.RescheduleEvent(EVENT_OVERWHELMING_POWER, 8s);
- break;
- }
- }
-
- void JustDied(Unit* /*Killer*/) override
- {
- if (!pInstance)
- return;
-
- if (IsEncounterComplete(pInstance, me))
- {
- pInstance->SetData(TYPE_ASSEMBLY, DONE);
- me->CastSpell(me, 65195, true); // credit
- Talk(SAY_STEELBREAKER_ENCOUNTER_DEFEATED);
- }
- else
- {
- RestoreAssemblyHealth(pInstance->GetGuidData(DATA_BRUNDIR), pInstance->GetGuidData(DATA_MOLGEIM), me);
- me->CastSpell(me, SPELL_SUPERCHARGE, true);
- Talk(SAY_STEELBREAKER_DEATH);
- }
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->GetTypeId() != TYPEID_PLAYER)
- return;
-
- if (_phase == 3)
- me->CastSpell(me, SPELL_ELECTRICAL_CHARGE, true);
-
- Talk(SAY_STEELBREAKER_SLAY);
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_ADD_CHARGE)
- me->CastSpell(me, SPELL_ELECTRICAL_CHARGE, true);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
- {
- if (spellInfo->Id == SPELL_SUPERCHARGE)
- UpdatePhase();
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch(events.ExecuteEvent())
- {
- case EVENT_FUSION_PUNCH:
- me->CastSpell(me->GetVictim(), SPELL_FUSION_PUNCH, false);
- events.Repeat(15s, 20s);
- break;
- case EVENT_STATIC_DISRUPTION:
- if (Unit* pTarget = SelectTarget(SelectTargetMethod::MinDistance, 0, 0, true))
- me->CastSpell(pTarget, SPELL_STATIC_DISRUPTION, false);
-
- events.Repeat(20s, 40s);
- break;
- case EVENT_OVERWHELMING_POWER:
- Talk(SAY_STEELBREAKER_POWER);
- me->CastSpell(me->GetVictim(), SPELL_OVERWHELMING_POWER, true);
- events.RepeatEvent(RAID_MODE(61000, 36000));
- break;
- case EVENT_ENRAGE:
- Talk(SAY_STEELBREAKER_BERSERK);
- me->CastSpell(me, SPELL_BERSERK, true);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class CastRunesEvent : public BasicEvent
-{
-public:
- CastRunesEvent(Creature& owner) : BasicEvent(), _owner(owner) { }
-
- bool Execute(uint64 /*eventTime*/, uint32 /*diff*/) override
- {
- if (!_owner.IsInCombat())
- _owner.CastSpell(&_owner, SPELL_RUNE_OF_POWER_OOC_CHANNEL, true);
- return true;
- }
-
-private:
- Creature& _owner;
-};
-
-class boss_runemaster_molgeim : public CreatureScript
-{
-public:
- boss_runemaster_molgeim() : CreatureScript("boss_runemaster_molgeim") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_runemaster_molgeimAI : public ScriptedAI
- {
- boss_runemaster_molgeimAI(Creature* c) : ScriptedAI(c), summons(me)
- {
- pInstance = c->GetInstanceScript();
- }
-
- InstanceScript* pInstance;
- SummonList summons;
- EventMap events;
- uint8 _phase;
-
- void Reset() override
- {
- me->SetLootMode(0);
- RespawnAssemblyOfIron(pInstance, me);
-
- _phase = 0;
- events.Reset();
- summons.DespawnAll();
-
- if (pInstance)
- pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED);
-
- me->m_Events.AddEvent(new CastRunesEvent(*me), me->m_Events.CalculateTime(8000));
- }
-
- void JustReachedHome() override
- {
- me->setActive(false);
- me->RemoveAllAuras();
- }
-
- void JustEngagedWith(Unit* who) override
- {
- me->InterruptNonMeleeSpells(false);
- me->setActive(true);
- me->SetInCombatWithZone();
- events.ScheduleEvent(EVENT_ENRAGE, 15min);
- UpdatePhase();
-
- if (!pInstance)
- return;
-
- for (uint8 i = 0; i < 3; ++i)
- if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i)))
- if (!boss->IsInCombat())
- boss->AI()->AttackStart(who);
- }
-
- void UpdatePhase()
- {
- if (_phase >= 3)
- return;
-
- ++_phase;
-
- switch (_phase)
- {
- case 1:
- events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 20s);
- events.RescheduleEvent(EVENT_RUNE_OF_POWER, 30s);
- break;
- case 2:
- events.RescheduleEvent(EVENT_RUNE_OF_DEATH, 35s);
- break;
- case 3:
- me->ResetLootMode();
- events.RescheduleEvent(EVENT_RUNE_OF_SUMMONING, 20s, 30s);
- break;
- }
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (!pInstance)
- return;
-
- if (IsEncounterComplete(pInstance, me))
- {
- pInstance->SetData(TYPE_ASSEMBLY, DONE);
- me->CastSpell(me, 65195, true); // credit
- Talk(SAY_MOLGEIM_ENCOUNTER_DEFEATED);
- }
- else
- {
- RestoreAssemblyHealth(pInstance->GetGuidData(DATA_STEELBREAKER), pInstance->GetGuidData(DATA_BRUNDIR), me);
- me->CastSpell(me, SPELL_SUPERCHARGE, true);
- Talk(SAY_MOLGEIM_DEATH);
- }
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->GetTypeId() != TYPEID_PLAYER)
- return;
-
- Talk(SAY_MOLGEIM_SLAY);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
- {
- if (spellInfo->Id == SPELL_SUPERCHARGE)
- UpdatePhase();
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch(events.ExecuteEvent())
- {
- case EVENT_RUNE_OF_POWER:
- {
- Unit* target = DoSelectLowestHpFriendly(60);
- if (!target || !target->IsAlive())
- target = me;
-
- me->CastSpell(target, SPELL_RUNE_OF_POWER, true);
- events.Repeat(1min);
- break;
- }
- case EVENT_SHIELD_OF_RUNES:
- me->CastSpell(me, SPELL_SHIELD_OF_RUNES, false);
- events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 27s, 34s);
- break;
- case EVENT_RUNE_OF_DEATH:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random))
- me->CastSpell(target, SPELL_RUNE_OF_DEATH, true);
-
- Talk(SAY_MOLGEIM_RUNE_DEATH);
- events.Repeat(30s, 40s);
- break;
- case EVENT_RUNE_OF_SUMMONING:
- Talk(SAY_MOLGEIM_SUMMON);
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target, SPELL_RUNE_OF_SUMMONING);
- events.Repeat(30s, 45s);
- break;
- case EVENT_ENRAGE:
- me->CastSpell(me, SPELL_BERSERK, true);
- Talk(SAY_MOLGEIM_BERSERK);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class npc_assembly_lightning : public CreatureScript
-{
-public:
- npc_assembly_lightning() : CreatureScript("npc_assembly_lightning") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_assembly_lightningAI : public ScriptedAI
- {
- npc_assembly_lightningAI(Creature* c) : ScriptedAI(c)
- {
- _boomed = false;
- }
-
- void MoveInLineOfSight(Unit*) override {}
- void AttackStart(Unit*) override {}
- void UpdateAI(uint32) override {}
- void EnterEvadeMode(EvadeReason /* why */) override {}
- void OnCharmed(bool /*apply*/) override {}
-
- bool _boomed;
-
- void Reset() override
- {
- if (Player* target = SelectTargetFromPlayerList(150))
- me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f);
- else
- me->DespawnOrUnsummon(1);
- }
-
- void MovementInform(uint32 type, uint32 /*id*/) override
- {
- if (type == FOLLOW_MOTION_TYPE && !_boomed)
- {
- _boomed = true;
- me->CastSpell(me, SPELL_LIGHTNING_BLAST, true);
- me->DespawnOrUnsummon(1000);
- }
- }
- };
-};
-
-class boss_stormcaller_brundir : public CreatureScript
-{
-public:
- boss_stormcaller_brundir() : CreatureScript("boss_stormcaller_brundir") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_stormcaller_brundirAI : public ScriptedAI
- {
- boss_stormcaller_brundirAI(Creature* c) : ScriptedAI(c)
- {
- pInstance = c->GetInstanceScript();
- }
-
- EventMap events;
- InstanceScript* pInstance;
- uint32 _phase;
- ObjectGuid _flyTargetGUID;
- uint32 _channelTimer;
-
- bool _stunnedAchievement;
-
- void Reset() override
- {
- me->SetLootMode(0);
- RespawnAssemblyOfIron(pInstance, me);
-
- _channelTimer = 0;
- _phase = 0;
- _flyTargetGUID.Clear();
- _stunnedAchievement = true;
-
- events.Reset();
-
- me->SetDisableGravity(false);
- me->SetRegeneratingHealth(true);
- me->SetReactState(REACT_AGGRESSIVE);
- if (pInstance)
- pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED);
- }
-
- void JustReachedHome() override
- {
- me->setActive(false);
- me->RemoveAllAuras();
- }
-
- void JustEngagedWith(Unit* who) override
- {
- me->InterruptNonMeleeSpells(false);
- me->setActive(true);
- me->SetInCombatWithZone();
- events.ScheduleEvent(EVENT_ENRAGE, 15min);
- UpdatePhase();
-
- if (!pInstance)
- return;
-
- for (uint8 i = 0; i < 3; ++i)
- if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i)))
- if (!boss->IsInCombat())
- boss->AI()->AttackStart(who);
- }
-
- void UpdatePhase()
- {
- if (_phase >= 3)
- return;
-
- ++_phase;
-
- switch (_phase)
- {
- case 1:
- events.RescheduleEvent(EVENT_CHAIN_LIGHTNING, 9s, 17s);
- events.RescheduleEvent(EVENT_OVERLOAD, 25s, 40s);
- break;
- case 2:
- events.RescheduleEvent(EVENT_LIGHTNING_WHIRL, 20s, 40s);
- break;
- case 3:
- me->ResetLootMode();
- me->CastSpell(me, SPELL_STORMSHIELD, true);
- events.RescheduleEvent(EVENT_LIGHTNING_TENDRILS, 15s, 16s);
- break;
- }
- }
-
- void JustDied(Unit* /*Killer*/) override
- {
- if (!pInstance)
- return;
- me->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), 427.5, me->GetOrientation());
- if (IsEncounterComplete(pInstance, me))
- {
- pInstance->SetData(TYPE_ASSEMBLY, DONE);
- me->CastSpell(me, 65195, true); // credit
- Talk(SAY_BRUNDIR_ENCOUNTER_DEFEATED);
- }
- else
- {
- RestoreAssemblyHealth(pInstance->GetGuidData(DATA_STEELBREAKER), pInstance->GetGuidData(DATA_MOLGEIM), me);
- me->CastSpell(me, SPELL_SUPERCHARGE, true);
- Talk(SAY_BRUNDIR_DEATH);
- }
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
- return;
-
- Talk(SAY_BRUNDIR_SLAY);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
- {
- if (spellInfo->Id == SPELL_SUPERCHARGE)
- UpdatePhase();
- }
-
- void SpellHitTarget(Unit* /*target*/, SpellInfo const* spellInfo) override
- {
- if (spellInfo->Id == SPELL_CHAIN_LIGHTNING || spellInfo->Id == uint32(RAID_MODE(61916, 63482))) // Lightning Whirl triggered
- _stunnedAchievement = false;
- }
-
- uint32 GetData(uint32 param) const override
- {
- if (param == DATA_BRUNDIR)
- return _stunnedAchievement;
-
- return 0;
- }
-
- void MovementInform(uint32 type, uint32 point) override
- {
- if (type == POINT_MOTION_TYPE && point == POINT_CHANNEL_STEELBREAKER)
- me->CastSpell(me, SPELL_LIGHTNING_CHANNEL_PRE, true);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!me->IsInCombat() && me->GetReactState() == REACT_AGGRESSIVE)
- {
- _channelTimer += diff;
- if (_channelTimer >= 10000)
- {
- _channelTimer = 0;
- float o = urand(0, 5) * M_PI / 3.0f;
- me->InterruptNonMeleeSpells(false);
- me->GetMotionMaster()->MovePoint(POINT_CHANNEL_STEELBREAKER, 1587.18f + 10.0f * cos(o), 121.02f + 10.0f * std::sin(o), 427.3f);
- }
- }
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_CHAIN_LIGHTNING:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target, SPELL_CHAIN_LIGHTNING, false);
-
- events.Repeat(9s, 17s);
- break;
- case EVENT_OVERLOAD:
- Talk(EMOTE_BRUNDIR_OVERLOAD);
- me->CastSpell(me, SPELL_OVERLOAD, true);
- events.RescheduleEvent(EVENT_OVERLOAD, 25s, 40s);
- break;
- case EVENT_LIGHTNING_WHIRL:
- Talk(SAY_BRUNDIR_SPECIAL);
- me->CastSpell(me, SPELL_LIGHTNING_WHIRL, true);
- events.Repeat(10s, 25s);
- break;
- case EVENT_LIGHTNING_TENDRILS:
- {
- // Reschedule old
- events.Repeat(35s);
- events.DelayEvents(18s);
- Talk(SAY_BRUNDIR_FLIGHT);
-
- Unit* oldVictim = me->GetVictim();
- _flyTargetGUID = oldVictim->GetGUID();
- me->SetRegeneratingHealth(false);
- me->SetDisableGravity(true);
- me->SetHover(true);
-
- me->CombatStop();
- me->StopMoving();
- me->SetReactState(REACT_PASSIVE);
- me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty);
- me->SetUnitFlag(UNIT_FLAG_STUNNED);
-
- me->CastSpell(me, SPELL_LIGHTNING_TENDRILS, true);
- me->CastSpell(me, 61883, true);
- events.ScheduleEvent(EVENT_LIGHTNING_LAND, 16s);
- events.ScheduleEvent(EVENT_LIGHTNING_FLIGHT, 1s);
- break;
- }
- case EVENT_LIGHTNING_LAND:
- {
- float speed = me->GetDistance(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()) / (1000.0f * 0.001f);
- me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), speed);
- events.ScheduleEvent(EVENT_LAND_LAND, 1s);
- break;
- }
- case EVENT_LAND_LAND:
- me->SetCanFly(false);
- me->SetHover(false);
- me->SetReactState(REACT_AGGRESSIVE);
- me->SetDisableGravity(false);
- if (Unit* flyTarget = ObjectAccessor::GetUnit(*me, _flyTargetGUID))
- {
- me->Attack(flyTarget, false);
- }
-
- me->SetRegeneratingHealth(true);
- _flyTargetGUID.Clear();
- me->RemoveAura(SPELL_LIGHTNING_TENDRILS);
- me->RemoveAura(61883);
- DoResetThreatList();
- events.CancelEvent(EVENT_LIGHTNING_FLIGHT);
- break;
- case EVENT_ENRAGE:
- Talk(SAY_BRUNDIR_BERSERK);
- me->CastSpell(me, SPELL_BERSERK, true);
- break;
- case EVENT_LIGHTNING_FLIGHT:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
- {
- me->GetMotionMaster()->MovePoint(0, *target);
- }
- events.ScheduleEvent(EVENT_LIGHTNING_FLIGHT, 6s);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class spell_shield_of_runes : public SpellScriptLoader
-{
-public:
- spell_shield_of_runes() : SpellScriptLoader("spell_shield_of_runes") { }
-
- class spell_shield_of_runes_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_shield_of_runes_AuraScript);
-
- void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* owner = GetUnitOwner())
- if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL && aurEff->GetAmount() <= 0)
- owner->CastSpell(owner, SPELL_SHIELD_OF_RUNES_BUFF, false);
- }
-
- void Register() override
- {
- AfterEffectRemove += AuraEffectRemoveFn(spell_shield_of_runes_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_shield_of_runes_AuraScript();
- }
-};
-
-class spell_assembly_meltdown : public SpellScriptLoader
-{
-public:
- spell_assembly_meltdown() : SpellScriptLoader("spell_assembly_meltdown") { }
-
- class spell_assembly_meltdown_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_assembly_meltdown_SpellScript);
-
- void HandleInstaKill(SpellEffIndex /*effIndex*/)
- {
- if (InstanceScript* instance = GetCaster()->GetInstanceScript())
- if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_STEELBREAKER)))
- Steelbreaker->AI()->DoAction(ACTION_ADD_CHARGE);
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_assembly_meltdown_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_assembly_meltdown_SpellScript();
- }
-};
-
-class spell_assembly_rune_of_summoning : public SpellScriptLoader
-{
-public:
- spell_assembly_rune_of_summoning() : SpellScriptLoader("spell_assembly_rune_of_summoning") { }
-
- class spell_assembly_rune_of_summoning_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_assembly_rune_of_summoning_AuraScript);
-
- void OnPeriodic(AuraEffect const* aurEff)
- {
- PreventDefaultAction();
- if (aurEff->GetTickNumber() % 2 == 0)
- GetTarget()->CastSpell(GetTarget(), SPELL_RUNE_OF_SUMMONING_SUMMON, true, nullptr, aurEff, GetTarget()->IsSummon() ? GetTarget()->ToTempSummon()->GetSummonerGUID() : ObjectGuid::Empty);
- }
-
- void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (TempSummon* summ = GetTarget()->ToTempSummon())
- summ->DespawnOrUnsummon(1);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_assembly_rune_of_summoning_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
- OnEffectRemove += AuraEffectRemoveFn(spell_assembly_rune_of_summoning_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_assembly_rune_of_summoning_AuraScript();
- }
-};
-
-class achievement_assembly_of_iron : public AchievementCriteriaScript
-{
-public:
- achievement_assembly_of_iron(char const* name, uint32 entry) : AchievementCriteriaScript(name),
- _targetEntry(entry)
- {
- }
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetAuraCount(SPELL_SUPERCHARGE) >= 2 && (!_targetEntry || target->GetEntry() == _targetEntry);
- }
-
-private:
- uint32 const _targetEntry;
-};
-
-class achievement_cant_do_that_while_stunned : public AchievementCriteriaScript
-{
-public:
- achievement_cant_do_that_while_stunned() : AchievementCriteriaScript("achievement_cant_do_that_while_stunned") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- bool allow = target && target->GetAuraCount(SPELL_SUPERCHARGE) >= 2;
- if (!allow)
- return false;
-
- if (InstanceScript* instance = target->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(DATA_BRUNDIR)))
- return cr->AI()->GetData(DATA_BRUNDIR);
-
- return false;
- }
-};
void AddSC_boss_assembly_of_iron()
{
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.h
new file mode 100644
index 00000000000000..988d1207765070
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.h
@@ -0,0 +1,908 @@
+#ifndef BOSS_ASSEMBLY_OF_IRON_H_
+#define BOSS_ASSEMBLY_OF_IRON_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "SpellAuraEffects.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "ulduar.h"
+
+enum AssemblySpells
+{
+ // Any boss
+ SPELL_SUPERCHARGE = 61920,
+ SPELL_BERSERK = 47008,
+
+ // Steelbreaker
+ SPELL_HIGH_VOLTAGE_10 = 61890,
+ SPELL_HIGH_VOLTAGE_25 = 63498,
+ SPELL_FUSION_PUNCH_10 = 61903,
+ SPELL_FUSION_PUNCH_25 = 63493,
+ SPELL_STATIC_DISRUPTION_10 = 61911,
+ SPELL_STATIC_DISRUPTION_25 = 63495,
+ SPELL_OVERWHELMING_POWER_10 = 64637,
+ SPELL_OVERWHELMING_POWER_25 = 61888,
+ SPELL_ELECTRICAL_CHARGE = 61902,
+
+ // Runemaster Molgeim
+ SPELL_SHIELD_OF_RUNES_BUFF = 62277,
+ SPELL_SHIELD_OF_RUNES_10 = 62274,
+ SPELL_SHIELD_OF_RUNES_25 = 63489,
+ SPELL_RUNE_OF_POWER = 61973,
+ SPELL_RUNE_OF_DEATH_10 = 62269,
+ SPELL_RUNE_OF_DEATH_25 = 63490,
+ SPELL_RUNE_OF_SUMMONING = 62273,
+ SPELL_RUNE_OF_SUMMONING_SUMMON = 62020,
+ SPELL_LIGHTNING_BLAST_10 = 62054,
+ SPELL_LIGHTNING_BLAST_25 = 63491,
+ CREATURE_LIGHTNING_ELEMENTAL = 32958,
+ CREATURE_RUNE_OF_SUMMONING = 33051,
+ SPELL_RUNE_OF_POWER_OOC_CHANNEL = 61975,
+
+ // Stormcaller Brundir
+ SPELL_CHAIN_LIGHTNING_10 = 61879,
+ SPELL_CHAIN_LIGHTNING_25 = 63479,
+ SPELL_OVERLOAD_10 = 61869,
+ SPELL_OVERLOAD_25 = 63481,
+ SPELL_LIGHTNING_WHIRL_10 = 61915,
+ SPELL_LIGHTNING_WHIRL_25 = 63483,
+ SPELL_LIGHTNING_TENDRILS_10 = 61887,
+ SPELL_LIGHTNING_TENDRILS_25 = 63486,
+ SPELL_STORMSHIELD = 64187,
+ SPELL_LIGHTNING_CHANNEL_PRE = 61942,
+};
+
+#define SPELL_HIGH_VOLTAGE RAID_MODE(SPELL_HIGH_VOLTAGE_10, SPELL_HIGH_VOLTAGE_25)
+#define SPELL_FUSION_PUNCH RAID_MODE(SPELL_FUSION_PUNCH_10, SPELL_FUSION_PUNCH_25)
+#define SPELL_STATIC_DISRUPTION RAID_MODE(SPELL_STATIC_DISRUPTION_10, SPELL_STATIC_DISRUPTION_25)
+#define SPELL_OVERWHELMING_POWER RAID_MODE(SPELL_OVERWHELMING_POWER_10, SPELL_OVERWHELMING_POWER_25)
+#define SPELL_SHIELD_OF_RUNES RAID_MODE(SPELL_SHIELD_OF_RUNES_10, SPELL_SHIELD_OF_RUNES_25)
+#define SPELL_RUNE_OF_DEATH RAID_MODE(SPELL_RUNE_OF_DEATH_10, SPELL_RUNE_OF_DEATH_25)
+#define SPELL_LIGHTNING_BLAST RAID_MODE(SPELL_LIGHTNING_BLAST_10, SPELL_LIGHTNING_BLAST_25)
+#define SPELL_CHAIN_LIGHTNING RAID_MODE(SPELL_CHAIN_LIGHTNING_10, SPELL_CHAIN_LIGHTNING_25)
+#define SPELL_OVERLOAD RAID_MODE(SPELL_OVERLOAD_10, SPELL_OVERLOAD_25)
+#define SPELL_LIGHTNING_WHIRL RAID_MODE(SPELL_LIGHTNING_WHIRL_10, SPELL_LIGHTNING_WHIRL_25)
+#define SPELL_LIGHTNING_TENDRILS RAID_MODE(SPELL_LIGHTNING_TENDRILS_10, SPELL_LIGHTNING_TENDRILS_25)
+
+enum eEnums
+{
+ // Steelbreaker
+ EVENT_FUSION_PUNCH = 1,
+ EVENT_STATIC_DISRUPTION = 2,
+ EVENT_OVERWHELMING_POWER = 3,
+ //EVENT_CHECK_MAIN_TANK = 4,
+
+ // Molgeim
+ EVENT_RUNE_OF_POWER = 11,
+ EVENT_SHIELD_OF_RUNES = 12,
+ EVENT_RUNE_OF_DEATH = 13,
+ EVENT_RUNE_OF_SUMMONING = 14,
+ EVENT_LIGHTNING_BLAST = 15,
+
+ // Brundir
+ EVENT_CHAIN_LIGHTNING = 21,
+ EVENT_OVERLOAD = 22,
+ EVENT_LIGHTNING_WHIRL = 23,
+ EVENT_LIGHTNING_TENDRILS = 24,
+ EVENT_LIGHTNING_LAND = 25,
+ EVENT_LAND_LAND = 26,
+ EVENT_LIGHTNING_FLIGHT = 27,
+
+ EVENT_ENRAGE = 30
+};
+
+enum AssemblyYells
+{
+ SAY_STEELBREAKER_AGGRO = 0,
+ SAY_STEELBREAKER_SLAY = 1,
+ SAY_STEELBREAKER_POWER = 2,
+ SAY_STEELBREAKER_DEATH = 3,
+ SAY_STEELBREAKER_ENCOUNTER_DEFEATED = 4,
+ SAY_STEELBREAKER_BERSERK = 5,
+
+ SAY_MOLGEIM_AGGRO = 0,
+ SAY_MOLGEIM_SLAY = 1,
+ SAY_MOLGEIM_RUNE_DEATH = 2,
+ SAY_MOLGEIM_SUMMON = 3,
+ SAY_MOLGEIM_DEATH = 4,
+ SAY_MOLGEIM_ENCOUNTER_DEFEATED = 5,
+ SAY_MOLGEIM_BERSERK = 6,
+
+ SAY_BRUNDIR_AGGRO = 0,
+ SAY_BRUNDIR_SLAY = 1,
+ SAY_BRUNDIR_SPECIAL = 2,
+ SAY_BRUNDIR_FLIGHT = 3,
+ SAY_BRUNDIR_DEATH = 4,
+ SAY_BRUNDIR_ENCOUNTER_DEFEATED = 5,
+ SAY_BRUNDIR_BERSERK = 6,
+ EMOTE_BRUNDIR_OVERLOAD = 7
+};
+
+enum Misc
+{
+ ACTION_ADD_CHARGE = 1,
+ POINT_CHANNEL_STEELBREAKER = 1
+};
+
+class boss_steelbreaker : public CreatureScript
+{
+public:
+ boss_steelbreaker() : CreatureScript("boss_steelbreaker") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_steelbreakerAI : public ScriptedAI
+ {
+ boss_steelbreakerAI(Creature* c) : ScriptedAI(c)
+ {
+ pInstance = c->GetInstanceScript();
+ }
+
+ EventMap events;
+ InstanceScript* pInstance;
+ uint8 _phase;
+
+ void Reset() override
+ {
+ me->SetLootMode(0);
+ RespawnAssemblyOfIron(pInstance, me);
+
+ _phase = 0;
+ events.Reset();
+ if (pInstance)
+ pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED);
+ }
+
+ void JustReachedHome() override
+ {
+ me->setActive(false);
+ me->RemoveAllAuras();
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ if (pInstance)
+ pInstance->SetData(TYPE_ASSEMBLY, IN_PROGRESS);
+
+ me->setActive(true);
+ me->SetInCombatWithZone();
+ me->CastSpell(me, SPELL_HIGH_VOLTAGE, true);
+ events.ScheduleEvent(EVENT_ENRAGE, 15min);
+ UpdatePhase();
+
+ if (!pInstance)
+ return;
+
+ if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + urand(0, 2))))
+ {
+ switch (boss->GetEntry())
+ {
+ case NPC_STEELBREAKER:
+ boss->AI()->Talk(SAY_STEELBREAKER_AGGRO);
+ break;
+ case NPC_MOLGEIM:
+ boss->AI()->Talk(SAY_MOLGEIM_AGGRO);
+ break;
+ case NPC_BRUNDIR:
+ boss->AI()->Talk(SAY_BRUNDIR_AGGRO);
+ break;
+ }
+ }
+
+ for (uint8 i = 0; i < 3; ++i)
+ if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i)))
+ if (!boss->IsInCombat())
+ boss->AI()->AttackStart(who);
+ }
+
+ void UpdatePhase()
+ {
+ if (_phase >= 3)
+ return;
+
+ ++_phase;
+
+ switch (_phase)
+ {
+ case 1:
+ events.RescheduleEvent(EVENT_FUSION_PUNCH, 15s);
+ break;
+ case 2:
+ events.RescheduleEvent(EVENT_STATIC_DISRUPTION, 20s);
+ break;
+ case 3:
+ me->ResetLootMode();
+ events.RescheduleEvent(EVENT_OVERWHELMING_POWER, 8s);
+ break;
+ }
+ }
+
+ void JustDied(Unit* /*Killer*/) override
+ {
+ if (!pInstance)
+ return;
+
+ if (IsEncounterComplete(pInstance, me))
+ {
+ pInstance->SetData(TYPE_ASSEMBLY, DONE);
+ me->CastSpell(me, 65195, true); // credit
+ Talk(SAY_STEELBREAKER_ENCOUNTER_DEFEATED);
+ }
+ else
+ {
+ RestoreAssemblyHealth(pInstance->GetGuidData(DATA_BRUNDIR), pInstance->GetGuidData(DATA_MOLGEIM), me);
+ me->CastSpell(me, SPELL_SUPERCHARGE, true);
+ Talk(SAY_STEELBREAKER_DEATH);
+ }
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ if (_phase == 3)
+ me->CastSpell(me, SPELL_ELECTRICAL_CHARGE, true);
+
+ Talk(SAY_STEELBREAKER_SLAY);
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_ADD_CHARGE)
+ me->CastSpell(me, SPELL_ELECTRICAL_CHARGE, true);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_SUPERCHARGE)
+ UpdatePhase();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch(events.ExecuteEvent())
+ {
+ case EVENT_FUSION_PUNCH:
+ me->CastSpell(me->GetVictim(), SPELL_FUSION_PUNCH, false);
+ events.Repeat(15s, 20s);
+ break;
+ case EVENT_STATIC_DISRUPTION:
+ if (Unit* pTarget = SelectTarget(SelectTargetMethod::MinDistance, 0, 0, true))
+ me->CastSpell(pTarget, SPELL_STATIC_DISRUPTION, false);
+
+ events.Repeat(20s, 40s);
+ break;
+ case EVENT_OVERWHELMING_POWER:
+ Talk(SAY_STEELBREAKER_POWER);
+ me->CastSpell(me->GetVictim(), SPELL_OVERWHELMING_POWER, true);
+ events.RepeatEvent(RAID_MODE(61000, 36000));
+ break;
+ case EVENT_ENRAGE:
+ Talk(SAY_STEELBREAKER_BERSERK);
+ me->CastSpell(me, SPELL_BERSERK, true);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class CastRunesEvent : public BasicEvent
+{
+public:
+ CastRunesEvent(Creature& owner) : BasicEvent(), _owner(owner) { }
+
+ bool Execute(uint64 /*eventTime*/, uint32 /*diff*/) override
+ {
+ if (!_owner.IsInCombat())
+ _owner.CastSpell(&_owner, SPELL_RUNE_OF_POWER_OOC_CHANNEL, true);
+ return true;
+ }
+
+private:
+ Creature& _owner;
+};
+
+class boss_runemaster_molgeim : public CreatureScript
+{
+public:
+ boss_runemaster_molgeim() : CreatureScript("boss_runemaster_molgeim") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_runemaster_molgeimAI : public ScriptedAI
+ {
+ boss_runemaster_molgeimAI(Creature* c) : ScriptedAI(c), summons(me)
+ {
+ pInstance = c->GetInstanceScript();
+ }
+
+ InstanceScript* pInstance;
+ SummonList summons;
+ EventMap events;
+ uint8 _phase;
+
+ void Reset() override
+ {
+ me->SetLootMode(0);
+ RespawnAssemblyOfIron(pInstance, me);
+
+ _phase = 0;
+ events.Reset();
+ summons.DespawnAll();
+
+ if (pInstance)
+ pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED);
+
+ me->m_Events.AddEvent(new CastRunesEvent(*me), me->m_Events.CalculateTime(8000));
+ }
+
+ void JustReachedHome() override
+ {
+ me->setActive(false);
+ me->RemoveAllAuras();
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ me->InterruptNonMeleeSpells(false);
+ me->setActive(true);
+ me->SetInCombatWithZone();
+ events.ScheduleEvent(EVENT_ENRAGE, 15min);
+ UpdatePhase();
+
+ if (!pInstance)
+ return;
+
+ for (uint8 i = 0; i < 3; ++i)
+ if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i)))
+ if (!boss->IsInCombat())
+ boss->AI()->AttackStart(who);
+ }
+
+ void UpdatePhase()
+ {
+ if (_phase >= 3)
+ return;
+
+ ++_phase;
+
+ switch (_phase)
+ {
+ case 1:
+ events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 20s);
+ events.RescheduleEvent(EVENT_RUNE_OF_POWER, 30s);
+ break;
+ case 2:
+ events.RescheduleEvent(EVENT_RUNE_OF_DEATH, 35s);
+ break;
+ case 3:
+ me->ResetLootMode();
+ events.RescheduleEvent(EVENT_RUNE_OF_SUMMONING, 20s, 30s);
+ break;
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (!pInstance)
+ return;
+
+ if (IsEncounterComplete(pInstance, me))
+ {
+ pInstance->SetData(TYPE_ASSEMBLY, DONE);
+ me->CastSpell(me, 65195, true); // credit
+ Talk(SAY_MOLGEIM_ENCOUNTER_DEFEATED);
+ }
+ else
+ {
+ RestoreAssemblyHealth(pInstance->GetGuidData(DATA_STEELBREAKER), pInstance->GetGuidData(DATA_BRUNDIR), me);
+ me->CastSpell(me, SPELL_SUPERCHARGE, true);
+ Talk(SAY_MOLGEIM_DEATH);
+ }
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Talk(SAY_MOLGEIM_SLAY);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_SUPERCHARGE)
+ UpdatePhase();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch(events.ExecuteEvent())
+ {
+ case EVENT_RUNE_OF_POWER:
+ {
+ Unit* target = DoSelectLowestHpFriendly(60);
+ if (!target || !target->IsAlive())
+ target = me;
+
+ me->CastSpell(target, SPELL_RUNE_OF_POWER, true);
+ events.Repeat(1min);
+ break;
+ }
+ case EVENT_SHIELD_OF_RUNES:
+ me->CastSpell(me, SPELL_SHIELD_OF_RUNES, false);
+ events.RescheduleEvent(EVENT_SHIELD_OF_RUNES, 27s, 34s);
+ break;
+ case EVENT_RUNE_OF_DEATH:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random))
+ me->CastSpell(target, SPELL_RUNE_OF_DEATH, true);
+
+ Talk(SAY_MOLGEIM_RUNE_DEATH);
+ events.Repeat(30s, 40s);
+ break;
+ case EVENT_RUNE_OF_SUMMONING:
+ Talk(SAY_MOLGEIM_SUMMON);
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target, SPELL_RUNE_OF_SUMMONING);
+ events.Repeat(30s, 45s);
+ break;
+ case EVENT_ENRAGE:
+ me->CastSpell(me, SPELL_BERSERK, true);
+ Talk(SAY_MOLGEIM_BERSERK);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class npc_assembly_lightning : public CreatureScript
+{
+public:
+ npc_assembly_lightning() : CreatureScript("npc_assembly_lightning") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_assembly_lightningAI : public ScriptedAI
+ {
+ npc_assembly_lightningAI(Creature* c) : ScriptedAI(c)
+ {
+ _boomed = false;
+ }
+
+ void MoveInLineOfSight(Unit*) override {}
+ void AttackStart(Unit*) override {}
+ void UpdateAI(uint32) override {}
+ void EnterEvadeMode(EvadeReason /* why */) override {}
+ void OnCharmed(bool /*apply*/) override {}
+
+ bool _boomed;
+
+ void Reset() override
+ {
+ if (Player* target = SelectTargetFromPlayerList(150))
+ me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f);
+ else
+ me->DespawnOrUnsummon(1);
+ }
+
+ void MovementInform(uint32 type, uint32 /*id*/) override
+ {
+ if (type == FOLLOW_MOTION_TYPE && !_boomed)
+ {
+ _boomed = true;
+ me->CastSpell(me, SPELL_LIGHTNING_BLAST, true);
+ me->DespawnOrUnsummon(1000);
+ }
+ }
+ };
+};
+
+class boss_stormcaller_brundir : public CreatureScript
+{
+public:
+ boss_stormcaller_brundir() : CreatureScript("boss_stormcaller_brundir") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_stormcaller_brundirAI : public ScriptedAI
+ {
+ boss_stormcaller_brundirAI(Creature* c) : ScriptedAI(c)
+ {
+ pInstance = c->GetInstanceScript();
+ }
+
+ EventMap events;
+ InstanceScript* pInstance;
+ uint32 _phase;
+ ObjectGuid _flyTargetGUID;
+ uint32 _channelTimer;
+
+ bool _stunnedAchievement;
+
+ void Reset() override
+ {
+ me->SetLootMode(0);
+ RespawnAssemblyOfIron(pInstance, me);
+
+ _channelTimer = 0;
+ _phase = 0;
+ _flyTargetGUID.Clear();
+ _stunnedAchievement = true;
+
+ events.Reset();
+
+ me->SetDisableGravity(false);
+ me->SetRegeneratingHealth(true);
+ me->SetReactState(REACT_AGGRESSIVE);
+ if (pInstance)
+ pInstance->SetData(TYPE_ASSEMBLY, NOT_STARTED);
+ }
+
+ void JustReachedHome() override
+ {
+ me->setActive(false);
+ me->RemoveAllAuras();
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ me->InterruptNonMeleeSpells(false);
+ me->setActive(true);
+ me->SetInCombatWithZone();
+ events.ScheduleEvent(EVENT_ENRAGE, 15min);
+ UpdatePhase();
+
+ if (!pInstance)
+ return;
+
+ for (uint8 i = 0; i < 3; ++i)
+ if (Creature* boss = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_STEELBREAKER + i)))
+ if (!boss->IsInCombat())
+ boss->AI()->AttackStart(who);
+ }
+
+ void UpdatePhase()
+ {
+ if (_phase >= 3)
+ return;
+
+ ++_phase;
+
+ switch (_phase)
+ {
+ case 1:
+ events.RescheduleEvent(EVENT_CHAIN_LIGHTNING, 9s, 17s);
+ events.RescheduleEvent(EVENT_OVERLOAD, 25s, 40s);
+ break;
+ case 2:
+ events.RescheduleEvent(EVENT_LIGHTNING_WHIRL, 20s, 40s);
+ break;
+ case 3:
+ me->ResetLootMode();
+ me->CastSpell(me, SPELL_STORMSHIELD, true);
+ events.RescheduleEvent(EVENT_LIGHTNING_TENDRILS, 15s, 16s);
+ break;
+ }
+ }
+
+ void JustDied(Unit* /*Killer*/) override
+ {
+ if (!pInstance)
+ return;
+ me->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), 427.5, me->GetOrientation());
+ if (IsEncounterComplete(pInstance, me))
+ {
+ pInstance->SetData(TYPE_ASSEMBLY, DONE);
+ me->CastSpell(me, 65195, true); // credit
+ Talk(SAY_BRUNDIR_ENCOUNTER_DEFEATED);
+ }
+ else
+ {
+ RestoreAssemblyHealth(pInstance->GetGuidData(DATA_STEELBREAKER), pInstance->GetGuidData(DATA_MOLGEIM), me);
+ me->CastSpell(me, SPELL_SUPERCHARGE, true);
+ Talk(SAY_BRUNDIR_DEATH);
+ }
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
+ return;
+
+ Talk(SAY_BRUNDIR_SLAY);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_SUPERCHARGE)
+ UpdatePhase();
+ }
+
+ void SpellHitTarget(Unit* /*target*/, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_CHAIN_LIGHTNING || spellInfo->Id == uint32(RAID_MODE(61916, 63482))) // Lightning Whirl triggered
+ _stunnedAchievement = false;
+ }
+
+ uint32 GetData(uint32 param) const override
+ {
+ if (param == DATA_BRUNDIR)
+ return _stunnedAchievement;
+
+ return 0;
+ }
+
+ void MovementInform(uint32 type, uint32 point) override
+ {
+ if (type == POINT_MOTION_TYPE && point == POINT_CHANNEL_STEELBREAKER)
+ me->CastSpell(me, SPELL_LIGHTNING_CHANNEL_PRE, true);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!me->IsInCombat() && me->GetReactState() == REACT_AGGRESSIVE)
+ {
+ _channelTimer += diff;
+ if (_channelTimer >= 10000)
+ {
+ _channelTimer = 0;
+ float o = urand(0, 5) * M_PI / 3.0f;
+ me->InterruptNonMeleeSpells(false);
+ me->GetMotionMaster()->MovePoint(POINT_CHANNEL_STEELBREAKER, 1587.18f + 10.0f * cos(o), 121.02f + 10.0f * std::sin(o), 427.3f);
+ }
+ }
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_CHAIN_LIGHTNING:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target, SPELL_CHAIN_LIGHTNING, false);
+
+ events.Repeat(9s, 17s);
+ break;
+ case EVENT_OVERLOAD:
+ Talk(EMOTE_BRUNDIR_OVERLOAD);
+ me->CastSpell(me, SPELL_OVERLOAD, true);
+ events.RescheduleEvent(EVENT_OVERLOAD, 25s, 40s);
+ break;
+ case EVENT_LIGHTNING_WHIRL:
+ Talk(SAY_BRUNDIR_SPECIAL);
+ me->CastSpell(me, SPELL_LIGHTNING_WHIRL, true);
+ events.Repeat(10s, 25s);
+ break;
+ case EVENT_LIGHTNING_TENDRILS:
+ {
+ // Reschedule old
+ events.Repeat(35s);
+ events.DelayEvents(18s);
+ Talk(SAY_BRUNDIR_FLIGHT);
+
+ Unit* oldVictim = me->GetVictim();
+ _flyTargetGUID = oldVictim->GetGUID();
+ me->SetRegeneratingHealth(false);
+ me->SetDisableGravity(true);
+ me->SetHover(true);
+
+ me->CombatStop();
+ me->StopMoving();
+ me->SetReactState(REACT_PASSIVE);
+ me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty);
+ me->SetUnitFlag(UNIT_FLAG_STUNNED);
+
+ me->CastSpell(me, SPELL_LIGHTNING_TENDRILS, true);
+ me->CastSpell(me, 61883, true);
+ events.ScheduleEvent(EVENT_LIGHTNING_LAND, 16s);
+ events.ScheduleEvent(EVENT_LIGHTNING_FLIGHT, 1s);
+ break;
+ }
+ case EVENT_LIGHTNING_LAND:
+ {
+ float speed = me->GetDistance(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()) / (1000.0f * 0.001f);
+ me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), speed);
+ events.ScheduleEvent(EVENT_LAND_LAND, 1s);
+ break;
+ }
+ case EVENT_LAND_LAND:
+ me->SetCanFly(false);
+ me->SetHover(false);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->SetDisableGravity(false);
+ if (Unit* flyTarget = ObjectAccessor::GetUnit(*me, _flyTargetGUID))
+ {
+ me->Attack(flyTarget, false);
+ }
+
+ me->SetRegeneratingHealth(true);
+ _flyTargetGUID.Clear();
+ me->RemoveAura(SPELL_LIGHTNING_TENDRILS);
+ me->RemoveAura(61883);
+ DoResetThreatList();
+ events.CancelEvent(EVENT_LIGHTNING_FLIGHT);
+ break;
+ case EVENT_ENRAGE:
+ Talk(SAY_BRUNDIR_BERSERK);
+ me->CastSpell(me, SPELL_BERSERK, true);
+ break;
+ case EVENT_LIGHTNING_FLIGHT:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
+ {
+ me->GetMotionMaster()->MovePoint(0, *target);
+ }
+ events.ScheduleEvent(EVENT_LIGHTNING_FLIGHT, 6s);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class spell_shield_of_runes : public SpellScriptLoader
+{
+public:
+ spell_shield_of_runes() : SpellScriptLoader("spell_shield_of_runes") { }
+
+ class spell_shield_of_runes_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_shield_of_runes_AuraScript);
+
+ void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* owner = GetUnitOwner())
+ if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL && aurEff->GetAmount() <= 0)
+ owner->CastSpell(owner, SPELL_SHIELD_OF_RUNES_BUFF, false);
+ }
+
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_shield_of_runes_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_shield_of_runes_AuraScript();
+ }
+};
+
+class spell_assembly_meltdown : public SpellScriptLoader
+{
+public:
+ spell_assembly_meltdown() : SpellScriptLoader("spell_assembly_meltdown") { }
+
+ class spell_assembly_meltdown_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_assembly_meltdown_SpellScript);
+
+ void HandleInstaKill(SpellEffIndex /*effIndex*/)
+ {
+ if (InstanceScript* instance = GetCaster()->GetInstanceScript())
+ if (Creature* Steelbreaker = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_STEELBREAKER)))
+ Steelbreaker->AI()->DoAction(ACTION_ADD_CHARGE);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_assembly_meltdown_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_assembly_meltdown_SpellScript();
+ }
+};
+
+class spell_assembly_rune_of_summoning : public SpellScriptLoader
+{
+public:
+ spell_assembly_rune_of_summoning() : SpellScriptLoader("spell_assembly_rune_of_summoning") { }
+
+ class spell_assembly_rune_of_summoning_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_assembly_rune_of_summoning_AuraScript);
+
+ void OnPeriodic(AuraEffect const* aurEff)
+ {
+ PreventDefaultAction();
+ if (aurEff->GetTickNumber() % 2 == 0)
+ GetTarget()->CastSpell(GetTarget(), SPELL_RUNE_OF_SUMMONING_SUMMON, true, nullptr, aurEff, GetTarget()->IsSummon() ? GetTarget()->ToTempSummon()->GetSummonerGUID() : ObjectGuid::Empty);
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (TempSummon* summ = GetTarget()->ToTempSummon())
+ summ->DespawnOrUnsummon(1);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_assembly_rune_of_summoning_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ OnEffectRemove += AuraEffectRemoveFn(spell_assembly_rune_of_summoning_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_assembly_rune_of_summoning_AuraScript();
+ }
+};
+
+class achievement_assembly_of_iron : public AchievementCriteriaScript
+{
+public:
+ achievement_assembly_of_iron(char const* name, uint32 entry) : AchievementCriteriaScript(name),
+ _targetEntry(entry)
+ {
+ }
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetAuraCount(SPELL_SUPERCHARGE) >= 2 && (!_targetEntry || target->GetEntry() == _targetEntry);
+ }
+
+private:
+ uint32 const _targetEntry;
+};
+
+class achievement_cant_do_that_while_stunned : public AchievementCriteriaScript
+{
+public:
+ achievement_cant_do_that_while_stunned() : AchievementCriteriaScript("achievement_cant_do_that_while_stunned") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ bool allow = target && target->GetAuraCount(SPELL_SUPERCHARGE) >= 2;
+ if (!allow)
+ return false;
+
+ if (InstanceScript* instance = target->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(DATA_BRUNDIR)))
+ return cr->AI()->GetData(DATA_BRUNDIR);
+
+ return false;
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp
index 904e01a8fd44c6..6c3308f663e46e 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_auriaya.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "Player.h"
@@ -24,472 +25,6 @@
#include "SpellScriptLoader.h"
#include "ulduar.h"
-enum AuriayaSpells
-{
- // BASIC
- SPELL_TERRIFYING_SCREECH = 64386,
- SPELL_SENTINEL_BLAST_10 = 64389,
- SPELL_SENTINEL_BLAST_25 = 64678,
- SPELL_SONIC_SCREECH_10 = 64422,
- SPELL_SONIC_SCREECH_25 = 64688,
- SPELL_GUARDIAN_SWARM = 64396,
- SPELL_ENRAGE = 47008,
- SPELL_ACTIVATE_FERAL_DEFENDER = 64449,
-
- // Sanctum Sentry
- SPELL_SAVAGE_POUNCE_10 = 64666,
- SPELL_SAVAGE_POUNCE_25 = 64374,
- SPELL_RIP_FLESH_10 = 64375,
- SPELL_RIP_FLESH_25 = 64667,
- SPELL_STRENGTH_OF_THE_PACK = 64369,
-
- // Feral Defender
- SPELL_FERAL_ESSENCE = 64455,
- SPELL_FERAL_POUNCE_10 = 64478,
- SPELL_FERAL_POUNCE_25 = 64669,
- SPELL_FERAL_RUSH_10 = 64496,
- SPELL_FERAL_RUSH_25 = 64674,
- //SPELL_SEEPING_FERAL_ESSENCE_SUMMON = 64457,
- SPELL_SEEPING_FERAL_ESSENCE_10 = 64458,
- SPELL_SEEPING_FERAL_ESSENCE_25 = 64676,
-};
-
-#define SPELL_SONIC_SCREECH RAID_MODE(SPELL_SONIC_SCREECH_10, SPELL_SONIC_SCREECH_25)
-#define SPELL_SENTINEL_BLAST RAID_MODE(SPELL_SENTINEL_BLAST_10, SPELL_SENTINEL_BLAST_25)
-#define SPELL_SAVAGE_POUNCE RAID_MODE(SPELL_SAVAGE_POUNCE_10, SPELL_SAVAGE_POUNCE_25)
-#define SPELL_RIP_FLESH RAID_MODE(SPELL_RIP_FLESH_10, SPELL_RIP_FLESH_25)
-#define SPELL_FERAL_POUNCE RAID_MODE(SPELL_FERAL_POUNCE_10, SPELL_FERAL_POUNCE_25)
-#define SPELL_FERAL_RUSH RAID_MODE(SPELL_FERAL_RUSH_10, SPELL_FERAL_RUSH_25)
-//#define SPELL_SEEPING_FERAL_ESSENCE RAID_MODE(SPELL_SEEPING_FERAL_ESSENCE_10, SPELL_SEEPING_FERAL_ESSENCE_25)
-
-enum AuriayaNPC
-{
- NPC_FERAL_DEFENDER = 34035,
- NPC_SANCTUM_SENTRY = 34014,
- NPC_SEEPING_FERAL_ESSENCE = 34098,
-};
-
-enum AuriayaEvents
-{
- EVENT_SUMMON_FERAL_DEFENDER = 1,
- EVENT_TERRIFYING_SCREECH = 2,
- EVENT_SONIC_SCREECH = 3,
- EVENT_GUARDIAN_SWARM = 4,
- EVENT_SENTINEL_BLAST = 5,
- EVENT_REMOVE_IMMUNE = 6,
-
- EVENT_RESPAWN_FERAL_DEFENDER = 9,
- EVENT_ENRAGE = 10,
-};
-
-enum Texts
-{
- SAY_AGGRO = 0,
- SAY_SLAY = 1,
- SAY_BERSERK = 2,
- EMOTE_DEATH = 3,
- EMOTE_FEAR = 4,
- EMOTE_DEFFENDER = 5,
-};
-
-enum Misc
-{
- ACTION_FERAL_RESPAWN = 1,
- ACTION_FERAL_DEATH = 2,
- ACTION_DESPAWN_ADDS = 3,
- ACTION_FERAL_DEATH_WITH_STACK = 4,
-
- DATA_CRAZY_CAT = 10,
- DATA_NINE_LIVES = 11,
-};
-
-class boss_auriaya : public CreatureScript
-{
-public:
- boss_auriaya() : CreatureScript("boss_auriaya") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_auriayaAI : public ScriptedAI
- {
- boss_auriayaAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature)
- {
- m_pInstance = pCreature->GetInstanceScript();
- }
-
- InstanceScript* m_pInstance;
- EventMap events;
- SummonList summons;
-
- bool _feralDied;
- bool _nineLives;
-
- void Reset() override
- {
- _feralDied = false;
- _nineLives = false;
-
- events.Reset();
- EntryCheckPredicate pred(NPC_FERAL_DEFENDER);
- summons.DoAction(ACTION_DESPAWN_ADDS, pred);
- summons.DespawnAll();
-
- if (m_pInstance)
- m_pInstance->SetData(TYPE_AURIAYA, NOT_STARTED);
-
- for (uint8 i = 0; i < RAID_MODE(2, 4); ++i)
- me->SummonCreature(NPC_SANCTUM_SENTRY, me->GetPositionX() + urand(4, 12), me->GetPositionY() + urand(4, 12), me->GetPositionZ());
-
- me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false);
- }
-
- uint32 GetData(uint32 param) const override
- {
- if (param == DATA_CRAZY_CAT)
- return !_feralDied;
- else if (param == DATA_NINE_LIVES)
- return _nineLives;
-
- return 0;
- }
-
- void JustSummoned(Creature* cr) override
- {
- if (cr->GetEntry() == NPC_SANCTUM_SENTRY)
- cr->GetMotionMaster()->MoveFollow(me, 6, rand_norm() * 2 * 3.14f);
- else
- cr->SetInCombatWithZone();
-
- summons.Summon(cr);
- }
-
- void SummonedCreatureDies(Creature* cr, Unit*) override
- {
- if (cr->GetEntry() == NPC_SANCTUM_SENTRY)
- _feralDied = true;
- }
-
- void JustReachedHome() override { me->setActive(false); }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- if (m_pInstance)
- m_pInstance->SetData(TYPE_AURIAYA, IN_PROGRESS);
-
- events.ScheduleEvent(EVENT_TERRIFYING_SCREECH, 35s);
- events.ScheduleEvent(EVENT_SONIC_SCREECH, 45s);
- events.ScheduleEvent(EVENT_GUARDIAN_SWARM, 70s);
- events.ScheduleEvent(EVENT_SUMMON_FERAL_DEFENDER, 60s);
- events.ScheduleEvent(EVENT_SENTINEL_BLAST, 36s);
- events.ScheduleEvent(EVENT_ENRAGE, 10min);
-
- summons.DoZoneInCombat(NPC_SANCTUM_SENTRY);
-
- Talk(SAY_AGGRO);
- me->setActive(true);
- }
-
- void KilledUnit(Unit* victim) override
- {
- if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
- return;
-
- Talk(SAY_SLAY);
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (m_pInstance)
- m_pInstance->SetData(TYPE_AURIAYA, DONE);
-
- EntryCheckPredicate pred(NPC_FERAL_DEFENDER);
- summons.DoAction(ACTION_DESPAWN_ADDS, pred);
- summons.DespawnAll();
- Talk(EMOTE_DEATH);
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_FERAL_DEATH_WITH_STACK)
- events.ScheduleEvent(EVENT_RESPAWN_FERAL_DEFENDER, 25s);
- else if (param == ACTION_FERAL_DEATH)
- _nineLives = true;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_SUMMON_FERAL_DEFENDER:
- Talk(EMOTE_DEFFENDER);
- me->CastSpell(me, SPELL_ACTIVATE_FERAL_DEFENDER, true);
- me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true);
- events.ScheduleEvent(EVENT_REMOVE_IMMUNE, 3s);
- break;
- case EVENT_REMOVE_IMMUNE:
- me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false);
- break;
- case EVENT_TERRIFYING_SCREECH:
- Talk(EMOTE_FEAR);
- me->CastSpell(me, SPELL_TERRIFYING_SCREECH, false);
- events.Repeat(35s);
- break;
- case EVENT_SONIC_SCREECH:
- me->CastSpell(me, SPELL_SONIC_SCREECH, false);
- events.Repeat(50s);
- break;
- case EVENT_GUARDIAN_SWARM:
- me->CastSpell(me->GetVictim(), SPELL_GUARDIAN_SWARM, false);
- events.Repeat(40s);
- break;
- case EVENT_SENTINEL_BLAST:
- me->CastSpell(me, SPELL_SENTINEL_BLAST, false);
- events.Repeat(35s);
- events.DelayEvents(5000, 0);
- break;
- case EVENT_RESPAWN_FERAL_DEFENDER:
- {
- EntryCheckPredicate pred(NPC_FERAL_DEFENDER);
- summons.DoAction(ACTION_FERAL_RESPAWN, pred);
- break;
- }
- case EVENT_ENRAGE:
- Talk(SAY_BERSERK);
- me->CastSpell(me, SPELL_ENRAGE, true);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class npc_auriaya_sanctum_sentry : public CreatureScript
-{
-public:
- npc_auriaya_sanctum_sentry() : CreatureScript("npc_auriaya_sanctum_sentry") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_auriaya_sanctum_sentryAI : public ScriptedAI
- {
- npc_auriaya_sanctum_sentryAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- uint32 _savagePounceTimer;
- uint32 _ripFleshTimer;
-
- void JustEngagedWith(Unit*) override
- {
- if (me->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_AURIAYA)))
- cr->SetInCombatWithZone();
- }
-
- void Reset() override
- {
- _savagePounceTimer = 5000;
- _ripFleshTimer = 0;
-
- me->CastSpell(me, SPELL_STRENGTH_OF_THE_PACK, true);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- _savagePounceTimer += diff;
- _ripFleshTimer += diff;
-
- if (_savagePounceTimer >= 5000)
- {
- float dist = me->GetDistance(me->GetVictim());
- if (dist >= 8 && dist < 25 && me->IsWithinLOSInMap(me->GetVictim()))
- {
- me->CastSpell(me->GetVictim(), SPELL_SAVAGE_POUNCE, false);
- _savagePounceTimer = 0;
- return;
- }
- _savagePounceTimer = 200;
- }
- else if (_ripFleshTimer >= 10000)
- {
- me->CastSpell(me->GetVictim(), SPELL_RIP_FLESH, false);
- _ripFleshTimer = 0;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class npc_auriaya_feral_defender : public CreatureScript
-{
-public:
- npc_auriaya_feral_defender() : CreatureScript("npc_auriaya_feral_defender") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_auriaya_feral_defenderAI : public ScriptedAI
- {
- npc_auriaya_feral_defenderAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) { }
-
- int32 _feralRushTimer;
- int32 _feralPounceTimer;
- uint8 _feralEssenceStack;
- SummonList summons;
-
- void Reset() override
- {
- summons.DespawnAll();
- _feralRushTimer = 3000;
- _feralPounceTimer = 0;
- _feralEssenceStack = 8;
-
- if (Aura* aur = me->AddAura(SPELL_FERAL_ESSENCE, me))
- aur->SetStackAmount(_feralEssenceStack);
- }
-
- void JustDied(Unit*) override
- {
- // inform about our death, start timer
- if (me->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_AURIAYA)))
- cr->AI()->DoAction(_feralEssenceStack ? ACTION_FERAL_DEATH_WITH_STACK : ACTION_FERAL_DEATH);
-
- if (_feralEssenceStack)
- {
- if (Creature* cr = me->SummonCreature(NPC_SEEPING_FERAL_ESSENCE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.0f))
- summons.Summon(cr);
-
- --_feralEssenceStack;
- }
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_FERAL_RESPAWN)
- {
- me->setDeathState(DeathState::JustRespawned);
-
- if (Player* target = SelectTargetFromPlayerList(200))
- AttackStart(target);
- else
- {
- summons.DespawnAll();
- me->DespawnOrUnsummon(1);
- }
-
- if (_feralEssenceStack)
- if (Aura* aur = me->AddAura(SPELL_FERAL_ESSENCE, me))
- aur->SetStackAmount(_feralEssenceStack);
- }
- else if (param == ACTION_DESPAWN_ADDS)
- summons.DespawnAll();
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- _feralRushTimer += diff;
- _feralPounceTimer += diff;
-
- if (_feralRushTimer >= 6000)
- {
- DoResetThreatList();
- if (!UpdateVictim())
- return;
-
- me->CastSpell(me->GetVictim(), SPELL_FERAL_RUSH, true);
- _feralRushTimer = 0;
- }
- else if (_feralPounceTimer >= 6000)
- {
- me->CastSpell(me->GetVictim(), SPELL_FERAL_POUNCE, false);
- _feralPounceTimer = 0;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class spell_auriaya_sentinel_blast : public SpellScriptLoader
-{
-public:
- spell_auriaya_sentinel_blast() : SpellScriptLoader("spell_auriaya_sentinel_blast") { }
-
- class spell_auriaya_sentinel_blast_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_auriaya_sentinel_blast_SpellScript);
-
- void FilterTargets(std::list& unitList)
- {
- unitList.remove_if(PlayerOrPetCheck());
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_auriaya_sentinel_blast_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_auriaya_sentinel_blast_SpellScript();
- }
-};
-
-class achievement_auriaya_crazy_cat_lady : public AchievementCriteriaScript
-{
-public:
- achievement_auriaya_crazy_cat_lady() : AchievementCriteriaScript("achievement_auriaya_crazy_cat_lady") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- if (target)
- if (InstanceScript* instance = target->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_AURIAYA)))
- return cr->AI()->GetData(DATA_CRAZY_CAT);
-
- return false;
- }
-};
-
-class achievement_auriaya_nine_lives : public AchievementCriteriaScript
-{
-public:
- achievement_auriaya_nine_lives() : AchievementCriteriaScript("achievement_auriaya_nine_lives") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- if (target)
- if (InstanceScript* instance = target->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_AURIAYA)))
- return cr->AI()->GetData(DATA_NINE_LIVES);
-
- return false;
- }
-};
-
void AddSC_boss_auriaya()
{
new boss_auriaya();
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.h
new file mode 100644
index 00000000000000..69813f14dc2a71
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.h
@@ -0,0 +1,479 @@
+#ifndef BOSS_AURIAYA_H_
+#define BOSS_AURIAYA_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "SpellAuraEffects.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "ulduar.h"
+
+enum AuriayaSpells
+{
+ // BASIC
+ SPELL_TERRIFYING_SCREECH = 64386,
+ SPELL_SENTINEL_BLAST_10 = 64389,
+ SPELL_SENTINEL_BLAST_25 = 64678,
+ SPELL_SONIC_SCREECH_10 = 64422,
+ SPELL_SONIC_SCREECH_25 = 64688,
+ SPELL_GUARDIAN_SWARM = 64396,
+ SPELL_ENRAGE = 47008,
+ SPELL_ACTIVATE_FERAL_DEFENDER = 64449,
+
+ // Sanctum Sentry
+ SPELL_SAVAGE_POUNCE_10 = 64666,
+ SPELL_SAVAGE_POUNCE_25 = 64374,
+ SPELL_RIP_FLESH_10 = 64375,
+ SPELL_RIP_FLESH_25 = 64667,
+ SPELL_STRENGTH_OF_THE_PACK = 64369,
+
+ // Feral Defender
+ SPELL_FERAL_ESSENCE = 64455,
+ SPELL_FERAL_POUNCE_10 = 64478,
+ SPELL_FERAL_POUNCE_25 = 64669,
+ SPELL_FERAL_RUSH_10 = 64496,
+ SPELL_FERAL_RUSH_25 = 64674,
+ //SPELL_SEEPING_FERAL_ESSENCE_SUMMON = 64457,
+ SPELL_SEEPING_FERAL_ESSENCE_10 = 64458,
+ SPELL_SEEPING_FERAL_ESSENCE_25 = 64676,
+};
+
+#define SPELL_SONIC_SCREECH RAID_MODE(SPELL_SONIC_SCREECH_10, SPELL_SONIC_SCREECH_25)
+#define SPELL_SENTINEL_BLAST RAID_MODE(SPELL_SENTINEL_BLAST_10, SPELL_SENTINEL_BLAST_25)
+#define SPELL_SAVAGE_POUNCE RAID_MODE(SPELL_SAVAGE_POUNCE_10, SPELL_SAVAGE_POUNCE_25)
+#define SPELL_RIP_FLESH RAID_MODE(SPELL_RIP_FLESH_10, SPELL_RIP_FLESH_25)
+#define SPELL_FERAL_POUNCE RAID_MODE(SPELL_FERAL_POUNCE_10, SPELL_FERAL_POUNCE_25)
+#define SPELL_FERAL_RUSH RAID_MODE(SPELL_FERAL_RUSH_10, SPELL_FERAL_RUSH_25)
+//#define SPELL_SEEPING_FERAL_ESSENCE RAID_MODE(SPELL_SEEPING_FERAL_ESSENCE_10, SPELL_SEEPING_FERAL_ESSENCE_25)
+
+enum AuriayaNPC
+{
+ NPC_FERAL_DEFENDER = 34035,
+ NPC_SANCTUM_SENTRY = 34014,
+ NPC_SEEPING_FERAL_ESSENCE = 34098,
+};
+
+enum AuriayaEvents
+{
+ EVENT_SUMMON_FERAL_DEFENDER = 1,
+ EVENT_TERRIFYING_SCREECH = 2,
+ EVENT_SONIC_SCREECH = 3,
+ EVENT_GUARDIAN_SWARM = 4,
+ EVENT_SENTINEL_BLAST = 5,
+ EVENT_REMOVE_IMMUNE = 6,
+
+ EVENT_RESPAWN_FERAL_DEFENDER = 9,
+ EVENT_ENRAGE = 10,
+};
+
+enum Texts
+{
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_BERSERK = 2,
+ EMOTE_DEATH = 3,
+ EMOTE_FEAR = 4,
+ EMOTE_DEFFENDER = 5,
+};
+
+enum Misc
+{
+ ACTION_FERAL_RESPAWN = 1,
+ ACTION_FERAL_DEATH = 2,
+ ACTION_DESPAWN_ADDS = 3,
+ ACTION_FERAL_DEATH_WITH_STACK = 4,
+
+ DATA_CRAZY_CAT = 10,
+ DATA_NINE_LIVES = 11,
+};
+
+class boss_auriaya : public CreatureScript
+{
+public:
+ boss_auriaya() : CreatureScript("boss_auriaya") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_auriayaAI : public ScriptedAI
+ {
+ boss_auriayaAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature)
+ {
+ m_pInstance = pCreature->GetInstanceScript();
+ }
+
+ InstanceScript* m_pInstance;
+ EventMap events;
+ SummonList summons;
+
+ bool _feralDied;
+ bool _nineLives;
+
+ void Reset() override
+ {
+ _feralDied = false;
+ _nineLives = false;
+
+ events.Reset();
+ EntryCheckPredicate pred(NPC_FERAL_DEFENDER);
+ summons.DoAction(ACTION_DESPAWN_ADDS, pred);
+ summons.DespawnAll();
+
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_AURIAYA, NOT_STARTED);
+
+ for (uint8 i = 0; i < RAID_MODE(2, 4); ++i)
+ me->SummonCreature(NPC_SANCTUM_SENTRY, me->GetPositionX() + urand(4, 12), me->GetPositionY() + urand(4, 12), me->GetPositionZ());
+
+ me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false);
+ }
+
+ uint32 GetData(uint32 param) const override
+ {
+ if (param == DATA_CRAZY_CAT)
+ return !_feralDied;
+ else if (param == DATA_NINE_LIVES)
+ return _nineLives;
+
+ return 0;
+ }
+
+ void JustSummoned(Creature* cr) override
+ {
+ if (cr->GetEntry() == NPC_SANCTUM_SENTRY)
+ cr->GetMotionMaster()->MoveFollow(me, 6, rand_norm() * 2 * 3.14f);
+ else
+ cr->SetInCombatWithZone();
+
+ summons.Summon(cr);
+ }
+
+ void SummonedCreatureDies(Creature* cr, Unit*) override
+ {
+ if (cr->GetEntry() == NPC_SANCTUM_SENTRY)
+ _feralDied = true;
+ }
+
+ void JustReachedHome() override { me->setActive(false); }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_AURIAYA, IN_PROGRESS);
+
+ events.ScheduleEvent(EVENT_TERRIFYING_SCREECH, 35s);
+ events.ScheduleEvent(EVENT_SONIC_SCREECH, 45s);
+ events.ScheduleEvent(EVENT_GUARDIAN_SWARM, 70s);
+ events.ScheduleEvent(EVENT_SUMMON_FERAL_DEFENDER, 60s);
+ events.ScheduleEvent(EVENT_SENTINEL_BLAST, 36s);
+ events.ScheduleEvent(EVENT_ENRAGE, 10min);
+
+ summons.DoZoneInCombat(NPC_SANCTUM_SENTRY);
+
+ Talk(SAY_AGGRO);
+ me->setActive(true);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
+ return;
+
+ Talk(SAY_SLAY);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_AURIAYA, DONE);
+
+ EntryCheckPredicate pred(NPC_FERAL_DEFENDER);
+ summons.DoAction(ACTION_DESPAWN_ADDS, pred);
+ summons.DespawnAll();
+ Talk(EMOTE_DEATH);
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_FERAL_DEATH_WITH_STACK)
+ events.ScheduleEvent(EVENT_RESPAWN_FERAL_DEFENDER, 25s);
+ else if (param == ACTION_FERAL_DEATH)
+ _nineLives = true;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_SUMMON_FERAL_DEFENDER:
+ Talk(EMOTE_DEFFENDER);
+ me->CastSpell(me, SPELL_ACTIVATE_FERAL_DEFENDER, true);
+ me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true);
+ events.ScheduleEvent(EVENT_REMOVE_IMMUNE, 3s);
+ break;
+ case EVENT_REMOVE_IMMUNE:
+ me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, false);
+ break;
+ case EVENT_TERRIFYING_SCREECH:
+ Talk(EMOTE_FEAR);
+ me->CastSpell(me, SPELL_TERRIFYING_SCREECH, false);
+ events.Repeat(35s);
+ break;
+ case EVENT_SONIC_SCREECH:
+ me->CastSpell(me, SPELL_SONIC_SCREECH, false);
+ events.Repeat(50s);
+ break;
+ case EVENT_GUARDIAN_SWARM:
+ me->CastSpell(me->GetVictim(), SPELL_GUARDIAN_SWARM, false);
+ events.Repeat(40s);
+ break;
+ case EVENT_SENTINEL_BLAST:
+ me->CastSpell(me, SPELL_SENTINEL_BLAST, false);
+ events.Repeat(35s);
+ events.DelayEvents(5000, 0);
+ break;
+ case EVENT_RESPAWN_FERAL_DEFENDER:
+ {
+ EntryCheckPredicate pred(NPC_FERAL_DEFENDER);
+ summons.DoAction(ACTION_FERAL_RESPAWN, pred);
+ break;
+ }
+ case EVENT_ENRAGE:
+ Talk(SAY_BERSERK);
+ me->CastSpell(me, SPELL_ENRAGE, true);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class npc_auriaya_sanctum_sentry : public CreatureScript
+{
+public:
+ npc_auriaya_sanctum_sentry() : CreatureScript("npc_auriaya_sanctum_sentry") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_auriaya_sanctum_sentryAI : public ScriptedAI
+ {
+ npc_auriaya_sanctum_sentryAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ uint32 _savagePounceTimer;
+ uint32 _ripFleshTimer;
+
+ void JustEngagedWith(Unit*) override
+ {
+ if (me->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_AURIAYA)))
+ cr->SetInCombatWithZone();
+ }
+
+ void Reset() override
+ {
+ _savagePounceTimer = 5000;
+ _ripFleshTimer = 0;
+
+ me->CastSpell(me, SPELL_STRENGTH_OF_THE_PACK, true);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _savagePounceTimer += diff;
+ _ripFleshTimer += diff;
+
+ if (_savagePounceTimer >= 5000)
+ {
+ float dist = me->GetDistance(me->GetVictim());
+ if (dist >= 8 && dist < 25 && me->IsWithinLOSInMap(me->GetVictim()))
+ {
+ me->CastSpell(me->GetVictim(), SPELL_SAVAGE_POUNCE, false);
+ _savagePounceTimer = 0;
+ return;
+ }
+ _savagePounceTimer = 200;
+ }
+ else if (_ripFleshTimer >= 10000)
+ {
+ me->CastSpell(me->GetVictim(), SPELL_RIP_FLESH, false);
+ _ripFleshTimer = 0;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class npc_auriaya_feral_defender : public CreatureScript
+{
+public:
+ npc_auriaya_feral_defender() : CreatureScript("npc_auriaya_feral_defender") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_auriaya_feral_defenderAI : public ScriptedAI
+ {
+ npc_auriaya_feral_defenderAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) { }
+
+ int32 _feralRushTimer;
+ int32 _feralPounceTimer;
+ uint8 _feralEssenceStack;
+ SummonList summons;
+
+ void Reset() override
+ {
+ summons.DespawnAll();
+ _feralRushTimer = 3000;
+ _feralPounceTimer = 0;
+ _feralEssenceStack = 8;
+
+ if (Aura* aur = me->AddAura(SPELL_FERAL_ESSENCE, me))
+ aur->SetStackAmount(_feralEssenceStack);
+ }
+
+ void JustDied(Unit*) override
+ {
+ // inform about our death, start timer
+ if (me->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_AURIAYA)))
+ cr->AI()->DoAction(_feralEssenceStack ? ACTION_FERAL_DEATH_WITH_STACK : ACTION_FERAL_DEATH);
+
+ if (_feralEssenceStack)
+ {
+ if (Creature* cr = me->SummonCreature(NPC_SEEPING_FERAL_ESSENCE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.0f))
+ summons.Summon(cr);
+
+ --_feralEssenceStack;
+ }
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_FERAL_RESPAWN)
+ {
+ me->setDeathState(DeathState::JustRespawned);
+
+ if (Player* target = SelectTargetFromPlayerList(200))
+ AttackStart(target);
+ else
+ {
+ summons.DespawnAll();
+ me->DespawnOrUnsummon(1);
+ }
+
+ if (_feralEssenceStack)
+ if (Aura* aur = me->AddAura(SPELL_FERAL_ESSENCE, me))
+ aur->SetStackAmount(_feralEssenceStack);
+ }
+ else if (param == ACTION_DESPAWN_ADDS)
+ summons.DespawnAll();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _feralRushTimer += diff;
+ _feralPounceTimer += diff;
+
+ if (_feralRushTimer >= 6000)
+ {
+ DoResetThreatList();
+ if (!UpdateVictim())
+ return;
+
+ me->CastSpell(me->GetVictim(), SPELL_FERAL_RUSH, true);
+ _feralRushTimer = 0;
+ }
+ else if (_feralPounceTimer >= 6000)
+ {
+ me->CastSpell(me->GetVictim(), SPELL_FERAL_POUNCE, false);
+ _feralPounceTimer = 0;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class spell_auriaya_sentinel_blast : public SpellScriptLoader
+{
+public:
+ spell_auriaya_sentinel_blast() : SpellScriptLoader("spell_auriaya_sentinel_blast") { }
+
+ class spell_auriaya_sentinel_blast_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_auriaya_sentinel_blast_SpellScript);
+
+ void FilterTargets(std::list& unitList)
+ {
+ unitList.remove_if(PlayerOrPetCheck());
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_auriaya_sentinel_blast_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_auriaya_sentinel_blast_SpellScript();
+ }
+};
+
+class achievement_auriaya_crazy_cat_lady : public AchievementCriteriaScript
+{
+public:
+ achievement_auriaya_crazy_cat_lady() : AchievementCriteriaScript("achievement_auriaya_crazy_cat_lady") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ if (target)
+ if (InstanceScript* instance = target->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_AURIAYA)))
+ return cr->AI()->GetData(DATA_CRAZY_CAT);
+
+ return false;
+ }
+};
+
+class achievement_auriaya_nine_lives : public AchievementCriteriaScript
+{
+public:
+ achievement_auriaya_nine_lives() : AchievementCriteriaScript("achievement_auriaya_nine_lives") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ if (target)
+ if (InstanceScript* instance = target->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_AURIAYA)))
+ return cr->AI()->GetData(DATA_NINE_LIVES);
+
+ return false;
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
index 02b7569b726882..af453be0826dfd 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_flame_leviathan.h"
#include "AchievementCriteriaScript.h"
#include "CombatAI.h"
#include "CreatureScript.h"
@@ -33,467 +34,6 @@
#include "Vehicle.h"
#include "ulduar.h"
-enum LeviathanSpells
-{
- // Leviathan basic
- SPELL_PURSUED = 62374,
- SPELL_GATHERING_SPEED = 62375,
- SPELL_BATTERING_RAM = 62376,
- SPELL_FLAME_VENTS = 62396,
- SPELL_MISSILE_BARRAGE = 62400,
- SPELL_NAPALM_10 = 63666,
- SPELL_NAPALM_25 = 65026,
- SPELL_INVIS_AND_STEALTH_DETECT = 18950,
- SPELL_TRANSITUS_SHIELD_IMPACT = 48387,
-
- // Shutdown spells
- SPELL_SYSTEMS_SHUTDOWN = 62475,
- SPELL_OVERLOAD_CIRCUIT = 62399,
-
- // hard mode
- SPELL_TOWER_OF_STORMS = 65076,
- SPELL_TOWER_OF_FLAMES = 65075,
- SPELL_TOWER_OF_FROST = 65077,
- SPELL_TOWER_OF_LIFE = 64482,
-
- SPELL_HODIRS_FURY = 62533,
- SPELL_FREYA_WARD = 62906, // removed spawn effect
- SPELL_MIMIRONS_INFERNO = 62909,
- SPELL_THORIMS_HAMMER = 62911,
-
- SPELL_FREYA_DUMMY_BLUE = 63294,
- SPELL_FREYA_DUMMY_GREEN = 63295,
- SPELL_FREYA_DUMMY_YELLOW = 63292,
-
- // Leviathan turret spell
- SPELL_SEARING_FLAME = 62402,
- // On turret Destory
- SPELL_SMOKE_TRAIL = 63575,
-
- // Pool of tar blaze
- SPELL_BLAZE = 62292,
-
- // Pyrite
- SPELL_LIQUID_PYRITE = 62494,
- SPELL_DUSTY_EXPLOSION = 63360,
- SPELL_DUST_CLOUD_IMPACT = 54740,
-};
-
-enum GosNpcs
-{
- NPC_FLAME_LEVIATHAN_TURRET = 33139,
- NPC_SEAT = 33114,
- NPC_MECHANOLIFT = 33214,
- NPC_LIQUID = 33189,
-
- // Starting event
- NPC_ULDUAR_COLOSSUS = 33237,
- NPC_BRANN_RADIO = 34054,
- NPC_ULDUAR_GAUNTLET_GENERATOR = 33571,
- NPC_DEFENDER_GENERATED = 33572,
-
- // Hard Mode
- NPC_THORIM_HAMMER_TARGET = 33364,
- NPC_THORIM_HAMMER = 33365,
- NPC_FREYA_WARD_TARGET = 33366,
- NPC_FREYA_WARD = 33367,
- NPC_MIMIRONS_INFERNO_TARGET = 33369,
- NPC_MIMIRONS_INFERNO = 33370,
- NPC_HODIRS_FURY_TARGET = 33108,
- NPC_HODIRS_FURY = 33212,
-};
-
-enum Events
-{
- EVENT_PURSUE = 1,
- EVENT_MISSILE = 2,
- EVENT_VENT = 3,
- EVENT_SPEED = 4,
- EVENT_SUMMON = 5,
- EVENT_REINSTALL = 6,
- EVENT_HODIRS_FURY = 7,
- EVENT_FREYA = 8,
- EVENT_MIMIRONS_INFERNO = 9,
- EVENT_THORIMS_HAMMER = 10,
- EVENT_SOUND_BEGINNING = 11,
- EVENT_POSITION_CHECK = 12,
-};
-
-enum Texts
-{
- FLAME_LEVIATHAN_SAY_AGGRO = 0,
- FLAME_LEVIATHAN_SAY_SLAY = 1,
- FLAME_LEVIATHAN_SAY_DEATH = 2,
- FLAME_LEVIATHAN_SAY_PURSUE = 3,
- FLAME_LEVIATHAN_SAY_HARDMODE = 4,
- FLAME_LEVIATHAN_SAY_TOWER_NONE = 5,
- FLAME_LEVIATHAN_SAY_TOWER_FROST = 6,
- FLAME_LEVIATHAN_SAY_TOWER_FLAME = 7,
- FLAME_LEVIATHAN_SAY_TOWER_NATURE = 8,
- FLAME_LEVIATHAN_SAY_TOWER_STORM = 9,
- FLAME_LEVIATHAN_SAY_PLAYER_RIDING = 10,
- FLAME_LEVIATHAN_SAY_OVERLOAD = 11,
- FLAME_LEVIATHAN_EMOTE_PURSUE = 12,
- FLAME_LEVIATHAN_EMOTE_OVERLOAD = 13,
- FLAME_LEVIATHAN_EMOTE_REPAIR = 14,
- FLAME_LEVIATHAN_EMOTE_FROST = 15,
- FLAME_LEVIATHAN_EMOTE_FLAME = 16,
- FLAME_LEVIATHAN_EMOTE_NATURE = 17,
- FLAME_LEVIATHAN_EMOTE_STORM = 18,
- FLAME_LEVIATHAN_EMOTE_REACTIVATE = 19,
-
- // NPC_BRANN_RADIO
- BRANN_RADIO_SAY_FL_START_0 = 0,
- BRANN_RADIO_SAY_FL_START_1 = 1,
- BRANN_RADIO_SAY_FL_START_2 = 2,
- BRANN_RADIO_SAY_GENERATORS = 3,
- BRANN_RADIO_SAY_STATIONS = 4,
- BRANN_RADIO_SAY_TOWER_THORIM = 5,
- BRANN_RADIO_SAY_TOWER_HODIR = 6,
- BRANN_RADIO_SAY_TOWER_FREYA = 7,
- BRANN_RADIO_SAY_TOWER_MIMIRON = 8,
-
- // Vehicle Repair - Said by a spell, BroadcastTextID, same as FLAME_LEVIATHAN_EMOTE_REPAIR
- VEHICLE_EMOTE_REPAIR = 33538,
-};
-
-enum Seats
-{
- SEAT_PLAYER = 0,
- SEAT_TURRET = 1,
- SEAT_DEVICE = 2,
- SEAT_CANNON = 7,
-};
-
-enum Misc
-{
- DATA_EVENT_STARTED = 1,
- DATA_GET_TOWER_COUNT = 2,
- DATA_GET_SHUTDOWN = 3,
-
- TOWER_OF_STORMS = 2,
- TOWER_OF_FLAMES = 1,
- TOWER_OF_FROST = 3,
- TOWER_OF_LIFE = 0,
-
- ACTION_START_NORGANNON_EVENT = 1,
- ACTION_START_NORGANNON_BRANN = 2,
- ACTION_START_BRANN_EVENT = 3,
- ACTION_DESPAWN_ADDS = 4,
- ACTION_DELAY_CANNON = 5,
- ACTION_DESTROYED_TURRET = 6,
-};
-
-const Position homePos = {322.39f, -14.5f, 409.8f, 3.14f};
-
-class boss_flame_leviathan : public CreatureScript
-{
-public:
- boss_flame_leviathan() : CreatureScript("boss_flame_leviathan") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_flame_leviathanAI : public ScriptedAI
- {
- boss_flame_leviathanAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me)
- {
- m_pInstance = pCreature->GetInstanceScript();
- assert(vehicle);
- }
-
- InstanceScript* m_pInstance;
- Vehicle* vehicle;
- EventMap events;
- SummonList summons;
-
- uint32 _startTimer;
- uint32 _speakTimer;
- uint8 _towersCount;
- bool _shutdown;
- uint32 _destroyedTurretCount;
-
- // Custom
- void BindPlayers();
- void RadioSay(uint8 textid);
- void ActivateTowers();
- void TurnGates(bool _start, bool _death);
- void TurnHealStations(bool _apply);
- void ScheduleEvents();
- void SummonTowerHelpers(uint8 towerId);
-
- // Original
- void JustReachedHome() override
- {
- // For achievement
- if (m_pInstance)
- m_pInstance->SetData(DATA_UNBROKEN_ACHIEVEMENT, 0);
- me->setActive(false);
- }
-
- void MoveInLineOfSight(Unit*) override {}
- void JustSummoned(Creature* cr) override
- {
- if (cr->GetEntry() != NPC_FLAME_LEVIATHAN_TURRET && cr->GetEntry() != NPC_SEAT)
- summons.Summon(cr);
- }
-
- void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); }
- void SpellHit(Unit* caster, SpellInfo const* spellInfo) override;
- void JustDied(Unit*) override;
- void KilledUnit(Unit* who) override;
- void SpellHitTarget(Unit* target, SpellInfo const* spell) override;
-
- void AttackStart(Unit* who) override
- {
- if (Unit* veh = who->GetVehicleBase())
- ScriptedAI::AttackStart(veh);
- else
- ScriptedAI::AttackStart(who);
- }
-
- void JustEngagedWith(Unit*) override
- {
- ScheduleEvents();
- Talk(FLAME_LEVIATHAN_SAY_AGGRO);
-
- me->setActive(true);
- me->SetHomePosition(homePos);
- TurnHealStations(false);
- ActivateTowers();
- if (m_pInstance)
- m_pInstance->SetData(TYPE_LEVIATHAN, SPECIAL);
-
- BindPlayers();
- me->SetInCombatWithZone();
-
- if (!_startTimer)
- {
- TurnGates(true, false);
- }
- }
-
- void InitializeAI() override
- {
- if (m_pInstance && m_pInstance->GetData(TYPE_LEVIATHAN) == SPECIAL)
- {
- me->SetHomePosition(homePos);
- me->UpdatePosition(homePos);
- me->StopMovingOnCurrentPos();
- }
-
- ScriptedAI::InitializeAI();
- }
-
- void Reset() override
- {
- // Special immunity case
- me->CastSpell(me, SPELL_INVIS_AND_STEALTH_DETECT, true);
- me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED, true);
-
- summons.DoAction(ACTION_DESPAWN_ADDS);
- summons.DespawnAll();
- events.Reset();
-
- _shutdown = false;
- _startTimer = 1;
- _speakTimer = 0;
- _towersCount = 0;
- _destroyedTurretCount = 0;
-
- if (m_pInstance)
- {
- if (m_pInstance->GetData(TYPE_LEVIATHAN) != SPECIAL)
- {
- m_pInstance->SetData(TYPE_LEVIATHAN, NOT_STARTED);
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- }
- else
- {
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- m_pInstance->SetData(DATA_VEHICLE_SPAWN, VEHICLE_POS_LEVIATHAN);
- _startTimer = 0;
- }
- }
-
- TurnGates(false, false);
- TurnHealStations(true);
- }
-
- uint32 GetData(uint32 param) const override
- {
- if (param == DATA_GET_TOWER_COUNT)
- return _towersCount;
- if (param == DATA_GET_SHUTDOWN)
- return !_shutdown;
-
- return 0;
- }
-
- void UpdateAI(uint32 diff) override
- {
- // THIS IS USED ONLY FOR FIRST ENGAGE!
- if (_startTimer)
- {
- _startTimer += diff;
- if (_startTimer >= 4000)
- {
- // Colossus dead, players in range
- if (me->FindNearestCreature(NPC_ULDUAR_COLOSSUS, 250.0f, true) || !SelectTargetFromPlayerList(250.0f))
- _startTimer = 1;
- else
- {
- _startTimer = 0;
- _speakTimer = 1;
- }
- }
- return;
- }
-
- if (_speakTimer)
- {
- _speakTimer += diff;
- if (_speakTimer <= 10000)
- {
- _speakTimer = 10000;
- RadioSay(BRANN_RADIO_SAY_FL_START_0);
- }
- else if (_speakTimer > 16000 && _speakTimer < 20000)
- {
- _speakTimer = 20000;
- RadioSay(BRANN_RADIO_SAY_FL_START_1);
- }
- else if (_speakTimer > 24000 && _speakTimer < 40000)
- {
- _speakTimer = 40000;
- RadioSay(BRANN_RADIO_SAY_FL_START_2);
- }
- else if (_speakTimer > 41000 && _speakTimer < 60000)
- {
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- TurnGates(true, false);
- me->MonsterMoveWithSpeed(homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), 100.0f);
- me->UpdatePosition(homePos);
- _speakTimer = 60000;
- }
- else if (_speakTimer > 63500)
- {
- me->SetInCombatWithZone();
- if (!me->GetVictim())
- {
- me->CastSpell(me, SPELL_PURSUED, false);
- events.RescheduleEvent(EVENT_PURSUE, 31s);
- }
- _speakTimer = 0;
- }
- return;
- }
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_POSITION_CHECK:
- if (me->GetPositionX() > 450 || me->GetPositionX() < 120)
- {
- EnterEvadeMode();
- return;
- }
- events.Repeat(5s);
- break;
- case EVENT_PURSUE:
- Talk(FLAME_LEVIATHAN_SAY_PURSUE);
- me->CastSpell(me, SPELL_PURSUED, false);
- events.RescheduleEvent(EVENT_PURSUE, 31s);
- return;
- case EVENT_SPEED:
- me->CastSpell(me, SPELL_GATHERING_SPEED, false);
- events.Repeat(15s);
- return;
- case EVENT_MISSILE:
- me->CastSpell(me, SPELL_MISSILE_BARRAGE, true);
- events.Repeat(4s);
- return;
- case EVENT_VENT:
- me->CastSpell(me, SPELL_FLAME_VENTS, false);
- events.Repeat(20s);
- return;
- case EVENT_SUMMON:
- if(summons.size() < 20)
- if (Creature* lift = DoSummonFlyer(NPC_MECHANOLIFT, me, 30.0f, 50.0f, 0))
- lift->GetMotionMaster()->MoveRandom(100);
-
- events.Repeat(4s);
- return;
- case EVENT_SOUND_BEGINNING:
- if (_towersCount)
- Talk(FLAME_LEVIATHAN_SAY_HARDMODE);
- else
- Talk(FLAME_LEVIATHAN_SAY_TOWER_NONE);
- return;
- case EVENT_REINSTALL:
- for (uint8 i = RAID_MODE(0, 2); i < 4; ++i)
- if (Unit* seat = vehicle->GetPassenger(i))
- if (seat->GetTypeId() == TYPEID_UNIT)
- seat->ToCreature()->AI()->EnterEvadeMode();
- Talk(FLAME_LEVIATHAN_EMOTE_REACTIVATE);
- return;
- case EVENT_THORIMS_HAMMER:
- SummonTowerHelpers(TOWER_OF_STORMS);
- events.Repeat(1min, 2min);
- Talk(FLAME_LEVIATHAN_EMOTE_STORM);
- Talk(FLAME_LEVIATHAN_SAY_TOWER_STORM);
- return;
- case EVENT_FREYA:
- SummonTowerHelpers(TOWER_OF_LIFE);
- Talk(FLAME_LEVIATHAN_EMOTE_NATURE);
- Talk(FLAME_LEVIATHAN_SAY_TOWER_NATURE);
- return;
- case EVENT_MIMIRONS_INFERNO:
- SummonTowerHelpers(TOWER_OF_FLAMES);
- Talk(FLAME_LEVIATHAN_EMOTE_FLAME);
- Talk(FLAME_LEVIATHAN_SAY_TOWER_FLAME);
- return;
- case EVENT_HODIRS_FURY:
- SummonTowerHelpers(TOWER_OF_FROST);
- Talk(FLAME_LEVIATHAN_EMOTE_FROST);
- Talk(FLAME_LEVIATHAN_SAY_TOWER_FROST);
- return;
- }
-
- if(me->isAttackReady() && !me->HasUnitState(UNIT_STATE_STUNNED))
- {
- if(me->IsWithinCombatRange(me->GetVictim(), 15.0f))
- {
- me->CastSpell(me->GetVictim(), SPELL_BATTERING_RAM, false);
- me->resetAttackTimer();
- }
- }
- }
-
- void DoAction(int32 action) override
- {
- if (action == ACTION_DESTROYED_TURRET)
- {
- ++_destroyedTurretCount;
-
- if (_destroyedTurretCount == RAID_MODE(2, 4))
- {
- _destroyedTurretCount = 0;
- me->CastSpell(me, SPELL_SYSTEMS_SHUTDOWN, true);
- }
- }
- }
- };
-};
-
void boss_flame_leviathan::boss_flame_leviathanAI::BindPlayers()
{
me->GetMap()->ToInstanceMap()->PermBindAllPlayers();
@@ -700,1425 +240,6 @@ void boss_flame_leviathan::boss_flame_leviathanAI::SpellHitTarget(Unit* target,
}
}
-class boss_flame_leviathan_seat : public CreatureScript
-{
-public:
- boss_flame_leviathan_seat() : CreatureScript("boss_flame_leviathan_seat") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_flame_leviathan_seatAI : public VehicleAI
- {
- boss_flame_leviathan_seatAI(Creature* creature) : VehicleAI(creature), vehicle(creature->GetVehicleKit())
- {
- ASSERT(vehicle);
- me->SetReactState(REACT_PASSIVE);
- }
-
- Vehicle* vehicle;
- uint32 _despawnTimer;
-
- void EnterEvadeMode(EvadeReason /*why*/) override
- {
- vehicle->InstallAllAccessories(false);
- }
-
- void Reset() override
- {
- _despawnTimer = !me->GetMap()->Is25ManRaid();
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (_despawnTimer)
- {
- _despawnTimer += diff;
- if (_despawnTimer >= 2000)
- {
- _despawnTimer = 0;
- if (Vehicle* veh = me->GetVehicle())
- if (veh->GetPassenger(0) == me || veh->GetPassenger(1) == me)
- me->DespawnOrUnsummon(1);
- }
- }
-
- VehicleAI::UpdateAI(diff);
- }
-
- void AttackStart(Unit*) override { }
-
- void PassengerBoarded(Unit* who, int8 seatId, bool apply) override
- {
- if (who->GetTypeId() != TYPEID_PLAYER || !me->GetVehicle())
- return;
-
- who->ApplySpellImmune(63847, IMMUNITY_ID, 63847, apply); // SPELL_FLAME_VENTS_TRIGGER
- who->ApplySpellImmune(SPELL_MISSILE_BARRAGE, IMMUNITY_ID, SPELL_MISSILE_BARRAGE, apply);
- who->ApplySpellImmune(SPELL_BATTERING_RAM, IMMUNITY_ID, SPELL_BATTERING_RAM, apply);
-
- if (seatId == SEAT_PLAYER)
- {
- if (Unit* turret = me->GetVehicleKit()->GetPassenger(SEAT_TURRET))
- {
- if (apply)
- {
- turret->ReplaceAllUnitFlags(UNIT_FLAG_NONE);
- turret->GetAI()->AttackStart(who);
- if (Creature* leviathan = me->GetVehicleCreatureBase())
- leviathan->AI()->Talk(FLAME_LEVIATHAN_SAY_PLAYER_RIDING);
- }
- else
- {
- turret->ReplaceAllUnitFlags(UNIT_FLAG_NOT_SELECTABLE);
- turret->SetImmuneToAll(true);
- if (turret->GetTypeId() == TYPEID_UNIT)
- turret->ToCreature()->AI()->EnterEvadeMode();
- }
- }
- }
- }
- };
-};
-
-class boss_flame_leviathan_defense_turret : public CreatureScript
-{
-public:
- boss_flame_leviathan_defense_turret() : CreatureScript("boss_flame_leviathan_defense_turret") { }
-
- struct boss_flame_leviathan_defense_turretAI : public TurretAI
- {
- boss_flame_leviathan_defense_turretAI(Creature* creature) : TurretAI(creature)
- {
- _setHealth = false;
- _instance = creature->GetInstanceScript();
- }
-
- InstanceScript* _instance;
-
- bool _setHealth;
- void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (!CanAIAttack(who))
- {
- _setHealth = true;
- damage = 0;
- }
- }
-
- void JustDied(Unit* killer) override
- {
- if (Player* player = killer->ToPlayer())
- player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, me);
-
- if (Vehicle* vehicle = me->GetVehicle())
- if (Unit* device = vehicle->GetPassenger(SEAT_DEVICE))
- device->ReplaceAllUnitFlags(UNIT_FLAG_NONE); // unselectable
-
- if (Creature* leviathan = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(TYPE_LEVIATHAN)))
- leviathan->AI()->DoAction(ACTION_DESTROYED_TURRET);
- }
-
- bool CanAIAttack(Unit const* who) const override
- {
- if (!who || who->GetTypeId() != TYPEID_PLAYER || !who->GetVehicle() || who->GetVehicleBase()->GetEntry() != NPC_SEAT)
- return false;
- return true;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (_setHealth)
- {
- me->SetHealth(std::min(me->GetHealth() + 1, me->GetMaxHealth()));
- _setHealth = false;
- }
-
- TurretAI::UpdateAI(diff);
- }
-
- void KilledUnit(Unit* who) override
- {
- if (Player* plr = who->ToPlayer()) // make sure that there's no death player on the seat.
- if (plr->GetVehicle())
- plr->ExitVehicle();
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetUlduarAI(creature);
- }
-};
-
-class boss_flame_leviathan_overload_device : public CreatureScript
-{
-public:
- boss_flame_leviathan_overload_device() : CreatureScript("boss_flame_leviathan_overload_device") { }
-
- struct boss_flame_leviathan_overload_deviceAI : public NullCreatureAI
- {
- boss_flame_leviathan_overload_deviceAI(Creature* creature) : NullCreatureAI(creature)
- {
- }
-
- void OnSpellClick(Unit* /*clicker*/, bool& result) override
- {
- if (!result)
- return;
-
- if (me->GetVehicle())
- {
- me->RemoveNpcFlag(UNIT_NPC_FLAG_SPELLCLICK);
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
-
- if (Unit* player = me->GetVehicle()->GetPassenger(SEAT_PLAYER))
- {
- me->GetVehicleBase()->CastSpell(player, SPELL_SMOKE_TRAIL, true);
- player->ExitVehicle();
- }
- }
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetUlduarAI(creature);
- }
-};
-
-class npc_freya_ward : public CreatureScript
-{
-public:
- npc_freya_ward() : CreatureScript("npc_freya_ward") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_freya_wardAI : public NullCreatureAI
- {
- npc_freya_wardAI(Creature* c) : NullCreatureAI(c), summons(c)
- {
- }
-
- SummonList summons;
- uint32 _castTimer;
- bool _summoned;
-
- void Reset() override
- {
- _summoned = false;
- _castTimer = 25000;
- summons.DespawnAll();
- if (Creature* cr = me->FindNearestCreature(NPC_FREYA_WARD_TARGET, 60.0f, true))
- if (Aura* aur = cr->AddAura(SPELL_FREYA_DUMMY_GREEN, cr))
- {
- aur->SetMaxDuration(-1);
- aur->SetDuration(-1);
- }
- }
-
- void JustSummoned(Creature* cr) override
- {
- _summoned = true;
- summons.Summon(cr);
- }
-
- void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); }
-
- void UpdateAI(uint32 diff) override
- {
- if (_summoned)
- {
- for (SummonList::const_iterator itr = summons.begin(); itr != summons.end();)
- {
- Creature* summon = ObjectAccessor::GetCreature(*me, *itr);
- ++itr;
- if (summon)
- {
- summon->ToTempSummon()->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN);
- if (Unit* target = summon->SelectNearestTarget(200.0f))
- summon->AI()->AttackStart(target);
- }
- }
- _summoned = false;
- }
-
- _castTimer += diff;
- if (_castTimer >= 29 * IN_MILLISECONDS)
- {
- if (Creature* cr = me->FindNearestCreature(NPC_FREYA_WARD_TARGET, 60.0f, true))
- {
- me->CastSpell(cr, SPELL_FREYA_WARD, false);
- me->CastSpell(cr, 62947 /*SPELL_FREYA_WARD_SECOND_SUMMON*/, false);
- }
-
- _castTimer = 0;
- }
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_DESPAWN_ADDS)
- summons.DespawnAll();
- }
- };
-};
-
-class npc_hodirs_fury : public CreatureScript
-{
-public:
- npc_hodirs_fury() : CreatureScript("npc_hodirs_fury") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_hodirs_furyAI : public NullCreatureAI
- {
- npc_hodirs_furyAI(Creature* c) : NullCreatureAI(c)
- {
- }
-
- uint32 _timeToHit;
- uint32 _switchTargetTimer;
-
- void Reset() override
- {
- _timeToHit = 0;
- _switchTargetTimer = 30000;
- me->SetWalk(true);
-
- if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_BLUE, me))
- {
- aur->SetMaxDuration(-1);
- aur->SetDuration(-1);
- }
- }
-
- void MovementInform(uint32 type, uint32 /*param*/) override
- {
- if (type == FOLLOW_MOTION_TYPE && !_timeToHit)
- {
- _timeToHit = 1;
- _switchTargetTimer = 0;
- me->SetControlled(true, UNIT_STATE_STUNNED);
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (_timeToHit)
- {
- _timeToHit += diff;
- if (_timeToHit >= 5000)
- {
- if (Creature* cr = me->SummonCreature(NPC_HODIRS_FURY, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40, 0, TEMPSUMMON_TIMED_DESPAWN, 10000))
- cr->CastSpell(me, SPELL_HODIRS_FURY, true);
-
- _switchTargetTimer = 25000; // Switch target soon
- _timeToHit = 0;
- }
- return;
- }
-
- _switchTargetTimer += diff;
- if (_switchTargetTimer >= 30000)
- {
- if(Unit* target = me->SelectNearbyTarget(nullptr, 200.0f))
- {
- if (target->GetVehicleBase() && target->GetVehicleBase()->GetEntry() == NPC_SEAT)
- {
- _switchTargetTimer = 20000;
- return;
- }
- me->SetControlled(false, UNIT_STATE_STUNNED);
- me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f);
- _switchTargetTimer = 0;
- }
- else
- _switchTargetTimer = 25000;
- }
- }
- };
-};
-
-class npc_mimirons_inferno : public CreatureScript
-{
-public:
- npc_mimirons_inferno() : CreatureScript("npc_mimirons_inferno") { }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetUlduarAI(creature);
- }
-
- struct npc_mimirons_infernoAI : public npc_escortAI
- {
- npc_mimirons_infernoAI(Creature* creature) : npc_escortAI(creature), summons(me)
- {
- me->SetReactState(REACT_PASSIVE);
- }
-
- SummonList summons;
- uint32 _spellTimer;
- uint32 _recastTimer;
-
- void AttackStart(Unit*) override { }
- void MoveInLineOfSight(Unit*) override { }
- void WaypointReached(uint32 /*waypointId*/) override { }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_DESPAWN_ADDS)
- summons.DespawnAll();
- }
-
- void Reset() override
- {
- summons.DespawnAll();
- _spellTimer = 0;
- Start(false, false, ObjectGuid::Empty, nullptr, false, true);
- if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_YELLOW, me))
- {
- aur->SetMaxDuration(-1);
- aur->SetDuration(-1);
- }
- }
-
- void JustSummoned(Creature* cr) override { summons.Summon(cr); }
- void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); }
-
- void UpdateAI(uint32 diff) override
- {
- npc_escortAI::UpdateAI(diff);
-
- _spellTimer += diff;
- if (_spellTimer >= 2000)
- {
- if (Creature* cr = me->SummonCreature(NPC_MIMIRONS_INFERNO, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000))
- cr->CastSpell(me, SPELL_MIMIRONS_INFERNO, true);
-
- _spellTimer = 0;
- }
- }
- };
-};
-
-class npc_thorims_hammer : public CreatureScript
-{
-public:
- npc_thorims_hammer() : CreatureScript("npc_thorims_hammer") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_thorims_hammerAI : public NullCreatureAI
- {
- npc_thorims_hammerAI(Creature* c) : NullCreatureAI(c)
- {
- }
-
- uint32 _beamTimer;
- uint32 _finishTime;
- uint32 _removeTimer;
-
- void Reset() override
- {
- _finishTime = 5000 + rand() % 15000;
- _beamTimer = 1;
- _removeTimer = 0;
- me->CastSpell(me, SPELL_FREYA_DUMMY_BLUE, true);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (_beamTimer)
- {
- _beamTimer += diff;
- if (_beamTimer >= _finishTime)
- {
- if (Creature* cr = me->SummonCreature(NPC_THORIM_HAMMER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40, 0, TEMPSUMMON_TIMED_DESPAWN, 5000))
- cr->CastSpell(me, SPELL_THORIMS_HAMMER, false);
-
- _beamTimer = 0;
- _removeTimer = 1;
- me->DespawnOrUnsummon(5 * IN_MILLISECONDS);
- }
- }
- if (_removeTimer)
- {
- _removeTimer += diff;
- if (_removeTimer >= 3 * IN_MILLISECONDS)
- {
- _removeTimer = 0;
- me->RemoveAura(SPELL_FREYA_DUMMY_BLUE);
- }
- }
- }
- };
-};
-
-class npc_pool_of_tar : public CreatureScript
-{
-public:
- npc_pool_of_tar() : CreatureScript("npc_pool_of_tar") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_pool_of_tarAI : public NullCreatureAI
- {
- npc_pool_of_tarAI(Creature* c) : NullCreatureAI(c)
- {
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- damage = 0;
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
- {
- if (spellInfo->SchoolMask & SPELL_SCHOOL_MASK_FIRE && !me->HasAura(SPELL_BLAZE))
- me->CastSpell(me, SPELL_BLAZE, true);
- }
- };
-};
-
-class npc_brann_radio : public CreatureScript
-{
-public:
- npc_brann_radio() : CreatureScript("npc_brann_radio") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_brann_radioAI : public NullCreatureAI
- {
- npc_brann_radioAI(Creature* c) : NullCreatureAI(c)
- {
- _lock = (me->GetInstanceScript() && me->GetInstanceScript()->GetData(TYPE_LEVIATHAN) > NOT_STARTED);
- _helpLock = _lock;
- }
-
- bool _lock;
- bool _helpLock;
-
- void Reset() override
- {
- me->SetReactState(REACT_AGGRESSIVE);
- }
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (!_lock)
- {
- if (who->GetTypeId() != TYPEID_PLAYER && !who->IsVehicle())
- return;
-
- // MIMIRON
- else if (me->GetDistance2d(-81.9207f, 111.432f) < 5.0f)
- {
- if (me->GetDistance2d(who) <= 60.0f && who->GetPositionZ() > 430.0f)
- {
- Talk(BRANN_RADIO_SAY_TOWER_MIMIRON);
- _lock = true;
- }
- }
- // FREYA
- else if (me->GetDistance2d(-221.475f, -271.087f) < 5.0f)
- {
- if (me->GetDistance2d(who) <= 60.0f && who->GetPositionZ() < 380.0f)
- {
- Talk(BRANN_RADIO_SAY_TOWER_FREYA);
- _lock = true;
- }
- }
- // STATIONS
- else if (me->GetDistance2d(73.8978f, -29.3306f) < 5.0f)
- {
- if (me->GetDistance2d(who) <= 40.0f)
- {
- Talk(BRANN_RADIO_SAY_STATIONS);
- _lock = true;
- }
- }
- // HODIR
- else if (me->GetDistance2d(68.7679f, -325.026f) < 5.0f)
- {
- if (me->GetDistance2d(who) <= 40.0f)
- {
- Talk(BRANN_RADIO_SAY_TOWER_HODIR);
- _lock = true;
- }
- }
- // THORIM
- else if (me->GetDistance2d(174.442f, 345.679f) < 5.0f)
- {
- if (me->GetDistance2d(who) <= 60.0f)
- {
- Talk(BRANN_RADIO_SAY_TOWER_THORIM);
- _lock = true;
- }
- }
- // COME A BIT CLOSER
- else if (me->GetDistance2d(-508.898f, -32.9631f) < 5.0f)
- {
- if (who->GetPositionX() >= -480.0f)
- {
- Talk(BRANN_RADIO_SAY_GENERATORS);
- _lock = true;
- }
- }
- }
- }
- };
-};
-
-class npc_storm_beacon_spawn : public CreatureScript
-{
-public:
- npc_storm_beacon_spawn() : CreatureScript("npc_storm_beacon_spawn") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_storm_beacon_spawnAI : public NullCreatureAI
- {
- npc_storm_beacon_spawnAI(Creature* c) : NullCreatureAI(c)
- {
- _amount = 0;
- _checkTimer = 0;
- }
-
- uint8 _amount;
- uint32 _checkTimer;
-
- void UpdateAI(uint32 diff) override
- {
- if (_amount < 40)
- {
- _checkTimer += diff;
- if (_checkTimer >= 4000)
- {
- _checkTimer = 0;
- if (Unit* target = me->SelectNearbyTarget(nullptr, 80.0f))
- {
- ++_amount;
- if (Creature* cr = me->SummonCreature(NPC_DEFENDER_GENERATED, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 4, me->GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 900000))
- cr->AI()->AttackStart(target);
- }
- }
- }
- }
- };
-};
-
-class boss_flame_leviathan_safety_container : public CreatureScript
-{
-public:
- boss_flame_leviathan_safety_container() : CreatureScript("boss_flame_leviathan_safety_container") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_flame_leviathan_safety_containerAI : public NullCreatureAI
- {
- boss_flame_leviathan_safety_containerAI(Creature* c) : NullCreatureAI(c)
- {
- _allowTimer = 0;
- }
-
- uint32 _allowTimer;
-
- void MovementInform(uint32 /*type*/, uint32 id) override
- {
- if (id == me->GetEntry())
- {
- if (Creature* liquid = me->SummonCreature(NPC_LIQUID, *me))
- {
- liquid->CastSpell(liquid, SPELL_LIQUID_PYRITE, true);
- liquid->CastSpell(liquid, SPELL_DUST_CLOUD_IMPACT, true);
- }
-
- me->DespawnOrUnsummon(1);
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- _allowTimer += diff;
- if (_allowTimer >= 5000 && !me->GetVehicle() && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)
- {
- float x, y, z;
- me->GetPosition(x, y, z);
- z = me->GetMapHeight(x, y, z);
- me->GetMotionMaster()->MovePoint(me->GetEntry(), x, y, z);
- me->SetPosition(x, y, z, 0);
- }
- }
- };
-};
-
-class npc_mechanolift : public CreatureScript
-{
-public:
- npc_mechanolift() : CreatureScript("npc_mechanolift") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_mechanoliftAI : public NullCreatureAI
- {
- npc_mechanoliftAI(Creature* c) : NullCreatureAI(c)
- {
- me->SetSpeed(MOVE_RUN, rand_norm() + 0.5f);
- }
-
- int32 _startTimer;
- uint32 _evadeTimer;
-
- void Reset() override
- {
- _startTimer = urand(1, 5000);
- _evadeTimer = 0;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (_startTimer)
- {
- _startTimer -= diff;
- if (_startTimer <= 0)
- {
- me->GetMotionMaster()->MovePath(3000000 + urand(0, 11), true);
- _startTimer = 0;
- }
- }
-
- _evadeTimer += diff;
- if (_evadeTimer >= 10000)
- {
- _EnterEvadeMode();
- _evadeTimer = 0;
- }
- }
- };
-};
-
-class go_ulduar_tower : public GameObjectScript
-{
-public:
- go_ulduar_tower() : GameObjectScript("go_ulduar_tower") { }
-
- void OnDestroyed(GameObject* go, Player* /*player*/) override
- {
- Creature* trigger = go->FindNearestCreature(NPC_ULDUAR_GAUNTLET_GENERATOR, 15.0f, true);
- if (trigger)
- trigger->DisappearAndDie();
- }
-};
-
-class spell_load_into_catapult : public SpellScriptLoader
-{
- enum Spells
- {
- SPELL_PASSENGER_LOADED = 62340,
- };
-
-public:
- spell_load_into_catapult() : SpellScriptLoader("spell_load_into_catapult") { }
-
- class spell_load_into_catapult_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_load_into_catapult_AuraScript);
-
- void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- Unit* owner = GetOwner()->ToUnit();
- if (!owner)
- return;
-
- owner->CastSpell(owner, SPELL_PASSENGER_LOADED, true);
- }
-
- void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- Unit* owner = GetOwner()->ToUnit();
- if (!owner)
- return;
-
- owner->RemoveAurasDueToSpell(SPELL_PASSENGER_LOADED);
- }
-
- void Register() override
- {
- OnEffectApply += AuraEffectApplyFn(spell_load_into_catapult_AuraScript::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL);
- OnEffectRemove += AuraEffectRemoveFn(spell_load_into_catapult_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_load_into_catapult_AuraScript();
- }
-};
-
-class spell_auto_repair : public SpellScriptLoader
-{
- enum Spells
- {
- SPELL_AUTO_REPAIR = 62705,
- };
-
-public:
- spell_auto_repair() : SpellScriptLoader("spell_auto_repair") {}
-
- class spell_auto_repair_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_auto_repair_SpellScript);
-
- void FilterTargets(std::list& targets)
- {
- std::list tmplist;
- for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr)
- if (!(*itr)->ToUnit()->HasAura(SPELL_AUTO_REPAIR))
- tmplist.push_back(*itr);
-
- targets.clear();
- for (std::list::iterator itr = tmplist.begin(); itr != tmplist.end(); ++itr)
- targets.push_back(*itr);
- }
-
- void HandleScript(SpellEffIndex /*eff*/)
- {
- Vehicle* vehicle = GetHitUnit()->GetVehicleKit();
- if (!vehicle)
- return;
-
- Unit* driver = vehicle->GetPassenger(0);
- if (!driver)
- return;
-
- //driver->TextEmote(VEHICLE_EMOTE_REPAIR, driver, true); // No source
-
- // Actually should/could use basepoints (100) for this spell effect as percentage of health, but oh well.
- vehicle->GetBase()->SetFullHealth();
-
- // Achievement
- if (InstanceScript* instance = vehicle->GetBase()->GetInstanceScript())
- instance->SetData(DATA_UNBROKEN_ACHIEVEMENT, 0);
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_auto_repair_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENTRY);
- OnEffectHitTarget += SpellEffectFn(spell_auto_repair_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_auto_repair_SpellScript();
- }
-};
-
-class spell_systems_shutdown : public SpellScriptLoader
-{
-public:
- spell_systems_shutdown() : SpellScriptLoader("spell_systems_shutdown") { }
-
- class spell_systems_shutdown_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_systems_shutdown_AuraScript);
-
- void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- Creature* owner = GetOwner()->ToCreature();
- if (!owner)
- return;
-
- owner->SetControlled(true, UNIT_STATE_STUNNED);
- owner->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED);
- if (Vehicle* veh = owner->GetVehicleKit())
- if (Unit* cannon = veh->GetPassenger(SEAT_CANNON))
- cannon->GetAI()->DoAction(ACTION_DELAY_CANNON);
- }
-
- void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- Creature* owner = GetOwner()->ToCreature();
- if (!owner)
- return;
-
- owner->SetControlled(false, UNIT_STATE_STUNNED);
- }
-
- void Register() override
- {
- OnEffectApply += AuraEffectApplyFn(spell_systems_shutdown_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL);
- OnEffectRemove += AuraEffectRemoveFn(spell_systems_shutdown_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_systems_shutdown_AuraScript();
- }
-};
-
-class FlameLeviathanPursuedTargetSelector
-{
- enum Area
- {
- AREA_FORMATION_GROUNDS = 4652,
- };
-
-public:
- explicit FlameLeviathanPursuedTargetSelector() {};
-
- bool operator()(WorldObject* target) const
- {
- //! No players, only vehicles (todo: check if blizzlike)
- Creature* creatureTarget = target->ToCreature();
- if (!creatureTarget)
- return true;
-
- //! NPC entries must match
- if (creatureTarget->GetEntry() != NPC_SALVAGED_DEMOLISHER && creatureTarget->GetEntry() != NPC_SALVAGED_SIEGE_ENGINE)
- return true;
-
- //! NPC must be a valid vehicle installation
- Vehicle* vehicle = creatureTarget->GetVehicleKit();
- if (!vehicle)
- return true;
-
- //! Entity needs to be in appropriate area
- if (target->GetAreaId() != AREA_FORMATION_GROUNDS)
- return true;
-
- //! Vehicle must be in use by player
- bool playerFound = false;
- for (SeatMap::const_iterator itr = vehicle->Seats.begin(); itr != vehicle->Seats.end() && !playerFound; ++itr)
- if (itr->second.Passenger.Guid.IsPlayer())
- playerFound = true;
-
- return !playerFound;
- }
-};
-
-class spell_pursue : public SpellScriptLoader
-{
-public:
- spell_pursue() : SpellScriptLoader("spell_pursue") {}
-
- class spell_pursue_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_pursue_SpellScript);
-
- void FilterTargets(std::list& targets)
- {
- targets.remove_if(FlameLeviathanPursuedTargetSelector());
- if (targets.empty())
- {
- if (Creature* caster = GetCaster()->ToCreature())
- caster->AI()->EnterEvadeMode();
- }
- else
- {
- //! In the end, only one target should be selected
- WorldObject* _target = Acore::Containers::SelectRandomContainerElement(targets);
- targets.clear();
- if (_target)
- targets.push_back(_target);
- }
- }
-
- void HandleScript(SpellEffIndex /*eff*/)
- {
- Creature* target = GetHitCreature();
- Unit* caster = GetCaster();
- if (!target || !caster)
- return;
-
- caster->GetThreatMgr().ResetAllThreat();
- caster->GetAI()->AttackStart(target); // Chase target
- caster->AddThreat(target, 10000000.0f);
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_pursue_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
- OnEffectHitTarget += SpellEffectFn(spell_pursue_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_pursue_SpellScript();
- }
-};
-
-class spell_vehicle_throw_passenger : public SpellScriptLoader
-{
-public:
- spell_vehicle_throw_passenger() : SpellScriptLoader("spell_vehicle_throw_passenger") {}
-
- class spell_vehicle_throw_passenger_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_vehicle_throw_passenger_SpellScript);
- void HandleScript()
- {
- Spell* baseSpell = GetSpell();
- SpellCastTargets targets = baseSpell->m_targets;
- if (Vehicle* vehicle = GetCaster()->GetVehicleKit())
- if (Unit* passenger = vehicle->GetPassenger(3))
- {
- // use 99 because it is 3d search
- std::list targetList;
- Acore::WorldObjectSpellAreaTargetCheck check(99, GetExplTargetDest(), GetCaster(), GetCaster(), GetSpellInfo(), TARGET_CHECK_DEFAULT, nullptr);
- Acore::WorldObjectListSearcher searcher(GetCaster(), targetList, check);
- Cell::VisitAllObjects(GetCaster(), searcher, 99.0f);
- float minDist = 99 * 99;
- Unit* target = nullptr;
- for (std::list::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
- {
- if (Unit* unit = (*itr)->ToUnit())
- if (unit->GetEntry() == NPC_SEAT)
- if (Vehicle* seat = unit->GetVehicleKit())
- if (!seat->GetPassenger(0))
- if (Unit* device = seat->GetPassenger(2))
- if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
- {
- float dist = unit->GetExactDistSq(targets.GetDstPos());
- if (dist < minDist)
- {
- minDist = dist;
- target = unit;
- }
- }
- }
- if (target && target->IsWithinDist2d(targets.GetDstPos(), GetSpellInfo()->Effects[EFFECT_0].CalcRadius() * 2)) // now we use *2 because the location of the seat is not correct
- {
- passenger->ExitVehicle();
- passenger->EnterVehicle(target, 0);
- }
- else
- {
- passenger->ExitVehicle();
- float x, y, z;
- targets.GetDstPos()->GetPosition(x, y, z);
- passenger->GetMotionMaster()->MoveJump(x, y, z, targets.GetSpeedXY(), targets.GetSpeedZ());
- }
- }
- }
-
- void Register() override
- {
- AfterCast += SpellCastFn(spell_vehicle_throw_passenger_SpellScript::HandleScript);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_vehicle_throw_passenger_SpellScript();
- }
-};
-
-class spell_tar_blaze : public SpellScriptLoader
-{
-public:
- spell_tar_blaze() : SpellScriptLoader("spell_tar_blaze") { }
-
- class spell_tar_blaze_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_tar_blaze_AuraScript);
-
- void OnPeriodic(AuraEffect const* aurEff)
- {
- GetUnitOwner()->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_tar_blaze_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_tar_blaze_AuraScript();
- }
-};
-
-class spell_vehicle_grab_pyrite : public SpellScriptLoader
-{
-public:
- spell_vehicle_grab_pyrite() : SpellScriptLoader("spell_vehicle_grab_pyrite") {}
-
- class spell_vehicle_grab_pyrite_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_vehicle_grab_pyrite_SpellScript);
- void HandleScript(SpellEffIndex /*effIndex*/)
- {
- if (Unit* target = GetHitUnit())
- if (Unit* seat = GetCaster()->GetVehicleBase())
- {
- if (Vehicle* vSeat = seat->GetVehicleKit())
- if (Unit* pyrite = vSeat->GetPassenger(1))
- pyrite->ExitVehicle();
-
- if (Unit* parent = seat->GetVehicleBase())
- {
- GetCaster()->CastSpell(parent, 62496 /*SPELL_ADD_PYRITE*/, true);
- target->CastSpell(seat, GetEffectValue());
-
- if (target->GetTypeId() == TYPEID_UNIT)
- target->ToCreature()->DespawnOrUnsummon(1300);
- }
- }
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_vehicle_grab_pyrite_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_vehicle_grab_pyrite_SpellScript();
- }
-};
-
-class spell_vehicle_circuit_overload : public SpellScriptLoader
-{
-public:
- spell_vehicle_circuit_overload() : SpellScriptLoader("spell_vehicle_circuit_overload") { }
-
- class spell_vehicle_circuit_overload_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_vehicle_circuit_overload_AuraScript);
-
- void OnPeriodic(AuraEffect const* /*aurEff*/)
- {
- if (Unit* target = GetTarget())
- if (int(target->GetAppliedAuras().count(SPELL_OVERLOAD_CIRCUIT)) >= (target->GetMap()->Is25ManRaid() ? 4 : 2))
- {
- target->CastSpell(target, SPELL_SYSTEMS_SHUTDOWN, true);
- target->RemoveAurasDueToSpell(SPELL_OVERLOAD_CIRCUIT);
- }
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_vehicle_circuit_overload_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_vehicle_circuit_overload_AuraScript();
- }
-};
-
-class spell_orbital_supports : public SpellScriptLoader
-{
-public:
- spell_orbital_supports() : SpellScriptLoader("spell_orbital_supports") { }
-
- class spell_orbital_supports_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_orbital_supports_AuraScript);
-
- bool CheckAreaTarget(Unit* target)
- {
- return target->GetEntry() == NPC_LEVIATHAN;
- }
- void Register() override
- {
- DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_orbital_supports_AuraScript::CheckAreaTarget);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_orbital_supports_AuraScript();
- }
-};
-
-class spell_thorims_hammer : public SpellScriptLoader
-{
-public:
- spell_thorims_hammer() : SpellScriptLoader("spell_thorims_hammer") { }
-
- class spell_thorims_hammer_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_thorims_hammer_SpellScript);
-
- void RecalculateDamage(SpellEffIndex effIndex)
- {
- if (!GetHitUnit() || effIndex == EFFECT_1)
- {
- PreventHitDefaultEffect(effIndex);
- return;
- }
-
- float dist = GetHitUnit()->GetExactDist2d(GetCaster());
- if (dist <= 7.0f)
- {
- SetHitDamage(GetSpellInfo()->Effects[EFFECT_1].CalcValue());
- }
- else
- {
- dist -= 6.0f;
- SetHitDamage(int32(GetSpellInfo()->Effects[EFFECT_1].CalcValue() / std::max(dist, 1.0f)));
- }
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_thorims_hammer_SpellScript::RecalculateDamage, EFFECT_ALL, SPELL_EFFECT_SCHOOL_DAMAGE);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_thorims_hammer_SpellScript();
- }
-};
-
-class spell_transitus_shield_beam : public SpellScriptLoader
-{
-public:
- spell_transitus_shield_beam() : SpellScriptLoader("spell_transitus_shield_beam") { }
-
- class spell_transitus_shield_beam_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_transitus_shield_beam_AuraScript);
-
- void HandleOnEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
- {
- Unit* caster = GetCaster();
- if (!caster)
- {
- return;
- }
-
- Unit* target = GetTarget();
-
- if (!target)
- {
- return;
- }
-
- switch (aurEff->GetEffIndex())
- {
- case EFFECT_0:
- caster->AddAura(SPELL_TRANSITUS_SHIELD_IMPACT, target);
- break;
- }
- }
-
- void HandleOnEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- Unit* caster = GetCaster();
-
- if (!caster)
- {
- return;
- }
-
- Unit* target = GetTarget();
-
- if (target)
- {
- target->RemoveAurasDueToSpell(SPELL_TRANSITUS_SHIELD_IMPACT);
- }
- }
-
- void Register()
- {
- OnEffectApply += AuraEffectApplyFn(spell_transitus_shield_beam_AuraScript::HandleOnEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
- OnEffectRemove += AuraEffectRemoveFn(spell_transitus_shield_beam_AuraScript::HandleOnEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_transitus_shield_beam_AuraScript();
- }
-};
-
-class spell_shield_generator : public SpellScriptLoader
-{
-public:
- spell_shield_generator() : SpellScriptLoader("spell_shield_generator") { }
-
- class spell_shield_generator_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_shield_generator_AuraScript);
-
- uint32 absorbPct;
-
- bool Load() override
- {
- absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster());
- return true;
- }
-
- void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
- {
- // Set absorbtion amount to unlimited
- amount = -1;
- }
-
- void Absorb(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& absorbAmount)
- {
- absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct);
- }
-
- void Register() override
- {
- DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_shield_generator_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB);
- OnEffectAbsorb += AuraEffectAbsorbFn(spell_shield_generator_AuraScript::Absorb, EFFECT_0);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_shield_generator_AuraScript();
- }
-};
-
-class spell_demolisher_ride_vehicle : public SpellScriptLoader
-{
-public:
- spell_demolisher_ride_vehicle() : SpellScriptLoader("spell_demolisher_ride_vehicle") {}
-
- class spell_demolisher_ride_vehicle_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_demolisher_ride_vehicle_SpellScript);
-
- SpellCastResult CheckCast()
- {
- if (GetCaster()->GetTypeId() != TYPEID_PLAYER)
- return SPELL_CAST_OK;
-
- Unit* target = this->GetExplTargetUnit();
- if (!target || target->GetEntry() != NPC_SALVAGED_DEMOLISHER)
- return SPELL_FAILED_DONT_REPORT;
-
- Vehicle* veh = target->GetVehicleKit();
- if (veh && veh->GetPassenger(0))
- if (Unit* target2 = veh->GetPassenger(1))
- if (Vehicle* veh2 = target2->GetVehicleKit())
- {
- if (!veh2->GetPassenger(0))
- target2->HandleSpellClick(GetCaster());
-
- return SPELL_FAILED_DONT_REPORT;
- }
-
- return SPELL_CAST_OK;
- }
-
- void Register() override
- {
- OnCheckCast += SpellCheckCastFn(spell_demolisher_ride_vehicle_SpellScript::CheckCast);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_demolisher_ride_vehicle_SpellScript();
- }
-};
-
-class achievement_flame_leviathan_towers : public AchievementCriteriaScript
-{
-public:
- achievement_flame_leviathan_towers(char const* name, uint32 count) : AchievementCriteriaScript(name),
- _towerCount(count)
- {
- }
-
- bool OnCheck(Player* /*player*/, Unit* target /*Flame Leviathan*/, uint32 /*criteria_id*/) override
- {
- return target && _towerCount <= target->GetAI()->GetData(DATA_GET_TOWER_COUNT);
- }
-
-private:
- uint32 const _towerCount;
-};
-
-class achievement_flame_leviathan_shutout : public AchievementCriteriaScript
-{
-public:
- achievement_flame_leviathan_shutout() : AchievementCriteriaScript("achievement_flame_leviathan_shutout") {}
-
- bool OnCheck(Player* /*player*/, Unit* target /*Flame Leviathan*/, uint32 /*criteria_id*/) override
- {
- if (target)
- if (target->GetAI()->GetData(DATA_GET_SHUTDOWN))
- return true;
- return false;
- }
-};
-
-class achievement_flame_leviathan_garage : public AchievementCriteriaScript
-{
-public:
- achievement_flame_leviathan_garage(char const* name, uint32 entry1, uint32 entry2) : AchievementCriteriaScript(name),
- _entry1(entry1), _entry2(entry2)
- {
- }
-
- bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override
- {
- if (Vehicle* vehicle = player->GetVehicle())
- if (vehicle->GetCreatureEntry() == _entry1 || vehicle->GetCreatureEntry() == _entry2)
- return true;
- return false;
- }
-
-private:
- uint32 const _entry1;
- uint32 const _entry2;
-};
-
-class achievement_flame_leviathan_unbroken : public AchievementCriteriaScript
-{
-public:
- achievement_flame_leviathan_unbroken() : AchievementCriteriaScript("achievement_flame_leviathan_unbroken") {}
-
- bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override
- {
- if (player->GetInstanceScript())
- if (player->GetInstanceScript()->GetData(DATA_UNBROKEN_ACHIEVEMENT))
- return true;
- return false;
- }
-};
-
void AddSC_boss_flame_leviathan()
{
new boss_flame_leviathan();
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.h
new file mode 100644
index 00000000000000..ce05709d31fa83
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.h
@@ -0,0 +1,1902 @@
+#ifndef BOSS_FLAME_LEVIATHAN_H_
+#define BOSS_FLAME_LEVIATHAN_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CombatAI.h"
+#include "CreatureScript.h"
+#include "GameObjectScript.h"
+#include "GridNotifiers.h"
+#include "Opcodes.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "ScriptedEscortAI.h"
+#include "Spell.h"
+#include "SpellAuraEffects.h"
+#include "SpellAuras.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "Vehicle.h"
+#include "ulduar.h"
+
+enum LeviathanSpells
+{
+ // Leviathan basic
+ SPELL_PURSUED = 62374,
+ SPELL_GATHERING_SPEED = 62375,
+ SPELL_BATTERING_RAM = 62376,
+ SPELL_FLAME_VENTS = 62396,
+ SPELL_MISSILE_BARRAGE = 62400,
+ SPELL_NAPALM_10 = 63666,
+ SPELL_NAPALM_25 = 65026,
+ SPELL_INVIS_AND_STEALTH_DETECT = 18950,
+ SPELL_TRANSITUS_SHIELD_IMPACT = 48387,
+
+ // Shutdown spells
+ SPELL_SYSTEMS_SHUTDOWN = 62475,
+ SPELL_OVERLOAD_CIRCUIT = 62399,
+
+ // hard mode
+ SPELL_TOWER_OF_STORMS = 65076,
+ SPELL_TOWER_OF_FLAMES = 65075,
+ SPELL_TOWER_OF_FROST = 65077,
+ SPELL_TOWER_OF_LIFE = 64482,
+
+ SPELL_HODIRS_FURY = 62533,
+ SPELL_FREYA_WARD = 62906, // removed spawn effect
+ SPELL_MIMIRONS_INFERNO = 62909,
+ SPELL_THORIMS_HAMMER = 62911,
+
+ SPELL_FREYA_DUMMY_BLUE = 63294,
+ SPELL_FREYA_DUMMY_GREEN = 63295,
+ SPELL_FREYA_DUMMY_YELLOW = 63292,
+
+ // Leviathan turret spell
+ SPELL_SEARING_FLAME = 62402,
+ // On turret Destory
+ SPELL_SMOKE_TRAIL = 63575,
+
+ // Pool of tar blaze
+ SPELL_BLAZE = 62292,
+
+ // Pyrite
+ SPELL_LIQUID_PYRITE = 62494,
+ SPELL_DUSTY_EXPLOSION = 63360,
+ SPELL_DUST_CLOUD_IMPACT = 54740,
+};
+
+enum GosNpcs
+{
+ NPC_FLAME_LEVIATHAN_TURRET = 33139,
+ NPC_SEAT = 33114,
+ NPC_MECHANOLIFT = 33214,
+ NPC_LIQUID = 33189,
+
+ // Starting event
+ NPC_ULDUAR_COLOSSUS = 33237,
+ NPC_BRANN_RADIO = 34054,
+ NPC_ULDUAR_GAUNTLET_GENERATOR = 33571,
+ NPC_DEFENDER_GENERATED = 33572,
+
+ // Hard Mode
+ NPC_THORIM_HAMMER_TARGET = 33364,
+ NPC_THORIM_HAMMER = 33365,
+ NPC_FREYA_WARD_TARGET = 33366,
+ NPC_FREYA_WARD = 33367,
+ NPC_MIMIRONS_INFERNO_TARGET = 33369,
+ NPC_MIMIRONS_INFERNO = 33370,
+ NPC_HODIRS_FURY_TARGET = 33108,
+ NPC_HODIRS_FURY = 33212,
+};
+
+enum Events
+{
+ EVENT_PURSUE = 1,
+ EVENT_MISSILE = 2,
+ EVENT_VENT = 3,
+ EVENT_SPEED = 4,
+ EVENT_SUMMON = 5,
+ EVENT_REINSTALL = 6,
+ EVENT_HODIRS_FURY = 7,
+ EVENT_FREYA = 8,
+ EVENT_MIMIRONS_INFERNO = 9,
+ EVENT_THORIMS_HAMMER = 10,
+ EVENT_SOUND_BEGINNING = 11,
+ EVENT_POSITION_CHECK = 12,
+};
+
+enum Texts
+{
+ FLAME_LEVIATHAN_SAY_AGGRO = 0,
+ FLAME_LEVIATHAN_SAY_SLAY = 1,
+ FLAME_LEVIATHAN_SAY_DEATH = 2,
+ FLAME_LEVIATHAN_SAY_PURSUE = 3,
+ FLAME_LEVIATHAN_SAY_HARDMODE = 4,
+ FLAME_LEVIATHAN_SAY_TOWER_NONE = 5,
+ FLAME_LEVIATHAN_SAY_TOWER_FROST = 6,
+ FLAME_LEVIATHAN_SAY_TOWER_FLAME = 7,
+ FLAME_LEVIATHAN_SAY_TOWER_NATURE = 8,
+ FLAME_LEVIATHAN_SAY_TOWER_STORM = 9,
+ FLAME_LEVIATHAN_SAY_PLAYER_RIDING = 10,
+ FLAME_LEVIATHAN_SAY_OVERLOAD = 11,
+ FLAME_LEVIATHAN_EMOTE_PURSUE = 12,
+ FLAME_LEVIATHAN_EMOTE_OVERLOAD = 13,
+ FLAME_LEVIATHAN_EMOTE_REPAIR = 14,
+ FLAME_LEVIATHAN_EMOTE_FROST = 15,
+ FLAME_LEVIATHAN_EMOTE_FLAME = 16,
+ FLAME_LEVIATHAN_EMOTE_NATURE = 17,
+ FLAME_LEVIATHAN_EMOTE_STORM = 18,
+ FLAME_LEVIATHAN_EMOTE_REACTIVATE = 19,
+
+ // NPC_BRANN_RADIO
+ BRANN_RADIO_SAY_FL_START_0 = 0,
+ BRANN_RADIO_SAY_FL_START_1 = 1,
+ BRANN_RADIO_SAY_FL_START_2 = 2,
+ BRANN_RADIO_SAY_GENERATORS = 3,
+ BRANN_RADIO_SAY_STATIONS = 4,
+ BRANN_RADIO_SAY_TOWER_THORIM = 5,
+ BRANN_RADIO_SAY_TOWER_HODIR = 6,
+ BRANN_RADIO_SAY_TOWER_FREYA = 7,
+ BRANN_RADIO_SAY_TOWER_MIMIRON = 8,
+
+ // Vehicle Repair - Said by a spell, BroadcastTextID, same as FLAME_LEVIATHAN_EMOTE_REPAIR
+ VEHICLE_EMOTE_REPAIR = 33538,
+};
+
+enum Seats
+{
+ SEAT_PLAYER = 0,
+ SEAT_TURRET = 1,
+ SEAT_DEVICE = 2,
+ SEAT_CANNON = 7,
+};
+
+enum Misc
+{
+ DATA_EVENT_STARTED = 1,
+ DATA_GET_TOWER_COUNT = 2,
+ DATA_GET_SHUTDOWN = 3,
+
+ TOWER_OF_STORMS = 2,
+ TOWER_OF_FLAMES = 1,
+ TOWER_OF_FROST = 3,
+ TOWER_OF_LIFE = 0,
+
+ ACTION_START_NORGANNON_EVENT = 1,
+ ACTION_START_NORGANNON_BRANN = 2,
+ ACTION_START_BRANN_EVENT = 3,
+ ACTION_DESPAWN_ADDS = 4,
+ ACTION_DELAY_CANNON = 5,
+ ACTION_DESTROYED_TURRET = 6,
+};
+
+const Position homePos = {322.39f, -14.5f, 409.8f, 3.14f};
+
+class boss_flame_leviathan : public CreatureScript
+{
+public:
+ boss_flame_leviathan() : CreatureScript("boss_flame_leviathan") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_flame_leviathanAI : public ScriptedAI
+ {
+ boss_flame_leviathanAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me)
+ {
+ m_pInstance = pCreature->GetInstanceScript();
+ assert(vehicle);
+ }
+
+ InstanceScript* m_pInstance;
+ Vehicle* vehicle;
+ EventMap events;
+ SummonList summons;
+
+ uint32 _startTimer;
+ uint32 _speakTimer;
+ uint8 _towersCount;
+ bool _shutdown;
+ uint32 _destroyedTurretCount;
+
+ // Custom
+ void BindPlayers();
+ void RadioSay(uint8 textid);
+ void ActivateTowers();
+ void TurnGates(bool _start, bool _death);
+ void TurnHealStations(bool _apply);
+ void ScheduleEvents();
+ void SummonTowerHelpers(uint8 towerId);
+
+ // Original
+ void JustReachedHome() override
+ {
+ // For achievement
+ if (m_pInstance)
+ m_pInstance->SetData(DATA_UNBROKEN_ACHIEVEMENT, 0);
+ me->setActive(false);
+ }
+
+ void MoveInLineOfSight(Unit*) override {}
+ void JustSummoned(Creature* cr) override
+ {
+ if (cr->GetEntry() != NPC_FLAME_LEVIATHAN_TURRET && cr->GetEntry() != NPC_SEAT)
+ summons.Summon(cr);
+ }
+
+ void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); }
+ void SpellHit(Unit* caster, SpellInfo const* spellInfo) override;
+ void JustDied(Unit*) override;
+ void KilledUnit(Unit* who) override;
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override;
+
+ void AttackStart(Unit* who) override
+ {
+ if (Unit* veh = who->GetVehicleBase())
+ ScriptedAI::AttackStart(veh);
+ else
+ ScriptedAI::AttackStart(who);
+ }
+
+ void JustEngagedWith(Unit*) override
+ {
+ ScheduleEvents();
+ Talk(FLAME_LEVIATHAN_SAY_AGGRO);
+
+ me->setActive(true);
+ me->SetHomePosition(homePos);
+ TurnHealStations(false);
+ ActivateTowers();
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_LEVIATHAN, SPECIAL);
+
+ BindPlayers();
+ me->SetInCombatWithZone();
+
+ if (!_startTimer)
+ {
+ TurnGates(true, false);
+ }
+ }
+
+ void InitializeAI() override
+ {
+ if (m_pInstance && m_pInstance->GetData(TYPE_LEVIATHAN) == SPECIAL)
+ {
+ me->SetHomePosition(homePos);
+ me->UpdatePosition(homePos);
+ me->StopMovingOnCurrentPos();
+ }
+
+ ScriptedAI::InitializeAI();
+ }
+
+ void Reset() override
+ {
+ // Special immunity case
+ me->CastSpell(me, SPELL_INVIS_AND_STEALTH_DETECT, true);
+ me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED, true);
+
+ summons.DoAction(ACTION_DESPAWN_ADDS);
+ summons.DespawnAll();
+ events.Reset();
+
+ _shutdown = false;
+ _startTimer = 1;
+ _speakTimer = 0;
+ _towersCount = 0;
+ _destroyedTurretCount = 0;
+
+ if (m_pInstance)
+ {
+ if (m_pInstance->GetData(TYPE_LEVIATHAN) != SPECIAL)
+ {
+ m_pInstance->SetData(TYPE_LEVIATHAN, NOT_STARTED);
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ }
+ else
+ {
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ m_pInstance->SetData(DATA_VEHICLE_SPAWN, VEHICLE_POS_LEVIATHAN);
+ _startTimer = 0;
+ }
+ }
+
+ TurnGates(false, false);
+ TurnHealStations(true);
+ }
+
+ uint32 GetData(uint32 param) const override
+ {
+ if (param == DATA_GET_TOWER_COUNT)
+ return _towersCount;
+ if (param == DATA_GET_SHUTDOWN)
+ return !_shutdown;
+
+ return 0;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ // THIS IS USED ONLY FOR FIRST ENGAGE!
+ if (_startTimer)
+ {
+ _startTimer += diff;
+ if (_startTimer >= 4000)
+ {
+ // Colossus dead, players in range
+ if (me->FindNearestCreature(NPC_ULDUAR_COLOSSUS, 250.0f, true) || !SelectTargetFromPlayerList(250.0f))
+ _startTimer = 1;
+ else
+ {
+ _startTimer = 0;
+ _speakTimer = 1;
+ }
+ }
+ return;
+ }
+
+ if (_speakTimer)
+ {
+ _speakTimer += diff;
+ if (_speakTimer <= 10000)
+ {
+ _speakTimer = 10000;
+ RadioSay(BRANN_RADIO_SAY_FL_START_0);
+ }
+ else if (_speakTimer > 16000 && _speakTimer < 20000)
+ {
+ _speakTimer = 20000;
+ RadioSay(BRANN_RADIO_SAY_FL_START_1);
+ }
+ else if (_speakTimer > 24000 && _speakTimer < 40000)
+ {
+ _speakTimer = 40000;
+ RadioSay(BRANN_RADIO_SAY_FL_START_2);
+ }
+ else if (_speakTimer > 41000 && _speakTimer < 60000)
+ {
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ TurnGates(true, false);
+ me->MonsterMoveWithSpeed(homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), 100.0f);
+ me->UpdatePosition(homePos);
+ _speakTimer = 60000;
+ }
+ else if (_speakTimer > 63500)
+ {
+ me->SetInCombatWithZone();
+ if (!me->GetVictim())
+ {
+ me->CastSpell(me, SPELL_PURSUED, false);
+ events.RescheduleEvent(EVENT_PURSUE, 31s);
+ }
+ _speakTimer = 0;
+ }
+ return;
+ }
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_POSITION_CHECK:
+ if (me->GetPositionX() > 450 || me->GetPositionX() < 120)
+ {
+ EnterEvadeMode();
+ return;
+ }
+ events.Repeat(5s);
+ break;
+ case EVENT_PURSUE:
+ Talk(FLAME_LEVIATHAN_SAY_PURSUE);
+ me->CastSpell(me, SPELL_PURSUED, false);
+ events.RescheduleEvent(EVENT_PURSUE, 31s);
+ return;
+ case EVENT_SPEED:
+ me->CastSpell(me, SPELL_GATHERING_SPEED, false);
+ events.Repeat(15s);
+ return;
+ case EVENT_MISSILE:
+ me->CastSpell(me, SPELL_MISSILE_BARRAGE, true);
+ events.Repeat(4s);
+ return;
+ case EVENT_VENT:
+ me->CastSpell(me, SPELL_FLAME_VENTS, false);
+ events.Repeat(20s);
+ return;
+ case EVENT_SUMMON:
+ if(summons.size() < 20)
+ if (Creature* lift = DoSummonFlyer(NPC_MECHANOLIFT, me, 30.0f, 50.0f, 0))
+ lift->GetMotionMaster()->MoveRandom(100);
+
+ events.Repeat(4s);
+ return;
+ case EVENT_SOUND_BEGINNING:
+ if (_towersCount)
+ Talk(FLAME_LEVIATHAN_SAY_HARDMODE);
+ else
+ Talk(FLAME_LEVIATHAN_SAY_TOWER_NONE);
+ return;
+ case EVENT_REINSTALL:
+ for (uint8 i = RAID_MODE(0, 2); i < 4; ++i)
+ if (Unit* seat = vehicle->GetPassenger(i))
+ if (seat->GetTypeId() == TYPEID_UNIT)
+ seat->ToCreature()->AI()->EnterEvadeMode();
+ Talk(FLAME_LEVIATHAN_EMOTE_REACTIVATE);
+ return;
+ case EVENT_THORIMS_HAMMER:
+ SummonTowerHelpers(TOWER_OF_STORMS);
+ events.Repeat(1min, 2min);
+ Talk(FLAME_LEVIATHAN_EMOTE_STORM);
+ Talk(FLAME_LEVIATHAN_SAY_TOWER_STORM);
+ return;
+ case EVENT_FREYA:
+ SummonTowerHelpers(TOWER_OF_LIFE);
+ Talk(FLAME_LEVIATHAN_EMOTE_NATURE);
+ Talk(FLAME_LEVIATHAN_SAY_TOWER_NATURE);
+ return;
+ case EVENT_MIMIRONS_INFERNO:
+ SummonTowerHelpers(TOWER_OF_FLAMES);
+ Talk(FLAME_LEVIATHAN_EMOTE_FLAME);
+ Talk(FLAME_LEVIATHAN_SAY_TOWER_FLAME);
+ return;
+ case EVENT_HODIRS_FURY:
+ SummonTowerHelpers(TOWER_OF_FROST);
+ Talk(FLAME_LEVIATHAN_EMOTE_FROST);
+ Talk(FLAME_LEVIATHAN_SAY_TOWER_FROST);
+ return;
+ }
+
+ if(me->isAttackReady() && !me->HasUnitState(UNIT_STATE_STUNNED))
+ {
+ if(me->IsWithinCombatRange(me->GetVictim(), 15.0f))
+ {
+ me->CastSpell(me->GetVictim(), SPELL_BATTERING_RAM, false);
+ me->resetAttackTimer();
+ }
+ }
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_DESTROYED_TURRET)
+ {
+ ++_destroyedTurretCount;
+
+ if (_destroyedTurretCount == RAID_MODE(2, 4))
+ {
+ _destroyedTurretCount = 0;
+ me->CastSpell(me, SPELL_SYSTEMS_SHUTDOWN, true);
+ }
+ }
+ }
+ };
+};
+
+class boss_flame_leviathan_seat : public CreatureScript
+{
+public:
+ boss_flame_leviathan_seat() : CreatureScript("boss_flame_leviathan_seat") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_flame_leviathan_seatAI : public VehicleAI
+ {
+ boss_flame_leviathan_seatAI(Creature* creature) : VehicleAI(creature), vehicle(creature->GetVehicleKit())
+ {
+ ASSERT(vehicle);
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ Vehicle* vehicle;
+ uint32 _despawnTimer;
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ vehicle->InstallAllAccessories(false);
+ }
+
+ void Reset() override
+ {
+ _despawnTimer = !me->GetMap()->Is25ManRaid();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_despawnTimer)
+ {
+ _despawnTimer += diff;
+ if (_despawnTimer >= 2000)
+ {
+ _despawnTimer = 0;
+ if (Vehicle* veh = me->GetVehicle())
+ if (veh->GetPassenger(0) == me || veh->GetPassenger(1) == me)
+ me->DespawnOrUnsummon(1);
+ }
+ }
+
+ VehicleAI::UpdateAI(diff);
+ }
+
+ void AttackStart(Unit*) override { }
+
+ void PassengerBoarded(Unit* who, int8 seatId, bool apply) override
+ {
+ if (who->GetTypeId() != TYPEID_PLAYER || !me->GetVehicle())
+ return;
+
+ who->ApplySpellImmune(63847, IMMUNITY_ID, 63847, apply); // SPELL_FLAME_VENTS_TRIGGER
+ who->ApplySpellImmune(SPELL_MISSILE_BARRAGE, IMMUNITY_ID, SPELL_MISSILE_BARRAGE, apply);
+ who->ApplySpellImmune(SPELL_BATTERING_RAM, IMMUNITY_ID, SPELL_BATTERING_RAM, apply);
+
+ if (seatId == SEAT_PLAYER)
+ {
+ if (Unit* turret = me->GetVehicleKit()->GetPassenger(SEAT_TURRET))
+ {
+ if (apply)
+ {
+ turret->ReplaceAllUnitFlags(UNIT_FLAG_NONE);
+ turret->GetAI()->AttackStart(who);
+ if (Creature* leviathan = me->GetVehicleCreatureBase())
+ leviathan->AI()->Talk(FLAME_LEVIATHAN_SAY_PLAYER_RIDING);
+ }
+ else
+ {
+ turret->ReplaceAllUnitFlags(UNIT_FLAG_NOT_SELECTABLE);
+ turret->SetImmuneToAll(true);
+ if (turret->GetTypeId() == TYPEID_UNIT)
+ turret->ToCreature()->AI()->EnterEvadeMode();
+ }
+ }
+ }
+ }
+ };
+};
+
+class boss_flame_leviathan_defense_turret : public CreatureScript
+{
+public:
+ boss_flame_leviathan_defense_turret() : CreatureScript("boss_flame_leviathan_defense_turret") { }
+
+ struct boss_flame_leviathan_defense_turretAI : public TurretAI
+ {
+ boss_flame_leviathan_defense_turretAI(Creature* creature) : TurretAI(creature)
+ {
+ _setHealth = false;
+ _instance = creature->GetInstanceScript();
+ }
+
+ InstanceScript* _instance;
+
+ bool _setHealth;
+ void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (!CanAIAttack(who))
+ {
+ _setHealth = true;
+ damage = 0;
+ }
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ if (Player* player = killer->ToPlayer())
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, me);
+
+ if (Vehicle* vehicle = me->GetVehicle())
+ if (Unit* device = vehicle->GetPassenger(SEAT_DEVICE))
+ device->ReplaceAllUnitFlags(UNIT_FLAG_NONE); // unselectable
+
+ if (Creature* leviathan = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(TYPE_LEVIATHAN)))
+ leviathan->AI()->DoAction(ACTION_DESTROYED_TURRET);
+ }
+
+ bool CanAIAttack(Unit const* who) const override
+ {
+ if (!who || who->GetTypeId() != TYPEID_PLAYER || !who->GetVehicle() || who->GetVehicleBase()->GetEntry() != NPC_SEAT)
+ return false;
+ return true;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_setHealth)
+ {
+ me->SetHealth(std::min(me->GetHealth() + 1, me->GetMaxHealth()));
+ _setHealth = false;
+ }
+
+ TurretAI::UpdateAI(diff);
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (Player* plr = who->ToPlayer()) // make sure that there's no death player on the seat.
+ if (plr->GetVehicle())
+ plr->ExitVehicle();
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI(creature);
+ }
+};
+
+class boss_flame_leviathan_overload_device : public CreatureScript
+{
+public:
+ boss_flame_leviathan_overload_device() : CreatureScript("boss_flame_leviathan_overload_device") { }
+
+ struct boss_flame_leviathan_overload_deviceAI : public NullCreatureAI
+ {
+ boss_flame_leviathan_overload_deviceAI(Creature* creature) : NullCreatureAI(creature)
+ {
+ }
+
+ void OnSpellClick(Unit* /*clicker*/, bool& result) override
+ {
+ if (!result)
+ return;
+
+ if (me->GetVehicle())
+ {
+ me->RemoveNpcFlag(UNIT_NPC_FLAG_SPELLCLICK);
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+
+ if (Unit* player = me->GetVehicle()->GetPassenger(SEAT_PLAYER))
+ {
+ me->GetVehicleBase()->CastSpell(player, SPELL_SMOKE_TRAIL, true);
+ player->ExitVehicle();
+ }
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI(creature);
+ }
+};
+
+class npc_freya_ward : public CreatureScript
+{
+public:
+ npc_freya_ward() : CreatureScript("npc_freya_ward") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_freya_wardAI : public NullCreatureAI
+ {
+ npc_freya_wardAI(Creature* c) : NullCreatureAI(c), summons(c)
+ {
+ }
+
+ SummonList summons;
+ uint32 _castTimer;
+ bool _summoned;
+
+ void Reset() override
+ {
+ _summoned = false;
+ _castTimer = 25000;
+ summons.DespawnAll();
+ if (Creature* cr = me->FindNearestCreature(NPC_FREYA_WARD_TARGET, 60.0f, true))
+ if (Aura* aur = cr->AddAura(SPELL_FREYA_DUMMY_GREEN, cr))
+ {
+ aur->SetMaxDuration(-1);
+ aur->SetDuration(-1);
+ }
+ }
+
+ void JustSummoned(Creature* cr) override
+ {
+ _summoned = true;
+ summons.Summon(cr);
+ }
+
+ void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_summoned)
+ {
+ for (SummonList::const_iterator itr = summons.begin(); itr != summons.end();)
+ {
+ Creature* summon = ObjectAccessor::GetCreature(*me, *itr);
+ ++itr;
+ if (summon)
+ {
+ summon->ToTempSummon()->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN);
+ if (Unit* target = summon->SelectNearestTarget(200.0f))
+ summon->AI()->AttackStart(target);
+ }
+ }
+ _summoned = false;
+ }
+
+ _castTimer += diff;
+ if (_castTimer >= 29 * IN_MILLISECONDS)
+ {
+ if (Creature* cr = me->FindNearestCreature(NPC_FREYA_WARD_TARGET, 60.0f, true))
+ {
+ me->CastSpell(cr, SPELL_FREYA_WARD, false);
+ me->CastSpell(cr, 62947 /*SPELL_FREYA_WARD_SECOND_SUMMON*/, false);
+ }
+
+ _castTimer = 0;
+ }
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_DESPAWN_ADDS)
+ summons.DespawnAll();
+ }
+ };
+};
+
+class npc_hodirs_fury : public CreatureScript
+{
+public:
+ npc_hodirs_fury() : CreatureScript("npc_hodirs_fury") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_hodirs_furyAI : public NullCreatureAI
+ {
+ npc_hodirs_furyAI(Creature* c) : NullCreatureAI(c)
+ {
+ }
+
+ uint32 _timeToHit;
+ uint32 _switchTargetTimer;
+
+ void Reset() override
+ {
+ _timeToHit = 0;
+ _switchTargetTimer = 30000;
+ me->SetWalk(true);
+
+ if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_BLUE, me))
+ {
+ aur->SetMaxDuration(-1);
+ aur->SetDuration(-1);
+ }
+ }
+
+ void MovementInform(uint32 type, uint32 /*param*/) override
+ {
+ if (type == FOLLOW_MOTION_TYPE && !_timeToHit)
+ {
+ _timeToHit = 1;
+ _switchTargetTimer = 0;
+ me->SetControlled(true, UNIT_STATE_STUNNED);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_timeToHit)
+ {
+ _timeToHit += diff;
+ if (_timeToHit >= 5000)
+ {
+ if (Creature* cr = me->SummonCreature(NPC_HODIRS_FURY, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40, 0, TEMPSUMMON_TIMED_DESPAWN, 10000))
+ cr->CastSpell(me, SPELL_HODIRS_FURY, true);
+
+ _switchTargetTimer = 25000; // Switch target soon
+ _timeToHit = 0;
+ }
+ return;
+ }
+
+ _switchTargetTimer += diff;
+ if (_switchTargetTimer >= 30000)
+ {
+ if(Unit* target = me->SelectNearbyTarget(nullptr, 200.0f))
+ {
+ if (target->GetVehicleBase() && target->GetVehicleBase()->GetEntry() == NPC_SEAT)
+ {
+ _switchTargetTimer = 20000;
+ return;
+ }
+ me->SetControlled(false, UNIT_STATE_STUNNED);
+ me->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f);
+ _switchTargetTimer = 0;
+ }
+ else
+ _switchTargetTimer = 25000;
+ }
+ }
+ };
+};
+
+class npc_mimirons_inferno : public CreatureScript
+{
+public:
+ npc_mimirons_inferno() : CreatureScript("npc_mimirons_inferno") { }
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI(creature);
+ }
+
+ struct npc_mimirons_infernoAI : public npc_escortAI
+ {
+ npc_mimirons_infernoAI(Creature* creature) : npc_escortAI(creature), summons(me)
+ {
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ SummonList summons;
+ uint32 _spellTimer;
+ uint32 _recastTimer;
+
+ void AttackStart(Unit*) override { }
+ void MoveInLineOfSight(Unit*) override { }
+ void WaypointReached(uint32 /*waypointId*/) override { }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_DESPAWN_ADDS)
+ summons.DespawnAll();
+ }
+
+ void Reset() override
+ {
+ summons.DespawnAll();
+ _spellTimer = 0;
+ Start(false, false, ObjectGuid::Empty, nullptr, false, true);
+ if (Aura* aur = me->AddAura(SPELL_FREYA_DUMMY_YELLOW, me))
+ {
+ aur->SetMaxDuration(-1);
+ aur->SetDuration(-1);
+ }
+ }
+
+ void JustSummoned(Creature* cr) override { summons.Summon(cr); }
+ void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); }
+
+ void UpdateAI(uint32 diff) override
+ {
+ npc_escortAI::UpdateAI(diff);
+
+ _spellTimer += diff;
+ if (_spellTimer >= 2000)
+ {
+ if (Creature* cr = me->SummonCreature(NPC_MIMIRONS_INFERNO, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000))
+ cr->CastSpell(me, SPELL_MIMIRONS_INFERNO, true);
+
+ _spellTimer = 0;
+ }
+ }
+ };
+};
+
+class npc_thorims_hammer : public CreatureScript
+{
+public:
+ npc_thorims_hammer() : CreatureScript("npc_thorims_hammer") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_thorims_hammerAI : public NullCreatureAI
+ {
+ npc_thorims_hammerAI(Creature* c) : NullCreatureAI(c)
+ {
+ }
+
+ uint32 _beamTimer;
+ uint32 _finishTime;
+ uint32 _removeTimer;
+
+ void Reset() override
+ {
+ _finishTime = 5000 + rand() % 15000;
+ _beamTimer = 1;
+ _removeTimer = 0;
+ me->CastSpell(me, SPELL_FREYA_DUMMY_BLUE, true);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_beamTimer)
+ {
+ _beamTimer += diff;
+ if (_beamTimer >= _finishTime)
+ {
+ if (Creature* cr = me->SummonCreature(NPC_THORIM_HAMMER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 40, 0, TEMPSUMMON_TIMED_DESPAWN, 5000))
+ cr->CastSpell(me, SPELL_THORIMS_HAMMER, false);
+
+ _beamTimer = 0;
+ _removeTimer = 1;
+ me->DespawnOrUnsummon(5 * IN_MILLISECONDS);
+ }
+ }
+ if (_removeTimer)
+ {
+ _removeTimer += diff;
+ if (_removeTimer >= 3 * IN_MILLISECONDS)
+ {
+ _removeTimer = 0;
+ me->RemoveAura(SPELL_FREYA_DUMMY_BLUE);
+ }
+ }
+ }
+ };
+};
+
+class npc_pool_of_tar : public CreatureScript
+{
+public:
+ npc_pool_of_tar() : CreatureScript("npc_pool_of_tar") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_pool_of_tarAI : public NullCreatureAI
+ {
+ npc_pool_of_tarAI(Creature* c) : NullCreatureAI(c)
+ {
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ damage = 0;
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->SchoolMask & SPELL_SCHOOL_MASK_FIRE && !me->HasAura(SPELL_BLAZE))
+ me->CastSpell(me, SPELL_BLAZE, true);
+ }
+ };
+};
+
+class npc_brann_radio : public CreatureScript
+{
+public:
+ npc_brann_radio() : CreatureScript("npc_brann_radio") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_brann_radioAI : public NullCreatureAI
+ {
+ npc_brann_radioAI(Creature* c) : NullCreatureAI(c)
+ {
+ _lock = (me->GetInstanceScript() && me->GetInstanceScript()->GetData(TYPE_LEVIATHAN) > NOT_STARTED);
+ _helpLock = _lock;
+ }
+
+ bool _lock;
+ bool _helpLock;
+
+ void Reset() override
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (!_lock)
+ {
+ if (who->GetTypeId() != TYPEID_PLAYER && !who->IsVehicle())
+ return;
+
+ // MIMIRON
+ else if (me->GetDistance2d(-81.9207f, 111.432f) < 5.0f)
+ {
+ if (me->GetDistance2d(who) <= 60.0f && who->GetPositionZ() > 430.0f)
+ {
+ Talk(BRANN_RADIO_SAY_TOWER_MIMIRON);
+ _lock = true;
+ }
+ }
+ // FREYA
+ else if (me->GetDistance2d(-221.475f, -271.087f) < 5.0f)
+ {
+ if (me->GetDistance2d(who) <= 60.0f && who->GetPositionZ() < 380.0f)
+ {
+ Talk(BRANN_RADIO_SAY_TOWER_FREYA);
+ _lock = true;
+ }
+ }
+ // STATIONS
+ else if (me->GetDistance2d(73.8978f, -29.3306f) < 5.0f)
+ {
+ if (me->GetDistance2d(who) <= 40.0f)
+ {
+ Talk(BRANN_RADIO_SAY_STATIONS);
+ _lock = true;
+ }
+ }
+ // HODIR
+ else if (me->GetDistance2d(68.7679f, -325.026f) < 5.0f)
+ {
+ if (me->GetDistance2d(who) <= 40.0f)
+ {
+ Talk(BRANN_RADIO_SAY_TOWER_HODIR);
+ _lock = true;
+ }
+ }
+ // THORIM
+ else if (me->GetDistance2d(174.442f, 345.679f) < 5.0f)
+ {
+ if (me->GetDistance2d(who) <= 60.0f)
+ {
+ Talk(BRANN_RADIO_SAY_TOWER_THORIM);
+ _lock = true;
+ }
+ }
+ // COME A BIT CLOSER
+ else if (me->GetDistance2d(-508.898f, -32.9631f) < 5.0f)
+ {
+ if (who->GetPositionX() >= -480.0f)
+ {
+ Talk(BRANN_RADIO_SAY_GENERATORS);
+ _lock = true;
+ }
+ }
+ }
+ }
+ };
+};
+
+class npc_storm_beacon_spawn : public CreatureScript
+{
+public:
+ npc_storm_beacon_spawn() : CreatureScript("npc_storm_beacon_spawn") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_storm_beacon_spawnAI : public NullCreatureAI
+ {
+ npc_storm_beacon_spawnAI(Creature* c) : NullCreatureAI(c)
+ {
+ _amount = 0;
+ _checkTimer = 0;
+ }
+
+ uint8 _amount;
+ uint32 _checkTimer;
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_amount < 40)
+ {
+ _checkTimer += diff;
+ if (_checkTimer >= 4000)
+ {
+ _checkTimer = 0;
+ if (Unit* target = me->SelectNearbyTarget(nullptr, 80.0f))
+ {
+ ++_amount;
+ if (Creature* cr = me->SummonCreature(NPC_DEFENDER_GENERATED, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 4, me->GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 900000))
+ cr->AI()->AttackStart(target);
+ }
+ }
+ }
+ }
+ };
+};
+
+class boss_flame_leviathan_safety_container : public CreatureScript
+{
+public:
+ boss_flame_leviathan_safety_container() : CreatureScript("boss_flame_leviathan_safety_container") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_flame_leviathan_safety_containerAI : public NullCreatureAI
+ {
+ boss_flame_leviathan_safety_containerAI(Creature* c) : NullCreatureAI(c)
+ {
+ _allowTimer = 0;
+ }
+
+ uint32 _allowTimer;
+
+ void MovementInform(uint32 /*type*/, uint32 id) override
+ {
+ if (id == me->GetEntry())
+ {
+ if (Creature* liquid = me->SummonCreature(NPC_LIQUID, *me))
+ {
+ liquid->CastSpell(liquid, SPELL_LIQUID_PYRITE, true);
+ liquid->CastSpell(liquid, SPELL_DUST_CLOUD_IMPACT, true);
+ }
+
+ me->DespawnOrUnsummon(1);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _allowTimer += diff;
+ if (_allowTimer >= 5000 && !me->GetVehicle() && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)
+ {
+ float x, y, z;
+ me->GetPosition(x, y, z);
+ z = me->GetMapHeight(x, y, z);
+ me->GetMotionMaster()->MovePoint(me->GetEntry(), x, y, z);
+ me->SetPosition(x, y, z, 0);
+ }
+ }
+ };
+};
+
+class npc_mechanolift : public CreatureScript
+{
+public:
+ npc_mechanolift() : CreatureScript("npc_mechanolift") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_mechanoliftAI : public NullCreatureAI
+ {
+ npc_mechanoliftAI(Creature* c) : NullCreatureAI(c)
+ {
+ me->SetSpeed(MOVE_RUN, rand_norm() + 0.5f);
+ }
+
+ int32 _startTimer;
+ uint32 _evadeTimer;
+
+ void Reset() override
+ {
+ _startTimer = urand(1, 5000);
+ _evadeTimer = 0;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_startTimer)
+ {
+ _startTimer -= diff;
+ if (_startTimer <= 0)
+ {
+ me->GetMotionMaster()->MovePath(3000000 + urand(0, 11), true);
+ _startTimer = 0;
+ }
+ }
+
+ _evadeTimer += diff;
+ if (_evadeTimer >= 10000)
+ {
+ _EnterEvadeMode();
+ _evadeTimer = 0;
+ }
+ }
+ };
+};
+
+class go_ulduar_tower : public GameObjectScript
+{
+public:
+ go_ulduar_tower() : GameObjectScript("go_ulduar_tower") { }
+
+ void OnDestroyed(GameObject* go, Player* /*player*/) override
+ {
+ Creature* trigger = go->FindNearestCreature(NPC_ULDUAR_GAUNTLET_GENERATOR, 15.0f, true);
+ if (trigger)
+ trigger->DisappearAndDie();
+ }
+};
+
+class spell_load_into_catapult : public SpellScriptLoader
+{
+ enum Spells
+ {
+ SPELL_PASSENGER_LOADED = 62340,
+ };
+
+public:
+ spell_load_into_catapult() : SpellScriptLoader("spell_load_into_catapult") { }
+
+ class spell_load_into_catapult_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_load_into_catapult_AuraScript);
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* owner = GetOwner()->ToUnit();
+ if (!owner)
+ return;
+
+ owner->CastSpell(owner, SPELL_PASSENGER_LOADED, true);
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* owner = GetOwner()->ToUnit();
+ if (!owner)
+ return;
+
+ owner->RemoveAurasDueToSpell(SPELL_PASSENGER_LOADED);
+ }
+
+ void Register() override
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_load_into_catapult_AuraScript::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL);
+ OnEffectRemove += AuraEffectRemoveFn(spell_load_into_catapult_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_load_into_catapult_AuraScript();
+ }
+};
+
+class spell_auto_repair : public SpellScriptLoader
+{
+ enum Spells
+ {
+ SPELL_AUTO_REPAIR = 62705,
+ };
+
+public:
+ spell_auto_repair() : SpellScriptLoader("spell_auto_repair") {}
+
+ class spell_auto_repair_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_auto_repair_SpellScript);
+
+ void FilterTargets(std::list& targets)
+ {
+ std::list tmplist;
+ for (std::list::iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ if (!(*itr)->ToUnit()->HasAura(SPELL_AUTO_REPAIR))
+ tmplist.push_back(*itr);
+
+ targets.clear();
+ for (std::list::iterator itr = tmplist.begin(); itr != tmplist.end(); ++itr)
+ targets.push_back(*itr);
+ }
+
+ void HandleScript(SpellEffIndex /*eff*/)
+ {
+ Vehicle* vehicle = GetHitUnit()->GetVehicleKit();
+ if (!vehicle)
+ return;
+
+ Unit* driver = vehicle->GetPassenger(0);
+ if (!driver)
+ return;
+
+ //driver->TextEmote(VEHICLE_EMOTE_REPAIR, driver, true); // No source
+
+ // Actually should/could use basepoints (100) for this spell effect as percentage of health, but oh well.
+ vehicle->GetBase()->SetFullHealth();
+
+ // Achievement
+ if (InstanceScript* instance = vehicle->GetBase()->GetInstanceScript())
+ instance->SetData(DATA_UNBROKEN_ACHIEVEMENT, 0);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_auto_repair_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENTRY);
+ OnEffectHitTarget += SpellEffectFn(spell_auto_repair_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_auto_repair_SpellScript();
+ }
+};
+
+class spell_systems_shutdown : public SpellScriptLoader
+{
+public:
+ spell_systems_shutdown() : SpellScriptLoader("spell_systems_shutdown") { }
+
+ class spell_systems_shutdown_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_systems_shutdown_AuraScript);
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Creature* owner = GetOwner()->ToCreature();
+ if (!owner)
+ return;
+
+ owner->SetControlled(true, UNIT_STATE_STUNNED);
+ owner->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED);
+ if (Vehicle* veh = owner->GetVehicleKit())
+ if (Unit* cannon = veh->GetPassenger(SEAT_CANNON))
+ cannon->GetAI()->DoAction(ACTION_DELAY_CANNON);
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Creature* owner = GetOwner()->ToCreature();
+ if (!owner)
+ return;
+
+ owner->SetControlled(false, UNIT_STATE_STUNNED);
+ }
+
+ void Register() override
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_systems_shutdown_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL);
+ OnEffectRemove += AuraEffectRemoveFn(spell_systems_shutdown_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_systems_shutdown_AuraScript();
+ }
+};
+
+class FlameLeviathanPursuedTargetSelector
+{
+ enum Area
+ {
+ AREA_FORMATION_GROUNDS = 4652,
+ };
+
+public:
+ explicit FlameLeviathanPursuedTargetSelector() {};
+
+ bool operator()(WorldObject* target) const
+ {
+ //! No players, only vehicles (todo: check if blizzlike)
+ Creature* creatureTarget = target->ToCreature();
+ if (!creatureTarget)
+ return true;
+
+ //! NPC entries must match
+ if (creatureTarget->GetEntry() != NPC_SALVAGED_DEMOLISHER && creatureTarget->GetEntry() != NPC_SALVAGED_SIEGE_ENGINE)
+ return true;
+
+ //! NPC must be a valid vehicle installation
+ Vehicle* vehicle = creatureTarget->GetVehicleKit();
+ if (!vehicle)
+ return true;
+
+ //! Entity needs to be in appropriate area
+ if (target->GetAreaId() != AREA_FORMATION_GROUNDS)
+ return true;
+
+ //! Vehicle must be in use by player
+ bool playerFound = false;
+ for (SeatMap::const_iterator itr = vehicle->Seats.begin(); itr != vehicle->Seats.end() && !playerFound; ++itr)
+ if (itr->second.Passenger.Guid.IsPlayer())
+ playerFound = true;
+
+ return !playerFound;
+ }
+};
+
+class spell_pursue : public SpellScriptLoader
+{
+public:
+ spell_pursue() : SpellScriptLoader("spell_pursue") {}
+
+ class spell_pursue_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_pursue_SpellScript);
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove_if(FlameLeviathanPursuedTargetSelector());
+ if (targets.empty())
+ {
+ if (Creature* caster = GetCaster()->ToCreature())
+ caster->AI()->EnterEvadeMode();
+ }
+ else
+ {
+ //! In the end, only one target should be selected
+ WorldObject* _target = Acore::Containers::SelectRandomContainerElement(targets);
+ targets.clear();
+ if (_target)
+ targets.push_back(_target);
+ }
+ }
+
+ void HandleScript(SpellEffIndex /*eff*/)
+ {
+ Creature* target = GetHitCreature();
+ Unit* caster = GetCaster();
+ if (!target || !caster)
+ return;
+
+ caster->GetThreatMgr().ResetAllThreat();
+ caster->GetAI()->AttackStart(target); // Chase target
+ caster->AddThreat(target, 10000000.0f);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_pursue_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnEffectHitTarget += SpellEffectFn(spell_pursue_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_pursue_SpellScript();
+ }
+};
+
+class spell_vehicle_throw_passenger : public SpellScriptLoader
+{
+public:
+ spell_vehicle_throw_passenger() : SpellScriptLoader("spell_vehicle_throw_passenger") {}
+
+ class spell_vehicle_throw_passenger_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_vehicle_throw_passenger_SpellScript);
+ void HandleScript()
+ {
+ Spell* baseSpell = GetSpell();
+ SpellCastTargets targets = baseSpell->m_targets;
+ if (Vehicle* vehicle = GetCaster()->GetVehicleKit())
+ if (Unit* passenger = vehicle->GetPassenger(3))
+ {
+ // use 99 because it is 3d search
+ std::list targetList;
+ Acore::WorldObjectSpellAreaTargetCheck check(99, GetExplTargetDest(), GetCaster(), GetCaster(), GetSpellInfo(), TARGET_CHECK_DEFAULT, nullptr);
+ Acore::WorldObjectListSearcher searcher(GetCaster(), targetList, check);
+ Cell::VisitAllObjects(GetCaster(), searcher, 99.0f);
+ float minDist = 99 * 99;
+ Unit* target = nullptr;
+ for (std::list::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
+ {
+ if (Unit* unit = (*itr)->ToUnit())
+ if (unit->GetEntry() == NPC_SEAT)
+ if (Vehicle* seat = unit->GetVehicleKit())
+ if (!seat->GetPassenger(0))
+ if (Unit* device = seat->GetPassenger(2))
+ if (!device->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
+ {
+ float dist = unit->GetExactDistSq(targets.GetDstPos());
+ if (dist < minDist)
+ {
+ minDist = dist;
+ target = unit;
+ }
+ }
+ }
+ if (target && target->IsWithinDist2d(targets.GetDstPos(), GetSpellInfo()->Effects[EFFECT_0].CalcRadius() * 2)) // now we use *2 because the location of the seat is not correct
+ {
+ passenger->ExitVehicle();
+ passenger->EnterVehicle(target, 0);
+ }
+ else
+ {
+ passenger->ExitVehicle();
+ float x, y, z;
+ targets.GetDstPos()->GetPosition(x, y, z);
+ passenger->GetMotionMaster()->MoveJump(x, y, z, targets.GetSpeedXY(), targets.GetSpeedZ());
+ }
+ }
+ }
+
+ void Register() override
+ {
+ AfterCast += SpellCastFn(spell_vehicle_throw_passenger_SpellScript::HandleScript);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_vehicle_throw_passenger_SpellScript();
+ }
+};
+
+class spell_tar_blaze : public SpellScriptLoader
+{
+public:
+ spell_tar_blaze() : SpellScriptLoader("spell_tar_blaze") { }
+
+ class spell_tar_blaze_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_tar_blaze_AuraScript);
+
+ void OnPeriodic(AuraEffect const* aurEff)
+ {
+ GetUnitOwner()->CastSpell((Unit*)nullptr, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_tar_blaze_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_tar_blaze_AuraScript();
+ }
+};
+
+class spell_vehicle_grab_pyrite : public SpellScriptLoader
+{
+public:
+ spell_vehicle_grab_pyrite() : SpellScriptLoader("spell_vehicle_grab_pyrite") {}
+
+ class spell_vehicle_grab_pyrite_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_vehicle_grab_pyrite_SpellScript);
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* target = GetHitUnit())
+ if (Unit* seat = GetCaster()->GetVehicleBase())
+ {
+ if (Vehicle* vSeat = seat->GetVehicleKit())
+ if (Unit* pyrite = vSeat->GetPassenger(1))
+ pyrite->ExitVehicle();
+
+ if (Unit* parent = seat->GetVehicleBase())
+ {
+ GetCaster()->CastSpell(parent, 62496 /*SPELL_ADD_PYRITE*/, true);
+ target->CastSpell(seat, GetEffectValue());
+
+ if (target->GetTypeId() == TYPEID_UNIT)
+ target->ToCreature()->DespawnOrUnsummon(1300);
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_vehicle_grab_pyrite_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_vehicle_grab_pyrite_SpellScript();
+ }
+};
+
+class spell_vehicle_circuit_overload : public SpellScriptLoader
+{
+public:
+ spell_vehicle_circuit_overload() : SpellScriptLoader("spell_vehicle_circuit_overload") { }
+
+ class spell_vehicle_circuit_overload_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_vehicle_circuit_overload_AuraScript);
+
+ void OnPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ if (Unit* target = GetTarget())
+ if (int(target->GetAppliedAuras().count(SPELL_OVERLOAD_CIRCUIT)) >= (target->GetMap()->Is25ManRaid() ? 4 : 2))
+ {
+ target->CastSpell(target, SPELL_SYSTEMS_SHUTDOWN, true);
+ target->RemoveAurasDueToSpell(SPELL_OVERLOAD_CIRCUIT);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_vehicle_circuit_overload_AuraScript::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_vehicle_circuit_overload_AuraScript();
+ }
+};
+
+class spell_orbital_supports : public SpellScriptLoader
+{
+public:
+ spell_orbital_supports() : SpellScriptLoader("spell_orbital_supports") { }
+
+ class spell_orbital_supports_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_orbital_supports_AuraScript);
+
+ bool CheckAreaTarget(Unit* target)
+ {
+ return target->GetEntry() == NPC_LEVIATHAN;
+ }
+ void Register() override
+ {
+ DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_orbital_supports_AuraScript::CheckAreaTarget);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_orbital_supports_AuraScript();
+ }
+};
+
+class spell_thorims_hammer : public SpellScriptLoader
+{
+public:
+ spell_thorims_hammer() : SpellScriptLoader("spell_thorims_hammer") { }
+
+ class spell_thorims_hammer_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_thorims_hammer_SpellScript);
+
+ void RecalculateDamage(SpellEffIndex effIndex)
+ {
+ if (!GetHitUnit() || effIndex == EFFECT_1)
+ {
+ PreventHitDefaultEffect(effIndex);
+ return;
+ }
+
+ float dist = GetHitUnit()->GetExactDist2d(GetCaster());
+ if (dist <= 7.0f)
+ {
+ SetHitDamage(GetSpellInfo()->Effects[EFFECT_1].CalcValue());
+ }
+ else
+ {
+ dist -= 6.0f;
+ SetHitDamage(int32(GetSpellInfo()->Effects[EFFECT_1].CalcValue() / std::max(dist, 1.0f)));
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_thorims_hammer_SpellScript::RecalculateDamage, EFFECT_ALL, SPELL_EFFECT_SCHOOL_DAMAGE);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_thorims_hammer_SpellScript();
+ }
+};
+
+class spell_transitus_shield_beam : public SpellScriptLoader
+{
+public:
+ spell_transitus_shield_beam() : SpellScriptLoader("spell_transitus_shield_beam") { }
+
+ class spell_transitus_shield_beam_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_transitus_shield_beam_AuraScript);
+
+ void HandleOnEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* caster = GetCaster();
+ if (!caster)
+ {
+ return;
+ }
+
+ Unit* target = GetTarget();
+
+ if (!target)
+ {
+ return;
+ }
+
+ switch (aurEff->GetEffIndex())
+ {
+ case EFFECT_0:
+ caster->AddAura(SPELL_TRANSITUS_SHIELD_IMPACT, target);
+ break;
+ }
+ }
+
+ void HandleOnEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* caster = GetCaster();
+
+ if (!caster)
+ {
+ return;
+ }
+
+ Unit* target = GetTarget();
+
+ if (target)
+ {
+ target->RemoveAurasDueToSpell(SPELL_TRANSITUS_SHIELD_IMPACT);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_transitus_shield_beam_AuraScript::HandleOnEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
+ OnEffectRemove += AuraEffectRemoveFn(spell_transitus_shield_beam_AuraScript::HandleOnEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_transitus_shield_beam_AuraScript();
+ }
+};
+
+class spell_shield_generator : public SpellScriptLoader
+{
+public:
+ spell_shield_generator() : SpellScriptLoader("spell_shield_generator") { }
+
+ class spell_shield_generator_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_shield_generator_AuraScript);
+
+ uint32 absorbPct;
+
+ bool Load() override
+ {
+ absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster());
+ return true;
+ }
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
+ {
+ // Set absorbtion amount to unlimited
+ amount = -1;
+ }
+
+ void Absorb(AuraEffect* /*aurEff*/, DamageInfo& dmgInfo, uint32& absorbAmount)
+ {
+ absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct);
+ }
+
+ void Register() override
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_shield_generator_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB);
+ OnEffectAbsorb += AuraEffectAbsorbFn(spell_shield_generator_AuraScript::Absorb, EFFECT_0);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_shield_generator_AuraScript();
+ }
+};
+
+class spell_demolisher_ride_vehicle : public SpellScriptLoader
+{
+public:
+ spell_demolisher_ride_vehicle() : SpellScriptLoader("spell_demolisher_ride_vehicle") {}
+
+ class spell_demolisher_ride_vehicle_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_demolisher_ride_vehicle_SpellScript);
+
+ SpellCastResult CheckCast()
+ {
+ if (GetCaster()->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_CAST_OK;
+
+ Unit* target = this->GetExplTargetUnit();
+ if (!target || target->GetEntry() != NPC_SALVAGED_DEMOLISHER)
+ return SPELL_FAILED_DONT_REPORT;
+
+ Vehicle* veh = target->GetVehicleKit();
+ if (veh && veh->GetPassenger(0))
+ if (Unit* target2 = veh->GetPassenger(1))
+ if (Vehicle* veh2 = target2->GetVehicleKit())
+ {
+ if (!veh2->GetPassenger(0))
+ target2->HandleSpellClick(GetCaster());
+
+ return SPELL_FAILED_DONT_REPORT;
+ }
+
+ return SPELL_CAST_OK;
+ }
+
+ void Register() override
+ {
+ OnCheckCast += SpellCheckCastFn(spell_demolisher_ride_vehicle_SpellScript::CheckCast);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_demolisher_ride_vehicle_SpellScript();
+ }
+};
+
+class achievement_flame_leviathan_towers : public AchievementCriteriaScript
+{
+public:
+ achievement_flame_leviathan_towers(char const* name, uint32 count) : AchievementCriteriaScript(name),
+ _towerCount(count)
+ {
+ }
+
+ bool OnCheck(Player* /*player*/, Unit* target /*Flame Leviathan*/, uint32 /*criteria_id*/) override
+ {
+ return target && _towerCount <= target->GetAI()->GetData(DATA_GET_TOWER_COUNT);
+ }
+
+private:
+ uint32 const _towerCount;
+};
+
+class achievement_flame_leviathan_shutout : public AchievementCriteriaScript
+{
+public:
+ achievement_flame_leviathan_shutout() : AchievementCriteriaScript("achievement_flame_leviathan_shutout") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target /*Flame Leviathan*/, uint32 /*criteria_id*/) override
+ {
+ if (target)
+ if (target->GetAI()->GetData(DATA_GET_SHUTDOWN))
+ return true;
+ return false;
+ }
+};
+
+class achievement_flame_leviathan_garage : public AchievementCriteriaScript
+{
+public:
+ achievement_flame_leviathan_garage(char const* name, uint32 entry1, uint32 entry2) : AchievementCriteriaScript(name),
+ _entry1(entry1), _entry2(entry2)
+ {
+ }
+
+ bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override
+ {
+ if (Vehicle* vehicle = player->GetVehicle())
+ if (vehicle->GetCreatureEntry() == _entry1 || vehicle->GetCreatureEntry() == _entry2)
+ return true;
+ return false;
+ }
+
+private:
+ uint32 const _entry1;
+ uint32 const _entry2;
+};
+
+class achievement_flame_leviathan_unbroken : public AchievementCriteriaScript
+{
+public:
+ achievement_flame_leviathan_unbroken() : AchievementCriteriaScript("achievement_flame_leviathan_unbroken") {}
+
+ bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override
+ {
+ if (player->GetInstanceScript())
+ if (player->GetInstanceScript()->GetData(DATA_UNBROKEN_ACHIEVEMENT))
+ return true;
+ return false;
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp
index 4d3610adba6889..3ade61219aeeb0 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_freya.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "PassiveAI.h"
@@ -23,1264 +24,6 @@
#include "SpellAuras.h"
#include "ulduar.h"
-enum FreyaSpells
-{
- // LIFEBINDER
- SPELL_AUTO_GROW = 62559,
- SPELL_LIFEBINDER_PHERONOMES = 62619,
- SPELL_LIFEBINDER_VISUAL = 62579,
- SPELL_LIFEBINDER_HEAL_10 = 62584,
- SPELL_LIFEBINDER_HEAL_25 = 64185,
-
- // FREYA
- SPELL_TOUCH_OF_EONAR_10 = 62528,
- SPELL_TOUCH_OF_EONAR_25 = 62892,
- SPELL_ATTUNED_TO_NATURE = 62519,
- SPELL_SUMMON_LIFEBINDER = 62870,
- SPELL_SUNBEAM_10 = 62623,
- SPELL_SUNBEAM_25 = 62872,
- SPELL_NATURE_BOMB_FLIGHT = 64648,
- SPELL_NATURE_BOMB_DAMAGE_10 = 64587,
- SPELL_NATURE_BOMB_DAMAGE_25 = 64650,
- SPELL_GREEN_BANISH_STATE = 32567,
- SPELL_BERSERK = 47008,
-
- // HARD MODE
- SPELL_GROUND_TREMOR_FREYA_10 = 62437,
- SPELL_GROUND_TREMOR_FREYA_25 = 62859,
- SPELL_IRON_ROOTS_FREYA_10 = 62862,
- SPELL_IRON_ROOTS_FREYA_25 = 62439,
- SPELL_IRON_ROOTS_FREYA_DAMAGE_10 = 62861,
- SPELL_IRON_ROOTS_FREYA_DAMAGE_25 = 62438,
- SPELL_UNSTABLE_SUN_FREYA_DAMAGE_10 = 62451,
- SPELL_UNSTABLE_SUN_FREYA_DAMAGE_25 = 62865,
- SPELL_UNSTABLE_SUN_VISUAL = 62216,
-
- // ELDERS
- SPELL_DRAINED_OF_POWER = 62467,
- SPELL_STONEBARK_ESSENCE = 62483,
- SPELL_IRONBRANCH_ESSENCE = 62484,
- SPELL_BRIGHTLEAF_ESSENCE = 62485,
-
- // BRIGHTLEAF
- SPELL_BRIGHTLEAF_FLUX = 62239,
- SPELL_SOLAR_FLARE_10 = 62240,
- SPELL_SOLAR_FLARE_25 = 64087,
- SPELL_UNSTABLE_SUN_BEAM_AURA = 62211,
- SPELL_PHOTOSYNTHESIS = 62209,
- SPELL_UNSTABLE_SUN_DAMAGE_10 = 62217,
- SPELL_UNSTABLE_SUN_DAMAGE_25 = 62922,
-
- // IRONBRANCH
- SPELL_IMPALE_10 = 62310,
- SPELL_IMPALE_25 = 62928,
- SPELL_IRON_ROOTS_10 = 62275,
- SPELL_IRON_ROOTS_25 = 62929,
- SPELL_IRON_ROOTS_DAMAGE_10 = 62283,
- SPELL_IRON_ROOTS_DAMAGE_25 = 62930,
- SPELL_THORN_SWARM_10 = 62285,
- SPELL_THORN_SWARM_25 = 62931,
-
- // STONEBARK
- SPELL_FISTS_OF_STONE = 62344,
- SPELL_GROUND_TREMOR_10 = 62325,
- SPELL_GROUND_TREMOR_25 = 62932,
- SPELL_PETRIFIED_BARK_10 = 62337,
- SPELL_PETRIFIED_BARK_25 = 62933,
-
- // SNAPLASHER
- SPELL_HARDENED_BARK_10 = 62664,
- SPELL_HARDENED_BARK_25 = 64191,
-
- // ANCIENT WATER SPIRIT
- SPELL_TIDAL_WAVE_10 = 62653,
- SPELL_TIDAL_WAVE_25 = 62935,
- SPELL_TIDAL_WAVE_DAMAGE_10 = 62654,
- SPELL_TIDAL_WAVE_DAMAGE_25 = 62936,
- SPELL_TIDAL_WAVE_AURA = 62655,
-
- // STORM LASHER
- SPELL_LIGHTNING_LASH_10 = 62648,
- SPELL_LIGHTNING_LASH_25 = 62939,
- SPELL_STORMBOLT_10 = 62649,
- SPELL_STORMBOLT_25 = 62938,
-
- // ANCIENT CONSERVATOR
- SPELL_CONSERVATOR_GRIP = 62532,
- SPELL_NATURE_FURY_10 = 62589,
- SPELL_NATURE_FURY_25 = 63571,
- SPELL_POTENT_PHEROMONES = 62541,
- SPELL_HEALTHY_SPORE_VISUAL = 62538,
- SPELL_HEALTHY_SPORE_SUMMON = 62566,
-
- // DETONATING LASHER
- SPELL_DETONATE_10 = 62598,
- SPELL_DETONATE_25 = 62937,
- SPELL_FLAME_LASH = 62608,
-
- // ACHIEVEMENT
- SPELL_DEFORESTATION_CREDIT = 65015,
-};
-
-#define SPELL_GROUND_TREMOR RAID_MODE(SPELL_GROUND_TREMOR_10, SPELL_GROUND_TREMOR_25)
-#define SPELL_PETRIFIED_BARK RAID_MODE(SPELL_PETRIFIED_BARK_10, SPELL_PETRIFIED_BARK_25)
-#define SPELL_IRON_ROOTS RAID_MODE(SPELL_IRON_ROOTS_10, SPELL_IRON_ROOTS_25)
-#define SPELL_IMPALE RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25)
-#define SPELL_THORN_SWARM RAID_MODE(SPELL_THORN_SWARM_10, SPELL_THORN_SWARM_25)
-#define SPELL_UNSTABLE_SUN_DAMAGE RAID_MODE(SPELL_UNSTABLE_SUN_DAMAGE_10, SPELL_UNSTABLE_SUN_DAMAGE_25)
-#define SPELL_SOLAR_FLARE RAID_MODE(SPELL_SOLAR_FLARE_10, SPELL_SOLAR_FLARE_25)
-#define SPELL_TOUCH_OF_EONAR RAID_MODE(SPELL_TOUCH_OF_EONAR_10, SPELL_TOUCH_OF_EONAR_25)
-#define SPELL_LIFEBINDER_HEAL RAID_MODE(SPELL_LIFEBINDER_HEAL_10, SPELL_LIFEBINDER_HEAL_25)
-#define SPELL_TIDAL_WAVE RAID_MODE(SPELL_TIDAL_WAVE_10, SPELL_TIDAL_WAVE_25)
-#define SPELL_TIDAL_WAVE_DAMAGE RAID_MODE(SPELL_TIDAL_WAVE_DAMAGE_10, SPELL_TIDAL_WAVE_DAMAGE_25)
-#define SPELL_NATURE_FURY RAID_MODE(SPELL_NATURE_FURY_10, SPELL_NATURE_FURY_25)
-#define SPELL_HARDENED_BARK RAID_MODE(SPELL_HARDENED_BARK_10, SPELL_HARDENED_BARK_25)
-#define SPELL_DETONATE RAID_MODE(SPELL_DETONATE_10, SPELL_DETONATE_25)
-//#define SPELL_NATURE_BOMB_DAMAGE RAID_MODE(SPELL_NATURE_BOMB_DAMAGE_10, SPELL_NATURE_BOMB_DAMAGE_25)
-#define SPELL_SUNBEAM RAID_MODE(SPELL_SUNBEAM_10, SPELL_SUNBEAM_25)
-#define SPELL_GROUND_TREMOR_FREYA RAID_MODE(SPELL_GROUND_TREMOR_FREYA_10, SPELL_GROUND_TREMOR_FREYA_25)
-#define SPELL_IRON_ROOTS_FREYA RAID_MODE(SPELL_IRON_ROOTS_FREYA_10, SPELL_IRON_ROOTS_FREYA_25)
-#define SPELL_UNSTABLE_SUN_FREYA_DAMAGE RAID_MODE(SPELL_UNSTABLE_SUN_FREYA_DAMAGE_10, SPELL_UNSTABLE_SUN_FREYA_DAMAGE_25)
-#define SPELL_LIGHTNING_LASH RAID_MODE(SPELL_LIGHTNING_LASH_10, SPELL_LIGHTNING_LASH_25)
-#define SPELL_STORMBOLT RAID_MODE(SPELL_STORMBOLT_10, SPELL_STORMBOLT_25)
-
-enum FreyaEvents
-{
- // FREYA
- EVENT_FREYA_ADDS_SPAM = 1,
- EVENT_FREYA_LIFEBINDER = 2,
- EVENT_FREYA_NATURE_BOMB = 3,
- EVENT_FREYA_SUNBEAM = 4,
- EVENT_FREYA_BERSERK = 5,
- // HARD MODE
- EVENT_FREYA_GROUND_TREMOR = 6,
- EVENT_FREYA_IRON_ROOT = 7,
- EVENT_FREYA_UNSTABLE_SUN_BEAM = 8,
- EVENT_FREYA_RESPAWN_TRIO = 9,
-
- // STONEBARK
- EVENT_STONEBARK_FISTS_OF_STONE = 10,
- EVENT_STONEBARK_GROUND_TREMOR = 11,
- EVENT_STONEBARK_PETRIFIED_BARK = 12,
-
- // BRIGHTLEAF
- EVENT_BRIGHTLEAF_FLUX = 20,
- EVENT_BRIGHTLEAF_SOLAR_FLARE = 21,
- EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM = 22,
- EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM = 23,
-
- // IRONBRANCH
- EVENT_IRONBRANCH_IMPALE = 30,
- EVENT_IRONBRANCH_IRON_ROOT = 31,
- EVENT_IRONBRANCH_THORN_SWARM = 32,
-
- // SUMMONS
- EVENT_ANCIENT_CONSERVATOR_NATURE_FURY = 40,
- EVENT_ANCIENT_CONSERVATOR_GRIP = 41,
- EVENT_WATER_SPIRIT_CHARGE = 45,
- EVENT_WATER_SPIRIT_DAMAGE = 46,
- EVENT_STORM_LASHER_LIGHTNING_LASH = 50,
- EVENT_STORM_LASHER_STORMBOLT = 51,
- EVENT_DETONATING_LASHER_FLAME_LASH = 55,
-};
-
-enum Texts
-{
- // Elder Brightleaf / Elder Ironbranch / Elder Stonebark
- SAY_ELDER_AGGRO = 0,
- SAY_ELDER_SLAY = 1,
- SAY_ELDER_DEATH = 2,
-
- // Freya
- SAY_AGGRO = 0,
- SAY_AGGRO_WITH_ELDER = 1,
- SAY_SLAY = 2,
- SAY_DEATH = 3,
- SAY_BERSERK = 4,
- SAY_SUMMON_CONSERVATOR = 5,
- SAY_SUMMON_TRIO = 6,
- SAY_SUMMON_LASHERS = 7,
- EMOTE_LIFEBINDERS_GIFT = 8,
- EMOTE_ALLIES_OF_NATURE = 9,
- EMOTE_GROUND_TREMOR = 10,
- EMOTE_IRON_ROOTS = 11,
-};
-
-enum FreyaNPCs
-{
- NPC_NATURE_BOMB = 34129,
- NPC_IRON_ROOT_TRIGGER = 33088,
- NPC_FREYA_UNSTABLE_SUN_BEAM = 33170,
- NPC_UNSTABLE_SUN_BRIGHTLEAF = 33050, // 10 SECS?
-
- // FIRST WAVE
- NPC_STORM_LASHER = 32919,
- NPC_ANCIENT_WATER_SPIRIT = 33202,
- NPC_SNAPLASHER = 32916,
-
- // SEC WAVE
- NPC_ANCIENT_CONSERVATOR = 33203,
- NPC_HEALTHY_SPORE = 33215,
-
- // THIRD WAVE
- NPC_DETONATING_LASHER = 32918,
-};
-
-enum Misc
-{
- ACTION_REMOVE_10_STACK = 10,
- ACTION_REMOVE_25_STACK = 25,
- ACTION_REMOVE_2_STACK = 2,
- ACTION_RESPAWN_TRIO = 1,
- ACTION_LUMBERJACKED = -1,
-
- EVENT_PHASE_ADDS = 1,
- EVENT_PHASE_FINAL = 2,
-
- DATA_GET_ELDER_COUNT = 1,
- DATA_BACK_TO_NATURE = 2,
-
- CRITERIA_LUMBERJACKED = 21686,
-};
-
-class boss_freya : public CreatureScript
-{
-public:
- boss_freya() : CreatureScript("boss_freya") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_freyaAI : public ScriptedAI
- {
- boss_freyaAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
- {
- m_pInstance = pCreature->GetInstanceScript();
- if (!me->IsAlive())
- if (m_pInstance)
- m_pInstance->SetData(TYPE_FREYA, DONE);
- }
-
- InstanceScript* m_pInstance;
- EventMap events;
- SummonList summons;
-
- uint8 _waveNumber;
- uint8 _trioKilled;
- uint8 _spawnedAmount;
- uint8 _lumberjacked;
- bool _respawningTrio;
- bool _backToNature;
- uint8 _deforestation;
-
- ObjectGuid _elderGUID[3];
-
- void Reset() override
- {
- if (m_pInstance && m_pInstance->GetData(TYPE_FREYA) != DONE)
- m_pInstance->SetData(TYPE_FREYA, NOT_STARTED);
-
- events.Reset();
- summons.DespawnAll();
-
- for (uint8 i = 0; i < 3; ++i)
- {
- if (!_elderGUID[i])
- continue;
-
- if (Creature* elder = ObjectAccessor::GetCreature(*me, _elderGUID[i]))
- elder->AI()->EnterEvadeMode();
-
- _elderGUID[i].Clear();
- }
-
- _lumberjacked = 0;
- _spawnedAmount = 0;
- _trioKilled = 0;
- _waveNumber = urand(1, 3);
- _respawningTrio = false;
- _backToNature = true;
- _deforestation = 0;
- }
-
- void KilledUnit(Unit* victim) override
- {
- if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
- return;
-
- Talk(SAY_SLAY);
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (damage >= me->GetHealth())
- {
- damage = 0;
- if (m_pInstance->GetData(TYPE_FREYA) != DONE)
- {
- Talk(SAY_DEATH);
-
- me->SetReactState(REACT_PASSIVE);
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetFaction(FACTION_FRIENDLY);
- me->RemoveAllAuras();
- me->AttackStop();
- events.Reset();
-
- summons.DespawnAll();
- events.Reset();
-
- uint8 _elderCount = 0;
- for (uint8 i = 0; i < 3; ++i)
- {
- if (!_elderGUID[i])
- continue;
-
- if (Creature* e = ObjectAccessor::GetCreature(*me, _elderGUID[i]))
- e->DespawnOrUnsummon();
-
- ++_elderCount;
- }
-
- uint32 chestId = RAID_MODE(GO_FREYA_CHEST, GO_FREYA_CHEST_HERO);
- chestId -= 2 * _elderCount; // offset
-
- me->DespawnOrUnsummon(5000);
- if (GameObject* go = me->SummonGameObject(chestId, 2345.61f, -71.20f, 425.104f, 3.0f, 0, 0, 0, 0, 0))
- {
- go->ReplaceAllGameObjectFlags((GameObjectFlags)0);
- go->SetLootRecipient(me->GetMap());
- }
-
- // Defeat credit
- if (m_pInstance)
- {
- me->CastSpell(me, 65074, true); // credit
- m_pInstance->SetData(TYPE_FREYA, DONE);
- }
- }
- }
- }
-
- void JustSummoned(Creature* cr) override
- {
- if (cr->GetEntry() == NPC_FREYA_UNSTABLE_SUN_BEAM)
- {
- cr->CastSpell(cr, SPELL_UNSTABLE_SUN_VISUAL, true);
- cr->CastSpell(cr, SPELL_UNSTABLE_SUN_FREYA_DAMAGE, true);
- }
- summons.Summon(cr);
- }
-
- void SpawnWave()
- {
- _waveNumber = _waveNumber == 1 ? 3 : _waveNumber - 1;
- Talk(EMOTE_ALLIES_OF_NATURE);
-
- // Wave of three
- if (_waveNumber == 1)
- {
- Talk(SAY_SUMMON_TRIO);
- me->SummonCreature(NPC_ANCIENT_WATER_SPIRIT, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
- me->SummonCreature(NPC_STORM_LASHER, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
- me->SummonCreature(NPC_SNAPLASHER, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
- }
- // Ancient Conservator
- else if (_waveNumber == 2)
- {
- Talk(SAY_SUMMON_CONSERVATOR);
- me->SummonCreature(NPC_ANCIENT_CONSERVATOR, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_CORPSE_DESPAWN);
- }
- // Detonating Lashers
- else if (_waveNumber == 3)
- {
- Talk(SAY_SUMMON_LASHERS);
- for (uint8 i = 0; i < 10; ++i)
- me->SummonCreature(NPC_DETONATING_LASHER, me->GetPositionX() + urand(5, 20), me->GetPositionY() + urand(5, 20), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_CORPSE_DESPAWN);
- }
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_LUMBERJACKED)
- {
- if (!m_pInstance)
- return;
-
- ++_lumberjacked;
- if (_lumberjacked == 1)
- m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_LUMBERJACKED);
- else if (_lumberjacked == 3)
- m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 65296 /*SPELL_LUMBERJACKED*/, 0, me);
- return;
- }
-
- if (param == ACTION_RESPAWN_TRIO)
- {
- if (!_respawningTrio)
- {
- _respawningTrio = true;
- events.ScheduleEvent(EVENT_FREYA_RESPAWN_TRIO, 10s);
- }
-
- ++_trioKilled;
- return;
- }
-
- // Deforestation Achievement Counter
- if (param == ACTION_REMOVE_10_STACK)
- {
- ++_deforestation;
- if (_deforestation >= 6 && m_pInstance)
- m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_DEFORESTATION_CREDIT, 0, me);
- // do not return
- }
-
- if (Aura* aur = me->GetAura(SPELL_ATTUNED_TO_NATURE))
- {
- // Back to Nature achievement
- if (aur->GetStackAmount() - param < 25)
- _backToNature = false;
-
- if (aur->GetStackAmount() > param)
- aur->SetStackAmount(aur->GetStackAmount() - param);
- else // Aura out of stack
- {
- events.ScheduleEvent(EVENT_FREYA_NATURE_BOMB, 5s);
- events.SetPhase(EVENT_PHASE_FINAL);
- aur->Remove();
- return;
- }
- }
- }
-
- uint32 GetData(uint32 param) const override
- {
- if (param == DATA_GET_ELDER_COUNT)
- {
- uint8 _count = 0;
- for (uint8 i = 0; i < 3; ++i)
- if (_elderGUID[i])
- ++_count;
-
- return _count;
- }
- if (param == DATA_BACK_TO_NATURE)
- return _backToNature;
-
- return 0;
- }
-
- void JustReachedHome() override { me->setActive(false); }
-
- void JustEngagedWith(Unit*) override
- {
- me->setActive(true);
- me->SetInCombatWithZone();
- me->CastSpell(me, SPELL_TOUCH_OF_EONAR, true);
- if (Aura* aur = me->AddAura(SPELL_ATTUNED_TO_NATURE, me))
- aur->SetStackAmount(150);
-
- events.ScheduleEvent(EVENT_FREYA_ADDS_SPAM, 10s, 0, EVENT_PHASE_ADDS);
- events.ScheduleEvent(EVENT_FREYA_LIFEBINDER, 30s);
- events.ScheduleEvent(EVENT_FREYA_SUNBEAM, 17s);
- events.ScheduleEvent(EVENT_FREYA_BERSERK, 10min);
- events.SetPhase(EVENT_PHASE_ADDS);
-
- if( !m_pInstance )
- return;
-
- if (m_pInstance->GetData(TYPE_FREYA) != DONE)
- m_pInstance->SetData(TYPE_FREYA, IN_PROGRESS);
-
- // HARD MODE CHECKS
- Creature* elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_STONEBARK));
- if (elder && elder->IsAlive())
- {
- elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true);
- elder->CastSpell(elder, SPELL_STONEBARK_ESSENCE, true);
- elder->SetInCombatWithZone();
-
- events.ScheduleEvent(EVENT_FREYA_GROUND_TREMOR, 35s);
- _elderGUID[0] = elder->GetGUID();
- }
-
- elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_IRONBRANCH));
- if (elder && elder->IsAlive())
- {
- elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true);
- elder->CastSpell(elder, SPELL_IRONBRANCH_ESSENCE, true);
- elder->SetInCombatWithZone();
-
- events.ScheduleEvent(EVENT_FREYA_IRON_ROOT, 20s);
- _elderGUID[1] = elder->GetGUID();
- }
-
- elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_BRIGHTLEAF));
- if (elder && elder->IsAlive())
- {
- elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true);
- elder->CastSpell(elder, SPELL_BRIGHTLEAF_ESSENCE, true);
- elder->SetInCombatWithZone();
-
- events.ScheduleEvent(EVENT_FREYA_UNSTABLE_SUN_BEAM, 1min);
- _elderGUID[2] = elder->GetGUID();
- }
-
- if (_elderGUID[0] || _elderGUID[1] || _elderGUID[2])
- {
- Talk(SAY_AGGRO_WITH_ELDER);
- }
- else
- {
- Talk(SAY_AGGRO);
- }
- }
-
- void SpellHitTarget(Unit* target, SpellInfo const* spell) override
- {
- if (spell->Id == SPELL_NATURE_BOMB_FLIGHT)
- me->SummonCreature(NPC_NATURE_BOMB, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_FREYA_ADDS_SPAM:
- if (_spawnedAmount < 6)
- SpawnWave();
- else if (me->GetAura(SPELL_ATTUNED_TO_NATURE))
- {
- me->RemoveAura(SPELL_ATTUNED_TO_NATURE);
- events.ScheduleEvent(EVENT_FREYA_NATURE_BOMB, 5s);
- events.SetPhase(EVENT_PHASE_FINAL);
- return;
- }
- _spawnedAmount++;
- events.Repeat(1min);
- break;
- case EVENT_FREYA_LIFEBINDER:
- {
- Talk(EMOTE_LIFEBINDERS_GIFT);
- events.Repeat(45s);
- float x, y, z;
- for (uint8 i = 0; i < 10; ++i)
- {
- x = me->GetPositionX() + urand(7, 25);
- y = me->GetPositionY() + urand(7, 25);
- z = me->GetMapHeight(x, y, me->GetPositionZ());
- if (me->IsWithinLOS(x, y, z))
- {
- me->CastSpell(x, y, z, SPELL_SUMMON_LIFEBINDER, true);
- return;
- }
- }
-
- me->CastSpell(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), SPELL_SUMMON_LIFEBINDER, true);
- break;
- }
- case EVENT_FREYA_SUNBEAM:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random))
- me->CastSpell(target, SPELL_SUNBEAM, false);
- events.Repeat(15s, 20s);
- break;
- case EVENT_FREYA_RESPAWN_TRIO:
- _deforestation = 0;
- _respawningTrio = false;
- if (_trioKilled < 3)
- summons.DoAction(ACTION_RESPAWN_TRIO);
-
- _trioKilled = 0;
- break;
- case EVENT_FREYA_NATURE_BOMB:
- {
- uint8 _minCount = me->GetMap()->Is25ManRaid() ? urand(7, 10) : urand(3, 4);
- Map::PlayerList const& pList = me->GetMap()->GetPlayers();
- for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
- {
- if (me->GetDistance(itr->GetSource()) > 70 || !itr->GetSource()->IsAlive())
- continue;
-
- me->CastSpell(itr->GetSource(), SPELL_NATURE_BOMB_FLIGHT, true);
-
- if (!(--_minCount))
- break;
- }
- events.Repeat(18s);
- break;
- }
- case EVENT_FREYA_BERSERK:
- Talk(SAY_BERSERK);
- me->CastSpell(me, SPELL_BERSERK, true);
- break;
- case EVENT_FREYA_GROUND_TREMOR:
- Talk(EMOTE_GROUND_TREMOR);
- me->CastSpell(me, SPELL_GROUND_TREMOR_FREYA, false);
- events.Repeat(25s, 35s);
- break;
- case EVENT_FREYA_IRON_ROOT:
- Talk(EMOTE_IRON_ROOTS);
- me->CastCustomSpell(SPELL_IRON_ROOTS_FREYA, SPELLVALUE_MAX_TARGETS, 1, me, false);
- events.Repeat(45s, 55s);
- break;
- case EVENT_FREYA_UNSTABLE_SUN_BEAM:
- me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
- if (Is25ManRaid())
- {
- me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
- me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
- }
- events.Repeat(38s, 48s);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
-
- bool CheckEvadeIfOutOfCombatArea() const override
- {
- return me->GetPositionX() < 2135.0f;
- }
- };
-};
-
-class boss_freya_elder_stonebark : public CreatureScript
-{
-public:
- boss_freya_elder_stonebark() : CreatureScript("boss_freya_elder_stonebark") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_freya_elder_stonebarkAI : public ScriptedAI
- {
- boss_freya_elder_stonebarkAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- }
-
- EventMap events;
- uint8 _chargesCount;
-
- void Reset() override
- {
- events.Reset();
- _chargesCount = 0;
- }
-
- void KilledUnit(Unit*) override
- {
- if (urand(0, 1))
- return;
-
- Talk(SAY_ELDER_SLAY);
- }
-
- void JustDied(Unit* killer) override
- {
- if (killer && me->GetEntry() == killer->GetEntry())
- return;
- Talk(SAY_ELDER_DEATH);
-
- // Lumberjacked
- if (me->GetInstanceScript())
- if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA)))
- freya->AI()->DoAction(ACTION_LUMBERJACKED);
- }
-
- void JustEngagedWith(Unit*) override
- {
- events.ScheduleEvent(EVENT_STONEBARK_FISTS_OF_STONE, 40s);
- events.ScheduleEvent(EVENT_STONEBARK_GROUND_TREMOR, 5s);
- events.ScheduleEvent(EVENT_STONEBARK_PETRIFIED_BARK, 20s);
-
- if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation
- Talk(SAY_ELDER_AGGRO);
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType damageType, SpellSchoolMask damageSchoolMask) override
- {
- if ((damageType == DIRECT_DAMAGE || (damageType == SPELL_DIRECT_DAMAGE && damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)) && _chargesCount)
- {
- --_chargesCount;
- damage = 0;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_STONEBARK_FISTS_OF_STONE:
- me->CastSpell(me, SPELL_FISTS_OF_STONE, false);
- events.Repeat(1min);
- break;
- case EVENT_STONEBARK_GROUND_TREMOR:
- if (!me->HasAura(SPELL_FISTS_OF_STONE))
- me->CastSpell(me, SPELL_GROUND_TREMOR, false);
- events.Repeat(20s);
- break;
- case EVENT_STONEBARK_PETRIFIED_BARK:
- _chargesCount = RAID_MODE(60, 120);
- me->CastSpell(me, SPELL_PETRIFIED_BARK, false);
- events.Repeat(30s);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_freya_elder_brightleaf : public CreatureScript
-{
-public:
- boss_freya_elder_brightleaf() : CreatureScript("boss_freya_elder_brightleaf") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_freya_elder_brightleafAI : public ScriptedAI
- {
- boss_freya_elder_brightleafAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature)
- {
- }
-
- EventMap events;
- SummonList summons;
-
- void Reset() override
- {
- events.Reset();
- summons.DespawnAll();
- }
-
- void KilledUnit(Unit*) override
- {
- if (urand(0, 1))
- return;
-
- Talk(SAY_ELDER_SLAY);
- }
-
- void JustDied(Unit* killer) override
- {
- if (killer && me->GetEntry() == killer->GetEntry())
- return;
- Talk(SAY_ELDER_DEATH);
-
- // Lumberjacked
- if (me->GetInstanceScript())
- if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA)))
- freya->AI()->DoAction(ACTION_LUMBERJACKED);
- }
-
- void JustEngagedWith(Unit*) override
- {
- events.ScheduleEvent(EVENT_BRIGHTLEAF_FLUX, 10s);
- events.ScheduleEvent(EVENT_BRIGHTLEAF_SOLAR_FLARE, 5s);
- events.ScheduleEvent(EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM, 8s);
-
- if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation
- Talk(SAY_ELDER_AGGRO);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_BRIGHTLEAF_FLUX:
- if (Aura* aur = me->AddAura(SPELL_BRIGHTLEAF_FLUX, me))
- aur->SetStackAmount(urand(1, 10));
- events.Repeat(10s);
- break;
- case EVENT_BRIGHTLEAF_SOLAR_FLARE:
- if (Aura* aur = me->GetAura(SPELL_BRIGHTLEAF_FLUX))
- {
- me->CastCustomSpell(SPELL_SOLAR_FLARE, SPELLVALUE_MAX_TARGETS, aur->GetStackAmount(), me, false);
- me->RemoveAura(aur);
- }
- events.Repeat(15s);
- break;
- case EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM:
- events.ScheduleEvent(EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM, 15s);
- if (Creature* beam = me->SummonCreature(NPC_UNSTABLE_SUN_BRIGHTLEAF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()))
- {
- beam->CastSpell(beam, SPELL_UNSTABLE_SUN_BEAM_AURA, true);
- beam->CastSpell(beam, SPELL_PHOTOSYNTHESIS, true);
- summons.Summon(beam);
- }
- if (Creature* beam = me->SummonCreature(NPC_UNSTABLE_SUN_BRIGHTLEAF, me->GetPositionX() + 8, me->GetPositionY() + 8, me->GetPositionZ()))
- {
- beam->CastSpell(beam, SPELL_UNSTABLE_SUN_BEAM_AURA, true);
- beam->CastSpell(beam, SPELL_PHOTOSYNTHESIS, true);
- summons.Summon(beam);
- }
- events.Repeat(20s);
- break;
- case EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM:
- for (SummonList::iterator i = summons.begin(); i != summons.end();)
- {
- Creature* summon = ObjectAccessor::GetCreature(*me, *i);
- ++i;
- if (summon)
- summon->CastSpell(summon, SPELL_UNSTABLE_SUN_DAMAGE, false);
- }
-
- summons.DespawnAll();
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_freya_elder_ironbranch : public CreatureScript
-{
-public:
- boss_freya_elder_ironbranch() : CreatureScript("boss_freya_elder_ironbranch") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_freya_elder_ironbranchAI : public ScriptedAI
- {
- boss_freya_elder_ironbranchAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- }
-
- EventMap events;
-
- void Reset() override
- {
- events.Reset();
- }
-
- void KilledUnit(Unit*) override
- {
- if (urand(0, 1))
- return;
-
- Talk(SAY_ELDER_SLAY);
- }
-
- void JustDied(Unit* killer) override
- {
- if (killer && me->GetEntry() == killer->GetEntry())
- return;
- Talk(SAY_ELDER_DEATH);
-
- // Lumberjacked
- if (me->GetInstanceScript())
- if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA)))
- freya->AI()->DoAction(ACTION_LUMBERJACKED);
- }
-
- void JustEngagedWith(Unit*) override
- {
- events.ScheduleEvent(EVENT_IRONBRANCH_IMPALE, 10s);
- events.ScheduleEvent(EVENT_IRONBRANCH_IRON_ROOT, 15s);
- events.ScheduleEvent(EVENT_IRONBRANCH_THORN_SWARM, 3s);
-
- if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation
- Talk(SAY_ELDER_AGGRO);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_IRONBRANCH_IMPALE:
- me->CastSpell(me->GetVictim(), SPELL_IMPALE, false);
- events.Repeat(17s);
- break;
- case EVENT_IRONBRANCH_IRON_ROOT:
- me->CastCustomSpell(SPELL_IRON_ROOTS, SPELLVALUE_MAX_TARGETS, 1, me, false);
- events.Repeat(20s);
- break;
- case EVENT_IRONBRANCH_THORN_SWARM:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_THORN_SWARM, false);
- events.Repeat(14s);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_freya_iron_root : public CreatureScript
-{
-public:
- boss_freya_iron_root() : CreatureScript("boss_freya_iron_root") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_freya_iron_rootAI : public NullCreatureAI
- {
- boss_freya_iron_rootAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (!me->IsSummon())
- return;
-
- if (Unit* target = ObjectAccessor::GetUnit(*me, me->ToTempSummon()->GetSummonerGUID()))
- {
- if (me->GetEntry() == NPC_IRON_ROOT_TRIGGER) // Iron Branch spell
- target->RemoveAura(target->GetMap()->Is25ManRaid() ? SPELL_IRON_ROOTS_DAMAGE_25 : SPELL_IRON_ROOTS_DAMAGE_10);
- else
- target->RemoveAura(target->GetMap()->Is25ManRaid() ? SPELL_IRON_ROOTS_FREYA_DAMAGE_25 : SPELL_IRON_ROOTS_FREYA_DAMAGE_10);
- }
- }
- };
-};
-
-class boss_freya_lifebinder : public CreatureScript
-{
-public:
- boss_freya_lifebinder() : CreatureScript("boss_freya_lifebinder") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_freya_lifebinderAI : public NullCreatureAI
- {
- boss_freya_lifebinderAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- }
-
- uint32 _healTimer;
-
- void Reset() override
- {
- me->CastSpell(me, SPELL_LIFEBINDER_VISUAL, true);
- me->CastSpell(me, SPELL_LIFEBINDER_PHERONOMES, true);
- me->CastSpell(me, SPELL_AUTO_GROW, true);
- _healTimer = 0;
- }
-
- void UpdateAI(uint32 diff) override
- {
- _healTimer += diff;
- if (_healTimer >= 12000)
- {
- me->RemoveAurasDueToSpell(SPELL_AUTO_GROW);
- me->CastSpell(me, me->GetMap()->Is25ManRaid() ? SPELL_LIFEBINDER_HEAL_25 : SPELL_LIFEBINDER_HEAL_10, true);
- me->DespawnOrUnsummon(2000);
- _healTimer = 0;
- }
- }
- };
-};
-
-class boss_freya_healthy_spore : public CreatureScript
-{
-public:
- boss_freya_healthy_spore() : CreatureScript("boss_freya_healthy_spore") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_freya_healthy_sporeAI : public NullCreatureAI
- {
- boss_freya_healthy_sporeAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- }
-
- uint32 _despawnTimer;
-
- void Reset() override
- {
- me->CastSpell(me, SPELL_POTENT_PHEROMONES, true);
- me->CastSpell(me, SPELL_HEALTHY_SPORE_VISUAL, true);
- me->CastSpell(me, SPELL_AUTO_GROW, true);
- _despawnTimer = 0;
- }
-
- void UpdateAI(uint32 diff) override
- {
- _despawnTimer += diff;
- if (_despawnTimer >= 22000)
- {
- me->RemoveAurasDueToSpell(SPELL_AUTO_GROW);
- me->DespawnOrUnsummon(2200);
- _despawnTimer = 0;
- }
- }
- };
-};
-
-class boss_freya_summons : public CreatureScript
-{
-public:
- boss_freya_summons() : CreatureScript("boss_freya_summons") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_freya_summonsAI : public ScriptedAI
- {
- boss_freya_summonsAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- _freyaGUID = me->GetInstanceScript() ? me->GetInstanceScript()->GetGuidData(TYPE_FREYA) : ObjectGuid::Empty;
- _isTrio = me->GetEntry() == NPC_ANCIENT_WATER_SPIRIT || me->GetEntry() == NPC_STORM_LASHER || me->GetEntry() == NPC_SNAPLASHER;
- _hasDied = false;
- }
-
- EventMap events;
- ObjectGuid _freyaGUID;
- uint8 _stackCount;
- bool _hasDied;
- bool _isTrio;
-
- void Reset() override
- {
- _stackCount = 0;
- events.Reset();
- if (Unit* target = SelectTargetFromPlayerList(70))
- AttackStart(target);
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (Creature* freya = ObjectAccessor::GetCreature(*me, _freyaGUID))
- {
- if (!_hasDied)
- freya->AI()->DoAction(_stackCount);
-
- if (_isTrio)
- {
- freya->AI()->DoAction(ACTION_RESPAWN_TRIO);
- _hasDied = true;
- }
- }
- if (me->GetEntry() == NPC_DETONATING_LASHER)
- me->CastSpell(me, SPELL_DETONATE, true);
- }
-
- void DoAction(int32 param) override
- {
- if (_isTrio && param == ACTION_RESPAWN_TRIO)
- {
- me->setDeathState(DeathState::JustRespawned);
- Reset();
- }
- }
-
- void JustEngagedWith(Unit*) override
- {
- if (me->GetEntry() == NPC_ANCIENT_CONSERVATOR)
- {
- me->CastSpell(me, SPELL_HEALTHY_SPORE_SUMMON, true);
- events.ScheduleEvent(EVENT_ANCIENT_CONSERVATOR_GRIP, 6s);
- events.ScheduleEvent(EVENT_ANCIENT_CONSERVATOR_NATURE_FURY, 14s);
- _stackCount = ACTION_REMOVE_25_STACK;
- }
- else if (me->GetEntry() == NPC_ANCIENT_WATER_SPIRIT)
- {
- events.ScheduleEvent(EVENT_WATER_SPIRIT_CHARGE, 12s);
- _stackCount = ACTION_REMOVE_10_STACK;
- }
- else if (me->GetEntry() == NPC_STORM_LASHER)
- {
- events.ScheduleEvent(EVENT_STORM_LASHER_LIGHTNING_LASH, 10s);
- events.ScheduleEvent(EVENT_STORM_LASHER_STORMBOLT, 6s);
- _stackCount = ACTION_REMOVE_10_STACK;
- }
- else if (me->GetEntry() == NPC_DETONATING_LASHER)
- {
- events.ScheduleEvent(EVENT_DETONATING_LASHER_FLAME_LASH, 10s);
- _stackCount = ACTION_REMOVE_2_STACK;
- }
- else if (me->GetEntry() == NPC_SNAPLASHER)
- {
- me->CastSpell(me, SPELL_HARDENED_BARK, true);
- _stackCount = ACTION_REMOVE_10_STACK;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_ANCIENT_CONSERVATOR_NATURE_FURY:
- me->CastSpell(me->GetVictim(), SPELL_NATURE_FURY, false);
- events.Repeat(14s);
- break;
- case EVENT_ANCIENT_CONSERVATOR_GRIP:
- me->CastSpell(me, SPELL_CONSERVATOR_GRIP, true);
- break;
- case EVENT_WATER_SPIRIT_CHARGE:
- me->CastSpell(me, SPELL_TIDAL_WAVE_AURA, true);
- me->CastSpell(me->GetVictim(), SPELL_TIDAL_WAVE, false);
- events.Repeat(12s);
- events.ScheduleEvent(EVENT_WATER_SPIRIT_DAMAGE, 3s);
- break;
- case EVENT_WATER_SPIRIT_DAMAGE:
- me->CastSpell(me, SPELL_TIDAL_WAVE_DAMAGE, false);
- break;
- case EVENT_STORM_LASHER_LIGHTNING_LASH:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target, SPELL_LIGHTNING_LASH, false);
- events.Repeat(10s);
- break;
- case EVENT_STORM_LASHER_STORMBOLT:
- me->CastSpell(me->GetVictim(), SPELL_STORMBOLT, false);
- events.Repeat(6s);
- break;
- case EVENT_DETONATING_LASHER_FLAME_LASH:
- me->CastSpell(me->GetVictim(), SPELL_FLAME_LASH, false);
- DoResetThreatList();
- if (Unit* target = SelectTargetFromPlayerList(80))
- AttackStart(target);
- else
- me->DespawnOrUnsummon(1);
- events.Repeat(10s);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_freya_nature_bomb : public CreatureScript
-{
-public:
- boss_freya_nature_bomb() : CreatureScript("boss_freya_nature_bomb") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_freya_nature_bombAI : public NullCreatureAI
- {
- boss_freya_nature_bombAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- _goGUID.Clear();
- }
-
- ObjectGuid _goGUID;
- uint32 _explodeTimer;
-
- void Reset() override
- {
- me->SetObjectScale(0.5f);
- me->CastSpell(me, SPELL_GREEN_BANISH_STATE, true);
-
- _explodeTimer = 0;
- if (GameObject* go = me->SummonGameObject(194902 /*GO_NATURE_BOMB*/, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, 0, 0, 0, 0, 0))
- _goGUID = go->GetGUID();
- }
-
- uint32 Timer;
- void UpdateAI(uint32 diff) override
- {
- _explodeTimer += diff;
- if (_explodeTimer >= 11000)
- {
- me->CastSpell(me, me->GetMap()->Is25ManRaid() ? SPELL_NATURE_BOMB_DAMAGE_25 : SPELL_NATURE_BOMB_DAMAGE_10, false);
- me->DespawnOrUnsummon(1000);
- _explodeTimer = 0;
- }
-
- // Delay explosion a little, visual
- if (_explodeTimer >= 5000 && _explodeTimer < 10000)
- {
- _explodeTimer = 10000;
- if (GameObject* go = me->GetMap()->GetGameObject(_goGUID))
- go->SetGoState(GO_STATE_ACTIVE);
- }
- }
- };
-};
-
-class achievement_freya_getting_back_to_nature : public AchievementCriteriaScript
-{
-public:
- achievement_freya_getting_back_to_nature() : AchievementCriteriaScript("achievement_freya_getting_back_to_nature") {}
-
- bool OnCheck(Player* /*player*/, Unit* target /*Freya*/, uint32 /*criteria_id*/) override
- {
- if (target)
- if (target->GetAI()->GetData(DATA_BACK_TO_NATURE))
- return true;
- return false;
- }
-};
-
-class achievement_freya_knock_on_wood : public AchievementCriteriaScript
-{
-public:
- achievement_freya_knock_on_wood(char const* name, uint32 count) : AchievementCriteriaScript(name),
- _elderCount(count)
- {
- }
-
- bool OnCheck(Player* /*player*/, Unit* target /*Freya*/, uint32 /*criteria_id*/) override
- {
- return target && _elderCount <= target->GetAI()->GetData(DATA_GET_ELDER_COUNT);
- }
-
-private:
- uint32 const _elderCount;
-};
void AddSC_boss_freya()
{
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.h
new file mode 100644
index 00000000000000..415fd07cac1d2c
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.h
@@ -0,0 +1,1271 @@
+#ifndef BOSS_FREYA_H_
+#define BOSS_FREYA_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "SpellAuras.h"
+#include "ulduar.h"
+
+enum FreyaSpells
+{
+ // LIFEBINDER
+ SPELL_AUTO_GROW = 62559,
+ SPELL_LIFEBINDER_PHERONOMES = 62619,
+ SPELL_LIFEBINDER_VISUAL = 62579,
+ SPELL_LIFEBINDER_HEAL_10 = 62584,
+ SPELL_LIFEBINDER_HEAL_25 = 64185,
+
+ // FREYA
+ SPELL_TOUCH_OF_EONAR_10 = 62528,
+ SPELL_TOUCH_OF_EONAR_25 = 62892,
+ SPELL_ATTUNED_TO_NATURE = 62519,
+ SPELL_SUMMON_LIFEBINDER = 62870,
+ SPELL_SUNBEAM_10 = 62623,
+ SPELL_SUNBEAM_25 = 62872,
+ SPELL_NATURE_BOMB_FLIGHT = 64648,
+ SPELL_NATURE_BOMB_DAMAGE_10 = 64587,
+ SPELL_NATURE_BOMB_DAMAGE_25 = 64650,
+ SPELL_GREEN_BANISH_STATE = 32567,
+ SPELL_BERSERK = 47008,
+
+ // HARD MODE
+ SPELL_GROUND_TREMOR_FREYA_10 = 62437,
+ SPELL_GROUND_TREMOR_FREYA_25 = 62859,
+ SPELL_IRON_ROOTS_FREYA_10 = 62862,
+ SPELL_IRON_ROOTS_FREYA_25 = 62439,
+ SPELL_IRON_ROOTS_FREYA_DAMAGE_10 = 62861,
+ SPELL_IRON_ROOTS_FREYA_DAMAGE_25 = 62438,
+ SPELL_UNSTABLE_SUN_FREYA_DAMAGE_10 = 62451,
+ SPELL_UNSTABLE_SUN_FREYA_DAMAGE_25 = 62865,
+ SPELL_UNSTABLE_SUN_VISUAL = 62216,
+
+ // ELDERS
+ SPELL_DRAINED_OF_POWER = 62467,
+ SPELL_STONEBARK_ESSENCE = 62483,
+ SPELL_IRONBRANCH_ESSENCE = 62484,
+ SPELL_BRIGHTLEAF_ESSENCE = 62485,
+
+ // BRIGHTLEAF
+ SPELL_BRIGHTLEAF_FLUX = 62239,
+ SPELL_SOLAR_FLARE_10 = 62240,
+ SPELL_SOLAR_FLARE_25 = 64087,
+ SPELL_UNSTABLE_SUN_BEAM_AURA = 62211,
+ SPELL_PHOTOSYNTHESIS = 62209,
+ SPELL_UNSTABLE_SUN_DAMAGE_10 = 62217,
+ SPELL_UNSTABLE_SUN_DAMAGE_25 = 62922,
+
+ // IRONBRANCH
+ SPELL_IMPALE_10 = 62310,
+ SPELL_IMPALE_25 = 62928,
+ SPELL_IRON_ROOTS_10 = 62275,
+ SPELL_IRON_ROOTS_25 = 62929,
+ SPELL_IRON_ROOTS_DAMAGE_10 = 62283,
+ SPELL_IRON_ROOTS_DAMAGE_25 = 62930,
+ SPELL_THORN_SWARM_10 = 62285,
+ SPELL_THORN_SWARM_25 = 62931,
+
+ // STONEBARK
+ SPELL_FISTS_OF_STONE = 62344,
+ SPELL_GROUND_TREMOR_10 = 62325,
+ SPELL_GROUND_TREMOR_25 = 62932,
+ SPELL_PETRIFIED_BARK_10 = 62337,
+ SPELL_PETRIFIED_BARK_25 = 62933,
+
+ // SNAPLASHER
+ SPELL_HARDENED_BARK_10 = 62664,
+ SPELL_HARDENED_BARK_25 = 64191,
+
+ // ANCIENT WATER SPIRIT
+ SPELL_TIDAL_WAVE_10 = 62653,
+ SPELL_TIDAL_WAVE_25 = 62935,
+ SPELL_TIDAL_WAVE_DAMAGE_10 = 62654,
+ SPELL_TIDAL_WAVE_DAMAGE_25 = 62936,
+ SPELL_TIDAL_WAVE_AURA = 62655,
+
+ // STORM LASHER
+ SPELL_LIGHTNING_LASH_10 = 62648,
+ SPELL_LIGHTNING_LASH_25 = 62939,
+ SPELL_STORMBOLT_10 = 62649,
+ SPELL_STORMBOLT_25 = 62938,
+
+ // ANCIENT CONSERVATOR
+ SPELL_CONSERVATOR_GRIP = 62532,
+ SPELL_NATURE_FURY_10 = 62589,
+ SPELL_NATURE_FURY_25 = 63571,
+ SPELL_POTENT_PHEROMONES = 62541,
+ SPELL_HEALTHY_SPORE_VISUAL = 62538,
+ SPELL_HEALTHY_SPORE_SUMMON = 62566,
+
+ // DETONATING LASHER
+ SPELL_DETONATE_10 = 62598,
+ SPELL_DETONATE_25 = 62937,
+ SPELL_FLAME_LASH = 62608,
+
+ // ACHIEVEMENT
+ SPELL_DEFORESTATION_CREDIT = 65015,
+};
+
+#define SPELL_GROUND_TREMOR RAID_MODE(SPELL_GROUND_TREMOR_10, SPELL_GROUND_TREMOR_25)
+#define SPELL_PETRIFIED_BARK RAID_MODE(SPELL_PETRIFIED_BARK_10, SPELL_PETRIFIED_BARK_25)
+#define SPELL_IRON_ROOTS RAID_MODE(SPELL_IRON_ROOTS_10, SPELL_IRON_ROOTS_25)
+#define SPELL_IMPALE RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25)
+#define SPELL_THORN_SWARM RAID_MODE(SPELL_THORN_SWARM_10, SPELL_THORN_SWARM_25)
+#define SPELL_UNSTABLE_SUN_DAMAGE RAID_MODE(SPELL_UNSTABLE_SUN_DAMAGE_10, SPELL_UNSTABLE_SUN_DAMAGE_25)
+#define SPELL_SOLAR_FLARE RAID_MODE(SPELL_SOLAR_FLARE_10, SPELL_SOLAR_FLARE_25)
+#define SPELL_TOUCH_OF_EONAR RAID_MODE(SPELL_TOUCH_OF_EONAR_10, SPELL_TOUCH_OF_EONAR_25)
+#define SPELL_LIFEBINDER_HEAL RAID_MODE(SPELL_LIFEBINDER_HEAL_10, SPELL_LIFEBINDER_HEAL_25)
+#define SPELL_TIDAL_WAVE RAID_MODE(SPELL_TIDAL_WAVE_10, SPELL_TIDAL_WAVE_25)
+#define SPELL_TIDAL_WAVE_DAMAGE RAID_MODE(SPELL_TIDAL_WAVE_DAMAGE_10, SPELL_TIDAL_WAVE_DAMAGE_25)
+#define SPELL_NATURE_FURY RAID_MODE(SPELL_NATURE_FURY_10, SPELL_NATURE_FURY_25)
+#define SPELL_HARDENED_BARK RAID_MODE(SPELL_HARDENED_BARK_10, SPELL_HARDENED_BARK_25)
+#define SPELL_DETONATE RAID_MODE(SPELL_DETONATE_10, SPELL_DETONATE_25)
+//#define SPELL_NATURE_BOMB_DAMAGE RAID_MODE(SPELL_NATURE_BOMB_DAMAGE_10, SPELL_NATURE_BOMB_DAMAGE_25)
+#define SPELL_SUNBEAM RAID_MODE(SPELL_SUNBEAM_10, SPELL_SUNBEAM_25)
+#define SPELL_GROUND_TREMOR_FREYA RAID_MODE(SPELL_GROUND_TREMOR_FREYA_10, SPELL_GROUND_TREMOR_FREYA_25)
+#define SPELL_IRON_ROOTS_FREYA RAID_MODE(SPELL_IRON_ROOTS_FREYA_10, SPELL_IRON_ROOTS_FREYA_25)
+#define SPELL_UNSTABLE_SUN_FREYA_DAMAGE RAID_MODE(SPELL_UNSTABLE_SUN_FREYA_DAMAGE_10, SPELL_UNSTABLE_SUN_FREYA_DAMAGE_25)
+#define SPELL_LIGHTNING_LASH RAID_MODE(SPELL_LIGHTNING_LASH_10, SPELL_LIGHTNING_LASH_25)
+#define SPELL_STORMBOLT RAID_MODE(SPELL_STORMBOLT_10, SPELL_STORMBOLT_25)
+
+enum FreyaEvents
+{
+ // FREYA
+ EVENT_FREYA_ADDS_SPAM = 1,
+ EVENT_FREYA_LIFEBINDER = 2,
+ EVENT_FREYA_NATURE_BOMB = 3,
+ EVENT_FREYA_SUNBEAM = 4,
+ EVENT_FREYA_BERSERK = 5,
+ // HARD MODE
+ EVENT_FREYA_GROUND_TREMOR = 6,
+ EVENT_FREYA_IRON_ROOT = 7,
+ EVENT_FREYA_UNSTABLE_SUN_BEAM = 8,
+ EVENT_FREYA_RESPAWN_TRIO = 9,
+
+ // STONEBARK
+ EVENT_STONEBARK_FISTS_OF_STONE = 10,
+ EVENT_STONEBARK_GROUND_TREMOR = 11,
+ EVENT_STONEBARK_PETRIFIED_BARK = 12,
+
+ // BRIGHTLEAF
+ EVENT_BRIGHTLEAF_FLUX = 20,
+ EVENT_BRIGHTLEAF_SOLAR_FLARE = 21,
+ EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM = 22,
+ EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM = 23,
+
+ // IRONBRANCH
+ EVENT_IRONBRANCH_IMPALE = 30,
+ EVENT_IRONBRANCH_IRON_ROOT = 31,
+ EVENT_IRONBRANCH_THORN_SWARM = 32,
+
+ // SUMMONS
+ EVENT_ANCIENT_CONSERVATOR_NATURE_FURY = 40,
+ EVENT_ANCIENT_CONSERVATOR_GRIP = 41,
+ EVENT_WATER_SPIRIT_CHARGE = 45,
+ EVENT_WATER_SPIRIT_DAMAGE = 46,
+ EVENT_STORM_LASHER_LIGHTNING_LASH = 50,
+ EVENT_STORM_LASHER_STORMBOLT = 51,
+ EVENT_DETONATING_LASHER_FLAME_LASH = 55,
+};
+
+enum Texts
+{
+ // Elder Brightleaf / Elder Ironbranch / Elder Stonebark
+ SAY_ELDER_AGGRO = 0,
+ SAY_ELDER_SLAY = 1,
+ SAY_ELDER_DEATH = 2,
+
+ // Freya
+ SAY_AGGRO = 0,
+ SAY_AGGRO_WITH_ELDER = 1,
+ SAY_SLAY = 2,
+ SAY_DEATH = 3,
+ SAY_BERSERK = 4,
+ SAY_SUMMON_CONSERVATOR = 5,
+ SAY_SUMMON_TRIO = 6,
+ SAY_SUMMON_LASHERS = 7,
+ EMOTE_LIFEBINDERS_GIFT = 8,
+ EMOTE_ALLIES_OF_NATURE = 9,
+ EMOTE_GROUND_TREMOR = 10,
+ EMOTE_IRON_ROOTS = 11,
+};
+
+enum FreyaNPCs
+{
+ NPC_NATURE_BOMB = 34129,
+ NPC_IRON_ROOT_TRIGGER = 33088,
+ NPC_FREYA_UNSTABLE_SUN_BEAM = 33170,
+ NPC_UNSTABLE_SUN_BRIGHTLEAF = 33050, // 10 SECS?
+
+ // FIRST WAVE
+ NPC_STORM_LASHER = 32919,
+ NPC_ANCIENT_WATER_SPIRIT = 33202,
+ NPC_SNAPLASHER = 32916,
+
+ // SEC WAVE
+ NPC_ANCIENT_CONSERVATOR = 33203,
+ NPC_HEALTHY_SPORE = 33215,
+
+ // THIRD WAVE
+ NPC_DETONATING_LASHER = 32918,
+};
+
+enum Misc
+{
+ ACTION_REMOVE_10_STACK = 10,
+ ACTION_REMOVE_25_STACK = 25,
+ ACTION_REMOVE_2_STACK = 2,
+ ACTION_RESPAWN_TRIO = 1,
+ ACTION_LUMBERJACKED = -1,
+
+ EVENT_PHASE_ADDS = 1,
+ EVENT_PHASE_FINAL = 2,
+
+ DATA_GET_ELDER_COUNT = 1,
+ DATA_BACK_TO_NATURE = 2,
+
+ CRITERIA_LUMBERJACKED = 21686,
+};
+
+class boss_freya : public CreatureScript
+{
+public:
+ boss_freya() : CreatureScript("boss_freya") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_freyaAI : public ScriptedAI
+ {
+ boss_freyaAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
+ {
+ m_pInstance = pCreature->GetInstanceScript();
+ if (!me->IsAlive())
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_FREYA, DONE);
+ }
+
+ InstanceScript* m_pInstance;
+ EventMap events;
+ SummonList summons;
+
+ uint8 _waveNumber;
+ uint8 _trioKilled;
+ uint8 _spawnedAmount;
+ uint8 _lumberjacked;
+ bool _respawningTrio;
+ bool _backToNature;
+ uint8 _deforestation;
+
+ ObjectGuid _elderGUID[3];
+
+ void Reset() override
+ {
+ if (m_pInstance && m_pInstance->GetData(TYPE_FREYA) != DONE)
+ m_pInstance->SetData(TYPE_FREYA, NOT_STARTED);
+
+ events.Reset();
+ summons.DespawnAll();
+
+ for (uint8 i = 0; i < 3; ++i)
+ {
+ if (!_elderGUID[i])
+ continue;
+
+ if (Creature* elder = ObjectAccessor::GetCreature(*me, _elderGUID[i]))
+ elder->AI()->EnterEvadeMode();
+
+ _elderGUID[i].Clear();
+ }
+
+ _lumberjacked = 0;
+ _spawnedAmount = 0;
+ _trioKilled = 0;
+ _waveNumber = urand(1, 3);
+ _respawningTrio = false;
+ _backToNature = true;
+ _deforestation = 0;
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() != TYPEID_PLAYER || urand(0, 2))
+ return;
+
+ Talk(SAY_SLAY);
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (damage >= me->GetHealth())
+ {
+ damage = 0;
+ if (m_pInstance->GetData(TYPE_FREYA) != DONE)
+ {
+ Talk(SAY_DEATH);
+
+ me->SetReactState(REACT_PASSIVE);
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->SetFaction(FACTION_FRIENDLY);
+ me->RemoveAllAuras();
+ me->AttackStop();
+ events.Reset();
+
+ summons.DespawnAll();
+ events.Reset();
+
+ uint8 _elderCount = 0;
+ for (uint8 i = 0; i < 3; ++i)
+ {
+ if (!_elderGUID[i])
+ continue;
+
+ if (Creature* e = ObjectAccessor::GetCreature(*me, _elderGUID[i]))
+ e->DespawnOrUnsummon();
+
+ ++_elderCount;
+ }
+
+ uint32 chestId = RAID_MODE(GO_FREYA_CHEST, GO_FREYA_CHEST_HERO);
+ chestId -= 2 * _elderCount; // offset
+
+ me->DespawnOrUnsummon(5000);
+ if (GameObject* go = me->SummonGameObject(chestId, 2345.61f, -71.20f, 425.104f, 3.0f, 0, 0, 0, 0, 0))
+ {
+ go->ReplaceAllGameObjectFlags((GameObjectFlags)0);
+ go->SetLootRecipient(me->GetMap());
+ }
+
+ // Defeat credit
+ if (m_pInstance)
+ {
+ me->CastSpell(me, 65074, true); // credit
+ m_pInstance->SetData(TYPE_FREYA, DONE);
+ }
+ }
+ }
+ }
+
+ void JustSummoned(Creature* cr) override
+ {
+ if (cr->GetEntry() == NPC_FREYA_UNSTABLE_SUN_BEAM)
+ {
+ cr->CastSpell(cr, SPELL_UNSTABLE_SUN_VISUAL, true);
+ cr->CastSpell(cr, SPELL_UNSTABLE_SUN_FREYA_DAMAGE, true);
+ }
+ summons.Summon(cr);
+ }
+
+ void SpawnWave()
+ {
+ _waveNumber = _waveNumber == 1 ? 3 : _waveNumber - 1;
+ Talk(EMOTE_ALLIES_OF_NATURE);
+
+ // Wave of three
+ if (_waveNumber == 1)
+ {
+ Talk(SAY_SUMMON_TRIO);
+ me->SummonCreature(NPC_ANCIENT_WATER_SPIRIT, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
+ me->SummonCreature(NPC_STORM_LASHER, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
+ me->SummonCreature(NPC_SNAPLASHER, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
+ }
+ // Ancient Conservator
+ else if (_waveNumber == 2)
+ {
+ Talk(SAY_SUMMON_CONSERVATOR);
+ me->SummonCreature(NPC_ANCIENT_CONSERVATOR, me->GetPositionX() + urand(5, 15), me->GetPositionY() + urand(5, 15), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_CORPSE_DESPAWN);
+ }
+ // Detonating Lashers
+ else if (_waveNumber == 3)
+ {
+ Talk(SAY_SUMMON_LASHERS);
+ for (uint8 i = 0; i < 10; ++i)
+ me->SummonCreature(NPC_DETONATING_LASHER, me->GetPositionX() + urand(5, 20), me->GetPositionY() + urand(5, 20), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_CORPSE_DESPAWN);
+ }
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_LUMBERJACKED)
+ {
+ if (!m_pInstance)
+ return;
+
+ ++_lumberjacked;
+ if (_lumberjacked == 1)
+ m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, CRITERIA_LUMBERJACKED);
+ else if (_lumberjacked == 3)
+ m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 65296 /*SPELL_LUMBERJACKED*/, 0, me);
+ return;
+ }
+
+ if (param == ACTION_RESPAWN_TRIO)
+ {
+ if (!_respawningTrio)
+ {
+ _respawningTrio = true;
+ events.ScheduleEvent(EVENT_FREYA_RESPAWN_TRIO, 10s);
+ }
+
+ ++_trioKilled;
+ return;
+ }
+
+ // Deforestation Achievement Counter
+ if (param == ACTION_REMOVE_10_STACK)
+ {
+ ++_deforestation;
+ if (_deforestation >= 6 && m_pInstance)
+ m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_DEFORESTATION_CREDIT, 0, me);
+ // do not return
+ }
+
+ if (Aura* aur = me->GetAura(SPELL_ATTUNED_TO_NATURE))
+ {
+ // Back to Nature achievement
+ if (aur->GetStackAmount() - param < 25)
+ _backToNature = false;
+
+ if (aur->GetStackAmount() > param)
+ aur->SetStackAmount(aur->GetStackAmount() - param);
+ else // Aura out of stack
+ {
+ events.ScheduleEvent(EVENT_FREYA_NATURE_BOMB, 5s);
+ events.SetPhase(EVENT_PHASE_FINAL);
+ aur->Remove();
+ return;
+ }
+ }
+ }
+
+ uint32 GetData(uint32 param) const override
+ {
+ if (param == DATA_GET_ELDER_COUNT)
+ {
+ uint8 _count = 0;
+ for (uint8 i = 0; i < 3; ++i)
+ if (_elderGUID[i])
+ ++_count;
+
+ return _count;
+ }
+ if (param == DATA_BACK_TO_NATURE)
+ return _backToNature;
+
+ return 0;
+ }
+
+ void JustReachedHome() override { me->setActive(false); }
+
+ void JustEngagedWith(Unit*) override
+ {
+ me->setActive(true);
+ me->SetInCombatWithZone();
+ me->CastSpell(me, SPELL_TOUCH_OF_EONAR, true);
+ if (Aura* aur = me->AddAura(SPELL_ATTUNED_TO_NATURE, me))
+ aur->SetStackAmount(150);
+
+ events.ScheduleEvent(EVENT_FREYA_ADDS_SPAM, 10s, 0, EVENT_PHASE_ADDS);
+ events.ScheduleEvent(EVENT_FREYA_LIFEBINDER, 30s);
+ events.ScheduleEvent(EVENT_FREYA_SUNBEAM, 17s);
+ events.ScheduleEvent(EVENT_FREYA_BERSERK, 10min);
+ events.SetPhase(EVENT_PHASE_ADDS);
+
+ if( !m_pInstance )
+ return;
+
+ if (m_pInstance->GetData(TYPE_FREYA) != DONE)
+ m_pInstance->SetData(TYPE_FREYA, IN_PROGRESS);
+
+ // HARD MODE CHECKS
+ Creature* elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_STONEBARK));
+ if (elder && elder->IsAlive())
+ {
+ elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true);
+ elder->CastSpell(elder, SPELL_STONEBARK_ESSENCE, true);
+ elder->SetInCombatWithZone();
+
+ events.ScheduleEvent(EVENT_FREYA_GROUND_TREMOR, 35s);
+ _elderGUID[0] = elder->GetGUID();
+ }
+
+ elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_IRONBRANCH));
+ if (elder && elder->IsAlive())
+ {
+ elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true);
+ elder->CastSpell(elder, SPELL_IRONBRANCH_ESSENCE, true);
+ elder->SetInCombatWithZone();
+
+ events.ScheduleEvent(EVENT_FREYA_IRON_ROOT, 20s);
+ _elderGUID[1] = elder->GetGUID();
+ }
+
+ elder = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(NPC_ELDER_BRIGHTLEAF));
+ if (elder && elder->IsAlive())
+ {
+ elder->CastSpell(elder, SPELL_DRAINED_OF_POWER, true);
+ elder->CastSpell(elder, SPELL_BRIGHTLEAF_ESSENCE, true);
+ elder->SetInCombatWithZone();
+
+ events.ScheduleEvent(EVENT_FREYA_UNSTABLE_SUN_BEAM, 1min);
+ _elderGUID[2] = elder->GetGUID();
+ }
+
+ if (_elderGUID[0] || _elderGUID[1] || _elderGUID[2])
+ {
+ Talk(SAY_AGGRO_WITH_ELDER);
+ }
+ else
+ {
+ Talk(SAY_AGGRO);
+ }
+ }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_NATURE_BOMB_FLIGHT)
+ me->SummonCreature(NPC_NATURE_BOMB, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_FREYA_ADDS_SPAM:
+ if (_spawnedAmount < 6)
+ SpawnWave();
+ else if (me->GetAura(SPELL_ATTUNED_TO_NATURE))
+ {
+ me->RemoveAura(SPELL_ATTUNED_TO_NATURE);
+ events.ScheduleEvent(EVENT_FREYA_NATURE_BOMB, 5s);
+ events.SetPhase(EVENT_PHASE_FINAL);
+ return;
+ }
+ _spawnedAmount++;
+ events.Repeat(1min);
+ break;
+ case EVENT_FREYA_LIFEBINDER:
+ {
+ Talk(EMOTE_LIFEBINDERS_GIFT);
+ events.Repeat(45s);
+ float x, y, z;
+ for (uint8 i = 0; i < 10; ++i)
+ {
+ x = me->GetPositionX() + urand(7, 25);
+ y = me->GetPositionY() + urand(7, 25);
+ z = me->GetMapHeight(x, y, me->GetPositionZ());
+ if (me->IsWithinLOS(x, y, z))
+ {
+ me->CastSpell(x, y, z, SPELL_SUMMON_LIFEBINDER, true);
+ return;
+ }
+ }
+
+ me->CastSpell(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), SPELL_SUMMON_LIFEBINDER, true);
+ break;
+ }
+ case EVENT_FREYA_SUNBEAM:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random))
+ me->CastSpell(target, SPELL_SUNBEAM, false);
+ events.Repeat(15s, 20s);
+ break;
+ case EVENT_FREYA_RESPAWN_TRIO:
+ _deforestation = 0;
+ _respawningTrio = false;
+ if (_trioKilled < 3)
+ summons.DoAction(ACTION_RESPAWN_TRIO);
+
+ _trioKilled = 0;
+ break;
+ case EVENT_FREYA_NATURE_BOMB:
+ {
+ uint8 _minCount = me->GetMap()->Is25ManRaid() ? urand(7, 10) : urand(3, 4);
+ Map::PlayerList const& pList = me->GetMap()->GetPlayers();
+ for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
+ {
+ if (me->GetDistance(itr->GetSource()) > 70 || !itr->GetSource()->IsAlive())
+ continue;
+
+ me->CastSpell(itr->GetSource(), SPELL_NATURE_BOMB_FLIGHT, true);
+
+ if (!(--_minCount))
+ break;
+ }
+ events.Repeat(18s);
+ break;
+ }
+ case EVENT_FREYA_BERSERK:
+ Talk(SAY_BERSERK);
+ me->CastSpell(me, SPELL_BERSERK, true);
+ break;
+ case EVENT_FREYA_GROUND_TREMOR:
+ Talk(EMOTE_GROUND_TREMOR);
+ me->CastSpell(me, SPELL_GROUND_TREMOR_FREYA, false);
+ events.Repeat(25s, 35s);
+ break;
+ case EVENT_FREYA_IRON_ROOT:
+ Talk(EMOTE_IRON_ROOTS);
+ me->CastCustomSpell(SPELL_IRON_ROOTS_FREYA, SPELLVALUE_MAX_TARGETS, 1, me, false);
+ events.Repeat(45s, 55s);
+ break;
+ case EVENT_FREYA_UNSTABLE_SUN_BEAM:
+ me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
+ if (Is25ManRaid())
+ {
+ me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
+ me->SummonCreature(NPC_FREYA_UNSTABLE_SUN_BEAM, me->GetPositionX() + urand(7, 25), me->GetPositionY() + urand(7, 25), me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
+ }
+ events.Repeat(38s, 48s);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ bool CheckEvadeIfOutOfCombatArea() const override
+ {
+ return me->GetPositionX() < 2135.0f;
+ }
+ };
+};
+
+class boss_freya_elder_stonebark : public CreatureScript
+{
+public:
+ boss_freya_elder_stonebark() : CreatureScript("boss_freya_elder_stonebark") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_freya_elder_stonebarkAI : public ScriptedAI
+ {
+ boss_freya_elder_stonebarkAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ }
+
+ EventMap events;
+ uint8 _chargesCount;
+
+ void Reset() override
+ {
+ events.Reset();
+ _chargesCount = 0;
+ }
+
+ void KilledUnit(Unit*) override
+ {
+ if (urand(0, 1))
+ return;
+
+ Talk(SAY_ELDER_SLAY);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ if (killer && me->GetEntry() == killer->GetEntry())
+ return;
+ Talk(SAY_ELDER_DEATH);
+
+ // Lumberjacked
+ if (me->GetInstanceScript())
+ if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA)))
+ freya->AI()->DoAction(ACTION_LUMBERJACKED);
+ }
+
+ void JustEngagedWith(Unit*) override
+ {
+ events.ScheduleEvent(EVENT_STONEBARK_FISTS_OF_STONE, 40s);
+ events.ScheduleEvent(EVENT_STONEBARK_GROUND_TREMOR, 5s);
+ events.ScheduleEvent(EVENT_STONEBARK_PETRIFIED_BARK, 20s);
+
+ if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation
+ Talk(SAY_ELDER_AGGRO);
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType damageType, SpellSchoolMask damageSchoolMask) override
+ {
+ if ((damageType == DIRECT_DAMAGE || (damageType == SPELL_DIRECT_DAMAGE && damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL)) && _chargesCount)
+ {
+ --_chargesCount;
+ damage = 0;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_STONEBARK_FISTS_OF_STONE:
+ me->CastSpell(me, SPELL_FISTS_OF_STONE, false);
+ events.Repeat(1min);
+ break;
+ case EVENT_STONEBARK_GROUND_TREMOR:
+ if (!me->HasAura(SPELL_FISTS_OF_STONE))
+ me->CastSpell(me, SPELL_GROUND_TREMOR, false);
+ events.Repeat(20s);
+ break;
+ case EVENT_STONEBARK_PETRIFIED_BARK:
+ _chargesCount = RAID_MODE(60, 120);
+ me->CastSpell(me, SPELL_PETRIFIED_BARK, false);
+ events.Repeat(30s);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_freya_elder_brightleaf : public CreatureScript
+{
+public:
+ boss_freya_elder_brightleaf() : CreatureScript("boss_freya_elder_brightleaf") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_freya_elder_brightleafAI : public ScriptedAI
+ {
+ boss_freya_elder_brightleafAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature)
+ {
+ }
+
+ EventMap events;
+ SummonList summons;
+
+ void Reset() override
+ {
+ events.Reset();
+ summons.DespawnAll();
+ }
+
+ void KilledUnit(Unit*) override
+ {
+ if (urand(0, 1))
+ return;
+
+ Talk(SAY_ELDER_SLAY);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ if (killer && me->GetEntry() == killer->GetEntry())
+ return;
+ Talk(SAY_ELDER_DEATH);
+
+ // Lumberjacked
+ if (me->GetInstanceScript())
+ if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA)))
+ freya->AI()->DoAction(ACTION_LUMBERJACKED);
+ }
+
+ void JustEngagedWith(Unit*) override
+ {
+ events.ScheduleEvent(EVENT_BRIGHTLEAF_FLUX, 10s);
+ events.ScheduleEvent(EVENT_BRIGHTLEAF_SOLAR_FLARE, 5s);
+ events.ScheduleEvent(EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM, 8s);
+
+ if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation
+ Talk(SAY_ELDER_AGGRO);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_BRIGHTLEAF_FLUX:
+ if (Aura* aur = me->AddAura(SPELL_BRIGHTLEAF_FLUX, me))
+ aur->SetStackAmount(urand(1, 10));
+ events.Repeat(10s);
+ break;
+ case EVENT_BRIGHTLEAF_SOLAR_FLARE:
+ if (Aura* aur = me->GetAura(SPELL_BRIGHTLEAF_FLUX))
+ {
+ me->CastCustomSpell(SPELL_SOLAR_FLARE, SPELLVALUE_MAX_TARGETS, aur->GetStackAmount(), me, false);
+ me->RemoveAura(aur);
+ }
+ events.Repeat(15s);
+ break;
+ case EVENT_BRIGHTLEAF_UNSTABLE_SUN_BEAM:
+ events.ScheduleEvent(EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM, 15s);
+ if (Creature* beam = me->SummonCreature(NPC_UNSTABLE_SUN_BRIGHTLEAF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()))
+ {
+ beam->CastSpell(beam, SPELL_UNSTABLE_SUN_BEAM_AURA, true);
+ beam->CastSpell(beam, SPELL_PHOTOSYNTHESIS, true);
+ summons.Summon(beam);
+ }
+ if (Creature* beam = me->SummonCreature(NPC_UNSTABLE_SUN_BRIGHTLEAF, me->GetPositionX() + 8, me->GetPositionY() + 8, me->GetPositionZ()))
+ {
+ beam->CastSpell(beam, SPELL_UNSTABLE_SUN_BEAM_AURA, true);
+ beam->CastSpell(beam, SPELL_PHOTOSYNTHESIS, true);
+ summons.Summon(beam);
+ }
+ events.Repeat(20s);
+ break;
+ case EVENT_BRIGHTLEAF_DESPAWN_SUN_BEAM:
+ for (SummonList::iterator i = summons.begin(); i != summons.end();)
+ {
+ Creature* summon = ObjectAccessor::GetCreature(*me, *i);
+ ++i;
+ if (summon)
+ summon->CastSpell(summon, SPELL_UNSTABLE_SUN_DAMAGE, false);
+ }
+
+ summons.DespawnAll();
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_freya_elder_ironbranch : public CreatureScript
+{
+public:
+ boss_freya_elder_ironbranch() : CreatureScript("boss_freya_elder_ironbranch") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_freya_elder_ironbranchAI : public ScriptedAI
+ {
+ boss_freya_elder_ironbranchAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ }
+
+ EventMap events;
+
+ void Reset() override
+ {
+ events.Reset();
+ }
+
+ void KilledUnit(Unit*) override
+ {
+ if (urand(0, 1))
+ return;
+
+ Talk(SAY_ELDER_SLAY);
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ if (killer && me->GetEntry() == killer->GetEntry())
+ return;
+ Talk(SAY_ELDER_DEATH);
+
+ // Lumberjacked
+ if (me->GetInstanceScript())
+ if (Creature* freya = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_FREYA)))
+ freya->AI()->DoAction(ACTION_LUMBERJACKED);
+ }
+
+ void JustEngagedWith(Unit*) override
+ {
+ events.ScheduleEvent(EVENT_IRONBRANCH_IMPALE, 10s);
+ events.ScheduleEvent(EVENT_IRONBRANCH_IRON_ROOT, 15s);
+ events.ScheduleEvent(EVENT_IRONBRANCH_THORN_SWARM, 3s);
+
+ if (!me->HasAura(SPELL_DRAINED_OF_POWER)) // Prevents speech if combat is initiated by hardmode activation
+ Talk(SAY_ELDER_AGGRO);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_IRONBRANCH_IMPALE:
+ me->CastSpell(me->GetVictim(), SPELL_IMPALE, false);
+ events.Repeat(17s);
+ break;
+ case EVENT_IRONBRANCH_IRON_ROOT:
+ me->CastCustomSpell(SPELL_IRON_ROOTS, SPELLVALUE_MAX_TARGETS, 1, me, false);
+ events.Repeat(20s);
+ break;
+ case EVENT_IRONBRANCH_THORN_SWARM:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_THORN_SWARM, false);
+ events.Repeat(14s);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_freya_iron_root : public CreatureScript
+{
+public:
+ boss_freya_iron_root() : CreatureScript("boss_freya_iron_root") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_freya_iron_rootAI : public NullCreatureAI
+ {
+ boss_freya_iron_rootAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (!me->IsSummon())
+ return;
+
+ if (Unit* target = ObjectAccessor::GetUnit(*me, me->ToTempSummon()->GetSummonerGUID()))
+ {
+ if (me->GetEntry() == NPC_IRON_ROOT_TRIGGER) // Iron Branch spell
+ target->RemoveAura(target->GetMap()->Is25ManRaid() ? SPELL_IRON_ROOTS_DAMAGE_25 : SPELL_IRON_ROOTS_DAMAGE_10);
+ else
+ target->RemoveAura(target->GetMap()->Is25ManRaid() ? SPELL_IRON_ROOTS_FREYA_DAMAGE_25 : SPELL_IRON_ROOTS_FREYA_DAMAGE_10);
+ }
+ }
+ };
+};
+
+class boss_freya_lifebinder : public CreatureScript
+{
+public:
+ boss_freya_lifebinder() : CreatureScript("boss_freya_lifebinder") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_freya_lifebinderAI : public NullCreatureAI
+ {
+ boss_freya_lifebinderAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ }
+
+ uint32 _healTimer;
+
+ void Reset() override
+ {
+ me->CastSpell(me, SPELL_LIFEBINDER_VISUAL, true);
+ me->CastSpell(me, SPELL_LIFEBINDER_PHERONOMES, true);
+ me->CastSpell(me, SPELL_AUTO_GROW, true);
+ _healTimer = 0;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _healTimer += diff;
+ if (_healTimer >= 12000)
+ {
+ me->RemoveAurasDueToSpell(SPELL_AUTO_GROW);
+ me->CastSpell(me, me->GetMap()->Is25ManRaid() ? SPELL_LIFEBINDER_HEAL_25 : SPELL_LIFEBINDER_HEAL_10, true);
+ me->DespawnOrUnsummon(2000);
+ _healTimer = 0;
+ }
+ }
+ };
+};
+
+class boss_freya_healthy_spore : public CreatureScript
+{
+public:
+ boss_freya_healthy_spore() : CreatureScript("boss_freya_healthy_spore") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_freya_healthy_sporeAI : public NullCreatureAI
+ {
+ boss_freya_healthy_sporeAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ }
+
+ uint32 _despawnTimer;
+
+ void Reset() override
+ {
+ me->CastSpell(me, SPELL_POTENT_PHEROMONES, true);
+ me->CastSpell(me, SPELL_HEALTHY_SPORE_VISUAL, true);
+ me->CastSpell(me, SPELL_AUTO_GROW, true);
+ _despawnTimer = 0;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _despawnTimer += diff;
+ if (_despawnTimer >= 22000)
+ {
+ me->RemoveAurasDueToSpell(SPELL_AUTO_GROW);
+ me->DespawnOrUnsummon(2200);
+ _despawnTimer = 0;
+ }
+ }
+ };
+};
+
+class boss_freya_summons : public CreatureScript
+{
+public:
+ boss_freya_summons() : CreatureScript("boss_freya_summons") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_freya_summonsAI : public ScriptedAI
+ {
+ boss_freya_summonsAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ _freyaGUID = me->GetInstanceScript() ? me->GetInstanceScript()->GetGuidData(TYPE_FREYA) : ObjectGuid::Empty;
+ _isTrio = me->GetEntry() == NPC_ANCIENT_WATER_SPIRIT || me->GetEntry() == NPC_STORM_LASHER || me->GetEntry() == NPC_SNAPLASHER;
+ _hasDied = false;
+ }
+
+ EventMap events;
+ ObjectGuid _freyaGUID;
+ uint8 _stackCount;
+ bool _hasDied;
+ bool _isTrio;
+
+ void Reset() override
+ {
+ _stackCount = 0;
+ events.Reset();
+ if (Unit* target = SelectTargetFromPlayerList(70))
+ AttackStart(target);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (Creature* freya = ObjectAccessor::GetCreature(*me, _freyaGUID))
+ {
+ if (!_hasDied)
+ freya->AI()->DoAction(_stackCount);
+
+ if (_isTrio)
+ {
+ freya->AI()->DoAction(ACTION_RESPAWN_TRIO);
+ _hasDied = true;
+ }
+ }
+ if (me->GetEntry() == NPC_DETONATING_LASHER)
+ me->CastSpell(me, SPELL_DETONATE, true);
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (_isTrio && param == ACTION_RESPAWN_TRIO)
+ {
+ me->setDeathState(DeathState::JustRespawned);
+ Reset();
+ }
+ }
+
+ void JustEngagedWith(Unit*) override
+ {
+ if (me->GetEntry() == NPC_ANCIENT_CONSERVATOR)
+ {
+ me->CastSpell(me, SPELL_HEALTHY_SPORE_SUMMON, true);
+ events.ScheduleEvent(EVENT_ANCIENT_CONSERVATOR_GRIP, 6s);
+ events.ScheduleEvent(EVENT_ANCIENT_CONSERVATOR_NATURE_FURY, 14s);
+ _stackCount = ACTION_REMOVE_25_STACK;
+ }
+ else if (me->GetEntry() == NPC_ANCIENT_WATER_SPIRIT)
+ {
+ events.ScheduleEvent(EVENT_WATER_SPIRIT_CHARGE, 12s);
+ _stackCount = ACTION_REMOVE_10_STACK;
+ }
+ else if (me->GetEntry() == NPC_STORM_LASHER)
+ {
+ events.ScheduleEvent(EVENT_STORM_LASHER_LIGHTNING_LASH, 10s);
+ events.ScheduleEvent(EVENT_STORM_LASHER_STORMBOLT, 6s);
+ _stackCount = ACTION_REMOVE_10_STACK;
+ }
+ else if (me->GetEntry() == NPC_DETONATING_LASHER)
+ {
+ events.ScheduleEvent(EVENT_DETONATING_LASHER_FLAME_LASH, 10s);
+ _stackCount = ACTION_REMOVE_2_STACK;
+ }
+ else if (me->GetEntry() == NPC_SNAPLASHER)
+ {
+ me->CastSpell(me, SPELL_HARDENED_BARK, true);
+ _stackCount = ACTION_REMOVE_10_STACK;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_ANCIENT_CONSERVATOR_NATURE_FURY:
+ me->CastSpell(me->GetVictim(), SPELL_NATURE_FURY, false);
+ events.Repeat(14s);
+ break;
+ case EVENT_ANCIENT_CONSERVATOR_GRIP:
+ me->CastSpell(me, SPELL_CONSERVATOR_GRIP, true);
+ break;
+ case EVENT_WATER_SPIRIT_CHARGE:
+ me->CastSpell(me, SPELL_TIDAL_WAVE_AURA, true);
+ me->CastSpell(me->GetVictim(), SPELL_TIDAL_WAVE, false);
+ events.Repeat(12s);
+ events.ScheduleEvent(EVENT_WATER_SPIRIT_DAMAGE, 3s);
+ break;
+ case EVENT_WATER_SPIRIT_DAMAGE:
+ me->CastSpell(me, SPELL_TIDAL_WAVE_DAMAGE, false);
+ break;
+ case EVENT_STORM_LASHER_LIGHTNING_LASH:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target, SPELL_LIGHTNING_LASH, false);
+ events.Repeat(10s);
+ break;
+ case EVENT_STORM_LASHER_STORMBOLT:
+ me->CastSpell(me->GetVictim(), SPELL_STORMBOLT, false);
+ events.Repeat(6s);
+ break;
+ case EVENT_DETONATING_LASHER_FLAME_LASH:
+ me->CastSpell(me->GetVictim(), SPELL_FLAME_LASH, false);
+ DoResetThreatList();
+ if (Unit* target = SelectTargetFromPlayerList(80))
+ AttackStart(target);
+ else
+ me->DespawnOrUnsummon(1);
+ events.Repeat(10s);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_freya_nature_bomb : public CreatureScript
+{
+public:
+ boss_freya_nature_bomb() : CreatureScript("boss_freya_nature_bomb") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_freya_nature_bombAI : public NullCreatureAI
+ {
+ boss_freya_nature_bombAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ _goGUID.Clear();
+ }
+
+ ObjectGuid _goGUID;
+ uint32 _explodeTimer;
+
+ void Reset() override
+ {
+ me->SetObjectScale(0.5f);
+ me->CastSpell(me, SPELL_GREEN_BANISH_STATE, true);
+
+ _explodeTimer = 0;
+ if (GameObject* go = me->SummonGameObject(194902 /*GO_NATURE_BOMB*/, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, 0, 0, 0, 0, 0))
+ _goGUID = go->GetGUID();
+ }
+
+ uint32 Timer;
+ void UpdateAI(uint32 diff) override
+ {
+ _explodeTimer += diff;
+ if (_explodeTimer >= 11000)
+ {
+ me->CastSpell(me, me->GetMap()->Is25ManRaid() ? SPELL_NATURE_BOMB_DAMAGE_25 : SPELL_NATURE_BOMB_DAMAGE_10, false);
+ me->DespawnOrUnsummon(1000);
+ _explodeTimer = 0;
+ }
+
+ // Delay explosion a little, visual
+ if (_explodeTimer >= 5000 && _explodeTimer < 10000)
+ {
+ _explodeTimer = 10000;
+ if (GameObject* go = me->GetMap()->GetGameObject(_goGUID))
+ go->SetGoState(GO_STATE_ACTIVE);
+ }
+ }
+ };
+};
+
+class achievement_freya_getting_back_to_nature : public AchievementCriteriaScript
+{
+public:
+ achievement_freya_getting_back_to_nature() : AchievementCriteriaScript("achievement_freya_getting_back_to_nature") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target /*Freya*/, uint32 /*criteria_id*/) override
+ {
+ if (target)
+ if (target->GetAI()->GetData(DATA_BACK_TO_NATURE))
+ return true;
+ return false;
+ }
+};
+
+class achievement_freya_knock_on_wood : public AchievementCriteriaScript
+{
+public:
+ achievement_freya_knock_on_wood(char const* name, uint32 count) : AchievementCriteriaScript(name),
+ _elderCount(count)
+ {
+ }
+
+ bool OnCheck(Player* /*player*/, Unit* target /*Freya*/, uint32 /*criteria_id*/) override
+ {
+ return target && _elderCount <= target->GetAI()->GetData(DATA_GET_ELDER_COUNT);
+ }
+
+private:
+ uint32 const _elderCount;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp
index 2fa09a60471447..d4df0803222b21 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_general_vezax.h"
#include "AccountMgr.h"
#include "AchievementCriteriaScript.h"
#include "BanMgr.h"
@@ -28,665 +29,6 @@
#include "WorldSession.h"
#include "ulduar.h"
-enum VezaxSpellData
-{
- SPELL_VEZAX_BERSERK = 26662,
-
- SPELL_VEZAX_SHADOW_CRASH = 62660,
- SPELL_VEZAX_SHADOW_CRASH_DMG = 62659,
- SPELL_VEZAX_SHADOW_CRASH_AREA_AURA = 63277,
- SPELL_VEZAX_SHADOW_CRASH_AURA = 65269,
-
- SPELL_SEARING_FLAMES = 62661,
-
- SPELL_SURGE_OF_DARKNESS = 62662,
-
- SPELL_MARK_OF_THE_FACELESS_AURA = 63276,
- SPELL_MARK_OF_THE_FACELESS_EFFECT = 63278,
-
- SPELL_AURA_OF_DESPAIR_1 = 62692,
- SPELL_AURA_OF_DESPAIR_2 = 64848,
- SPELL_CORRUPTED_RAGE = 68415,
- SPELL_CORRUPTED_WISDOM = 64646,
- SPELL_SHAMANISTIC_RAGE = 30823,
- SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 = 31876,
-
- SPELL_SUMMON_SARONITE_VAPORS = 63081,
- NPC_SARONITE_VAPORS = 33488,
- SPELL_SARONITE_VAPORS_DMG = 63338,
- SPELL_SARONITE_VAPORS_ENERGIZE = 63337,
- SPELL_SARONITE_VAPORS_AURA = 63323,
- SPELL_SARONITE_VAPORS_DUMMYAURA = 63322,
-
- SPELL_SARONITE_ANIMUS_FORMATION_VISUAL = 63319,
- SPELL_SUMMON_SARONITE_ANIMUS = 63145,
- SPELL_SARONITE_BARRIER = 63364,
- SPELL_PROFOUND_DARKNESS = 63420,
-};
-
-enum VezaxNpcs
-{
- // NPC_VEZAX = 33271,
- // NPC_VEZAX_BUNNY = 33500,
- NPC_SARONITE_ANIMUS = 33524,
-};
-
-enum VezaxGOs
-{
- // GO_VEZAX_DOOR = 194750,
-};
-
-enum VezaxEvents
-{
- EVENT_SPELL_VEZAX_SHADOW_CRASH = 1,
- EVENT_SPELL_SEARING_FLAMES = 2,
- EVENT_SPELL_SURGE_OF_DARKNESS = 3,
- EVENT_SPELL_MARK_OF_THE_FACELESS = 4,
- EVENT_SPELL_SUMMON_SARONITE_VAPORS = 5,
- EVENT_SARONITE_VAPORS_SWIRL = 6,
- EVENT_SPELL_SUMMON_SARONITE_ANIMUS = 7,
- EVENT_DESPAWN_SARONITE_VAPORS = 8,
- EVENT_SPELL_PROFOUND_DARKNESS = 9,
- EVENT_BERSERK = 10,
- EVENT_RESTORE_TARGET = 11,
-};
-
-enum VezaxText
-{
- SAY_AGGRO = 0,
- SAY_SLAY = 1,
- SAY_SURGE_OF_DARKNESS = 2,
- SAY_DEATH = 3,
- SAY_BERSERK = 4,
- SAY_HARDMODE = 5,
- SAY_EMOTE_ANIMUS = 6,
- SAY_EMOTE_BARRIER = 7,
- SAY_EMOTE_SURGE_OF_DARKNESS = 8,
-};
-
-enum VaporsText
-{
- SAY_EMOTE_VAPORS = 0,
-};
-
-class boss_vezax : public CreatureScript
-{
-public:
- boss_vezax() : CreatureScript("boss_vezax") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_vezaxAI : public ScriptedAI
- {
- boss_vezaxAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
- {
- pInstance = pCreature->GetInstanceScript();
- }
-
- EventMap events;
- SummonList summons;
- uint8 vaporsCount;
- bool hardmodeAvailable;
- bool berserk;
- bool bAchievShadowdodger;
-
- InstanceScript* pInstance;
-
- void Reset() override
- {
- vaporsCount = 0;
- hardmodeAvailable = true;
- berserk = false;
- bAchievShadowdodger = true;
- events.Reset();
- summons.DespawnAll();
- me->SetLootMode(1);
-
- if (pInstance)
- pInstance->SetData(TYPE_VEZAX, NOT_STARTED);
- }
-
- void JustReachedHome() override
- {
- me->setActive(false);
- }
-
- void JustEngagedWith(Unit* /*pWho*/) override
- {
- me->setActive(true);
- me->SetInCombatWithZone();
-
- events.Reset();
- events.RescheduleEvent(EVENT_SPELL_VEZAX_SHADOW_CRASH, 13s);
- events.RescheduleEvent(EVENT_SPELL_SEARING_FLAMES, 10s, 1);
- events.RescheduleEvent(EVENT_SPELL_SURGE_OF_DARKNESS, 63s);
- events.RescheduleEvent(EVENT_SPELL_MARK_OF_THE_FACELESS, 20s);
- events.RescheduleEvent(EVENT_SPELL_SUMMON_SARONITE_VAPORS, 30s);
- events.RescheduleEvent(EVENT_BERSERK, 10min);
-
- Talk(SAY_AGGRO);
-
- if (pInstance)
- pInstance->SetData(TYPE_VEZAX, IN_PROGRESS);
-
- me->CastSpell(me, SPELL_AURA_OF_DESPAIR_1, true);
- }
-
- void DoAction(int32 param) override
- {
- switch( param )
- {
- case 1:
- hardmodeAvailable = false;
- break;
- case 2:
- me->RemoveAura(SPELL_SARONITE_BARRIER);
- me->SetLootMode(3);
- break;
- }
- }
-
- uint32 GetData(uint32 id) const override
- {
- switch (id)
- {
- case 1:
- return (me->GetLootMode() == 3 ? 1 : 0);
- case 2:
- return (bAchievShadowdodger ? 1 : 0);
- }
- return 0;
- }
-
- void SpellHitTarget(Unit* target, SpellInfo const* spell) override
- {
- if (target && spell && target->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_VEZAX_SHADOW_CRASH_DMG)
- bAchievShadowdodger = false;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if( !UpdateVictim() )
- return;
-
- if( !berserk && (me->GetPositionX() < 1720.0f || me->GetPositionX() > 1940.0f || me->GetPositionY() < 20.0f || me->GetPositionY() > 210.0f) )
- events.RescheduleEvent(EVENT_BERSERK, 1ms);
-
- events.Update(diff);
-
- if( me->HasUnitState(UNIT_STATE_CASTING) )
- return;
-
- switch( events.ExecuteEvent() )
- {
- case 0:
- break;
- case EVENT_BERSERK:
- berserk = true;
- me->CastSpell(me, SPELL_VEZAX_BERSERK, true);
- Talk(SAY_BERSERK);
- break;
- case EVENT_SPELL_VEZAX_SHADOW_CRASH:
- {
- events.Repeat(10s);
-
- std::vector players;
- Map::PlayerList const& pl = me->GetMap()->GetPlayers();
- for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
- {
- Player* temp = itr->GetSource();
- if( temp->IsAlive() && temp->GetDistance(me) > 15.0f )
- players.push_back(temp);
- }
- if (!players.empty())
- {
- me->setAttackTimer(BASE_ATTACK, 2000);
- Player* target = players.at(urand(0, players.size() - 1));
- me->SetGuidValue(UNIT_FIELD_TARGET, target->GetGUID());
- me->CastSpell(target, SPELL_VEZAX_SHADOW_CRASH, false);
- events.ScheduleEvent(EVENT_RESTORE_TARGET, 750ms);
- }
- }
- break;
- case EVENT_RESTORE_TARGET:
- if (me->GetVictim())
- me->SetGuidValue(UNIT_FIELD_TARGET, me->GetVictim()->GetGUID());
- break;
- case EVENT_SPELL_SEARING_FLAMES:
- if(!me->HasAura(SPELL_SARONITE_BARRIER))
- me->CastSpell(me->GetVictim(), SPELL_SEARING_FLAMES, false);
- events.Repeat(me->GetMap()->Is25ManRaid() ? 8s : 15s);
- break;
- case EVENT_SPELL_SURGE_OF_DARKNESS:
- Talk(SAY_SURGE_OF_DARKNESS);
- Talk(SAY_EMOTE_SURGE_OF_DARKNESS);
- me->CastSpell(me, SPELL_SURGE_OF_DARKNESS, false);
- events.Repeat(63s);
- events.DelayEvents(10000, 1);
- break;
- case EVENT_SPELL_MARK_OF_THE_FACELESS:
- {
- std::vector outside;
- std::vector inside;
- Map::PlayerList const& pl = me->GetMap()->GetPlayers();
- for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
- if( Player* tmp = itr->GetSource() )
- if( tmp->IsAlive() )
- {
- if( tmp->GetDistance(me) > 15.0f )
- outside.push_back(tmp);
- else
- inside.push_back(tmp);
- }
-
- Player* t = nullptr;
- if( outside.size() >= uint8(me->GetMap()->Is25ManRaid() ? 9 : 4) )
- t = outside.at(urand(0, outside.size() - 1));
- else if( !inside.empty() )
- t = inside.at(urand(0, inside.size() - 1));
-
- if (t)
- me->CastSpell(t, SPELL_MARK_OF_THE_FACELESS_AURA, false);
-
- events.Repeat(40s);
- }
- break;
- case EVENT_SPELL_SUMMON_SARONITE_VAPORS:
- {
- vaporsCount++;
- me->CastSpell(me, SPELL_SUMMON_SARONITE_VAPORS, false);
-
- if( vaporsCount < 6 || !hardmodeAvailable )
- events.Repeat(30s);
- else
- {
- for (ObjectGuid const& guid : summons)
- if (Creature* sv = ObjectAccessor::GetCreature(*me, guid))
- {
- sv->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- sv->GetMotionMaster()->MoveIdle();
- sv->GetMotionMaster()->MoveCharge(1852.78f, 81.38f, 342.461f, 28.0f);
- }
-
- events.DelayEvents(12000, 0);
- events.DelayEvents(12000, 1);
- events.ScheduleEvent(EVENT_SARONITE_VAPORS_SWIRL, 6s);
- }
- }
- break;
- case EVENT_SARONITE_VAPORS_SWIRL:
- if (summons.size())
- {
- Talk(SAY_EMOTE_ANIMUS);
- if( Creature* sv = ObjectAccessor::GetCreature(*me, *(summons.begin())) )
- sv->CastSpell(sv, SPELL_SARONITE_ANIMUS_FORMATION_VISUAL, true);
-
- events.ScheduleEvent(EVENT_SPELL_SUMMON_SARONITE_ANIMUS, 2s);
- break;
- }
- break;
- case EVENT_SPELL_SUMMON_SARONITE_ANIMUS:
- if (summons.size())
- {
- Talk(SAY_HARDMODE);
- Talk(SAY_EMOTE_BARRIER);
- me->CastSpell(me, SPELL_SARONITE_BARRIER, true);
- if( Creature* sv = ObjectAccessor::GetCreature(*me, *(summons.begin())) )
- sv->CastSpell(sv, SPELL_SUMMON_SARONITE_ANIMUS, true);
-
- events.ScheduleEvent(EVENT_DESPAWN_SARONITE_VAPORS, 2500ms);
- break;
- }
- break;
- case EVENT_DESPAWN_SARONITE_VAPORS:
- summons.DespawnEntry(NPC_SARONITE_VAPORS);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- summons.DespawnAll();
- if (pInstance)
- pInstance->SetData(TYPE_VEZAX, DONE);
-
- Talk(SAY_DEATH);
-
- if( GameObject* door = me->FindNearestGameObject(GO_VEZAX_DOOR, 500.0f) )
- if( door->GetGoState() != GO_STATE_ACTIVE )
- {
- door->SetLootState(GO_READY);
- door->UseDoorOrButton(0, false);
- }
- }
-
- void KilledUnit(Unit* who) override
- {
- if( who->GetTypeId() == TYPEID_PLAYER )
- Talk(SAY_SLAY);
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override {}
-
- void JustSummoned(Creature* summon) override
- {
- summons.Summon(summon);
- }
-
- void SummonedCreatureDespawn(Creature* s) override
- {
- summons.Despawn(s);
- }
- };
-};
-
-class npc_ulduar_saronite_vapors : public CreatureScript
-{
-public:
- npc_ulduar_saronite_vapors() : CreatureScript("npc_ulduar_saronite_vapors") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_saronite_vaporsAI : public NullCreatureAI
- {
- npc_ulduar_saronite_vaporsAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- pInstance = pCreature->GetInstanceScript();
- me->GetMotionMaster()->MoveRandom(4.0f);
- }
-
- InstanceScript* pInstance;
-
- void JustDied(Unit* /*killer*/) override
- {
- me->CastSpell(me, SPELL_SARONITE_VAPORS_AURA, true);
-
- // killed saronite vapors, hard mode unavailable
- if( pInstance )
- if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) )
- vezax->AI()->DoAction(1);
- }
-
- void IsSummonedBy(WorldObject* /*summoner*/) override
- {
- Talk(SAY_EMOTE_VAPORS);
- }
- };
-};
-
-class npc_ulduar_saronite_animus : public CreatureScript
-{
-public:
- npc_ulduar_saronite_animus() : CreatureScript("npc_ulduar_saronite_animus") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_saronite_animusAI : public ScriptedAI
- {
- npc_ulduar_saronite_animusAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- pInstance = pCreature->GetInstanceScript();
- if( pInstance )
- if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) )
- vezax->AI()->JustSummoned(me);
- timer = 0;
- me->SetInCombatWithZone();
- }
-
- InstanceScript* pInstance;
- uint16 timer;
-
- void JustDied(Unit* /*killer*/) override
- {
- me->DespawnOrUnsummon(3000);
-
- if( pInstance )
- if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) )
- vezax->AI()->DoAction(2);
- }
-
- void UpdateAI(uint32 diff) override
- {
- UpdateVictim();
-
- timer += diff;
- if (timer >= 2000)
- {
- me->CastSpell(me, SPELL_PROFOUND_DARKNESS, true);
- timer -= 2000;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class spell_aura_of_despair : public SpellScriptLoader
-{
-public:
- spell_aura_of_despair() : SpellScriptLoader("spell_aura_of_despair") { }
-
- class spell_aura_of_despair_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_aura_of_despair_AuraScript)
-
- void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* caster = GetCaster())
- if (Unit* target = GetTarget())
- {
- if (target->GetTypeId() != TYPEID_PLAYER)
- return;
-
- target->CastSpell(target, SPELL_AURA_OF_DESPAIR_2, true);
- if( target->HasSpell(SPELL_SHAMANISTIC_RAGE) )
- caster->CastSpell(target, SPELL_CORRUPTED_RAGE, true);
- else if( target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1) || target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 + 1) || target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 + 2) )
- caster->CastSpell(target, SPELL_CORRUPTED_WISDOM, true);
- }
- }
-
- void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* target = GetTarget())
- {
- target->RemoveAurasDueToSpell(SPELL_AURA_OF_DESPAIR_2);
- target->RemoveAurasDueToSpell(SPELL_CORRUPTED_RAGE);
- target->RemoveAurasDueToSpell(SPELL_CORRUPTED_WISDOM);
- }
- }
-
- void Register() override
- {
- OnEffectApply += AuraEffectApplyFn(spell_aura_of_despair_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PREVENT_REGENERATE_POWER, AURA_EFFECT_HANDLE_REAL);
- AfterEffectRemove += AuraEffectRemoveFn(spell_aura_of_despair_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PREVENT_REGENERATE_POWER, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_aura_of_despair_AuraScript();
- }
-};
-
-class spell_mark_of_the_faceless_periodic : public SpellScriptLoader
-{
-public:
- spell_mark_of_the_faceless_periodic() : SpellScriptLoader("spell_mark_of_the_faceless_periodic") { }
-
- class spell_mark_of_the_faceless_periodic_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_mark_of_the_faceless_periodic_AuraScript)
-
- void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
- {
- if (Unit* caster = GetCaster())
- if (Unit* target = GetTarget())
- if (target->GetMapId() == 603)
- {
- int32 dmg = 5000;
- caster->CastCustomSpell(target, SPELL_MARK_OF_THE_FACELESS_EFFECT, 0, &dmg, 0, true);
- }
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_mark_of_the_faceless_periodic_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_mark_of_the_faceless_periodic_AuraScript();
- }
-};
-
-class spell_mark_of_the_faceless_drainhealth : public SpellScriptLoader
-{
-public:
- spell_mark_of_the_faceless_drainhealth() : SpellScriptLoader("spell_mark_of_the_faceless_drainhealth") { }
-
- class spell_mark_of_the_faceless_drainhealth_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_mark_of_the_faceless_drainhealth_SpellScript);
-
- void FilterTargets(std::list& targets)
- {
- targets.remove(GetExplTargetUnit());
- if (targets.empty())
- Cancel();
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mark_of_the_faceless_drainhealth_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_DEST_AREA_ENEMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_mark_of_the_faceless_drainhealth_SpellScript();
- }
-};
-
-class spell_saronite_vapors_dummy : public SpellScriptLoader
-{
-public:
- spell_saronite_vapors_dummy() : SpellScriptLoader("spell_saronite_vapors_dummy") { }
-
- class spell_saronite_vapors_dummy_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_saronite_vapors_dummy_AuraScript)
-
- void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* caster = GetCaster())
- {
- int32 damage = 100 * pow(2.0f, (float)GetStackAmount());
- caster->CastCustomSpell(GetTarget(), SPELL_SARONITE_VAPORS_DMG, &damage, nullptr, nullptr, true);
- }
- }
-
- void Register() override
- {
- AfterEffectApply += AuraEffectApplyFn(spell_saronite_vapors_dummy_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_saronite_vapors_dummy_AuraScript();
- }
-};
-
-class spell_saronite_vapors_damage : public SpellScriptLoader
-{
-public:
- spell_saronite_vapors_damage() : SpellScriptLoader("spell_saronite_vapors_damage") { }
-
- class spell_saronite_vapors_damage_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_saronite_vapors_damage_SpellScript);
-
- void HandleAfterHit()
- {
- if (Unit* caster = GetCaster())
- if (GetHitDamage() > 2)
- {
- int32 mana = GetHitDamage() / 2;
- if (Unit* t = GetHitUnit())
- caster->CastCustomSpell(t, SPELL_SARONITE_VAPORS_ENERGIZE, &mana, nullptr, nullptr, true);
- }
- }
-
- void Register() override
- {
- AfterHit += SpellHitFn(spell_saronite_vapors_damage_SpellScript::HandleAfterHit);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_saronite_vapors_damage_SpellScript();
- }
-};
-
-class achievement_smell_saronite : public AchievementCriteriaScript
-{
-public:
- achievement_smell_saronite() : AchievementCriteriaScript("achievement_smell_saronite") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_VEZAX && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1);
- }
-};
-
-class achievement_shadowdodger : public AchievementCriteriaScript
-{
-public:
- achievement_shadowdodger() : AchievementCriteriaScript("achievement_shadowdodger") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_VEZAX && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(2);
- }
-};
-
-class go_ulduar_pure_saronite_deposit : public GameObjectScript
-{
-public:
- go_ulduar_pure_saronite_deposit() : GameObjectScript("go_ulduar_pure_saronite_deposit") { }
-
- bool OnGossipHello(Player* plr, GameObject* go) override
- {
- if (plr->IsGameMaster())
- return false;
-
- if (InstanceScript* pInstance = go->GetInstanceScript())
- if (pInstance->GetData(TYPE_XT002) != DONE && pInstance->GetData(TYPE_MIMIRON) != DONE && pInstance->GetData(TYPE_THORIM) != DONE && pInstance->GetData(TYPE_FREYA) != DONE && pInstance->GetData(TYPE_HODIR) != DONE)
- {
- std::string accountName;
- AccountMgr::GetName(plr->GetSession()->GetAccountId(), accountName);
- sBan->BanAccount(accountName, "0s", "Tele hack", "Server");
- return true;
- }
-
- return false;
- }
-};
-
void AddSC_boss_vezax()
{
new boss_vezax();
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.h
new file mode 100644
index 00000000000000..a3495ef648c45f
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.h
@@ -0,0 +1,676 @@
+#ifndef BOSS_GENERAL_VEZAX_H_
+#define BOSS_GENERAL_VEZAX_H_
+
+#include "AccountMgr.h"
+#include "AchievementCriteriaScript.h"
+#include "BanMgr.h"
+#include "CreatureScript.h"
+#include "GameObjectScript.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "WorldSession.h"
+#include "ulduar.h"
+
+enum VezaxSpellData
+{
+ SPELL_VEZAX_BERSERK = 26662,
+
+ SPELL_VEZAX_SHADOW_CRASH = 62660,
+ SPELL_VEZAX_SHADOW_CRASH_DMG = 62659,
+ SPELL_VEZAX_SHADOW_CRASH_AREA_AURA = 63277,
+ SPELL_VEZAX_SHADOW_CRASH_AURA = 65269,
+
+ SPELL_SEARING_FLAMES = 62661,
+
+ SPELL_SURGE_OF_DARKNESS = 62662,
+
+ SPELL_MARK_OF_THE_FACELESS_AURA = 63276,
+ SPELL_MARK_OF_THE_FACELESS_EFFECT = 63278,
+
+ SPELL_AURA_OF_DESPAIR_1 = 62692,
+ SPELL_AURA_OF_DESPAIR_2 = 64848,
+ SPELL_CORRUPTED_RAGE = 68415,
+ SPELL_CORRUPTED_WISDOM = 64646,
+ SPELL_SHAMANISTIC_RAGE = 30823,
+ SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 = 31876,
+
+ SPELL_SUMMON_SARONITE_VAPORS = 63081,
+ NPC_SARONITE_VAPORS = 33488,
+ SPELL_SARONITE_VAPORS_DMG = 63338,
+ SPELL_SARONITE_VAPORS_ENERGIZE = 63337,
+ SPELL_SARONITE_VAPORS_AURA = 63323,
+ SPELL_SARONITE_VAPORS_DUMMYAURA = 63322,
+
+ SPELL_SARONITE_ANIMUS_FORMATION_VISUAL = 63319,
+ SPELL_SUMMON_SARONITE_ANIMUS = 63145,
+ SPELL_SARONITE_BARRIER = 63364,
+ SPELL_PROFOUND_DARKNESS = 63420,
+};
+
+enum VezaxNpcs
+{
+ // NPC_VEZAX = 33271,
+ // NPC_VEZAX_BUNNY = 33500,
+ NPC_SARONITE_ANIMUS = 33524,
+};
+
+enum VezaxGOs
+{
+ // GO_VEZAX_DOOR = 194750,
+};
+
+enum VezaxEvents
+{
+ EVENT_SPELL_VEZAX_SHADOW_CRASH = 1,
+ EVENT_SPELL_SEARING_FLAMES = 2,
+ EVENT_SPELL_SURGE_OF_DARKNESS = 3,
+ EVENT_SPELL_MARK_OF_THE_FACELESS = 4,
+ EVENT_SPELL_SUMMON_SARONITE_VAPORS = 5,
+ EVENT_SARONITE_VAPORS_SWIRL = 6,
+ EVENT_SPELL_SUMMON_SARONITE_ANIMUS = 7,
+ EVENT_DESPAWN_SARONITE_VAPORS = 8,
+ EVENT_SPELL_PROFOUND_DARKNESS = 9,
+ EVENT_BERSERK = 10,
+ EVENT_RESTORE_TARGET = 11,
+};
+
+enum VezaxText
+{
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_SURGE_OF_DARKNESS = 2,
+ SAY_DEATH = 3,
+ SAY_BERSERK = 4,
+ SAY_HARDMODE = 5,
+ SAY_EMOTE_ANIMUS = 6,
+ SAY_EMOTE_BARRIER = 7,
+ SAY_EMOTE_SURGE_OF_DARKNESS = 8,
+};
+
+enum VaporsText
+{
+ SAY_EMOTE_VAPORS = 0,
+};
+
+class boss_vezax : public CreatureScript
+{
+public:
+ boss_vezax() : CreatureScript("boss_vezax") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_vezaxAI : public ScriptedAI
+ {
+ boss_vezaxAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
+ {
+ pInstance = pCreature->GetInstanceScript();
+ }
+
+ EventMap events;
+ SummonList summons;
+ uint8 vaporsCount;
+ bool hardmodeAvailable;
+ bool berserk;
+ bool bAchievShadowdodger;
+
+ InstanceScript* pInstance;
+
+ void Reset() override
+ {
+ vaporsCount = 0;
+ hardmodeAvailable = true;
+ berserk = false;
+ bAchievShadowdodger = true;
+ events.Reset();
+ summons.DespawnAll();
+ me->SetLootMode(1);
+
+ if (pInstance)
+ pInstance->SetData(TYPE_VEZAX, NOT_STARTED);
+ }
+
+ void JustReachedHome() override
+ {
+ me->setActive(false);
+ }
+
+ void JustEngagedWith(Unit* /*pWho*/) override
+ {
+ me->setActive(true);
+ me->SetInCombatWithZone();
+
+ events.Reset();
+ events.RescheduleEvent(EVENT_SPELL_VEZAX_SHADOW_CRASH, 13s);
+ events.RescheduleEvent(EVENT_SPELL_SEARING_FLAMES, 10s, 1);
+ events.RescheduleEvent(EVENT_SPELL_SURGE_OF_DARKNESS, 63s);
+ events.RescheduleEvent(EVENT_SPELL_MARK_OF_THE_FACELESS, 20s);
+ events.RescheduleEvent(EVENT_SPELL_SUMMON_SARONITE_VAPORS, 30s);
+ events.RescheduleEvent(EVENT_BERSERK, 10min);
+
+ Talk(SAY_AGGRO);
+
+ if (pInstance)
+ pInstance->SetData(TYPE_VEZAX, IN_PROGRESS);
+
+ me->CastSpell(me, SPELL_AURA_OF_DESPAIR_1, true);
+ }
+
+ void DoAction(int32 param) override
+ {
+ switch( param )
+ {
+ case 1:
+ hardmodeAvailable = false;
+ break;
+ case 2:
+ me->RemoveAura(SPELL_SARONITE_BARRIER);
+ me->SetLootMode(3);
+ break;
+ }
+ }
+
+ uint32 GetData(uint32 id) const override
+ {
+ switch (id)
+ {
+ case 1:
+ return (me->GetLootMode() == 3 ? 1 : 0);
+ case 2:
+ return (bAchievShadowdodger ? 1 : 0);
+ }
+ return 0;
+ }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override
+ {
+ if (target && spell && target->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_VEZAX_SHADOW_CRASH_DMG)
+ bAchievShadowdodger = false;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if( !UpdateVictim() )
+ return;
+
+ if( !berserk && (me->GetPositionX() < 1720.0f || me->GetPositionX() > 1940.0f || me->GetPositionY() < 20.0f || me->GetPositionY() > 210.0f) )
+ events.RescheduleEvent(EVENT_BERSERK, 1ms);
+
+ events.Update(diff);
+
+ if( me->HasUnitState(UNIT_STATE_CASTING) )
+ return;
+
+ switch( events.ExecuteEvent() )
+ {
+ case 0:
+ break;
+ case EVENT_BERSERK:
+ berserk = true;
+ me->CastSpell(me, SPELL_VEZAX_BERSERK, true);
+ Talk(SAY_BERSERK);
+ break;
+ case EVENT_SPELL_VEZAX_SHADOW_CRASH:
+ {
+ events.Repeat(10s);
+
+ std::vector players;
+ Map::PlayerList const& pl = me->GetMap()->GetPlayers();
+ for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
+ {
+ Player* temp = itr->GetSource();
+ if( temp->IsAlive() && temp->GetDistance(me) > 15.0f )
+ players.push_back(temp);
+ }
+ if (!players.empty())
+ {
+ me->setAttackTimer(BASE_ATTACK, 2000);
+ Player* target = players.at(urand(0, players.size() - 1));
+ me->SetGuidValue(UNIT_FIELD_TARGET, target->GetGUID());
+ me->CastSpell(target, SPELL_VEZAX_SHADOW_CRASH, false);
+ events.ScheduleEvent(EVENT_RESTORE_TARGET, 750ms);
+ }
+ }
+ break;
+ case EVENT_RESTORE_TARGET:
+ if (me->GetVictim())
+ me->SetGuidValue(UNIT_FIELD_TARGET, me->GetVictim()->GetGUID());
+ break;
+ case EVENT_SPELL_SEARING_FLAMES:
+ if(!me->HasAura(SPELL_SARONITE_BARRIER))
+ me->CastSpell(me->GetVictim(), SPELL_SEARING_FLAMES, false);
+ events.Repeat(me->GetMap()->Is25ManRaid() ? 8s : 15s);
+ break;
+ case EVENT_SPELL_SURGE_OF_DARKNESS:
+ Talk(SAY_SURGE_OF_DARKNESS);
+ Talk(SAY_EMOTE_SURGE_OF_DARKNESS);
+ me->CastSpell(me, SPELL_SURGE_OF_DARKNESS, false);
+ events.Repeat(63s);
+ events.DelayEvents(10000, 1);
+ break;
+ case EVENT_SPELL_MARK_OF_THE_FACELESS:
+ {
+ std::vector outside;
+ std::vector inside;
+ Map::PlayerList const& pl = me->GetMap()->GetPlayers();
+ for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
+ if( Player* tmp = itr->GetSource() )
+ if( tmp->IsAlive() )
+ {
+ if( tmp->GetDistance(me) > 15.0f )
+ outside.push_back(tmp);
+ else
+ inside.push_back(tmp);
+ }
+
+ Player* t = nullptr;
+ if( outside.size() >= uint8(me->GetMap()->Is25ManRaid() ? 9 : 4) )
+ t = outside.at(urand(0, outside.size() - 1));
+ else if( !inside.empty() )
+ t = inside.at(urand(0, inside.size() - 1));
+
+ if (t)
+ me->CastSpell(t, SPELL_MARK_OF_THE_FACELESS_AURA, false);
+
+ events.Repeat(40s);
+ }
+ break;
+ case EVENT_SPELL_SUMMON_SARONITE_VAPORS:
+ {
+ vaporsCount++;
+ me->CastSpell(me, SPELL_SUMMON_SARONITE_VAPORS, false);
+
+ if( vaporsCount < 6 || !hardmodeAvailable )
+ events.Repeat(30s);
+ else
+ {
+ for (ObjectGuid const& guid : summons)
+ if (Creature* sv = ObjectAccessor::GetCreature(*me, guid))
+ {
+ sv->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ sv->GetMotionMaster()->MoveIdle();
+ sv->GetMotionMaster()->MoveCharge(1852.78f, 81.38f, 342.461f, 28.0f);
+ }
+
+ events.DelayEvents(12000, 0);
+ events.DelayEvents(12000, 1);
+ events.ScheduleEvent(EVENT_SARONITE_VAPORS_SWIRL, 6s);
+ }
+ }
+ break;
+ case EVENT_SARONITE_VAPORS_SWIRL:
+ if (summons.size())
+ {
+ Talk(SAY_EMOTE_ANIMUS);
+ if( Creature* sv = ObjectAccessor::GetCreature(*me, *(summons.begin())) )
+ sv->CastSpell(sv, SPELL_SARONITE_ANIMUS_FORMATION_VISUAL, true);
+
+ events.ScheduleEvent(EVENT_SPELL_SUMMON_SARONITE_ANIMUS, 2s);
+ break;
+ }
+ break;
+ case EVENT_SPELL_SUMMON_SARONITE_ANIMUS:
+ if (summons.size())
+ {
+ Talk(SAY_HARDMODE);
+ Talk(SAY_EMOTE_BARRIER);
+ me->CastSpell(me, SPELL_SARONITE_BARRIER, true);
+ if( Creature* sv = ObjectAccessor::GetCreature(*me, *(summons.begin())) )
+ sv->CastSpell(sv, SPELL_SUMMON_SARONITE_ANIMUS, true);
+
+ events.ScheduleEvent(EVENT_DESPAWN_SARONITE_VAPORS, 2500ms);
+ break;
+ }
+ break;
+ case EVENT_DESPAWN_SARONITE_VAPORS:
+ summons.DespawnEntry(NPC_SARONITE_VAPORS);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ summons.DespawnAll();
+ if (pInstance)
+ pInstance->SetData(TYPE_VEZAX, DONE);
+
+ Talk(SAY_DEATH);
+
+ if( GameObject* door = me->FindNearestGameObject(GO_VEZAX_DOOR, 500.0f) )
+ if( door->GetGoState() != GO_STATE_ACTIVE )
+ {
+ door->SetLootState(GO_READY);
+ door->UseDoorOrButton(0, false);
+ }
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if( who->GetTypeId() == TYPEID_PLAYER )
+ Talk(SAY_SLAY);
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+
+ void JustSummoned(Creature* summon) override
+ {
+ summons.Summon(summon);
+ }
+
+ void SummonedCreatureDespawn(Creature* s) override
+ {
+ summons.Despawn(s);
+ }
+ };
+};
+
+class npc_ulduar_saronite_vapors : public CreatureScript
+{
+public:
+ npc_ulduar_saronite_vapors() : CreatureScript("npc_ulduar_saronite_vapors") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_saronite_vaporsAI : public NullCreatureAI
+ {
+ npc_ulduar_saronite_vaporsAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ pInstance = pCreature->GetInstanceScript();
+ me->GetMotionMaster()->MoveRandom(4.0f);
+ }
+
+ InstanceScript* pInstance;
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ me->CastSpell(me, SPELL_SARONITE_VAPORS_AURA, true);
+
+ // killed saronite vapors, hard mode unavailable
+ if( pInstance )
+ if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) )
+ vezax->AI()->DoAction(1);
+ }
+
+ void IsSummonedBy(WorldObject* /*summoner*/) override
+ {
+ Talk(SAY_EMOTE_VAPORS);
+ }
+ };
+};
+
+class npc_ulduar_saronite_animus : public CreatureScript
+{
+public:
+ npc_ulduar_saronite_animus() : CreatureScript("npc_ulduar_saronite_animus") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_saronite_animusAI : public ScriptedAI
+ {
+ npc_ulduar_saronite_animusAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = pCreature->GetInstanceScript();
+ if( pInstance )
+ if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) )
+ vezax->AI()->JustSummoned(me);
+ timer = 0;
+ me->SetInCombatWithZone();
+ }
+
+ InstanceScript* pInstance;
+ uint16 timer;
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ me->DespawnOrUnsummon(3000);
+
+ if( pInstance )
+ if( Creature* vezax = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_VEZAX)) )
+ vezax->AI()->DoAction(2);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ UpdateVictim();
+
+ timer += diff;
+ if (timer >= 2000)
+ {
+ me->CastSpell(me, SPELL_PROFOUND_DARKNESS, true);
+ timer -= 2000;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class spell_aura_of_despair : public SpellScriptLoader
+{
+public:
+ spell_aura_of_despair() : SpellScriptLoader("spell_aura_of_despair") { }
+
+ class spell_aura_of_despair_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_aura_of_despair_AuraScript)
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (Unit* target = GetTarget())
+ {
+ if (target->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ target->CastSpell(target, SPELL_AURA_OF_DESPAIR_2, true);
+ if( target->HasSpell(SPELL_SHAMANISTIC_RAGE) )
+ caster->CastSpell(target, SPELL_CORRUPTED_RAGE, true);
+ else if( target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1) || target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 + 1) || target->HasSpell(SPELL_JUDGEMENTS_OF_THE_WISDOM_RANK_1 + 2) )
+ caster->CastSpell(target, SPELL_CORRUPTED_WISDOM, true);
+ }
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* target = GetTarget())
+ {
+ target->RemoveAurasDueToSpell(SPELL_AURA_OF_DESPAIR_2);
+ target->RemoveAurasDueToSpell(SPELL_CORRUPTED_RAGE);
+ target->RemoveAurasDueToSpell(SPELL_CORRUPTED_WISDOM);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_aura_of_despair_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PREVENT_REGENERATE_POWER, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_aura_of_despair_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PREVENT_REGENERATE_POWER, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_aura_of_despair_AuraScript();
+ }
+};
+
+class spell_mark_of_the_faceless_periodic : public SpellScriptLoader
+{
+public:
+ spell_mark_of_the_faceless_periodic() : SpellScriptLoader("spell_mark_of_the_faceless_periodic") { }
+
+ class spell_mark_of_the_faceless_periodic_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mark_of_the_faceless_periodic_AuraScript)
+
+ void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (Unit* target = GetTarget())
+ if (target->GetMapId() == 603)
+ {
+ int32 dmg = 5000;
+ caster->CastCustomSpell(target, SPELL_MARK_OF_THE_FACELESS_EFFECT, 0, &dmg, 0, true);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_mark_of_the_faceless_periodic_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mark_of_the_faceless_periodic_AuraScript();
+ }
+};
+
+class spell_mark_of_the_faceless_drainhealth : public SpellScriptLoader
+{
+public:
+ spell_mark_of_the_faceless_drainhealth() : SpellScriptLoader("spell_mark_of_the_faceless_drainhealth") { }
+
+ class spell_mark_of_the_faceless_drainhealth_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_mark_of_the_faceless_drainhealth_SpellScript);
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove(GetExplTargetUnit());
+ if (targets.empty())
+ Cancel();
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mark_of_the_faceless_drainhealth_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_DEST_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_mark_of_the_faceless_drainhealth_SpellScript();
+ }
+};
+
+class spell_saronite_vapors_dummy : public SpellScriptLoader
+{
+public:
+ spell_saronite_vapors_dummy() : SpellScriptLoader("spell_saronite_vapors_dummy") { }
+
+ class spell_saronite_vapors_dummy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_saronite_vapors_dummy_AuraScript)
+
+ void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ int32 damage = 100 * pow(2.0f, (float)GetStackAmount());
+ caster->CastCustomSpell(GetTarget(), SPELL_SARONITE_VAPORS_DMG, &damage, nullptr, nullptr, true);
+ }
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_saronite_vapors_dummy_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_saronite_vapors_dummy_AuraScript();
+ }
+};
+
+class spell_saronite_vapors_damage : public SpellScriptLoader
+{
+public:
+ spell_saronite_vapors_damage() : SpellScriptLoader("spell_saronite_vapors_damage") { }
+
+ class spell_saronite_vapors_damage_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_saronite_vapors_damage_SpellScript);
+
+ void HandleAfterHit()
+ {
+ if (Unit* caster = GetCaster())
+ if (GetHitDamage() > 2)
+ {
+ int32 mana = GetHitDamage() / 2;
+ if (Unit* t = GetHitUnit())
+ caster->CastCustomSpell(t, SPELL_SARONITE_VAPORS_ENERGIZE, &mana, nullptr, nullptr, true);
+ }
+ }
+
+ void Register() override
+ {
+ AfterHit += SpellHitFn(spell_saronite_vapors_damage_SpellScript::HandleAfterHit);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_saronite_vapors_damage_SpellScript();
+ }
+};
+
+class achievement_smell_saronite : public AchievementCriteriaScript
+{
+public:
+ achievement_smell_saronite() : AchievementCriteriaScript("achievement_smell_saronite") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_VEZAX && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1);
+ }
+};
+
+class achievement_shadowdodger : public AchievementCriteriaScript
+{
+public:
+ achievement_shadowdodger() : AchievementCriteriaScript("achievement_shadowdodger") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_VEZAX && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(2);
+ }
+};
+
+class go_ulduar_pure_saronite_deposit : public GameObjectScript
+{
+public:
+ go_ulduar_pure_saronite_deposit() : GameObjectScript("go_ulduar_pure_saronite_deposit") { }
+
+ bool OnGossipHello(Player* plr, GameObject* go) override
+ {
+ if (plr->IsGameMaster())
+ return false;
+
+ if (InstanceScript* pInstance = go->GetInstanceScript())
+ if (pInstance->GetData(TYPE_XT002) != DONE && pInstance->GetData(TYPE_MIMIRON) != DONE && pInstance->GetData(TYPE_THORIM) != DONE && pInstance->GetData(TYPE_FREYA) != DONE && pInstance->GetData(TYPE_HODIR) != DONE)
+ {
+ std::string accountName;
+ AccountMgr::GetName(plr->GetSession()->GetAccountId(), accountName);
+ sBan->BanAccount(accountName, "0s", "Tele hack", "Server");
+ return true;
+ }
+
+ return false;
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp
index d3f8de2ebfd397..b55bf7d2e62860 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_hodir.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "PassiveAI.h"
@@ -26,1585 +27,6 @@
#include "SpellScriptLoader.h"
#include "ulduar.h"
-enum HodirSpellData
-{
- SPELL_BERSERK = 26662,
-
- SPELL_BITING_COLD_BOSS_AURA = 62038,
- SPELL_BITING_COLD_PLAYER_AURA = 62039,
- SPELL_BITING_COLD_DAMAGE = 62188,
-
- SPELL_FREEZE = 62469,
-
- SPELL_FLASH_FREEZE_CAST = 61968,
- SPELL_FLASH_FREEZE_INSTAKILL = 62226,
- SPELL_FLASH_FREEZE_TRAPPED_PLAYER = 61969,
- SPELL_FLASH_FREEZE_TRAPPED_NPC = 61990,
- SPELL_FLASH_FREEZE_VISUAL = 62148,
- SPELL_SAFE_AREA = 65705,
- SPELL_SAFE_AREA_TRIGGERED = 62464,
- SPELL_SHATTER_CHEST = 62501,
-
- SPELL_ICICLE_BOSS_AURA = 62227,
- SPELL_ICICLE_TBBA = 63545,
-
- SPELL_ICICLE_VISUAL_UNPACKED = 62234,
- SPELL_ICICLE_VISUAL_PACKED = 62462,
- SPELL_ICICLE_VISUAL_FALLING = 62453,
- SPELL_ICICLE_FALL_EFFECT_UNPACKED = 62236,
- SPELL_ICICLE_FALL_EFFECT_PACKED = 62460,
- SPELL_ICE_SHARDS_SMALL = 62457,
- SPELL_ICE_SHARDS_BIG = 65370,
- SPELL_SNOWDRIFT = 62463,
-
- SPELL_FROZEN_BLOWS_10 = 62478,
- SPELL_FROZEN_BLOWS_25 = 63512,
-
- // Helpers:
- SPELL_PRIEST_DISPELL_MAGIC = 63499,
- SPELL_PRIEST_GREAT_HEAL = 62809,
- SPELL_PRIEST_SMITE = 61923,
-
- SPELL_DRUID_WRATH = 62793,
- SPELL_DRUID_STARLIGHT_AREA_AURA = 62807,
-
- SPELL_SHAMAN_LAVA_BURST = 61924,
- SPELL_SHAMAN_STORM_CLOUD_10 = 65123,
- SPELL_SHAMAN_STORM_CLOUD_25 = 65133,
- SPELL_SHAMAN_STORM_POWER_10 = 63711,
- SPELL_SHAMAN_STORM_POWER_25 = 65134,
-
- SPELL_MAGE_FIREBALL = 61909,
- SPELL_MAGE_MELT_ICE = 64528,
- SPELL_MAGE_CONJURE_TOASTY_FIRE = 62823,
- SPELL_MAGE_SUMMON_TOASTY_FIRE = 62819,
- SPELL_MAGE_TOASTY_FIRE_AURA = 62821,
- SPELL_SINGED = 65280,
-};
-
-enum HodirNPCs
-{
- //NPC_HODIR = 32845,
-
- NPC_PAN_FIELD_MEDIC_PENNY = 32897,
- NPC_DAN_ELLIE_NIGHTFEATHER = 32901,
- NPC_SAN_ELEMENTALIST_AVUUN = 32900,
- NPC_MAN_MISSY_FLAMECUFFS = 32893,
-
- NPC_PAH_FIELD_MEDIC_JESSI = 33326,
- NPC_DAH_EIVI_NIGHTFEATHER = 33325,
- NPC_SAH_ELEMENTALIST_MAHFUUN = 33328,
- NPC_MAH_SISSY_FLAMECUFFS = 33327,
-
- NPC_PHN_BATTLEPRIEST_ELIZA = 32948,
- NPC_DHN_TOR_GREYCLOUD = 32941,
- NPC_SHN_SPIRITWALKER_YONA = 32950,
- NPC_MHN_VEESHA_BLAZEWEAVER = 32946,
-
- NPC_PHH_BATTLEPRIEST_GINA = 33330,
- NPC_DHH_KAR_GREYCLOUD = 33333,
- NPC_SHH_SPIRITWALKER_TARA = 33332,
- NPC_MHH_AMIRA_BLAZEWEAVER = 33331,
-
- NPC_FLASH_FREEZE_PLR = 32926,
- NPC_FLASH_FREEZE_NPC = 32938,
- NPC_ICICLE_UNPACKED = 33169,
- NPC_ICICLE_PACKED = 33173,
- NPC_TOASTY_FIRE = 33342,
- NPC_RARE_WINTER_CACHE_TRIGGER = 88101,
-};
-
-enum HodirEvents
-{
- // Hodir:
- EVENT_FLASH_FREEZE = 1,
- EVENT_FROZEN_BLOWS = 2,
- EVENT_BERSERK = 3,
- EVENT_FREEZE = 4,
- EVENT_SMALL_ICICLES_ENABLE = 5,
- EVENT_HARD_MODE_MISSED = 6,
- EVENT_DESPAWN_CHEST = 7,
- EVENT_FAIL_HM = 8,
-
- EVENT_TRY_FREE_HELPER = 10,
- EVENT_PRIEST_DISPELL_MAGIC = 11,
- EVENT_PRIEST_GREAT_HEAL = 12,
- EVENT_PRIEST_SMITE = 13,
- EVENT_DRUID_WRATH = 14,
- EVENT_DRUID_STARLIGHT = 15,
- EVENT_SHAMAN_LAVA_BURST = 16,
- EVENT_SHAMAN_STORM_CLOUD = 17,
- EVENT_MAGE_TOASTY_FIRE = 18,
- EVENT_MAGE_FIREBALL = 19,
- EVENT_MAGE_MELT_ICE = 20,
-};
-
-enum HodirText
-{
- TEXT_AGGRO = 0,
- TEXT_SLAY = 1,
- TEXT_FLASH_FREEZE = 2,
- TEXT_STALACTITE = 3,
- TEXT_DEATH = 4,
- TEXT_BERSERK = 5,
- TEXT_HM_MISS = 6,
- TEXT_EMOTE_FREEZE = 7,
- TEXT_EMOTE_BLOW = 8,
-};
-
-#define SPELL_FROZEN_BLOWS RAID_MODE(SPELL_FROZEN_BLOWS_10, SPELL_FROZEN_BLOWS_25)
-#define SPELL_SHAMAN_STORM_CLOUD RAID_MODE(SPELL_SHAMAN_STORM_CLOUD_10, SPELL_SHAMAN_STORM_CLOUD_25)
-
-enum HodirSounds
-{
- SOUND_HODIR_AGGRO = 15552,
- SOUND_HODIR_SLAIN_1 = 15553,
- SOUND_HODIR_SLAIN_2 = 15554,
- SOUND_HODIR_FLASH_FREEZE = 15555,
- SOUND_HODIR_FROZEN_BLOWS = 15556,
- SOUND_HODIR_DEFEATED = 15557,
- SOUND_HODIR_BERSERK = 15558,
-};
-
-struct HodirHelperData
-{
- uint32 id;
- float x, y;
-};
-HodirHelperData hhd[4][4] =
-{
- // Alliance:
- {
- {NPC_PAN_FIELD_MEDIC_PENNY, 2020.46f, -236.74f},
- {NPC_DAN_ELLIE_NIGHTFEATHER, 2007.21f, -241.57f},
- {NPC_SAN_ELEMENTALIST_AVUUN, 1999.14f, -230.69f},
- {NPC_MAN_MISSY_FLAMECUFFS, 1984.38f, -242.57f}
- },
- {
- {NPC_PAH_FIELD_MEDIC_JESSI, 2012.29f, -233.70f},
- {NPC_DAH_EIVI_NIGHTFEATHER, 1995.75f, -241.32f},
- {NPC_SAH_ELEMENTALIST_MAHFUUN, 1989.31f, -234.26f},
- {NPC_MAH_SISSY_FLAMECUFFS, 1977.87f, -233.99f}
- },
- // Horde:
- {
- {NPC_PHN_BATTLEPRIEST_ELIZA, 2020.46f, -236.74f},
- {NPC_DHN_TOR_GREYCLOUD, 2007.21f, -241.57f},
- {NPC_SHN_SPIRITWALKER_YONA, 1999.14f, -230.69f},
- {NPC_MHN_VEESHA_BLAZEWEAVER, 1984.38f, -242.57f}
- },
- {
- {NPC_PHH_BATTLEPRIEST_GINA, 2012.29f, -233.70f},
- {NPC_DHH_KAR_GREYCLOUD, 1995.75f, -241.32f},
- {NPC_SHH_SPIRITWALKER_TARA, 1989.31f, -234.6f},
- {NPC_MHH_AMIRA_BLAZEWEAVER, 1977.87f, -233.99f}
- }
-};
-
-class boss_hodir : public CreatureScript
-{
-public:
- boss_hodir() : CreatureScript("boss_hodir") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_hodirAI : public ScriptedAI
- {
- boss_hodirAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
- {
- pInstance = pCreature->GetInstanceScript();
- if (!me->IsAlive())
- if (pInstance)
- pInstance->SetData(TYPE_HODIR, DONE);
- }
-
- InstanceScript* pInstance;
- EventMap events;
- SummonList summons;
- ObjectGuid Helpers[8];
- bool berserk{ false };
- bool bAchievCheese{ true };
- bool bAchievGettingCold{ true };
- bool bAchievCacheRare{ true };
- bool bAchievCoolestFriends{ true };
- uint16 addSpawnTimer{ 0 };
-
- // Used to make Hodir disengage whenever he leaves his room
- const Position ENTRANCE_DOOR{ 1999.160034f, -297.792999f, 431.960999f, 0 };
- const Position EXIT_DOOR{ 1999.709961f, -166.259003f, 432.822998f, 0 };
-
- void Reset() override
- {
- events.Reset();
- summons.DespawnAll();
- berserk = false;
- bAchievCheese = true;
- bAchievGettingCold = true;
- bAchievCacheRare = true;
- bAchievCoolestFriends = true;
- me->SetSheath(SHEATH_STATE_MELEE);
-
- // Reset the spells cast after wipe
- me->RemoveAllAuras();
- pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA);
-
- if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE)
- {
- pInstance->SetData(TYPE_HODIR, NOT_STARTED);
- }
-
- if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 900.0f))
- {
- go->SetGoState(GO_STATE_ACTIVE);
- }
-
- // Reset helpers
- if (!summons.size())
- SpawnHelpers();
- }
-
- void JustEngagedWith(Unit* /*pWho*/) override
- {
- me->CastSpell(me, SPELL_BITING_COLD_BOSS_AURA, true);
- SmallIcicles(true);
- events.Reset();
- events.ScheduleEvent(EVENT_FLASH_FREEZE, 48s, 49s);
- events.ScheduleEvent(EVENT_FREEZE, 17s, 20s);
- events.ScheduleEvent(EVENT_BERSERK, 8min);
- events.ScheduleEvent(EVENT_HARD_MODE_MISSED, 3min);
- Talk(TEXT_AGGRO);
-
- if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE)
- {
- pInstance->SetData(TYPE_HODIR, IN_PROGRESS);
- }
-
- if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 300.0f))
- {
- go->SetGoState(GO_STATE_READY);
- }
- }
-
- void DoAction(int action) override
- {
- if (action)
- {
- switch (action)
- {
- case EVENT_FAIL_HM:
- if (pInstance)
- {
- if (GameObject* go = pInstance->instance->GetGameObject(pInstance->GetGuidData(GO_HODIR_CHEST_HARD)))
- {
- go->SetGoState(GO_STATE_ACTIVE);
- events.ScheduleEvent(EVENT_DESPAWN_CHEST, 3s);
- }
- }
- break;
- }
- }
- }
-
- void SmallIcicles(bool enable)
- {
- if( enable )
- me->CastSpell(me, SPELL_ICICLE_BOSS_AURA, true);
- else
- me->RemoveAura(SPELL_ICICLE_BOSS_AURA);
- }
-
- void SpellHitTarget(Unit* target, SpellInfo const* spell) override
- {
- switch( spell->Id )
- {
- case SPELL_ICICLE_TBBA:
- me->CastSpell(target, SPELL_ICICLE_VISUAL_UNPACKED, true);
- break;
- case SPELL_FLASH_FREEZE_VISUAL:
- {
- std::list fires;
- me->GetCreaturesWithEntryInRange(fires, 200.0f, NPC_TOASTY_FIRE);
- for (std::list::iterator itr = fires.begin(); itr != fires.end(); ++itr)
- (*itr)->AI()->DoAction(1); // remove it
- }
- break;
- }
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (damage >= me->GetHealth() || me->GetHealth() < 150000)
- {
- damage = 0;
- me->SetReactState(REACT_PASSIVE);
- if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
- {
- if (pInstance)
- {
- pInstance->SetData(TYPE_HODIR, DONE);
- me->CastSpell(me, 64899, true); // credit
- }
-
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetFaction(FACTION_FRIENDLY);
- me->GetMotionMaster()->Clear();
- me->AttackStop();
- me->CombatStop();
- me->InterruptNonMeleeSpells(true);
- me->RemoveAllAuras();
- pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA);
-
- events.Reset();
- summons.DespawnAll();
-
- if( GameObject* d = me->FindNearestGameObject(GO_HODIR_FROZEN_DOOR, 250.0f))
- {
- if( d->GetGoState() != GO_STATE_ACTIVE )
- {
- d->SetLootState(GO_READY);
- d->UseDoorOrButton(0, false);
- }
- }
- if (GameObject* d = me->FindNearestGameObject(GO_HODIR_DOOR, 250.0f))
- {
- if( d->GetGoState() != GO_STATE_ACTIVE )
- {
- d->SetLootState(GO_READY);
- d->UseDoorOrButton(0, false);
- }
- }
-
- if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 300.0f))
- {
- go->SetGoState(GO_STATE_ACTIVE);
- }
-
- Talk(TEXT_DEATH);
- me->DespawnOrUnsummon(10000);
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (me->GetPositionY() <= ENTRANCE_DOOR.GetPositionY() || me->GetPositionY() >= EXIT_DOOR.GetPositionY())
- {
- boss_hodirAI::EnterEvadeMode();
- return;
- }
-
- if (!UpdateVictim())
- {
- if (me->IsInCombat())
- {
- Map::PlayerList const& pl = me->GetMap()->GetPlayers();
- for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
- itr->GetSource()->CastSpell(itr->GetSource(), SPELL_FLASH_FREEZE_INSTAKILL, true);
- EnterEvadeMode();
- }
- return;
- }
-
- events.Update(diff);
-
- if( me->HasUnitState(UNIT_STATE_CASTING) )
- return;
-
- switch (events.ExecuteEvent())
- {
- case 0:
- break;
- case EVENT_BERSERK:
- {
- berserk = true;
- me->CastSpell(me, SPELL_BERSERK, true);
- Talk(TEXT_BERSERK);
- }
- break;
- case EVENT_HARD_MODE_MISSED:
- {
- Talk(TEXT_HM_MISS);
- bAchievCacheRare = false;
- if (pInstance)
- {
- if (GameObject* go = pInstance->instance->GetGameObject(pInstance->GetGuidData(GO_HODIR_CHEST_HARD)))
- {
- me->CastSpell(go, SPELL_SHATTER_CHEST, false);
- }
- }
- }
- break;
- case EVENT_DESPAWN_CHEST:
- if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE)
- pInstance->SetData(TYPE_HODIR_HM_FAIL, 0);
- break;
- case EVENT_FLASH_FREEZE:
- {
- std::list targets;
- Map::PlayerList const& pl = me->GetMap()->GetPlayers();
- for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
- targets.push_back(itr->GetSource());
- targets.remove_if(Acore::ObjectTypeIdCheck(TYPEID_PLAYER, false));
- targets.remove_if(Acore::UnitAuraCheck(true, SPELL_FLASH_FREEZE_TRAPPED_PLAYER));
- Acore::Containers::RandomResize(targets, (RAID_MODE(2,3)));
- for (std::list::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
- {
- float prevZ = (*itr)->GetPositionZ();
- (*itr)->m_positionZ = 432.7f;
- (*itr)->CastSpell((*itr), SPELL_ICICLE_VISUAL_PACKED, true);
- (*itr)->m_positionZ = prevZ;
- }
-
- me->CastSpell((Unit*)nullptr, SPELL_FLASH_FREEZE_CAST, false);
- me->PlayDirectSound(SOUND_HODIR_FLASH_FREEZE, 0);
- Talk(TEXT_FLASH_FREEZE);
- Talk(TEXT_EMOTE_FREEZE);
- SmallIcicles(false);
- events.ScheduleEvent(EVENT_FLASH_FREEZE, 48s, 49s);
- events.ScheduleEvent(EVENT_SMALL_ICICLES_ENABLE, Is25ManRaid() ? 12s : 24s);
- events.ScheduleEvent(EVENT_FROZEN_BLOWS, 15s);
- events.RescheduleEvent(EVENT_FREEZE, 17s, 20s);
- }
- break;
- case EVENT_SMALL_ICICLES_ENABLE:
- {
- SmallIcicles(true);
- }
- break;
- case EVENT_FROZEN_BLOWS:
- {
- Talk(TEXT_EMOTE_BLOW);
- Talk(TEXT_STALACTITE);
- me->CastSpell(me, Is25ManRaid()? SPELL_FROZEN_BLOWS_25 : SPELL_FROZEN_BLOWS_10, true);
- }
- break;
- case EVENT_FREEZE:
- if (Player* plr = SelectTargetFromPlayerList(50.0f, SPELL_FLASH_FREEZE_TRAPPED_PLAYER))
- {
- me->CastSpell(plr, SPELL_FREEZE, false);
- }
- else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
- {
- me->CastSpell(target, SPELL_FREEZE, false);
- }
- events.RescheduleEvent(EVENT_FREEZE, 17s, 20s);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
-
- Creature* GetHelper(uint8 index)
- {
- return Helpers[index] ? ObjectAccessor::GetCreature(*me, Helpers[index]) : nullptr;
- }
-
- void SpawnHelpers()
- {
- char faction = 'A';
- if( hhd[0][0].id )
- {
- Map::PlayerList const& cl = me->GetMap()->GetPlayers();
- for (Map::PlayerList::const_iterator itr = cl.begin(); itr != cl.end(); ++itr)
- if (!itr->GetSource()->IsGameMaster())
- {
- faction = (itr->GetSource()->GetTeamId() == TEAM_ALLIANCE ? 'A' : 'H');
- break;
- }
- }
-
- uint8 cnt = 0;
- if( faction )
- for( uint8 k = 0; k < 4; ++k )
- {
- if( (faction == 'A' && ( k > 1 || (k == 1 && RAID_MODE(1, 0)) )) ||
- (faction == 'H' && ( k < 2 || (k == 3 && RAID_MODE(1, 0)) )) )
- continue;
-
- for( uint8 i = 0; i < 4; ++i )
- {
- if( !hhd[k][i].id )
- continue;
-
- if( Creature* h_p = me->SummonCreature(hhd[k][i].id, hhd[k][i].x, hhd[k][i].y, 432.69f, M_PI / 2) )
- {
- h_p->SetFaction(1665);
- if( cnt < 8 )
- Helpers[cnt++] = h_p->GetGUID();
-
- if( Creature* c = h_p->SummonCreature(NPC_FLASH_FREEZE_NPC, h_p->GetPositionX(), h_p->GetPositionY(), h_p->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000) )
- {
- c->CastSpell(h_p, SPELL_FLASH_FREEZE_TRAPPED_NPC, true);
- JustSummoned(c);
- }
- }
- }
- }
- }
-
- void KilledUnit(Unit* who) override
- {
- if (who->GetTypeId() == TYPEID_PLAYER)
- Talk(TEXT_SLAY);
- }
-
- void JustSummoned(Creature* s) override
- {
- summons.Summon(s);
- }
-
- void SummonedCreatureDespawn(Creature* s) override
- {
- summons.Despawn(s);
- }
-
- bool CanAIAttack(Unit const* t) const override
- {
- if (t->GetTypeId() == TYPEID_PLAYER)
- return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER);
- else if (t->GetTypeId() == TYPEID_UNIT)
- return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC);
-
- return true;
- }
-
- void SetData(uint32 id, uint32 value) override
- {
- if (value)
- switch (id)
- {
- case 1:
- bAchievCheese = false;
- break;
- case 2:
- bAchievGettingCold = false;
- break;
- case 4:
- bAchievCoolestFriends = false;
- break;
- }
- }
-
- uint32 GetData(uint32 id) const override
- {
- switch (id)
- {
- case 1:
- return (bAchievCheese ? 1 : 0);
- case 2:
- return (bAchievGettingCold ? 1 : 0);
- case 3:
- return (bAchievCacheRare ? 1 : 0);
- case 4:
- return (bAchievCoolestFriends ? 1 : 0);
- }
- return 0;
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override {}
- };
-};
-
-class npc_ulduar_icicle : public CreatureScript
-{
-public:
- npc_ulduar_icicle() : CreatureScript("npc_ulduar_icicle") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_icicleAI : public NullCreatureAI
- {
- npc_ulduar_icicleAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- timer1 = 2000;
- timer2 = 5000;
- }
-
- uint16 timer1;
- uint16 timer2;
-
- void UpdateAI(uint32 diff) override
- {
- if( timer1 <= diff )
- {
- me->CastSpell(me, (me->GetEntry() == 33169 ? SPELL_ICICLE_FALL_EFFECT_UNPACKED : SPELL_ICICLE_FALL_EFFECT_PACKED), true);
- me->CastSpell(me, SPELL_ICICLE_VISUAL_FALLING, false);
- timer1 = 60000;
- }
- else
- timer1 -= diff;
-
- if (timer2 <= diff)
- {
- me->SetDisplayId(11686);
- timer2 = 60000;
- }
- else
- timer2 -= diff;
- }
- };
-};
-
-class npc_ulduar_flash_freeze : public CreatureScript
-{
-public:
- npc_ulduar_flash_freeze() : CreatureScript("npc_ulduar_flash_freeze") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_flash_freezeAI : public NullCreatureAI
- {
- npc_ulduar_flash_freezeAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- timer = 2500;
- pInstance = me->GetInstanceScript();
- }
-
- InstanceScript* pInstance;
- uint16 timer;
-
- void DamageTaken(Unit* doneBy, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
- {
- if (pInstance && doneBy)
- if (pInstance->GetData(TYPE_HODIR) == NOT_STARTED)
- if (Creature* hodir = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_HODIR)))
- hodir->AI()->AttackStart(doneBy);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (timer <= diff)
- {
- timer = 2500;
- if (me->IsSummon())
- {
- if (Unit* s = me->ToTempSummon()->GetSummonerUnit())
- {
- if ((s->GetTypeId() == TYPEID_PLAYER && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER)) || (s->GetTypeId() == TYPEID_UNIT && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC)))
- me->DespawnOrUnsummon(2000);
- else if (s->GetTypeId() == TYPEID_PLAYER)
- if (InstanceScript* instanceScript = me->GetInstanceScript())
- if (instanceScript->GetData(TYPE_HODIR) == NOT_STARTED)
- {
- s->CastSpell(s, SPELL_FLASH_FREEZE_INSTAKILL, true);
- me->DespawnOrUnsummon(2000);
- }
- }
- else
- {
- me->DespawnOrUnsummon(2000);
- }
- }
- }
- else
- timer -= diff;
- }
- };
-};
-
-class npc_ulduar_toasty_fire : public CreatureScript
-{
-public:
- npc_ulduar_toasty_fire() : CreatureScript("npc_ulduar_toasty_fire") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_toasty_fireAI : public NullCreatureAI
- {
- npc_ulduar_toasty_fireAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- me->CastSpell(me, SPELL_MAGE_TOASTY_FIRE_AURA, true);
- }
-
- void DoAction(int32 a) override
- {
- if (a == 1)
- {
- if( GameObject* fire = me->FindNearestGameObject(194300, 1.0f) )
- {
- fire->SetOwnerGUID(ObjectGuid::Empty);
- fire->Delete();
- }
- me->DespawnOrUnsummon(); // this will remove DynObjects
- }
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- switch( spell->Id )
- {
- case SPELL_ICE_SHARDS_SMALL:
- case SPELL_ICE_SHARDS_BIG:
- DoAction(1);
- break;
- }
- }
- };
-};
-
-class npc_ulduar_hodir_priest : public CreatureScript
-{
-public:
- npc_ulduar_hodir_priest() : CreatureScript("npc_ulduar_hodir_priest") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_hodir_priestAI : public ScriptedAI
- {
- npc_ulduar_hodir_priestAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- pInstance = me->GetInstanceScript();
- events.Reset();
- me->SetReactState(REACT_PASSIVE);
- }
-
- EventMap events;
- InstanceScript* pInstance;
-
- void AttackStart(Unit* who) override
- {
- AttackStartCaster(who, 17.0f);
- }
-
- void ScheduleAbilities()
- {
- events.ScheduleEvent(EVENT_PRIEST_DISPELL_MAGIC, 7s);
- events.ScheduleEvent(EVENT_PRIEST_GREAT_HEAL, 6s, 7s);
- events.ScheduleEvent(EVENT_PRIEST_SMITE, 2100ms);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC)
- {
- events.Reset();
- events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s);
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- events.Update(diff);
-
- if( me->HasUnitState(UNIT_STATE_CASTING) )
- return;
-
- switch( events.ExecuteEvent() )
- {
- case 0:
- break;
- case EVENT_TRY_FREE_HELPER:
- {
- if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) )
- if( pInstance )
- if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) )
- if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) )
- {
- AttackStart(hodir);
- ScheduleAbilities();
- break;
- }
- events.Repeat(2s);
- }
- break;
- case EVENT_PRIEST_DISPELL_MAGIC:
- me->CastCustomSpell(SPELL_PRIEST_DISPELL_MAGIC, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false);
- events.Repeat(7s);
- break;
- case EVENT_PRIEST_GREAT_HEAL:
- me->CastSpell(me, SPELL_PRIEST_GREAT_HEAL, false);
- events.Repeat(6s, 7s);
- break;
- case EVENT_PRIEST_SMITE:
- if (Unit* victim = me->GetVictim())
- me->CastSpell(victim, SPELL_PRIEST_SMITE, false);
- events.Repeat(2100ms);
- break;
- }
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override {}
-
- void EnterEvadeMode(EvadeReason /*why*/) override {}
- bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (pInstance)
- if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR)))
- hodir->AI()->SetData(4, 1);
- }
- };
-};
-
-class npc_ulduar_hodir_druid : public CreatureScript
-{
-public:
- npc_ulduar_hodir_druid() : CreatureScript("npc_ulduar_hodir_druid") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_hodir_druidAI : public ScriptedAI
- {
- npc_ulduar_hodir_druidAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- pInstance = me->GetInstanceScript();
- events.Reset();
- me->SetReactState(REACT_PASSIVE);
- }
-
- EventMap events;
- InstanceScript* pInstance;
-
- void AttackStart(Unit* who) override
- {
- AttackStartCaster(who, 22.0f);
- }
-
- void ScheduleAbilities()
- {
- events.ScheduleEvent(EVENT_DRUID_WRATH, 1600ms);
- events.ScheduleEvent(EVENT_DRUID_STARLIGHT, 10s);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC)
- {
- events.Reset();
- events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s);
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- events.Update(diff);
-
- if( me->HasUnitState(UNIT_STATE_CASTING) )
- return;
-
- switch( events.ExecuteEvent() )
- {
- case 0:
- break;
- case EVENT_TRY_FREE_HELPER:
- {
- if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) )
- if( pInstance )
- if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) )
- if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) )
- {
- AttackStart(hodir);
- ScheduleAbilities();
- break;
- }
- events.Repeat(2s);
- }
- break;
- case EVENT_DRUID_WRATH:
- if (Unit* victim = me->GetVictim())
- me->CastSpell(victim, SPELL_DRUID_WRATH, false);
- events.Repeat(1600ms);
- break;
- case EVENT_DRUID_STARLIGHT:
- if (me->GetPositionZ() < 433.0f) // ensure npc is on the ground
- {
- me->CastSpell(me, SPELL_DRUID_STARLIGHT_AREA_AURA, false);
- events.Repeat(15s);
- break;
- }
- events.Repeat(3s);
- break;
- }
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override {}
-
- void EnterEvadeMode(EvadeReason /*why*/) override {}
- bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (pInstance)
- if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR)))
- hodir->AI()->SetData(4, 1);
- }
- };
-};
-
-class npc_ulduar_hodir_shaman : public CreatureScript
-{
-public:
- npc_ulduar_hodir_shaman() : CreatureScript("npc_ulduar_hodir_shaman") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_hodir_shamanAI : public ScriptedAI
- {
- npc_ulduar_hodir_shamanAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- pInstance = me->GetInstanceScript();
- events.Reset();
- me->SetReactState(REACT_PASSIVE);
- }
-
- EventMap events;
- InstanceScript* pInstance;
-
- void AttackStart(Unit* who) override
- {
- AttackStartCaster(who, 25.0f);
- }
-
- void ScheduleAbilities()
- {
- events.ScheduleEvent(EVENT_SHAMAN_LAVA_BURST, 2600ms);
- events.ScheduleEvent(EVENT_SHAMAN_STORM_CLOUD, 10s);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC)
- {
- events.Reset();
- events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s);
- }
- }
-
- void SpellHitTarget(Unit* target, SpellInfo const* spell) override
- {
- if (target && spell->Id == SPELL_SHAMAN_STORM_CLOUD)
- if (Aura* a = target->GetAura(SPELL_SHAMAN_STORM_CLOUD, me->GetGUID()))
- a->SetStackAmount(spell->StackAmount);
- }
-
- void UpdateAI(uint32 diff) override
- {
- events.Update(diff);
-
- if( me->HasUnitState(UNIT_STATE_CASTING) )
- return;
-
- switch( events.ExecuteEvent() )
- {
- case 0:
- break;
- case EVENT_TRY_FREE_HELPER:
- {
- if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) )
- if( pInstance )
- if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) )
- if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) )
- {
- AttackStart(hodir);
- ScheduleAbilities();
- break;
- }
- events.Repeat(2s);
- }
- break;
- case EVENT_SHAMAN_LAVA_BURST:
- if (Unit* victim = me->GetVictim())
- me->CastSpell(victim, SPELL_SHAMAN_LAVA_BURST, false);
- events.Repeat(2600ms);
- break;
- case EVENT_SHAMAN_STORM_CLOUD:
- if (Player* target = ScriptedAI::SelectTargetFromPlayerList(35.0f, SPELL_SHAMAN_STORM_CLOUD))
- me->CastSpell(target, SPELL_SHAMAN_STORM_CLOUD, false);
- events.Repeat(30s);
- break;
- }
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override {}
-
- void EnterEvadeMode(EvadeReason /*why*/) override {}
- bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (pInstance)
- if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR)))
- hodir->AI()->SetData(4, 1);
- }
- };
-};
-
-class npc_ulduar_hodir_mage : public CreatureScript
-{
-public:
- npc_ulduar_hodir_mage() : CreatureScript("npc_ulduar_hodir_mage") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_hodir_mageAI : public ScriptedAI
- {
- npc_ulduar_hodir_mageAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- pInstance = me->GetInstanceScript();
- events.Reset();
- me->SetReactState(REACT_PASSIVE);
- }
-
- EventMap events;
- InstanceScript* pInstance;
-
- void AttackStart(Unit* who) override
- {
- AttackStartCaster(who, 30.0f);
- }
-
- void ScheduleAbilities()
- {
- events.ScheduleEvent(EVENT_MAGE_FIREBALL, 3100ms);
- events.ScheduleEvent(EVENT_MAGE_TOASTY_FIRE, 6s);
- events.ScheduleEvent(EVENT_MAGE_MELT_ICE, 1s);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC)
- {
- events.Reset();
- events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s);
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- events.Update(diff);
-
- if( me->HasUnitState(UNIT_STATE_CASTING) )
- return;
-
- switch( events.ExecuteEvent() )
- {
- case 0:
- break;
- case EVENT_TRY_FREE_HELPER:
- {
- if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) )
- if( pInstance )
- if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) )
- if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) )
- {
- AttackStart(hodir);
- ScheduleAbilities();
- break;
- }
- events.Repeat(2s);
- }
- break;
- case EVENT_MAGE_FIREBALL:
- if (Unit* victim = me->GetVictim())
- me->CastSpell(victim, SPELL_MAGE_FIREBALL, false);
- events.Repeat(3100ms);
- break;
- case EVENT_MAGE_TOASTY_FIRE:
- me->CastSpell(me, SPELL_MAGE_CONJURE_TOASTY_FIRE, false);
- events.Repeat(10s);
- break;
- case EVENT_MAGE_MELT_ICE:
- {
- std::list FB;
- bool found = false;
- me->GetCreaturesWithEntryInRange(FB, 150.0f, NPC_FLASH_FREEZE_NPC);
- for( std::list::const_iterator itr = FB.begin(); itr != FB.end(); ++itr )
- if( !((*itr)->HasAura(SPELL_MAGE_MELT_ICE)) )
- {
- me->CastSpell((*itr), SPELL_MAGE_MELT_ICE, false);
- found = true;
- break;
- }
-
- if( found )
- {
- events.DelayEvents(2s);
- events.Repeat(2s);
- break;
- }
- events.Repeat(5s);
- }
- break;
- }
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override {}
-
- void EnterEvadeMode(EvadeReason /*why*/) override {}
- bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (pInstance)
- if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR)))
- hodir->AI()->SetData(4, 1);
- }
- };
-};
-
-class spell_hodir_shatter_chest : public SpellScriptLoader
-{
-public:
- spell_hodir_shatter_chest() : SpellScriptLoader("spell_hodir_shatter_chest") { }
-
- class spell_hodir_shatter_chestSpellScript : public SpellScript
- {
- PrepareSpellScript(spell_hodir_shatter_chestSpellScript)
-
- void destroyWinterCache(SpellEffIndex effIndex)
- {
- PreventHitDefaultEffect(effIndex);
-
- if (Unit* hodir = GetCaster())
- hodir->GetAI()->DoAction(EVENT_FAIL_HM);
- }
-
- void Register() override
- {
- OnEffectHit += SpellEffectFn(spell_hodir_shatter_chestSpellScript::destroyWinterCache, EFFECT_0, SPELL_EFFECT_TRIGGER_MISSILE);
- };
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_hodir_shatter_chestSpellScript();
- }
-};
-
-class spell_hodir_biting_cold_main_aura : public SpellScriptLoader
-{
-public:
- spell_hodir_biting_cold_main_aura() : SpellScriptLoader("spell_hodir_biting_cold_main_aura") { }
-
- class spell_hodir_biting_cold_main_aura_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_hodir_biting_cold_main_aura_AuraScript)
-
- void HandleEffectPeriodic(AuraEffect const* aurEff)
- {
- if ((aurEff->GetTickNumber() % 4) == 0)
- if (Unit* target = GetTarget())
- if (target->GetTypeId() == TYPEID_PLAYER
- && !target->isMoving()
- && !target->HasAura(SPELL_BITING_COLD_PLAYER_AURA)
- && !target->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA))
- target->CastSpell(target, SPELL_BITING_COLD_PLAYER_AURA, true);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_biting_cold_main_aura_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_hodir_biting_cold_main_aura_AuraScript();
- }
-};
-
-class spell_hodir_biting_cold_player_aura : public SpellScriptLoader
-{
-public:
- spell_hodir_biting_cold_player_aura() : SpellScriptLoader("spell_hodir_biting_cold_player_aura") { }
-
- class spell_hodir_biting_cold_player_aura_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_hodir_biting_cold_player_aura_AuraScript)
-
- uint8 counter {0};
- bool prev {false};
-
- void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
- {
- if (Unit* target = GetTarget())
- {
- if (target->GetMapId() == 603)
- SetDuration(GetMaxDuration());
- if (target->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER))
- return;
- if (target->isMoving() || target->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA))
- {
- if (prev)
- {
- ModStackAmount(-1);
- prev = false;
- }
- else
- prev = true;
-
- if (counter >= 2)
- counter -= 2;
- else if (counter)
- --counter;
- }
- else
- {
- prev = false;
- ++counter;
- if (counter >= 4)
- {
- if (GetStackAmount() == 2) // increasing from 2 to 3 (not checking >= to improve performance)
- if (InstanceScript* pInstance = target->GetInstanceScript())
- if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR)))
- hodir->AI()->SetData(2, 1);
- ModStackAmount(1);
- counter = 0;
- }
- }
-
- const int32 dmg = 200 * pow(2.0f, GetStackAmount());
- target->CastCustomSpell(target, SPELL_BITING_COLD_DAMAGE, &dmg, 0, 0, true);
- }
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_biting_cold_player_aura_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_hodir_biting_cold_player_aura_AuraScript();
- }
-};
-
-class spell_hodir_periodic_icicle : public SpellScriptLoader
-{
-public:
- spell_hodir_periodic_icicle() : SpellScriptLoader("spell_hodir_periodic_icicle") { }
-
- class spell_hodir_periodic_icicle_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_hodir_periodic_icicle_SpellScript);
-
- void FilterTargets(std::list& targets)
- {
- targets.remove_if(Acore::ObjectTypeIdCheck(TYPEID_PLAYER, false));
- targets.remove_if(Acore::UnitAuraCheck(true, SPELL_FLASH_FREEZE_TRAPPED_PLAYER));
- Acore::Containers::RandomResize(targets, 1);
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_periodic_icicle_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_hodir_periodic_icicle_SpellScript();
- }
-};
-
-class FlashFreezeCheck
-{
-public:
- FlashFreezeCheck() { }
-
- bool operator()(WorldObject* target) const
- {
- if (Unit* unit = target->ToUnit())
- return unit->HasAura(SPELL_SAFE_AREA_TRIGGERED) || unit->IsPet();
- return true;
- }
-};
-
-class spell_hodir_flash_freeze : public SpellScriptLoader
-{
-public:
- spell_hodir_flash_freeze() : SpellScriptLoader("spell_hodir_flash_freeze") { }
-
- class spell_hodir_flash_freeze_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_hodir_flash_freeze_SpellScript);
-
- void FilterTargets(std::list& targets)
- {
- targets.remove_if(FlashFreezeCheck());
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_flash_freeze_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_flash_freeze_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY);
- }
- };
-
- class spell_hodir_flash_freeze_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_hodir_flash_freeze_AuraScript)
-
- void HandleEffectPeriodic(AuraEffect const* aurEff)
- {
- if (aurEff->GetTotalTicks() > 0 && aurEff->GetTickNumber() == uint32(aurEff->GetTotalTicks()) - 1)
- {
- Unit* target = GetTarget();
- Unit* caster = GetCaster();
- if (!target || !caster || caster->GetTypeId() != TYPEID_UNIT)
- return;
-
- if (Aura* aur = target->GetAura(target->GetTypeId() == TYPEID_PLAYER ? SPELL_FLASH_FREEZE_TRAPPED_PLAYER : SPELL_FLASH_FREEZE_TRAPPED_NPC))
- {
- if (Unit* caster2 = aur->GetCaster())
- {
- if (caster2->GetTypeId() == TYPEID_UNIT)
- {
- caster2->ToCreature()->DespawnOrUnsummon();
- }
- }
- target->CastSpell(target, SPELL_FLASH_FREEZE_INSTAKILL, true);
- return;
- }
- if (target->GetTypeId() == TYPEID_PLAYER)
- {
- caster->ToCreature()->AI()->SetData(1, 1);
- if( Creature* c = target->SummonCreature(NPC_FLASH_FREEZE_PLR, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 5 * 60 * 1000) )
- {
- c->CastSpell(target, SPELL_FLASH_FREEZE_TRAPPED_PLAYER, true);
- caster->ToCreature()->AI()->JustSummoned(c);
- }
- }
- else if (target->GetTypeId() == TYPEID_UNIT)
- {
- if( Creature* c = target->SummonCreature(NPC_FLASH_FREEZE_NPC, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000) )
- {
- c->CastSpell(target, SPELL_FLASH_FREEZE_TRAPPED_NPC, true);
- caster->ToCreature()->AI()->JustSummoned(c);
- }
- }
- }
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_flash_freeze_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_hodir_flash_freeze_SpellScript();
- }
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_hodir_flash_freeze_AuraScript();
- }
-};
-
-class spell_hodir_storm_power : public SpellScriptLoader
-{
-public:
- spell_hodir_storm_power() : SpellScriptLoader("spell_hodir_storm_power") { }
-
- class spell_hodir_storm_power_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_hodir_storm_power_AuraScript)
-
- void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* caster = GetCaster())
- if (Aura* a = caster->GetAura(GetId() == SPELL_SHAMAN_STORM_POWER_10 ? SPELL_SHAMAN_STORM_CLOUD_10 : SPELL_SHAMAN_STORM_CLOUD_25))
- a->ModStackAmount(-1);
- }
-
- void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* target = GetTarget())
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, GetId(), 0, GetCaster());
- }
-
- void Register() override
- {
- OnEffectApply += AuraEffectApplyFn(spell_hodir_storm_power_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, AURA_EFFECT_HANDLE_REAL);
- AfterEffectApply += AuraEffectApplyFn(spell_hodir_storm_power_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_hodir_storm_power_AuraScript();
- }
-};
-
-class spell_hodir_storm_cloud : public SpellScriptLoader
-{
-public:
- spell_hodir_storm_cloud() : SpellScriptLoader("spell_hodir_storm_cloud") { }
-
- class spell_hodir_storm_cloud_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_hodir_storm_cloud_AuraScript)
-
- void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
- {
- PreventDefaultAction();
- if (Unit* target = GetTarget())
- target->CastSpell((Unit*)nullptr, (GetId() == SPELL_SHAMAN_STORM_CLOUD_10 ? SPELL_SHAMAN_STORM_POWER_10 : SPELL_SHAMAN_STORM_POWER_25), true);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_storm_cloud_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_hodir_storm_cloud_AuraScript();
- }
-};
-
-class achievement_cheese_the_freeze : public AchievementCriteriaScript
-{
-public:
- achievement_cheese_the_freeze() : AchievementCriteriaScript("achievement_cheese_the_freeze") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1);
- }
-};
-
-class achievement_getting_cold_in_here : public AchievementCriteriaScript
-{
-public:
- achievement_getting_cold_in_here() : AchievementCriteriaScript("achievement_getting_cold_in_here") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(2);
- }
-};
-
-class achievement_i_could_say_that_this_cache_was_rare : public AchievementCriteriaScript
-{
-public:
- achievement_i_could_say_that_this_cache_was_rare() : AchievementCriteriaScript("achievement_i_could_say_that_this_cache_was_rare") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(3);
- }
-};
-
-class achievement_i_have_the_coolest_friends : public AchievementCriteriaScript
-{
-public:
- achievement_i_have_the_coolest_friends() : AchievementCriteriaScript("achievement_i_have_the_coolest_friends") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(4);
- }
-};
-
-class achievement_staying_buffed_all_winter_10 : public AchievementCriteriaScript
-{
-public:
- achievement_staying_buffed_all_winter_10() : AchievementCriteriaScript("achievement_staying_buffed_all_winter_10") {}
-
- bool OnCheck(Player* player, Unit* /*target*/, uint32 /*criteria_id*/) override
- {
- return player && player->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA) && player->HasAura(SPELL_DRUID_STARLIGHT_AREA_AURA) && player->HasAura(SPELL_SHAMAN_STORM_POWER_10);
- }
-};
-
-class achievement_staying_buffed_all_winter_25 : public AchievementCriteriaScript
-{
-public:
- achievement_staying_buffed_all_winter_25() : AchievementCriteriaScript("achievement_staying_buffed_all_winter_25") {}
-
- bool OnCheck(Player* player, Unit* /*target*/, uint32 /*criteria_id*/) override
- {
- return player && player->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA) && player->HasAura(SPELL_DRUID_STARLIGHT_AREA_AURA) && player->HasAura(SPELL_SHAMAN_STORM_POWER_25);
- }
-};
-
-class spell_hodir_toasty_fire : public SpellScriptLoader
-{
-public:
- spell_hodir_toasty_fire() : SpellScriptLoader("spell_hodir_toasty_fire") { }
-
- class spell_hodir_toasty_fire_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_hodir_toasty_fire_AuraScript);
-
- void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* target = GetTarget())
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, SPELL_MAGE_TOASTY_FIRE_AURA, 0, GetCaster());
- }
-
- void Register() override
- {
- AfterEffectApply += AuraEffectApplyFn(spell_hodir_toasty_fire_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MOD_STAT, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_hodir_toasty_fire_AuraScript();
- }
-};
-
-class spell_hodir_starlight : public SpellScriptLoader
-{
-public:
- spell_hodir_starlight() : SpellScriptLoader("spell_hodir_starlight") { }
-
- class spell_hodir_starlight_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_hodir_starlight_AuraScript);
-
- void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* target = GetTarget())
- if (target->GetTypeId() == TYPEID_PLAYER)
- target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, SPELL_DRUID_STARLIGHT_AREA_AURA, 0, GetCaster());
- }
-
- void Register() override
- {
- AfterEffectApply += AuraEffectApplyFn(spell_hodir_starlight_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MELEE_SLOW, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_hodir_starlight_AuraScript();
- }
-};
-
void AddSC_boss_hodir()
{
new boss_hodir();
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.h
new file mode 100644
index 00000000000000..db4b87011c8253
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.h
@@ -0,0 +1,1594 @@
+#ifndef BOSS_HODIR_H_
+#define BOSS_HODIR_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "SpellAuraEffects.h"
+#include "SpellAuras.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "ulduar.h"
+
+enum HodirSpellData
+{
+ SPELL_BERSERK = 26662,
+
+ SPELL_BITING_COLD_BOSS_AURA = 62038,
+ SPELL_BITING_COLD_PLAYER_AURA = 62039,
+ SPELL_BITING_COLD_DAMAGE = 62188,
+
+ SPELL_FREEZE = 62469,
+
+ SPELL_FLASH_FREEZE_CAST = 61968,
+ SPELL_FLASH_FREEZE_INSTAKILL = 62226,
+ SPELL_FLASH_FREEZE_TRAPPED_PLAYER = 61969,
+ SPELL_FLASH_FREEZE_TRAPPED_NPC = 61990,
+ SPELL_FLASH_FREEZE_VISUAL = 62148,
+ SPELL_SAFE_AREA = 65705,
+ SPELL_SAFE_AREA_TRIGGERED = 62464,
+ SPELL_SHATTER_CHEST = 62501,
+
+ SPELL_ICICLE_BOSS_AURA = 62227,
+ SPELL_ICICLE_TBBA = 63545,
+
+ SPELL_ICICLE_VISUAL_UNPACKED = 62234,
+ SPELL_ICICLE_VISUAL_PACKED = 62462,
+ SPELL_ICICLE_VISUAL_FALLING = 62453,
+ SPELL_ICICLE_FALL_EFFECT_UNPACKED = 62236,
+ SPELL_ICICLE_FALL_EFFECT_PACKED = 62460,
+ SPELL_ICE_SHARDS_SMALL = 62457,
+ SPELL_ICE_SHARDS_BIG = 65370,
+ SPELL_SNOWDRIFT = 62463,
+
+ SPELL_FROZEN_BLOWS_10 = 62478,
+ SPELL_FROZEN_BLOWS_25 = 63512,
+
+ // Helpers:
+ SPELL_PRIEST_DISPELL_MAGIC = 63499,
+ SPELL_PRIEST_GREAT_HEAL = 62809,
+ SPELL_PRIEST_SMITE = 61923,
+
+ SPELL_DRUID_WRATH = 62793,
+ SPELL_DRUID_STARLIGHT_AREA_AURA = 62807,
+
+ SPELL_SHAMAN_LAVA_BURST = 61924,
+ SPELL_SHAMAN_STORM_CLOUD_10 = 65123,
+ SPELL_SHAMAN_STORM_CLOUD_25 = 65133,
+ SPELL_SHAMAN_STORM_POWER_10 = 63711,
+ SPELL_SHAMAN_STORM_POWER_25 = 65134,
+
+ SPELL_MAGE_FIREBALL = 61909,
+ SPELL_MAGE_MELT_ICE = 64528,
+ SPELL_MAGE_CONJURE_TOASTY_FIRE = 62823,
+ SPELL_MAGE_SUMMON_TOASTY_FIRE = 62819,
+ SPELL_MAGE_TOASTY_FIRE_AURA = 62821,
+ SPELL_SINGED = 65280,
+};
+
+enum HodirNPCs
+{
+ //NPC_HODIR = 32845,
+
+ NPC_PAN_FIELD_MEDIC_PENNY = 32897,
+ NPC_DAN_ELLIE_NIGHTFEATHER = 32901,
+ NPC_SAN_ELEMENTALIST_AVUUN = 32900,
+ NPC_MAN_MISSY_FLAMECUFFS = 32893,
+
+ NPC_PAH_FIELD_MEDIC_JESSI = 33326,
+ NPC_DAH_EIVI_NIGHTFEATHER = 33325,
+ NPC_SAH_ELEMENTALIST_MAHFUUN = 33328,
+ NPC_MAH_SISSY_FLAMECUFFS = 33327,
+
+ NPC_PHN_BATTLEPRIEST_ELIZA = 32948,
+ NPC_DHN_TOR_GREYCLOUD = 32941,
+ NPC_SHN_SPIRITWALKER_YONA = 32950,
+ NPC_MHN_VEESHA_BLAZEWEAVER = 32946,
+
+ NPC_PHH_BATTLEPRIEST_GINA = 33330,
+ NPC_DHH_KAR_GREYCLOUD = 33333,
+ NPC_SHH_SPIRITWALKER_TARA = 33332,
+ NPC_MHH_AMIRA_BLAZEWEAVER = 33331,
+
+ NPC_FLASH_FREEZE_PLR = 32926,
+ NPC_FLASH_FREEZE_NPC = 32938,
+ NPC_ICICLE_UNPACKED = 33169,
+ NPC_ICICLE_PACKED = 33173,
+ NPC_TOASTY_FIRE = 33342,
+ NPC_RARE_WINTER_CACHE_TRIGGER = 88101,
+};
+
+enum HodirEvents
+{
+ // Hodir:
+ EVENT_FLASH_FREEZE = 1,
+ EVENT_FROZEN_BLOWS = 2,
+ EVENT_BERSERK = 3,
+ EVENT_FREEZE = 4,
+ EVENT_SMALL_ICICLES_ENABLE = 5,
+ EVENT_HARD_MODE_MISSED = 6,
+ EVENT_DESPAWN_CHEST = 7,
+ EVENT_FAIL_HM = 8,
+
+ EVENT_TRY_FREE_HELPER = 10,
+ EVENT_PRIEST_DISPELL_MAGIC = 11,
+ EVENT_PRIEST_GREAT_HEAL = 12,
+ EVENT_PRIEST_SMITE = 13,
+ EVENT_DRUID_WRATH = 14,
+ EVENT_DRUID_STARLIGHT = 15,
+ EVENT_SHAMAN_LAVA_BURST = 16,
+ EVENT_SHAMAN_STORM_CLOUD = 17,
+ EVENT_MAGE_TOASTY_FIRE = 18,
+ EVENT_MAGE_FIREBALL = 19,
+ EVENT_MAGE_MELT_ICE = 20,
+};
+
+enum HodirText
+{
+ TEXT_AGGRO = 0,
+ TEXT_SLAY = 1,
+ TEXT_FLASH_FREEZE = 2,
+ TEXT_STALACTITE = 3,
+ TEXT_DEATH = 4,
+ TEXT_BERSERK = 5,
+ TEXT_HM_MISS = 6,
+ TEXT_EMOTE_FREEZE = 7,
+ TEXT_EMOTE_BLOW = 8,
+};
+
+#define SPELL_FROZEN_BLOWS RAID_MODE(SPELL_FROZEN_BLOWS_10, SPELL_FROZEN_BLOWS_25)
+#define SPELL_SHAMAN_STORM_CLOUD RAID_MODE(SPELL_SHAMAN_STORM_CLOUD_10, SPELL_SHAMAN_STORM_CLOUD_25)
+
+enum HodirSounds
+{
+ SOUND_HODIR_AGGRO = 15552,
+ SOUND_HODIR_SLAIN_1 = 15553,
+ SOUND_HODIR_SLAIN_2 = 15554,
+ SOUND_HODIR_FLASH_FREEZE = 15555,
+ SOUND_HODIR_FROZEN_BLOWS = 15556,
+ SOUND_HODIR_DEFEATED = 15557,
+ SOUND_HODIR_BERSERK = 15558,
+};
+
+struct HodirHelperData
+{
+ uint32 id;
+ float x, y;
+};
+HodirHelperData hhd[4][4] =
+{
+ // Alliance:
+ {
+ {NPC_PAN_FIELD_MEDIC_PENNY, 2020.46f, -236.74f},
+ {NPC_DAN_ELLIE_NIGHTFEATHER, 2007.21f, -241.57f},
+ {NPC_SAN_ELEMENTALIST_AVUUN, 1999.14f, -230.69f},
+ {NPC_MAN_MISSY_FLAMECUFFS, 1984.38f, -242.57f}
+ },
+ {
+ {NPC_PAH_FIELD_MEDIC_JESSI, 2012.29f, -233.70f},
+ {NPC_DAH_EIVI_NIGHTFEATHER, 1995.75f, -241.32f},
+ {NPC_SAH_ELEMENTALIST_MAHFUUN, 1989.31f, -234.26f},
+ {NPC_MAH_SISSY_FLAMECUFFS, 1977.87f, -233.99f}
+ },
+ // Horde:
+ {
+ {NPC_PHN_BATTLEPRIEST_ELIZA, 2020.46f, -236.74f},
+ {NPC_DHN_TOR_GREYCLOUD, 2007.21f, -241.57f},
+ {NPC_SHN_SPIRITWALKER_YONA, 1999.14f, -230.69f},
+ {NPC_MHN_VEESHA_BLAZEWEAVER, 1984.38f, -242.57f}
+ },
+ {
+ {NPC_PHH_BATTLEPRIEST_GINA, 2012.29f, -233.70f},
+ {NPC_DHH_KAR_GREYCLOUD, 1995.75f, -241.32f},
+ {NPC_SHH_SPIRITWALKER_TARA, 1989.31f, -234.6f},
+ {NPC_MHH_AMIRA_BLAZEWEAVER, 1977.87f, -233.99f}
+ }
+};
+
+class boss_hodir : public CreatureScript
+{
+public:
+ boss_hodir() : CreatureScript("boss_hodir") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_hodirAI : public ScriptedAI
+ {
+ boss_hodirAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
+ {
+ pInstance = pCreature->GetInstanceScript();
+ if (!me->IsAlive())
+ if (pInstance)
+ pInstance->SetData(TYPE_HODIR, DONE);
+ }
+
+ InstanceScript* pInstance;
+ EventMap events;
+ SummonList summons;
+ ObjectGuid Helpers[8];
+ bool berserk{ false };
+ bool bAchievCheese{ true };
+ bool bAchievGettingCold{ true };
+ bool bAchievCacheRare{ true };
+ bool bAchievCoolestFriends{ true };
+ uint16 addSpawnTimer{ 0 };
+
+ // Used to make Hodir disengage whenever he leaves his room
+ const Position ENTRANCE_DOOR{ 1999.160034f, -297.792999f, 431.960999f, 0 };
+ const Position EXIT_DOOR{ 1999.709961f, -166.259003f, 432.822998f, 0 };
+
+ void Reset() override
+ {
+ events.Reset();
+ summons.DespawnAll();
+ berserk = false;
+ bAchievCheese = true;
+ bAchievGettingCold = true;
+ bAchievCacheRare = true;
+ bAchievCoolestFriends = true;
+ me->SetSheath(SHEATH_STATE_MELEE);
+
+ // Reset the spells cast after wipe
+ me->RemoveAllAuras();
+ pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA);
+
+ if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE)
+ {
+ pInstance->SetData(TYPE_HODIR, NOT_STARTED);
+ }
+
+ if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 900.0f))
+ {
+ go->SetGoState(GO_STATE_ACTIVE);
+ }
+
+ // Reset helpers
+ if (!summons.size())
+ SpawnHelpers();
+ }
+
+ void JustEngagedWith(Unit* /*pWho*/) override
+ {
+ me->CastSpell(me, SPELL_BITING_COLD_BOSS_AURA, true);
+ SmallIcicles(true);
+ events.Reset();
+ events.ScheduleEvent(EVENT_FLASH_FREEZE, 48s, 49s);
+ events.ScheduleEvent(EVENT_FREEZE, 17s, 20s);
+ events.ScheduleEvent(EVENT_BERSERK, 8min);
+ events.ScheduleEvent(EVENT_HARD_MODE_MISSED, 3min);
+ Talk(TEXT_AGGRO);
+
+ if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE)
+ {
+ pInstance->SetData(TYPE_HODIR, IN_PROGRESS);
+ }
+
+ if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 300.0f))
+ {
+ go->SetGoState(GO_STATE_READY);
+ }
+ }
+
+ void DoAction(int action) override
+ {
+ if (action)
+ {
+ switch (action)
+ {
+ case EVENT_FAIL_HM:
+ if (pInstance)
+ {
+ if (GameObject* go = pInstance->instance->GetGameObject(pInstance->GetGuidData(GO_HODIR_CHEST_HARD)))
+ {
+ go->SetGoState(GO_STATE_ACTIVE);
+ events.ScheduleEvent(EVENT_DESPAWN_CHEST, 3s);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ void SmallIcicles(bool enable)
+ {
+ if( enable )
+ me->CastSpell(me, SPELL_ICICLE_BOSS_AURA, true);
+ else
+ me->RemoveAura(SPELL_ICICLE_BOSS_AURA);
+ }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override
+ {
+ switch( spell->Id )
+ {
+ case SPELL_ICICLE_TBBA:
+ me->CastSpell(target, SPELL_ICICLE_VISUAL_UNPACKED, true);
+ break;
+ case SPELL_FLASH_FREEZE_VISUAL:
+ {
+ std::list fires;
+ me->GetCreaturesWithEntryInRange(fires, 200.0f, NPC_TOASTY_FIRE);
+ for (std::list::iterator itr = fires.begin(); itr != fires.end(); ++itr)
+ (*itr)->AI()->DoAction(1); // remove it
+ }
+ break;
+ }
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (damage >= me->GetHealth() || me->GetHealth() < 150000)
+ {
+ damage = 0;
+ me->SetReactState(REACT_PASSIVE);
+ if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
+ {
+ if (pInstance)
+ {
+ pInstance->SetData(TYPE_HODIR, DONE);
+ me->CastSpell(me, 64899, true); // credit
+ }
+
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->SetFaction(FACTION_FRIENDLY);
+ me->GetMotionMaster()->Clear();
+ me->AttackStop();
+ me->CombatStop();
+ me->InterruptNonMeleeSpells(true);
+ me->RemoveAllAuras();
+ pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BITING_COLD_PLAYER_AURA);
+
+ events.Reset();
+ summons.DespawnAll();
+
+ if( GameObject* d = me->FindNearestGameObject(GO_HODIR_FROZEN_DOOR, 250.0f))
+ {
+ if( d->GetGoState() != GO_STATE_ACTIVE )
+ {
+ d->SetLootState(GO_READY);
+ d->UseDoorOrButton(0, false);
+ }
+ }
+ if (GameObject* d = me->FindNearestGameObject(GO_HODIR_DOOR, 250.0f))
+ {
+ if( d->GetGoState() != GO_STATE_ACTIVE )
+ {
+ d->SetLootState(GO_READY);
+ d->UseDoorOrButton(0, false);
+ }
+ }
+
+ if (GameObject* go = me->FindNearestGameObject(GO_HODIR_FRONTDOOR, 300.0f))
+ {
+ go->SetGoState(GO_STATE_ACTIVE);
+ }
+
+ Talk(TEXT_DEATH);
+ me->DespawnOrUnsummon(10000);
+ }
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (me->GetPositionY() <= ENTRANCE_DOOR.GetPositionY() || me->GetPositionY() >= EXIT_DOOR.GetPositionY())
+ {
+ boss_hodirAI::EnterEvadeMode();
+ return;
+ }
+
+ if (!UpdateVictim())
+ {
+ if (me->IsInCombat())
+ {
+ Map::PlayerList const& pl = me->GetMap()->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
+ itr->GetSource()->CastSpell(itr->GetSource(), SPELL_FLASH_FREEZE_INSTAKILL, true);
+ EnterEvadeMode();
+ }
+ return;
+ }
+
+ events.Update(diff);
+
+ if( me->HasUnitState(UNIT_STATE_CASTING) )
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case 0:
+ break;
+ case EVENT_BERSERK:
+ {
+ berserk = true;
+ me->CastSpell(me, SPELL_BERSERK, true);
+ Talk(TEXT_BERSERK);
+ }
+ break;
+ case EVENT_HARD_MODE_MISSED:
+ {
+ Talk(TEXT_HM_MISS);
+ bAchievCacheRare = false;
+ if (pInstance)
+ {
+ if (GameObject* go = pInstance->instance->GetGameObject(pInstance->GetGuidData(GO_HODIR_CHEST_HARD)))
+ {
+ me->CastSpell(go, SPELL_SHATTER_CHEST, false);
+ }
+ }
+ }
+ break;
+ case EVENT_DESPAWN_CHEST:
+ if (pInstance && pInstance->GetData(TYPE_HODIR) != DONE)
+ pInstance->SetData(TYPE_HODIR_HM_FAIL, 0);
+ break;
+ case EVENT_FLASH_FREEZE:
+ {
+ std::list targets;
+ Map::PlayerList const& pl = me->GetMap()->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
+ targets.push_back(itr->GetSource());
+ targets.remove_if(Acore::ObjectTypeIdCheck(TYPEID_PLAYER, false));
+ targets.remove_if(Acore::UnitAuraCheck(true, SPELL_FLASH_FREEZE_TRAPPED_PLAYER));
+ Acore::Containers::RandomResize(targets, (RAID_MODE(2,3)));
+ for (std::list::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
+ {
+ float prevZ = (*itr)->GetPositionZ();
+ (*itr)->m_positionZ = 432.7f;
+ (*itr)->CastSpell((*itr), SPELL_ICICLE_VISUAL_PACKED, true);
+ (*itr)->m_positionZ = prevZ;
+ }
+
+ me->CastSpell((Unit*)nullptr, SPELL_FLASH_FREEZE_CAST, false);
+ me->PlayDirectSound(SOUND_HODIR_FLASH_FREEZE, 0);
+ Talk(TEXT_FLASH_FREEZE);
+ Talk(TEXT_EMOTE_FREEZE);
+ SmallIcicles(false);
+ events.ScheduleEvent(EVENT_FLASH_FREEZE, 48s, 49s);
+ events.ScheduleEvent(EVENT_SMALL_ICICLES_ENABLE, Is25ManRaid() ? 12s : 24s);
+ events.ScheduleEvent(EVENT_FROZEN_BLOWS, 15s);
+ events.RescheduleEvent(EVENT_FREEZE, 17s, 20s);
+ }
+ break;
+ case EVENT_SMALL_ICICLES_ENABLE:
+ {
+ SmallIcicles(true);
+ }
+ break;
+ case EVENT_FROZEN_BLOWS:
+ {
+ Talk(TEXT_EMOTE_BLOW);
+ Talk(TEXT_STALACTITE);
+ me->CastSpell(me, Is25ManRaid()? SPELL_FROZEN_BLOWS_25 : SPELL_FROZEN_BLOWS_10, true);
+ }
+ break;
+ case EVENT_FREEZE:
+ if (Player* plr = SelectTargetFromPlayerList(50.0f, SPELL_FLASH_FREEZE_TRAPPED_PLAYER))
+ {
+ me->CastSpell(plr, SPELL_FREEZE, false);
+ }
+ else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
+ {
+ me->CastSpell(target, SPELL_FREEZE, false);
+ }
+ events.RescheduleEvent(EVENT_FREEZE, 17s, 20s);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ Creature* GetHelper(uint8 index)
+ {
+ return Helpers[index] ? ObjectAccessor::GetCreature(*me, Helpers[index]) : nullptr;
+ }
+
+ void SpawnHelpers()
+ {
+ char faction = 'A';
+ if( hhd[0][0].id )
+ {
+ Map::PlayerList const& cl = me->GetMap()->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = cl.begin(); itr != cl.end(); ++itr)
+ if (!itr->GetSource()->IsGameMaster())
+ {
+ faction = (itr->GetSource()->GetTeamId() == TEAM_ALLIANCE ? 'A' : 'H');
+ break;
+ }
+ }
+
+ uint8 cnt = 0;
+ if( faction )
+ for( uint8 k = 0; k < 4; ++k )
+ {
+ if( (faction == 'A' && ( k > 1 || (k == 1 && RAID_MODE(1, 0)) )) ||
+ (faction == 'H' && ( k < 2 || (k == 3 && RAID_MODE(1, 0)) )) )
+ continue;
+
+ for( uint8 i = 0; i < 4; ++i )
+ {
+ if( !hhd[k][i].id )
+ continue;
+
+ if( Creature* h_p = me->SummonCreature(hhd[k][i].id, hhd[k][i].x, hhd[k][i].y, 432.69f, M_PI / 2) )
+ {
+ h_p->SetFaction(1665);
+ if( cnt < 8 )
+ Helpers[cnt++] = h_p->GetGUID();
+
+ if( Creature* c = h_p->SummonCreature(NPC_FLASH_FREEZE_NPC, h_p->GetPositionX(), h_p->GetPositionY(), h_p->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000) )
+ {
+ c->CastSpell(h_p, SPELL_FLASH_FREEZE_TRAPPED_NPC, true);
+ JustSummoned(c);
+ }
+ }
+ }
+ }
+ }
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ Talk(TEXT_SLAY);
+ }
+
+ void JustSummoned(Creature* s) override
+ {
+ summons.Summon(s);
+ }
+
+ void SummonedCreatureDespawn(Creature* s) override
+ {
+ summons.Despawn(s);
+ }
+
+ bool CanAIAttack(Unit const* t) const override
+ {
+ if (t->GetTypeId() == TYPEID_PLAYER)
+ return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER);
+ else if (t->GetTypeId() == TYPEID_UNIT)
+ return !t->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC);
+
+ return true;
+ }
+
+ void SetData(uint32 id, uint32 value) override
+ {
+ if (value)
+ switch (id)
+ {
+ case 1:
+ bAchievCheese = false;
+ break;
+ case 2:
+ bAchievGettingCold = false;
+ break;
+ case 4:
+ bAchievCoolestFriends = false;
+ break;
+ }
+ }
+
+ uint32 GetData(uint32 id) const override
+ {
+ switch (id)
+ {
+ case 1:
+ return (bAchievCheese ? 1 : 0);
+ case 2:
+ return (bAchievGettingCold ? 1 : 0);
+ case 3:
+ return (bAchievCacheRare ? 1 : 0);
+ case 4:
+ return (bAchievCoolestFriends ? 1 : 0);
+ }
+ return 0;
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+ };
+};
+
+class npc_ulduar_icicle : public CreatureScript
+{
+public:
+ npc_ulduar_icicle() : CreatureScript("npc_ulduar_icicle") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_icicleAI : public NullCreatureAI
+ {
+ npc_ulduar_icicleAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ timer1 = 2000;
+ timer2 = 5000;
+ }
+
+ uint16 timer1;
+ uint16 timer2;
+
+ void UpdateAI(uint32 diff) override
+ {
+ if( timer1 <= diff )
+ {
+ me->CastSpell(me, (me->GetEntry() == 33169 ? SPELL_ICICLE_FALL_EFFECT_UNPACKED : SPELL_ICICLE_FALL_EFFECT_PACKED), true);
+ me->CastSpell(me, SPELL_ICICLE_VISUAL_FALLING, false);
+ timer1 = 60000;
+ }
+ else
+ timer1 -= diff;
+
+ if (timer2 <= diff)
+ {
+ me->SetDisplayId(11686);
+ timer2 = 60000;
+ }
+ else
+ timer2 -= diff;
+ }
+ };
+};
+
+class npc_ulduar_flash_freeze : public CreatureScript
+{
+public:
+ npc_ulduar_flash_freeze() : CreatureScript("npc_ulduar_flash_freeze") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_flash_freezeAI : public NullCreatureAI
+ {
+ npc_ulduar_flash_freezeAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ timer = 2500;
+ pInstance = me->GetInstanceScript();
+ }
+
+ InstanceScript* pInstance;
+ uint16 timer;
+
+ void DamageTaken(Unit* doneBy, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
+ {
+ if (pInstance && doneBy)
+ if (pInstance->GetData(TYPE_HODIR) == NOT_STARTED)
+ if (Creature* hodir = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_HODIR)))
+ hodir->AI()->AttackStart(doneBy);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (timer <= diff)
+ {
+ timer = 2500;
+ if (me->IsSummon())
+ {
+ if (Unit* s = me->ToTempSummon()->GetSummonerUnit())
+ {
+ if ((s->GetTypeId() == TYPEID_PLAYER && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER)) || (s->GetTypeId() == TYPEID_UNIT && !s->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC)))
+ me->DespawnOrUnsummon(2000);
+ else if (s->GetTypeId() == TYPEID_PLAYER)
+ if (InstanceScript* instanceScript = me->GetInstanceScript())
+ if (instanceScript->GetData(TYPE_HODIR) == NOT_STARTED)
+ {
+ s->CastSpell(s, SPELL_FLASH_FREEZE_INSTAKILL, true);
+ me->DespawnOrUnsummon(2000);
+ }
+ }
+ else
+ {
+ me->DespawnOrUnsummon(2000);
+ }
+ }
+ }
+ else
+ timer -= diff;
+ }
+ };
+};
+
+class npc_ulduar_toasty_fire : public CreatureScript
+{
+public:
+ npc_ulduar_toasty_fire() : CreatureScript("npc_ulduar_toasty_fire") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_toasty_fireAI : public NullCreatureAI
+ {
+ npc_ulduar_toasty_fireAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ me->CastSpell(me, SPELL_MAGE_TOASTY_FIRE_AURA, true);
+ }
+
+ void DoAction(int32 a) override
+ {
+ if (a == 1)
+ {
+ if( GameObject* fire = me->FindNearestGameObject(194300, 1.0f) )
+ {
+ fire->SetOwnerGUID(ObjectGuid::Empty);
+ fire->Delete();
+ }
+ me->DespawnOrUnsummon(); // this will remove DynObjects
+ }
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ switch( spell->Id )
+ {
+ case SPELL_ICE_SHARDS_SMALL:
+ case SPELL_ICE_SHARDS_BIG:
+ DoAction(1);
+ break;
+ }
+ }
+ };
+};
+
+class npc_ulduar_hodir_priest : public CreatureScript
+{
+public:
+ npc_ulduar_hodir_priest() : CreatureScript("npc_ulduar_hodir_priest") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_hodir_priestAI : public ScriptedAI
+ {
+ npc_ulduar_hodir_priestAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = me->GetInstanceScript();
+ events.Reset();
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ EventMap events;
+ InstanceScript* pInstance;
+
+ void AttackStart(Unit* who) override
+ {
+ AttackStartCaster(who, 17.0f);
+ }
+
+ void ScheduleAbilities()
+ {
+ events.ScheduleEvent(EVENT_PRIEST_DISPELL_MAGIC, 7s);
+ events.ScheduleEvent(EVENT_PRIEST_GREAT_HEAL, 6s, 7s);
+ events.ScheduleEvent(EVENT_PRIEST_SMITE, 2100ms);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC)
+ {
+ events.Reset();
+ events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+
+ if( me->HasUnitState(UNIT_STATE_CASTING) )
+ return;
+
+ switch( events.ExecuteEvent() )
+ {
+ case 0:
+ break;
+ case EVENT_TRY_FREE_HELPER:
+ {
+ if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) )
+ if( pInstance )
+ if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) )
+ if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) )
+ {
+ AttackStart(hodir);
+ ScheduleAbilities();
+ break;
+ }
+ events.Repeat(2s);
+ }
+ break;
+ case EVENT_PRIEST_DISPELL_MAGIC:
+ me->CastCustomSpell(SPELL_PRIEST_DISPELL_MAGIC, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false);
+ events.Repeat(7s);
+ break;
+ case EVENT_PRIEST_GREAT_HEAL:
+ me->CastSpell(me, SPELL_PRIEST_GREAT_HEAL, false);
+ events.Repeat(6s, 7s);
+ break;
+ case EVENT_PRIEST_SMITE:
+ if (Unit* victim = me->GetVictim())
+ me->CastSpell(victim, SPELL_PRIEST_SMITE, false);
+ events.Repeat(2100ms);
+ break;
+ }
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+
+ void EnterEvadeMode(EvadeReason /*why*/) override {}
+ bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (pInstance)
+ if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR)))
+ hodir->AI()->SetData(4, 1);
+ }
+ };
+};
+
+class npc_ulduar_hodir_druid : public CreatureScript
+{
+public:
+ npc_ulduar_hodir_druid() : CreatureScript("npc_ulduar_hodir_druid") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_hodir_druidAI : public ScriptedAI
+ {
+ npc_ulduar_hodir_druidAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = me->GetInstanceScript();
+ events.Reset();
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ EventMap events;
+ InstanceScript* pInstance;
+
+ void AttackStart(Unit* who) override
+ {
+ AttackStartCaster(who, 22.0f);
+ }
+
+ void ScheduleAbilities()
+ {
+ events.ScheduleEvent(EVENT_DRUID_WRATH, 1600ms);
+ events.ScheduleEvent(EVENT_DRUID_STARLIGHT, 10s);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC)
+ {
+ events.Reset();
+ events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+
+ if( me->HasUnitState(UNIT_STATE_CASTING) )
+ return;
+
+ switch( events.ExecuteEvent() )
+ {
+ case 0:
+ break;
+ case EVENT_TRY_FREE_HELPER:
+ {
+ if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) )
+ if( pInstance )
+ if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) )
+ if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) )
+ {
+ AttackStart(hodir);
+ ScheduleAbilities();
+ break;
+ }
+ events.Repeat(2s);
+ }
+ break;
+ case EVENT_DRUID_WRATH:
+ if (Unit* victim = me->GetVictim())
+ me->CastSpell(victim, SPELL_DRUID_WRATH, false);
+ events.Repeat(1600ms);
+ break;
+ case EVENT_DRUID_STARLIGHT:
+ if (me->GetPositionZ() < 433.0f) // ensure npc is on the ground
+ {
+ me->CastSpell(me, SPELL_DRUID_STARLIGHT_AREA_AURA, false);
+ events.Repeat(15s);
+ break;
+ }
+ events.Repeat(3s);
+ break;
+ }
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+
+ void EnterEvadeMode(EvadeReason /*why*/) override {}
+ bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (pInstance)
+ if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR)))
+ hodir->AI()->SetData(4, 1);
+ }
+ };
+};
+
+class npc_ulduar_hodir_shaman : public CreatureScript
+{
+public:
+ npc_ulduar_hodir_shaman() : CreatureScript("npc_ulduar_hodir_shaman") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_hodir_shamanAI : public ScriptedAI
+ {
+ npc_ulduar_hodir_shamanAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = me->GetInstanceScript();
+ events.Reset();
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ EventMap events;
+ InstanceScript* pInstance;
+
+ void AttackStart(Unit* who) override
+ {
+ AttackStartCaster(who, 25.0f);
+ }
+
+ void ScheduleAbilities()
+ {
+ events.ScheduleEvent(EVENT_SHAMAN_LAVA_BURST, 2600ms);
+ events.ScheduleEvent(EVENT_SHAMAN_STORM_CLOUD, 10s);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC)
+ {
+ events.Reset();
+ events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s);
+ }
+ }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override
+ {
+ if (target && spell->Id == SPELL_SHAMAN_STORM_CLOUD)
+ if (Aura* a = target->GetAura(SPELL_SHAMAN_STORM_CLOUD, me->GetGUID()))
+ a->SetStackAmount(spell->StackAmount);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+
+ if( me->HasUnitState(UNIT_STATE_CASTING) )
+ return;
+
+ switch( events.ExecuteEvent() )
+ {
+ case 0:
+ break;
+ case EVENT_TRY_FREE_HELPER:
+ {
+ if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) )
+ if( pInstance )
+ if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) )
+ if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) )
+ {
+ AttackStart(hodir);
+ ScheduleAbilities();
+ break;
+ }
+ events.Repeat(2s);
+ }
+ break;
+ case EVENT_SHAMAN_LAVA_BURST:
+ if (Unit* victim = me->GetVictim())
+ me->CastSpell(victim, SPELL_SHAMAN_LAVA_BURST, false);
+ events.Repeat(2600ms);
+ break;
+ case EVENT_SHAMAN_STORM_CLOUD:
+ if (Player* target = ScriptedAI::SelectTargetFromPlayerList(35.0f, SPELL_SHAMAN_STORM_CLOUD))
+ me->CastSpell(target, SPELL_SHAMAN_STORM_CLOUD, false);
+ events.Repeat(30s);
+ break;
+ }
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+
+ void EnterEvadeMode(EvadeReason /*why*/) override {}
+ bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (pInstance)
+ if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR)))
+ hodir->AI()->SetData(4, 1);
+ }
+ };
+};
+
+class npc_ulduar_hodir_mage : public CreatureScript
+{
+public:
+ npc_ulduar_hodir_mage() : CreatureScript("npc_ulduar_hodir_mage") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_hodir_mageAI : public ScriptedAI
+ {
+ npc_ulduar_hodir_mageAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = me->GetInstanceScript();
+ events.Reset();
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ EventMap events;
+ InstanceScript* pInstance;
+
+ void AttackStart(Unit* who) override
+ {
+ AttackStartCaster(who, 30.0f);
+ }
+
+ void ScheduleAbilities()
+ {
+ events.ScheduleEvent(EVENT_MAGE_FIREBALL, 3100ms);
+ events.ScheduleEvent(EVENT_MAGE_TOASTY_FIRE, 6s);
+ events.ScheduleEvent(EVENT_MAGE_MELT_ICE, 1s);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if(spell->Id == SPELL_FLASH_FREEZE_TRAPPED_NPC)
+ {
+ events.Reset();
+ events.ScheduleEvent(EVENT_TRY_FREE_HELPER, 2s);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+
+ if( me->HasUnitState(UNIT_STATE_CASTING) )
+ return;
+
+ switch( events.ExecuteEvent() )
+ {
+ case 0:
+ break;
+ case EVENT_TRY_FREE_HELPER:
+ {
+ if( !me->HasAura(SPELL_FLASH_FREEZE_TRAPPED_NPC) )
+ if( pInstance )
+ if( ObjectGuid g = pInstance->GetGuidData(TYPE_HODIR) )
+ if( Creature* hodir = ObjectAccessor::GetCreature(*me, g) )
+ {
+ AttackStart(hodir);
+ ScheduleAbilities();
+ break;
+ }
+ events.Repeat(2s);
+ }
+ break;
+ case EVENT_MAGE_FIREBALL:
+ if (Unit* victim = me->GetVictim())
+ me->CastSpell(victim, SPELL_MAGE_FIREBALL, false);
+ events.Repeat(3100ms);
+ break;
+ case EVENT_MAGE_TOASTY_FIRE:
+ me->CastSpell(me, SPELL_MAGE_CONJURE_TOASTY_FIRE, false);
+ events.Repeat(10s);
+ break;
+ case EVENT_MAGE_MELT_ICE:
+ {
+ std::list FB;
+ bool found = false;
+ me->GetCreaturesWithEntryInRange(FB, 150.0f, NPC_FLASH_FREEZE_NPC);
+ for( std::list::const_iterator itr = FB.begin(); itr != FB.end(); ++itr )
+ if( !((*itr)->HasAura(SPELL_MAGE_MELT_ICE)) )
+ {
+ me->CastSpell((*itr), SPELL_MAGE_MELT_ICE, false);
+ found = true;
+ break;
+ }
+
+ if( found )
+ {
+ events.DelayEvents(2s);
+ events.Repeat(2s);
+ break;
+ }
+ events.Repeat(5s);
+ }
+ break;
+ }
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+
+ void EnterEvadeMode(EvadeReason /*why*/) override {}
+ bool CanAIAttack(Unit const* t) const override { return t->GetEntry() == NPC_HODIR; }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (pInstance)
+ if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR)))
+ hodir->AI()->SetData(4, 1);
+ }
+ };
+};
+
+class spell_hodir_shatter_chest : public SpellScriptLoader
+{
+public:
+ spell_hodir_shatter_chest() : SpellScriptLoader("spell_hodir_shatter_chest") { }
+
+ class spell_hodir_shatter_chestSpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_hodir_shatter_chestSpellScript)
+
+ void destroyWinterCache(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+
+ if (Unit* hodir = GetCaster())
+ hodir->GetAI()->DoAction(EVENT_FAIL_HM);
+ }
+
+ void Register() override
+ {
+ OnEffectHit += SpellEffectFn(spell_hodir_shatter_chestSpellScript::destroyWinterCache, EFFECT_0, SPELL_EFFECT_TRIGGER_MISSILE);
+ };
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_hodir_shatter_chestSpellScript();
+ }
+};
+
+class spell_hodir_biting_cold_main_aura : public SpellScriptLoader
+{
+public:
+ spell_hodir_biting_cold_main_aura() : SpellScriptLoader("spell_hodir_biting_cold_main_aura") { }
+
+ class spell_hodir_biting_cold_main_aura_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hodir_biting_cold_main_aura_AuraScript)
+
+ void HandleEffectPeriodic(AuraEffect const* aurEff)
+ {
+ if ((aurEff->GetTickNumber() % 4) == 0)
+ if (Unit* target = GetTarget())
+ if (target->GetTypeId() == TYPEID_PLAYER
+ && !target->isMoving()
+ && !target->HasAura(SPELL_BITING_COLD_PLAYER_AURA)
+ && !target->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA))
+ target->CastSpell(target, SPELL_BITING_COLD_PLAYER_AURA, true);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_biting_cold_main_aura_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hodir_biting_cold_main_aura_AuraScript();
+ }
+};
+
+class spell_hodir_biting_cold_player_aura : public SpellScriptLoader
+{
+public:
+ spell_hodir_biting_cold_player_aura() : SpellScriptLoader("spell_hodir_biting_cold_player_aura") { }
+
+ class spell_hodir_biting_cold_player_aura_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hodir_biting_cold_player_aura_AuraScript)
+
+ uint8 counter {0};
+ bool prev {false};
+
+ void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ if (Unit* target = GetTarget())
+ {
+ if (target->GetMapId() == 603)
+ SetDuration(GetMaxDuration());
+ if (target->HasAura(SPELL_FLASH_FREEZE_TRAPPED_PLAYER))
+ return;
+ if (target->isMoving() || target->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA))
+ {
+ if (prev)
+ {
+ ModStackAmount(-1);
+ prev = false;
+ }
+ else
+ prev = true;
+
+ if (counter >= 2)
+ counter -= 2;
+ else if (counter)
+ --counter;
+ }
+ else
+ {
+ prev = false;
+ ++counter;
+ if (counter >= 4)
+ {
+ if (GetStackAmount() == 2) // increasing from 2 to 3 (not checking >= to improve performance)
+ if (InstanceScript* pInstance = target->GetInstanceScript())
+ if (Creature* hodir = pInstance->instance->GetCreature(pInstance->GetGuidData(TYPE_HODIR)))
+ hodir->AI()->SetData(2, 1);
+ ModStackAmount(1);
+ counter = 0;
+ }
+ }
+
+ const int32 dmg = 200 * pow(2.0f, GetStackAmount());
+ target->CastCustomSpell(target, SPELL_BITING_COLD_DAMAGE, &dmg, 0, 0, true);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_biting_cold_player_aura_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hodir_biting_cold_player_aura_AuraScript();
+ }
+};
+
+class spell_hodir_periodic_icicle : public SpellScriptLoader
+{
+public:
+ spell_hodir_periodic_icicle() : SpellScriptLoader("spell_hodir_periodic_icicle") { }
+
+ class spell_hodir_periodic_icicle_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_hodir_periodic_icicle_SpellScript);
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove_if(Acore::ObjectTypeIdCheck(TYPEID_PLAYER, false));
+ targets.remove_if(Acore::UnitAuraCheck(true, SPELL_FLASH_FREEZE_TRAPPED_PLAYER));
+ Acore::Containers::RandomResize(targets, 1);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_periodic_icicle_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_hodir_periodic_icicle_SpellScript();
+ }
+};
+
+class FlashFreezeCheck
+{
+public:
+ FlashFreezeCheck() { }
+
+ bool operator()(WorldObject* target) const
+ {
+ if (Unit* unit = target->ToUnit())
+ return unit->HasAura(SPELL_SAFE_AREA_TRIGGERED) || unit->IsPet();
+ return true;
+ }
+};
+
+class spell_hodir_flash_freeze : public SpellScriptLoader
+{
+public:
+ spell_hodir_flash_freeze() : SpellScriptLoader("spell_hodir_flash_freeze") { }
+
+ class spell_hodir_flash_freeze_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_hodir_flash_freeze_SpellScript);
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove_if(FlashFreezeCheck());
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_flash_freeze_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hodir_flash_freeze_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ class spell_hodir_flash_freeze_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hodir_flash_freeze_AuraScript)
+
+ void HandleEffectPeriodic(AuraEffect const* aurEff)
+ {
+ if (aurEff->GetTotalTicks() > 0 && aurEff->GetTickNumber() == uint32(aurEff->GetTotalTicks()) - 1)
+ {
+ Unit* target = GetTarget();
+ Unit* caster = GetCaster();
+ if (!target || !caster || caster->GetTypeId() != TYPEID_UNIT)
+ return;
+
+ if (Aura* aur = target->GetAura(target->GetTypeId() == TYPEID_PLAYER ? SPELL_FLASH_FREEZE_TRAPPED_PLAYER : SPELL_FLASH_FREEZE_TRAPPED_NPC))
+ {
+ if (Unit* caster2 = aur->GetCaster())
+ {
+ if (caster2->GetTypeId() == TYPEID_UNIT)
+ {
+ caster2->ToCreature()->DespawnOrUnsummon();
+ }
+ }
+ target->CastSpell(target, SPELL_FLASH_FREEZE_INSTAKILL, true);
+ return;
+ }
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ {
+ caster->ToCreature()->AI()->SetData(1, 1);
+ if( Creature* c = target->SummonCreature(NPC_FLASH_FREEZE_PLR, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 5 * 60 * 1000) )
+ {
+ c->CastSpell(target, SPELL_FLASH_FREEZE_TRAPPED_PLAYER, true);
+ caster->ToCreature()->AI()->JustSummoned(c);
+ }
+ }
+ else if (target->GetTypeId() == TYPEID_UNIT)
+ {
+ if( Creature* c = target->SummonCreature(NPC_FLASH_FREEZE_NPC, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000) )
+ {
+ c->CastSpell(target, SPELL_FLASH_FREEZE_TRAPPED_NPC, true);
+ caster->ToCreature()->AI()->JustSummoned(c);
+ }
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_flash_freeze_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_hodir_flash_freeze_SpellScript();
+ }
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hodir_flash_freeze_AuraScript();
+ }
+};
+
+class spell_hodir_storm_power : public SpellScriptLoader
+{
+public:
+ spell_hodir_storm_power() : SpellScriptLoader("spell_hodir_storm_power") { }
+
+ class spell_hodir_storm_power_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hodir_storm_power_AuraScript)
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* caster = GetCaster())
+ if (Aura* a = caster->GetAura(GetId() == SPELL_SHAMAN_STORM_POWER_10 ? SPELL_SHAMAN_STORM_CLOUD_10 : SPELL_SHAMAN_STORM_CLOUD_25))
+ a->ModStackAmount(-1);
+ }
+
+ void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* target = GetTarget())
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, GetId(), 0, GetCaster());
+ }
+
+ void Register() override
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_hodir_storm_power_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectApply += AuraEffectApplyFn(spell_hodir_storm_power_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hodir_storm_power_AuraScript();
+ }
+};
+
+class spell_hodir_storm_cloud : public SpellScriptLoader
+{
+public:
+ spell_hodir_storm_cloud() : SpellScriptLoader("spell_hodir_storm_cloud") { }
+
+ class spell_hodir_storm_cloud_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hodir_storm_cloud_AuraScript)
+
+ void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ PreventDefaultAction();
+ if (Unit* target = GetTarget())
+ target->CastSpell((Unit*)nullptr, (GetId() == SPELL_SHAMAN_STORM_CLOUD_10 ? SPELL_SHAMAN_STORM_POWER_10 : SPELL_SHAMAN_STORM_POWER_25), true);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_hodir_storm_cloud_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hodir_storm_cloud_AuraScript();
+ }
+};
+
+class achievement_cheese_the_freeze : public AchievementCriteriaScript
+{
+public:
+ achievement_cheese_the_freeze() : AchievementCriteriaScript("achievement_cheese_the_freeze") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1);
+ }
+};
+
+class achievement_getting_cold_in_here : public AchievementCriteriaScript
+{
+public:
+ achievement_getting_cold_in_here() : AchievementCriteriaScript("achievement_getting_cold_in_here") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(2);
+ }
+};
+
+class achievement_i_could_say_that_this_cache_was_rare : public AchievementCriteriaScript
+{
+public:
+ achievement_i_could_say_that_this_cache_was_rare() : AchievementCriteriaScript("achievement_i_could_say_that_this_cache_was_rare") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(3);
+ }
+};
+
+class achievement_i_have_the_coolest_friends : public AchievementCriteriaScript
+{
+public:
+ achievement_i_have_the_coolest_friends() : AchievementCriteriaScript("achievement_i_have_the_coolest_friends") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_HODIR && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(4);
+ }
+};
+
+class achievement_staying_buffed_all_winter_10 : public AchievementCriteriaScript
+{
+public:
+ achievement_staying_buffed_all_winter_10() : AchievementCriteriaScript("achievement_staying_buffed_all_winter_10") {}
+
+ bool OnCheck(Player* player, Unit* /*target*/, uint32 /*criteria_id*/) override
+ {
+ return player && player->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA) && player->HasAura(SPELL_DRUID_STARLIGHT_AREA_AURA) && player->HasAura(SPELL_SHAMAN_STORM_POWER_10);
+ }
+};
+
+class achievement_staying_buffed_all_winter_25 : public AchievementCriteriaScript
+{
+public:
+ achievement_staying_buffed_all_winter_25() : AchievementCriteriaScript("achievement_staying_buffed_all_winter_25") {}
+
+ bool OnCheck(Player* player, Unit* /*target*/, uint32 /*criteria_id*/) override
+ {
+ return player && player->HasAura(SPELL_MAGE_TOASTY_FIRE_AURA) && player->HasAura(SPELL_DRUID_STARLIGHT_AREA_AURA) && player->HasAura(SPELL_SHAMAN_STORM_POWER_25);
+ }
+};
+
+class spell_hodir_toasty_fire : public SpellScriptLoader
+{
+public:
+ spell_hodir_toasty_fire() : SpellScriptLoader("spell_hodir_toasty_fire") { }
+
+ class spell_hodir_toasty_fire_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hodir_toasty_fire_AuraScript);
+
+ void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* target = GetTarget())
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, SPELL_MAGE_TOASTY_FIRE_AURA, 0, GetCaster());
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_hodir_toasty_fire_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MOD_STAT, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hodir_toasty_fire_AuraScript();
+ }
+};
+
+class spell_hodir_starlight : public SpellScriptLoader
+{
+public:
+ spell_hodir_starlight() : SpellScriptLoader("spell_hodir_starlight") { }
+
+ class spell_hodir_starlight_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hodir_starlight_AuraScript);
+
+ void HandleAfterEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* target = GetTarget())
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ target->ToPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, SPELL_DRUID_STARLIGHT_AREA_AURA, 0, GetCaster());
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_hodir_starlight_AuraScript::HandleAfterEffectApply, EFFECT_0, SPELL_AURA_MELEE_SLOW, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_hodir_starlight_AuraScript();
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp
index e7e21fa99ec91a..cf2d90a09cba15 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_ignis.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "GameTime.h"
@@ -27,527 +28,6 @@
#include "Vehicle.h"
#include "ulduar.h"
-#define SPELL_FLAME_JETS_10 62680
-#define SPELL_FLAME_JETS_25 63472
-#define S_FLAME_JETS RAID_MODE(SPELL_FLAME_JETS_10, SPELL_FLAME_JETS_25)
-#define SPELL_SCORCH_10 62546
-#define SPELL_SCORCH_25 63474
-#define S_SCORCH RAID_MODE(SPELL_SCORCH_10, SPELL_SCORCH_25)
-#define SPELL_ACTIVATE_CONSTRUCT 62488
-#define SPELL_STRENGTH_OF_THE_CREATOR 64473
-#define SPELL_SLAG_POT_10 62717
-#define SPELL_SLAG_POT_25 63477
-#define S_SLAG_POT RAID_MODE(SPELL_SLAG_POT_10, SPELL_SLAG_POT_25)
-#define SPELL_BERSERK 64238
-#define SPELL_GRAB 62707
-#define SPELL_GRAB_TRIGGERED 62708
-#define SPELL_GRAB_CONTROL_2 62711
-
-#define SPELL_SCORCHED_GROUND_10 62548
-#define SPELL_SCORCHED_GROUND_25 63476
-#define S_SCORCHED_GROUND RAID_MODE(SPELL_SCORCHED_GROUND_10, SPELL_SCORCHED_GROUND_25)
-#define SPELL_HEAT_AREA 62343
-#define SPELL_HEAT_BUFF 65667
-#define SPELL_MOLTEN 62373
-#define SPELL_BRITTLE_10 62382
-#define SPELL_BRITTLE_25 67114
-#define S_BRITTLE RAID_MODE(SPELL_BRITTLE_10, SPELL_BRITTLE_25)
-#define SPELL_SHATTER 62383
-
-#define BOSS_IGNIS 33118
-#define NPC_IRON_CONSTRUCT 33121
-#define NPC_SCORCHED_GROUND 33123
-#define NPC_WATER_TRIGGER 22515
-
-enum Texts
-{
- SAY_AGGRO = 0,
- SAY_SUMMON = 1,
- SAY_SLAG_POT = 2,
- SAY_SCORCH = 3,
- SAY_SLAY = 4,
- SAY_BERSERK = 5,
- SAY_DEATH = 6,
- EMOTE_JETS = 7,
-};
-
-#define ACHIEV_STOKIN_THE_FURNACE_EVENT 20951
-
-enum eEvents
-{
- EVENT_NONE = 0,
- EVENT_ACTIVATE_CONSTRUCT,
- EVENT_SPELL_SCORCH,
- EVENT_ENABLE_ROTATE,
- EVENT_SPELL_FLAME_JETS,
- EVENT_GRAB,
-};
-
-class npc_ulduar_iron_construct : public CreatureScript
-{
-public:
- npc_ulduar_iron_construct() : CreatureScript("npc_ulduar_iron_construct") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_iron_constructAI : public ScriptedAI
- {
- npc_ulduar_iron_constructAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- me->CastSpell(me, 38757, true);
- }
-
- uint16 timer;
-
- void Reset() override
- {
- timer = 1000;
- me->SetReactState(REACT_PASSIVE);
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- }
-
- void JustReachedHome() override
- {
- me->CastSpell(me, 38757, true);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if (spell->Id == SPELL_ACTIVATE_CONSTRUCT)
- {
- me->RemoveAura(38757);
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->SetReactState(REACT_AGGRESSIVE);
- if (InstanceScript* instance = me->GetInstanceScript())
- if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS)))
- {
- ignis->CastSpell(ignis, SPELL_STRENGTH_OF_THE_CREATOR, true);
- AttackStart(ignis->GetVictim());
- DoZoneInCombat();
- }
- }
- else if (spell->Id == SPELL_HEAT_BUFF)
- {
- if (Aura* heat = me->GetAura(SPELL_HEAT_BUFF))
- {
- if (heat->GetStackAmount() >= 10)
- {
- if (heat->GetStackAmount() > 10)
- {
- heat->ModStackAmount(-1);
- }
- me->CastSpell(me, SPELL_MOLTEN, true);
- me->GetThreatMgr().ResetAllThreat();
- }
- }
- }
- }
-
- void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if( damage >= RAID_MODE(3000U, 5000U) && me->GetAura(S_BRITTLE) )
- {
- me->CastSpell(me, SPELL_SHATTER, true);
- Unit::Kill(attacker, me);
-
- if (InstanceScript* instance = me->GetInstanceScript())
- if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS)))
- ignis->AI()->SetData(1337, 0);
- }
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- if (InstanceScript* instance = me->GetInstanceScript())
- if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS)))
- ignis->RemoveAuraFromStack(SPELL_STRENGTH_OF_THE_CREATOR);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- if (timer <= diff)
- {
- timer = 1000;
- if (Aura* a = me->GetAura(SPELL_MOLTEN))
- if (me->FindNearestCreature(NPC_WATER_TRIGGER, 18.0f, true))
- {
- me->RemoveAura(a);
- me->CastSpell(me, S_BRITTLE, true);
- }
- }
- else
- timer -= diff;
-
- DoMeleeAttackIfReady();
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override {}
- };
-};
-
-class boss_ignis : public CreatureScript
-{
-public:
- boss_ignis() : CreatureScript("boss_ignis") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_ignisAI : public ScriptedAI
- {
- boss_ignisAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- EventMap events;
- uint8 counter;
- bool bShattered;
- uint32 lastShatterMSTime;
-
- void Reset() override
- {
- events.Reset();
- me->SetControlled(false, UNIT_STATE_ROOT);
- me->DisableRotate(false);
- counter = 0;
- bShattered = false;
- lastShatterMSTime = 0;
-
- if( InstanceScript* m_pInstance = me->GetInstanceScript() )
- {
- m_pInstance->SetData(TYPE_IGNIS, NOT_STARTED);
- m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT);
- }
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- me->setActive(true);
-
- std::list icl;
- me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT);
- for( std::list::iterator itr = icl.begin(); itr != icl.end(); ++itr )
- {
- if (!(*itr)->IsAlive())
- {
- (*itr)->Respawn();
- (*itr)->UpdatePosition((*itr)->GetHomePosition(), true);
- (*itr)->StopMovingOnCurrentPos();
- }
- (*itr)->AI()->Reset();
- if (!(*itr)->HasAura(38757))
- (*itr)->CastSpell((*itr), 38757, true);
- }
-
- bShattered = false;
- lastShatterMSTime = 0;
- events.Reset();
- events.ScheduleEvent(EVENT_ACTIVATE_CONSTRUCT, RAID_MODE(40000, 30000));
- events.ScheduleEvent(EVENT_SPELL_SCORCH, 10s);
- events.ScheduleEvent(EVENT_SPELL_FLAME_JETS, 32s);
- events.ScheduleEvent(EVENT_GRAB, 25s);
-
- Talk(SAY_AGGRO);
- DoZoneInCombat();
-
- if( InstanceScript* m_pInstance = me->GetInstanceScript() )
- {
- m_pInstance->SetData(TYPE_IGNIS, IN_PROGRESS);
- m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT);
- m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT);
- }
- }
-
- void SetData(uint32 id, uint32 /*value*/) override
- {
- if (id == 1337)
- {
- if (lastShatterMSTime)
- if (getMSTimeDiff(lastShatterMSTime, GameTime::GetGameTimeMS().count()) <= 5000)
- bShattered = true;
-
- lastShatterMSTime = GameTime::GetGameTimeMS().count();
- }
- }
-
- uint32 GetData(uint32 id) const override
- {
- if (id == 1337)
- return (bShattered ? 1 : 0);
- return 0;
- }
-
- void JustReachedHome() override
- {
- me->setActive(false);
- }
-
- void KilledUnit(Unit* victim) override
- {
- if (victim->GetTypeId() == TYPEID_PLAYER)
- Talk(SAY_SLAY);
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- Talk(SAY_DEATH);
-
- if( me->GetInstanceScript() )
- me->GetInstanceScript()->SetData(TYPE_IGNIS, DONE);
-
- std::list icl;
- me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT);
- for( std::list::iterator itr = icl.begin(); itr != icl.end(); ++itr )
- if ((*itr)->IsAlive() && (*itr)->IsInCombat())
- Unit::Kill(*itr, *itr);
- }
-
- void SpellHit(Unit* caster, SpellInfo const* spell) override
- {
- if (caster && spell->Id == SPELL_GRAB_CONTROL_2)
- {
- //caster->ClearUnitState(UNIT_STATE_ONVEHICLE);
- me->CastSpell(caster, S_SLAG_POT, true);
- }
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override {}
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- if( me->GetPositionX() < 490.0f || me->GetPositionX() > 690.0f || me->GetPositionY() < 130.0f || me->GetPositionY() > 410.0f )
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
-
- events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case 0:
- break;
- case EVENT_ACTIVATE_CONSTRUCT:
- Talk(SAY_SUMMON);
- me->CastCustomSpell(SPELL_ACTIVATE_CONSTRUCT, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false);
- if (++counter >= 20)
- {
- Talk(SAY_BERSERK);
- me->CastSpell(me, SPELL_BERSERK, true);
- break;
- }
- events.RepeatEvent(RAID_MODE(40000, 30000));
- break;
- case EVENT_SPELL_SCORCH:
- Talk(SAY_SCORCH);
- me->SetControlled(true, UNIT_STATE_ROOT);
- me->DisableRotate(true);
- me->SendMovementFlagUpdate();
- me->CastSpell(me->GetVictim(), S_SCORCH, false);
- events.Repeat(20s);
- events.RescheduleEvent(EVENT_ENABLE_ROTATE, 3s);
- break;
- case EVENT_ENABLE_ROTATE:
- me->SetControlled(false, UNIT_STATE_ROOT);
- me->DisableRotate(false);
- break;
- case EVENT_SPELL_FLAME_JETS:
- Talk(EMOTE_JETS);
- me->CastSpell(me->GetVictim(), S_FLAME_JETS, false);
- events.Repeat(25s);
- break;
- case EVENT_GRAB:
- {
- std::list icl;
- me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT);
-
- GuidVector playerGUIDs;
- Map::PlayerList const& pl = me->GetMap()->GetPlayers();
- Player* temp = nullptr;
-
- for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
- {
- temp = itr->GetSource();
- if( !temp->IsAlive() || temp->GetExactDist2d(me) > 90.0f )
- continue;
- if( me->GetVictim() && temp->GetGUID() == me->GetVictim()->GetGUID() )
- continue;
- bool found = false;
- for (std::list::iterator iterator = icl.begin(); iterator != icl.end(); ++iterator)
- {
- if ((*iterator)->GetVictim() && (*iterator)->GetVictim()->GetGUID() == temp->GetGUID())
- {
- found = true;
- break;
- }
- }
-
- if( !found )
- playerGUIDs.push_back(temp->GetGUID());
- }
-
- if( !playerGUIDs.empty() )
- {
- int8 pos = urand(0, playerGUIDs.size() - 1);
- if( Player* pTarget = ObjectAccessor::GetPlayer(*me, playerGUIDs.at(pos)) )
- {
- Talk(SAY_SLAG_POT);
- me->CastSpell(pTarget, SPELL_GRAB, false);
- }
- }
-
- events.Repeat(24s);
- events.DelayEvents(6s);
- }
- break;
- }
-
- DoMeleeAttackIfReady();
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- me->SetControlled(false, UNIT_STATE_ROOT);
- me->DisableRotate(false);
- ScriptedAI::EnterEvadeMode(why);
- }
- };
-};
-
-class spell_ignis_scorch : public SpellScriptLoader
-{
-public:
- spell_ignis_scorch() : SpellScriptLoader("spell_ignis_scorch") { }
-
- class spell_ignis_scorch_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_ignis_scorch_AuraScript)
-
- void HandleEffectPeriodic(AuraEffect const* aurEff)
- {
- if (aurEff->GetTotalTicks() >= 0 && aurEff->GetTickNumber() == uint32(aurEff->GetTotalTicks()))
- if (Unit* c = GetCaster())
- if (Creature* s = c->SummonCreature(NPC_SCORCHED_GROUND, c->GetPositionX() + 20.0f * cos(c->GetOrientation()), c->GetPositionY() + 20.0f * std::sin(c->GetOrientation()), 361.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000))
- {
- if (!s->FindNearestCreature(NPC_WATER_TRIGGER, 25.0f, true)) // must be away from the water
- s->CastSpell(s, (aurEff->GetId() == 62546 ? SPELL_SCORCHED_GROUND_10 : SPELL_SCORCHED_GROUND_25), true);
- }
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_ignis_scorch_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_ignis_scorch_AuraScript();
- }
-};
-
-class spell_ignis_grab_initial : public SpellScriptLoader
-{
-public:
- spell_ignis_grab_initial() : SpellScriptLoader("spell_ignis_grab_initial") { }
-
- class spell_ignis_grab_initial_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_ignis_grab_initial_SpellScript);
-
- void HandleScript(SpellEffIndex /*effIndex*/)
- {
- if (Unit* t = GetHitUnit())
- t->CastSpell(t, SPELL_GRAB_TRIGGERED, true);
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_ignis_grab_initial_SpellScript::HandleScript, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_ignis_grab_initial_SpellScript();
- }
-};
-
-class spell_ignis_slag_pot : public SpellScriptLoader
-{
-public:
- spell_ignis_slag_pot() : SpellScriptLoader("spell_ignis_slag_pot") { }
-
- class spell_ignis_slag_pot_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_ignis_slag_pot_AuraScript)
-
- void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
- {
- if (Unit* c = GetCaster())
- if (Unit* t = GetTarget())
- c->CastSpell(t, (GetId() == 62717 ? 65722 : 65723), true);
- }
-
- void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* t = GetTarget())
- {
- t->ApplySpellImmune(GetId(), IMMUNITY_ID, 62549, true);
- t->ApplySpellImmune(GetId(), IMMUNITY_ID, 63475, true);
- }
- }
-
- void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (Unit* t = GetTarget())
- {
- t->ApplySpellImmune(GetId(), IMMUNITY_ID, 62549, false);
- t->ApplySpellImmune(GetId(), IMMUNITY_ID, 63475, false);
- if (t->IsAlive())
- t->CastSpell(t, (GetId() == 62717 ? 62836 : 63536), true);
- }
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_ignis_slag_pot_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
- OnEffectApply += AuraEffectApplyFn(spell_ignis_slag_pot_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
- AfterEffectRemove += AuraEffectRemoveFn(spell_ignis_slag_pot_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_ignis_slag_pot_AuraScript();
- }
-};
-
-class achievement_ignis_shattered : public AchievementCriteriaScript
-{
-public:
- achievement_ignis_shattered() : AchievementCriteriaScript("achievement_ignis_shattered") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- if (!target || target->GetTypeId() != TYPEID_UNIT)
- return false;
- return !!target->ToCreature()->AI()->GetData(1337);
- }
-};
-
void AddSC_boss_ignis()
{
new boss_ignis();
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.h
new file mode 100644
index 00000000000000..23aca7f8102efa
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.h
@@ -0,0 +1,537 @@
+#ifndef BOSS_IGNIS_H_
+#define BOSS_IGNIS_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "GameTime.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "SpellAuraEffects.h"
+#include "SpellAuras.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "Vehicle.h"
+#include "ulduar.h"
+
+#define SPELL_FLAME_JETS_10 62680
+#define SPELL_FLAME_JETS_25 63472
+#define S_FLAME_JETS RAID_MODE(SPELL_FLAME_JETS_10, SPELL_FLAME_JETS_25)
+#define SPELL_SCORCH_10 62546
+#define SPELL_SCORCH_25 63474
+#define S_SCORCH RAID_MODE(SPELL_SCORCH_10, SPELL_SCORCH_25)
+#define SPELL_ACTIVATE_CONSTRUCT 62488
+#define SPELL_STRENGTH_OF_THE_CREATOR 64473
+#define SPELL_SLAG_POT_10 62717
+#define SPELL_SLAG_POT_25 63477
+#define S_SLAG_POT RAID_MODE(SPELL_SLAG_POT_10, SPELL_SLAG_POT_25)
+#define SPELL_BERSERK 64238
+#define SPELL_GRAB 62707
+#define SPELL_GRAB_TRIGGERED 62708
+#define SPELL_GRAB_CONTROL_2 62711
+
+#define SPELL_SCORCHED_GROUND_10 62548
+#define SPELL_SCORCHED_GROUND_25 63476
+#define S_SCORCHED_GROUND RAID_MODE(SPELL_SCORCHED_GROUND_10, SPELL_SCORCHED_GROUND_25)
+#define SPELL_HEAT_AREA 62343
+#define SPELL_HEAT_BUFF 65667
+#define SPELL_MOLTEN 62373
+#define SPELL_BRITTLE_10 62382
+#define SPELL_BRITTLE_25 67114
+#define S_BRITTLE RAID_MODE(SPELL_BRITTLE_10, SPELL_BRITTLE_25)
+#define SPELL_SHATTER 62383
+
+#define BOSS_IGNIS 33118
+#define NPC_IRON_CONSTRUCT 33121
+#define NPC_SCORCHED_GROUND 33123
+#define NPC_WATER_TRIGGER 22515
+
+enum Texts
+{
+ SAY_AGGRO = 0,
+ SAY_SUMMON = 1,
+ SAY_SLAG_POT = 2,
+ SAY_SCORCH = 3,
+ SAY_SLAY = 4,
+ SAY_BERSERK = 5,
+ SAY_DEATH = 6,
+ EMOTE_JETS = 7,
+};
+
+#define ACHIEV_STOKIN_THE_FURNACE_EVENT 20951
+
+enum eEvents
+{
+ EVENT_NONE = 0,
+ EVENT_ACTIVATE_CONSTRUCT,
+ EVENT_SPELL_SCORCH,
+ EVENT_ENABLE_ROTATE,
+ EVENT_SPELL_FLAME_JETS,
+ EVENT_GRAB,
+};
+
+class npc_ulduar_iron_construct : public CreatureScript
+{
+public:
+ npc_ulduar_iron_construct() : CreatureScript("npc_ulduar_iron_construct") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_iron_constructAI : public ScriptedAI
+ {
+ npc_ulduar_iron_constructAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ me->CastSpell(me, 38757, true);
+ }
+
+ uint16 timer;
+
+ void Reset() override
+ {
+ timer = 1000;
+ me->SetReactState(REACT_PASSIVE);
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ }
+
+ void JustReachedHome() override
+ {
+ me->CastSpell(me, 38757, true);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_ACTIVATE_CONSTRUCT)
+ {
+ me->RemoveAura(38757);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ if (InstanceScript* instance = me->GetInstanceScript())
+ if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS)))
+ {
+ ignis->CastSpell(ignis, SPELL_STRENGTH_OF_THE_CREATOR, true);
+ AttackStart(ignis->GetVictim());
+ DoZoneInCombat();
+ }
+ }
+ else if (spell->Id == SPELL_HEAT_BUFF)
+ {
+ if (Aura* heat = me->GetAura(SPELL_HEAT_BUFF))
+ {
+ if (heat->GetStackAmount() >= 10)
+ {
+ if (heat->GetStackAmount() > 10)
+ {
+ heat->ModStackAmount(-1);
+ }
+ me->CastSpell(me, SPELL_MOLTEN, true);
+ me->GetThreatMgr().ResetAllThreat();
+ }
+ }
+ }
+ }
+
+ void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if( damage >= RAID_MODE(3000U, 5000U) && me->GetAura(S_BRITTLE) )
+ {
+ me->CastSpell(me, SPELL_SHATTER, true);
+ Unit::Kill(attacker, me);
+
+ if (InstanceScript* instance = me->GetInstanceScript())
+ if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS)))
+ ignis->AI()->SetData(1337, 0);
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ if (InstanceScript* instance = me->GetInstanceScript())
+ if (Creature* ignis = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_IGNIS)))
+ ignis->RemoveAuraFromStack(SPELL_STRENGTH_OF_THE_CREATOR);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ if (timer <= diff)
+ {
+ timer = 1000;
+ if (Aura* a = me->GetAura(SPELL_MOLTEN))
+ if (me->FindNearestCreature(NPC_WATER_TRIGGER, 18.0f, true))
+ {
+ me->RemoveAura(a);
+ me->CastSpell(me, S_BRITTLE, true);
+ }
+ }
+ else
+ timer -= diff;
+
+ DoMeleeAttackIfReady();
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+ };
+};
+
+class boss_ignis : public CreatureScript
+{
+public:
+ boss_ignis() : CreatureScript("boss_ignis") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_ignisAI : public ScriptedAI
+ {
+ boss_ignisAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ EventMap events;
+ uint8 counter;
+ bool bShattered;
+ uint32 lastShatterMSTime;
+
+ void Reset() override
+ {
+ events.Reset();
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->DisableRotate(false);
+ counter = 0;
+ bShattered = false;
+ lastShatterMSTime = 0;
+
+ if( InstanceScript* m_pInstance = me->GetInstanceScript() )
+ {
+ m_pInstance->SetData(TYPE_IGNIS, NOT_STARTED);
+ m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT);
+ }
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ me->setActive(true);
+
+ std::list icl;
+ me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT);
+ for( std::list::iterator itr = icl.begin(); itr != icl.end(); ++itr )
+ {
+ if (!(*itr)->IsAlive())
+ {
+ (*itr)->Respawn();
+ (*itr)->UpdatePosition((*itr)->GetHomePosition(), true);
+ (*itr)->StopMovingOnCurrentPos();
+ }
+ (*itr)->AI()->Reset();
+ if (!(*itr)->HasAura(38757))
+ (*itr)->CastSpell((*itr), 38757, true);
+ }
+
+ bShattered = false;
+ lastShatterMSTime = 0;
+ events.Reset();
+ events.ScheduleEvent(EVENT_ACTIVATE_CONSTRUCT, RAID_MODE(40000, 30000));
+ events.ScheduleEvent(EVENT_SPELL_SCORCH, 10s);
+ events.ScheduleEvent(EVENT_SPELL_FLAME_JETS, 32s);
+ events.ScheduleEvent(EVENT_GRAB, 25s);
+
+ Talk(SAY_AGGRO);
+ DoZoneInCombat();
+
+ if( InstanceScript* m_pInstance = me->GetInstanceScript() )
+ {
+ m_pInstance->SetData(TYPE_IGNIS, IN_PROGRESS);
+ m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT);
+ m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_STOKIN_THE_FURNACE_EVENT);
+ }
+ }
+
+ void SetData(uint32 id, uint32 /*value*/) override
+ {
+ if (id == 1337)
+ {
+ if (lastShatterMSTime)
+ if (getMSTimeDiff(lastShatterMSTime, GameTime::GetGameTimeMS().count()) <= 5000)
+ bShattered = true;
+
+ lastShatterMSTime = GameTime::GetGameTimeMS().count();
+ }
+ }
+
+ uint32 GetData(uint32 id) const override
+ {
+ if (id == 1337)
+ return (bShattered ? 1 : 0);
+ return 0;
+ }
+
+ void JustReachedHome() override
+ {
+ me->setActive(false);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ Talk(SAY_DEATH);
+
+ if( me->GetInstanceScript() )
+ me->GetInstanceScript()->SetData(TYPE_IGNIS, DONE);
+
+ std::list icl;
+ me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT);
+ for( std::list::iterator itr = icl.begin(); itr != icl.end(); ++itr )
+ if ((*itr)->IsAlive() && (*itr)->IsInCombat())
+ Unit::Kill(*itr, *itr);
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ if (caster && spell->Id == SPELL_GRAB_CONTROL_2)
+ {
+ //caster->ClearUnitState(UNIT_STATE_ONVEHICLE);
+ me->CastSpell(caster, S_SLAG_POT, true);
+ }
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ if( me->GetPositionX() < 490.0f || me->GetPositionX() > 690.0f || me->GetPositionY() < 130.0f || me->GetPositionY() > 410.0f )
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case 0:
+ break;
+ case EVENT_ACTIVATE_CONSTRUCT:
+ Talk(SAY_SUMMON);
+ me->CastCustomSpell(SPELL_ACTIVATE_CONSTRUCT, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false);
+ if (++counter >= 20)
+ {
+ Talk(SAY_BERSERK);
+ me->CastSpell(me, SPELL_BERSERK, true);
+ break;
+ }
+ events.RepeatEvent(RAID_MODE(40000, 30000));
+ break;
+ case EVENT_SPELL_SCORCH:
+ Talk(SAY_SCORCH);
+ me->SetControlled(true, UNIT_STATE_ROOT);
+ me->DisableRotate(true);
+ me->SendMovementFlagUpdate();
+ me->CastSpell(me->GetVictim(), S_SCORCH, false);
+ events.Repeat(20s);
+ events.RescheduleEvent(EVENT_ENABLE_ROTATE, 3s);
+ break;
+ case EVENT_ENABLE_ROTATE:
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->DisableRotate(false);
+ break;
+ case EVENT_SPELL_FLAME_JETS:
+ Talk(EMOTE_JETS);
+ me->CastSpell(me->GetVictim(), S_FLAME_JETS, false);
+ events.Repeat(25s);
+ break;
+ case EVENT_GRAB:
+ {
+ std::list icl;
+ me->GetCreaturesWithEntryInRange(icl, 300.0f, NPC_IRON_CONSTRUCT);
+
+ GuidVector playerGUIDs;
+ Map::PlayerList const& pl = me->GetMap()->GetPlayers();
+ Player* temp = nullptr;
+
+ for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
+ {
+ temp = itr->GetSource();
+ if( !temp->IsAlive() || temp->GetExactDist2d(me) > 90.0f )
+ continue;
+ if( me->GetVictim() && temp->GetGUID() == me->GetVictim()->GetGUID() )
+ continue;
+ bool found = false;
+ for (std::list::iterator iterator = icl.begin(); iterator != icl.end(); ++iterator)
+ {
+ if ((*iterator)->GetVictim() && (*iterator)->GetVictim()->GetGUID() == temp->GetGUID())
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if( !found )
+ playerGUIDs.push_back(temp->GetGUID());
+ }
+
+ if( !playerGUIDs.empty() )
+ {
+ int8 pos = urand(0, playerGUIDs.size() - 1);
+ if( Player* pTarget = ObjectAccessor::GetPlayer(*me, playerGUIDs.at(pos)) )
+ {
+ Talk(SAY_SLAG_POT);
+ me->CastSpell(pTarget, SPELL_GRAB, false);
+ }
+ }
+
+ events.Repeat(24s);
+ events.DelayEvents(6s);
+ }
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->DisableRotate(false);
+ ScriptedAI::EnterEvadeMode(why);
+ }
+ };
+};
+
+class spell_ignis_scorch : public SpellScriptLoader
+{
+public:
+ spell_ignis_scorch() : SpellScriptLoader("spell_ignis_scorch") { }
+
+ class spell_ignis_scorch_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_ignis_scorch_AuraScript)
+
+ void HandleEffectPeriodic(AuraEffect const* aurEff)
+ {
+ if (aurEff->GetTotalTicks() >= 0 && aurEff->GetTickNumber() == uint32(aurEff->GetTotalTicks()))
+ if (Unit* c = GetCaster())
+ if (Creature* s = c->SummonCreature(NPC_SCORCHED_GROUND, c->GetPositionX() + 20.0f * cos(c->GetOrientation()), c->GetPositionY() + 20.0f * std::sin(c->GetOrientation()), 361.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000))
+ {
+ if (!s->FindNearestCreature(NPC_WATER_TRIGGER, 25.0f, true)) // must be away from the water
+ s->CastSpell(s, (aurEff->GetId() == 62546 ? SPELL_SCORCHED_GROUND_10 : SPELL_SCORCHED_GROUND_25), true);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_ignis_scorch_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_ignis_scorch_AuraScript();
+ }
+};
+
+class spell_ignis_grab_initial : public SpellScriptLoader
+{
+public:
+ spell_ignis_grab_initial() : SpellScriptLoader("spell_ignis_grab_initial") { }
+
+ class spell_ignis_grab_initial_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_ignis_grab_initial_SpellScript);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ if (Unit* t = GetHitUnit())
+ t->CastSpell(t, SPELL_GRAB_TRIGGERED, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_ignis_grab_initial_SpellScript::HandleScript, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_ignis_grab_initial_SpellScript();
+ }
+};
+
+class spell_ignis_slag_pot : public SpellScriptLoader
+{
+public:
+ spell_ignis_slag_pot() : SpellScriptLoader("spell_ignis_slag_pot") { }
+
+ class spell_ignis_slag_pot_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_ignis_slag_pot_AuraScript)
+
+ void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ if (Unit* c = GetCaster())
+ if (Unit* t = GetTarget())
+ c->CastSpell(t, (GetId() == 62717 ? 65722 : 65723), true);
+ }
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* t = GetTarget())
+ {
+ t->ApplySpellImmune(GetId(), IMMUNITY_ID, 62549, true);
+ t->ApplySpellImmune(GetId(), IMMUNITY_ID, 63475, true);
+ }
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Unit* t = GetTarget())
+ {
+ t->ApplySpellImmune(GetId(), IMMUNITY_ID, 62549, false);
+ t->ApplySpellImmune(GetId(), IMMUNITY_ID, 63475, false);
+ if (t->IsAlive())
+ t->CastSpell(t, (GetId() == 62717 ? 62836 : 63536), true);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_ignis_slag_pot_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ OnEffectApply += AuraEffectApplyFn(spell_ignis_slag_pot_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_ignis_slag_pot_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_ignis_slag_pot_AuraScript();
+ }
+};
+
+class achievement_ignis_shattered : public AchievementCriteriaScript
+{
+public:
+ achievement_ignis_shattered() : AchievementCriteriaScript("achievement_ignis_shattered") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ if (!target || target->GetTypeId() != TYPEID_UNIT)
+ return false;
+ return !!target->ToCreature()->AI()->GetData(1337);
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp
index 6af801f5439721..7a4354e307e449 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_kologarn.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "PassiveAI.h"
@@ -26,867 +27,6 @@
#include "Vehicle.h"
#include "ulduar.h"
-enum KologarnSays
-{
- SAY_AGGRO = 0,
- SAY_SLAY = 1,
- SAY_LEFT_ARM_GONE = 2,
- SAY_RIGHT_ARM_GONE = 3,
- SAY_SHOCKWAVE = 4,
- SAY_GRAB_PLAYER = 5,
- SAY_DEATH = 6,
- SAY_BERSERK = 7,
- EMOTE_STONE_GRIP = 8,
- EMOTE_EYES = 9
-};
-
-enum KologarnSpells
-{
- SPELL_KOLOGARN_REDUCE_PARRY = 64651,
-
- // BASIC
- SPELL_OVERHEAD_SMASH_10 = 63356,
- SPELL_OVERHEAD_SMASH_25 = 64003,
- SPELL_ONEARMED_OVERHEAD_SMASH_10 = 63573,
- SPELL_ONEARMED_OVERHEAD_SMASH_25 = 64006,
- SPELL_PETRIFYING_BREATH_10 = 62030,
- SPELL_PETRIFYING_BREATH_25 = 63980,
- SPELL_STONE_SHOUT_10 = 63716,
- SPELL_STONE_SHOUT_25 = 64005,
-
- // EYEBEAM
- SPELL_FOCUSED_EYEBEAM_SUMMON = 63342,
- SPELL_FOCUSED_EYEBEAM_10 = 63347,
- SPELL_FOCUSED_EYEBEAM_25 = 63977,
- SPELL_FOCUSED_EYEBEAM_RIGHT = 63702,
- SPELL_FOCUSED_EYEBEAM_LEFT = 63676,
-
- // ARMS
- SPELL_ARM_DEAD_10 = 63629,
- SPELL_ARM_DEAD_25 = 63979,
- SPELL_RUBBLE_FALL_10 = 63821,
- SPELL_RUBBLE_FALL_25 = 64001,
- SPELL_ARM_RESPAWN_VISUAL = 64753,
-
- // LEFT ARM
- SPELL_ARM_SWEEP_10 = 63766,
- SPELL_ARM_SWEEP_25 = 63983,
-
- // RIGHT ARM
- SPELL_STONE_GRIP_10 = 62166,
- SPELL_STONE_GRIP_25 = 63981,
- SPELL_RIDE_RIGHT_ARM_10 = 62056,
- SPELL_RIDE_RIGHT_ARM_25 = 63985,
-
- // RUBBLE TRASH
- SPELL_RUBBLE_ATTACK_10 = 63818,
- SPELL_RUBBLE_ATTACK_25 = 63978,
-};
-
-#define SPELL_PETRIFYING_BREATH RAID_MODE(SPELL_PETRIFYING_BREATH_10, SPELL_PETRIFYING_BREATH_25)
-#define SPELL_OVERHEAD_SMASH RAID_MODE(SPELL_OVERHEAD_SMASH_10, SPELL_OVERHEAD_SMASH_25)
-#define SPELL_ONEARMED_OVERHEAD_SMASH RAID_MODE(SPELL_ONEARMED_OVERHEAD_SMASH_10, SPELL_ONEARMED_OVERHEAD_SMASH_25)
-#define SPELL_ARM_DEAD RAID_MODE(SPELL_ARM_DEAD_10, SPELL_ARM_DEAD_25)
-#define SPELL_ARM_SWEEP RAID_MODE(SPELL_ARM_SWEEP_10, SPELL_ARM_SWEEP_25)
-#define SPELL_STONE_GRIP RAID_MODE(SPELL_STONE_GRIP_10, SPELL_STONE_GRIP_25)
-#define SPELL_FOCUSED_EYEBEAM RAID_MODE(SPELL_FOCUSED_EYEBEAM_10, SPELL_FOCUSED_EYEBEAM_25)
-#define SPELL_RUBBLE_FALL RAID_MODE(SPELL_RUBBLE_FALL_10, SPELL_RUBBLE_FALL_25)
-#define SPELL_RUBBLE_ATTACK RAID_MODE(SPELL_RUBBLE_ATTACK_10, SPELL_RUBBLE_ATTACK_25)
-#define SPELL_RIDE_RIGHT_ARM RAID_MODE(SPELL_RIDE_RIGHT_ARM_10, SPELL_RIDE_RIGHT_ARM_25)
-#define SPELL_STONE_SHOUT RAID_MODE(SPELL_STONE_SHOUT_10, SPELL_STONE_SHOUT_25)
-
-enum KologarnEvents
-{
- EVENT_SMASH = 1,
- EVENT_GRIP = 2,
- EVENT_SWEEP = 3,
- EVENT_RESTORE_ARM_LEFT = 4,
- EVENT_RESTORE_ARM_RIGHT = 5,
- EVENT_FOCUSED_EYEBEAM = 6,
- EVENT_STONE_SHOUT = 7,
- EVENT_PREPARE_BREATH = 8, // Kologarn can't cast breath on pull
-};
-
-enum KologarnNPCs
-{
- NPC_LEFT_ARM = 32933,
- NPC_RIGHT_ARM = 32934,
- NPC_SWEEP_TRIGGER = 33661,
- NPC_EYE_LEFT = 33632,
- NPC_EYE_RIGHT = 33802,
- NPC_RUBBLE_TRIGGER = 33809,
- NPC_RUBBLE_SUMMON = 33768,
-};
-
-enum KologarnSounds
-{
- SOUND_AGGRO = 15586,
- SOUND_SLAY1 = 15587,
- SOUND_SLAY2 = 15588,
- SOUND_LARM_GONE = 15589,
- SOUND_RARM_GONE = 15590,
- SOUND_SHOCKWAVE = 15591,
- SOUND_GRIP = 15592,
- SOUND_DEATH = 15593,
- SOUND_BERSERK = 15594,
-};
-
-enum Misc
-{
- ACHIEVEMENT_DISARMED_CRITERIA = 21687,
-
- DATA_KOLOGARN_LOOKS_ACHIEV = 55,
- DATA_KOLOGARN_RUBBLE_ACHIEV = 56,
- DATA_KOLOGARN_ARMS_ACHIEV = 57,
-};
-
-class boss_kologarn : public CreatureScript
-{
-public:
- boss_kologarn() : CreatureScript("boss_kologarn") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_kologarnAI : public ScriptedAI
- {
- boss_kologarnAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me), breathReady(false)
- {
- m_pInstance = me->GetInstanceScript();
- eyebeamTarget = nullptr;
- assert(vehicle);
- me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
- }
-
- InstanceScript* m_pInstance;
-
- Vehicle* vehicle;
- ObjectGuid _left, _right;
- EventMap events;
- SummonList summons;
-
- Unit* eyebeamTarget;
-
- bool _looksAchievement, breathReady;
- uint8 _rubbleAchievement;
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (who->GetTypeId() == TYPEID_PLAYER && me->GetExactDist2d(who) < 45.0f && me->getStandState() == UNIT_STAND_STATE_SUBMERGED)
- {
- me->SetStandState(UNIT_STAND_STATE_STAND);
- if (Unit* arm = ObjectAccessor::GetCreature(*me, _left))
- arm->CastSpell(arm, SPELL_ARM_RESPAWN_VISUAL, true);
- if (Unit* arm = ObjectAccessor::GetCreature(*me, _right))
- arm->CastSpell(arm, SPELL_ARM_RESPAWN_VISUAL, true);
- }
-
- if (me->GetExactDist2d(who) < 30.0f)
- ScriptedAI::MoveInLineOfSight(who);
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- if (!_EnterEvadeMode(why))
- return;
- Reset();
- me->setActive(false);
- }
-
- void AttachLeftArm()
- {
- if (Unit* arm = ObjectAccessor::GetCreature(*me, _left))
- arm->SetHealth(arm->GetMaxHealth());
- else if (Creature* accessory = me->SummonCreature(NPC_LEFT_ARM, *me, TEMPSUMMON_MANUAL_DESPAWN))
- {
- accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
- if (!me->HandleSpellClick(accessory, 0))
- accessory->DespawnOrUnsummon();
- else
- {
- _left = accessory->GetGUID();
- accessory->SetOrientation(M_PI);
- accessory->CastSpell(accessory, SPELL_ARM_RESPAWN_VISUAL, true);
- }
- }
- }
-
- void AttachRightArm()
- {
- if (Unit* arm = ObjectAccessor::GetCreature(*me, _right))
- arm->SetHealth(arm->GetMaxHealth());
- else if (Creature* accessory = me->SummonCreature(NPC_RIGHT_ARM, *me, TEMPSUMMON_MANUAL_DESPAWN))
- {
- accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
- if (!me->HandleSpellClick(accessory, 1))
- accessory->DespawnOrUnsummon();
- else
- {
- _right = accessory->GetGUID();
- accessory->SetOrientation(M_PI);
- accessory->CastSpell(accessory, SPELL_ARM_RESPAWN_VISUAL, true);
- }
- }
- }
-
- void Reset() override
- {
- _rubbleAchievement = 0;
- _looksAchievement = true;
-
- me->SetDisableGravity(true);
- me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
- me->DisableRotate(true);
-
- events.Reset();
- summons.DespawnAll();
-
- if (m_pInstance)
- {
- m_pInstance->SetData(TYPE_KOLOGARN, NOT_STARTED);
-
- // Open the door inside Kologarn chamber
- if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS)))
- door->SetGoState(GO_STATE_ACTIVE);
- }
-
- AttachLeftArm();
- AttachRightArm();
-
- // Reset breath on pull
- breathReady = false;
- }
-
- void DoAction(int32 param) override
- {
- if (param == DATA_KOLOGARN_LOOKS_ACHIEV)
- _looksAchievement = false;
- if (param == DATA_KOLOGARN_RUBBLE_ACHIEV)
- {
- // Means arm died
- if (m_pInstance && (!_left || !_right))
- m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_DISARMED_CRITERIA);
-
- ++_rubbleAchievement;
- }
- }
-
- uint32 GetData(uint32 param) const override
- {
- if (param == DATA_KOLOGARN_LOOKS_ACHIEV)
- return _looksAchievement;
- else if (param == DATA_KOLOGARN_RUBBLE_ACHIEV)
- return (_rubbleAchievement >= 5);
- else if (param == DATA_KOLOGARN_ARMS_ACHIEV)
- return !_rubbleAchievement;
-
- return 0;
- }
-
- void AttackStart(Unit* who) override
- {
- me->Attack(who, true);
- }
-
- void JustSummoned(Creature* cr) override
- {
- if (cr->GetEntry() != NPC_LEFT_ARM && cr->GetEntry() != NPC_RIGHT_ARM)
- summons.Summon(cr);
- }
-
- void JustDied(Unit*) override
- {
- summons.DespawnAll();
- me->StopMoving();
- if (m_pInstance)
- m_pInstance->SetData(TYPE_KOLOGARN, DONE);
-
- Talk(SAY_DEATH);
-
- if (m_pInstance)
- {
- // Open the door inside Kologarn chamber
- if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS)))
- door->SetGoState(GO_STATE_ACTIVE);
- }
-
- if (GameObject* bridge = me->FindNearestGameObject(GO_KOLOGARN_BRIDGE, 100))
- bridge->SetGoState(GO_STATE_READY);
-
- // Summon Chest
- if (GameObject* go = me->SummonGameObject(RAID_MODE(GO_KOLOGARN_CHEST, GO_KOLOGARN_CHEST_HERO), 1839.62f, -35.98f, 448.81f, 3.6f, 0, 0, 0, 0, 7 * 86400))
- {
- me->RemoveGameObject(go, false);
- go->SetSpellId(1); // hack to make it despawn
- go->ReplaceAllGameObjectFlags((GameObjectFlags)0);
- go->SetLootRecipient(me);
- }
- if (Creature* arm = ObjectAccessor::GetCreature(*me, _left))
- arm->DespawnOrUnsummon(3000); // visual
- if (Creature* arm = ObjectAccessor::GetCreature(*me, _right))
- arm->DespawnOrUnsummon(3000); // visual
- }
-
- void KilledUnit(Unit*) override
- {
- if (!urand(0, 2))
- return;
-
- Talk(SAY_SLAY);
- }
-
- void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
- {
- if (!me->IsAlive())
- return;
-
- if (!apply)
- {
- // left arm
- if (who->GetGUID() == _left)
- {
- _left.Clear();
- if (me->IsInCombat())
- {
- Talk(SAY_LEFT_ARM_GONE);
- events.ScheduleEvent(EVENT_RESTORE_ARM_LEFT, 50s);
- }
- }
- else
- {
- _right.Clear();
- if (me->IsInCombat())
- {
- Talk(SAY_RIGHT_ARM_GONE);
- events.ScheduleEvent(EVENT_RESTORE_ARM_RIGHT, 50s);
- }
- }
-
- me->CastSpell(me, SPELL_ARM_DEAD, true);
- if (!_right && !_left)
- events.ScheduleEvent(EVENT_STONE_SHOUT, 5s);
- }
- }
-
- void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (who && who->GetEntry() == me->GetEntry() && me->GetHealth())
- {
- damage = std::min(damage, me->GetHealth() - 1);
- me->LowerPlayerDamageReq(damage);
- }
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- if (m_pInstance)
- m_pInstance->SetData(TYPE_KOLOGARN, IN_PROGRESS);
-
- events.ScheduleEvent(EVENT_SMASH, 8s);
- events.ScheduleEvent(EVENT_SWEEP, 17s);
- events.ScheduleEvent(EVENT_GRIP, 15s);
- events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 10s);
- events.ScheduleEvent(EVENT_PREPARE_BREATH, 3s);
- //events.ScheduleEvent(EVENT_ENRAGE, x); no info
-
- Talk(SAY_AGGRO);
- me->setActive(true);
-
- // Close the door inside Kologarn chamber
- if (m_pInstance)
- {
- if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS)))
- {
- door->SetGoState(GO_STATE_READY);
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_PREPARE_BREATH:
- breathReady = true;
- break;
- case EVENT_STONE_SHOUT:
- if (_left || _right)
- {
- return;
- }
-
- me->CastSpell(me->GetVictim(), SPELL_STONE_SHOUT, false);
- events.ScheduleEvent(EVENT_STONE_SHOUT, 2s);
- break;
- case EVENT_SMASH:
- if (_left && _right)
- me->CastSpell(me->GetVictim(), SPELL_OVERHEAD_SMASH, false);
- else if (_left || _right)
- me->CastSpell(me->GetVictim(), SPELL_ONEARMED_OVERHEAD_SMASH, false);
-
- events.DelayEvents(1s);
- events.ScheduleEvent(EVENT_SMASH, 14s);
- return;
- case EVENT_SWEEP:
- if (_left)
- {
- if (Creature* cr = me->FindNearestCreature(NPC_SWEEP_TRIGGER, 300))
- cr->CastSpell(cr, SPELL_ARM_SWEEP, false);
-
- if (urand(0, 1))
- Talk(SAY_SHOCKWAVE);
- }
-
- events.DelayEvents(1s);
- events.ScheduleEvent(EVENT_SWEEP, 17s);
- return;
- case EVENT_GRIP:
- events.ScheduleEvent(EVENT_GRIP, 25s);
- if (!_right)
- break;
-
- me->CastSpell(me, SPELL_STONE_GRIP, false);
- Talk(SAY_GRAB_PLAYER);
- Talk(EMOTE_STONE_GRIP);
- return;
- case EVENT_FOCUSED_EYEBEAM:
- {
- events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 20s);
-
- if ((eyebeamTarget = SelectTarget(SelectTargetMethod::MinDistance, 0, 0, true)))
- {
- me->CastSpell(eyebeamTarget, SPELL_FOCUSED_EYEBEAM_SUMMON, false);
- }
-
- Talk(EMOTE_EYES);
- return;
- }
- case EVENT_RESTORE_ARM_LEFT:
- // shouldn't happen
- AttachLeftArm();
- return;
- case EVENT_RESTORE_ARM_RIGHT:
- // shouldn't happen
- AttachRightArm();
- return;
- }
-
- //Make sure our attack is ready and we aren't currently casting before checking distance
- if (me->isAttackReady() && me->GetVictim()) // victim could die by a spell (IMPORTANT!!!) and kologarn entered evade mode
- {
- //If we are within range melee the target
- if (me->IsWithinMeleeRange(me->GetVictim()))
- {
- me->AttackerStateUpdate(me->GetVictim());
- me->resetAttackTimer();
- return;
- }
- else if (Unit* tgt = me->SelectNearbyTarget())
- {
- me->AttackerStateUpdate(tgt);
- me->resetAttackTimer();
- return;
- }
-
- if (breathReady)
- me->CastSpell(me->GetVictim(), SPELL_PETRIFYING_BREATH, false);
- me->resetAttackTimer();
- }
- }
- };
-};
-
-// also used for left arm, all functions except JustDied wont be used by left arm
-class boss_kologarn_arms : public CreatureScript
-{
-public:
- boss_kologarn_arms() : CreatureScript("boss_kologarn_arms") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_kologarn_armsAI : public ScriptedAI
- {
- boss_kologarn_armsAI(Creature* c) : ScriptedAI(c) { }
-
- int32 _damageDone;
- bool _combatStarted;
-
- void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override {}
- void MoveInLineOfSight(Unit*) override {}
- void AttackStart(Unit*) override {}
- void UpdateAI(uint32 /*diff*/) override {}
-
- void Reset() override
- {
- _combatStarted = false;
- _damageDone = 0;
- }
-
- void PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool apply) override
- {
- if (!apply)
- _damageDone = 0;
- else
- {
- //who->ClearUnitState(UNIT_STATE_ONVEHICLE);
- if (!_damageDone)
- _damageDone = RAID_MODE(80000, 380000);
- }
- }
-
- void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (!_combatStarted)
- if (InstanceScript* instance = me->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_KOLOGARN)))
- {
- _combatStarted = true;
- if (!cr->IsInCombat() && who)
- cr->AI()->AttackStart(who);
- }
-
- if (_damageDone > 0)
- {
- _damageDone -= damage;
- if (_damageDone <= 0 || damage >= me->GetHealth())
- me->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE);
- }
- }
-
- void JustDied(Unit*) override
- {
- float x, y, z;
- // left arm
- if( me->GetEntry() == NPC_LEFT_ARM )
- {
- x = 1776.97f;
- y = -44.8396f;
- z = 448.888f;
- }
- else
- {
- x = 1777.82f;
- y = -3.50803f;
- z = 448.888f;
- }
-
- if (Creature* cr = me->SummonTrigger(x, y, z, 0, 5000))
- {
- cr->CastSpell(cr, SPELL_RUBBLE_FALL, true);
-
- if (me->GetInstanceScript())
- if (Creature* kologarn = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN)))
- for (uint8 i = 0; i < 5; ++i)
- if (Creature* cr2 = kologarn->SummonCreature(NPC_RUBBLE_SUMMON, cr->GetPositionX() + irand(-5, 5), cr->GetPositionY() + irand(-5, 5), cr->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000))
- {
- cr2->SetInCombatWithZone();
- if (Unit* target = SelectTargetFromPlayerList(100))
- cr2->AI()->AttackStart(target);
- }
- }
-
- if (me->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN)))
- cr->AI()->DoAction(DATA_KOLOGARN_RUBBLE_ACHIEV);
-
- me->ExitVehicle();
- }
- };
-};
-
-class boss_kologarn_eyebeam : public CreatureScript
-{
-public:
- boss_kologarn_eyebeam() : CreatureScript("boss_kologarn_eyebeam") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
- struct boss_kologarn_eyebeamAI : public ScriptedAI
- {
- boss_kologarn_eyebeamAI(Creature* c) : ScriptedAI(c), _timer(1), _damaged(false), justSpawned(true)
- {
- m_pInstance = (InstanceScript*)c->GetInstanceScript();
- }
-
- InstanceScript* m_pInstance;
- uint32 _timer;
- bool _damaged, justSpawned;
-
- void DamageDealt(Unit* /*victim*/, uint32& damage, DamageEffectType /*damageType*/) override
- {
- if (damage > 0 && !_damaged && me->GetInstanceScript())
- {
- _damaged = true;
- if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN)))
- cr->AI()->DoAction(DATA_KOLOGARN_LOOKS_ACHIEV);
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (justSpawned)
- {
- me->DespawnOrUnsummon(10000);
- if (Creature* cr = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(TYPE_KOLOGARN)))
- {
- me->CastSpell(cr, me->GetEntry() == NPC_EYE_LEFT ? SPELL_FOCUSED_EYEBEAM_LEFT : SPELL_FOCUSED_EYEBEAM_RIGHT, true);
- }
- me->CastSpell(me, SPELL_FOCUSED_EYEBEAM, true);
- justSpawned = false;
- }
- if (_timer)
- {
- _timer += diff;
- if (_timer >= 2000)
- {
- me->CastSpell(me, (me->GetMap()->Is25ManRaid() ? SPELL_FOCUSED_EYEBEAM_25 : SPELL_FOCUSED_EYEBEAM_10), true);
- _timer = 0;
- }
- }
- }
- };
-};
-
-// predicate function to select non main tank target
-class StoneGripTargetSelector
-{
-public:
- StoneGripTargetSelector(Creature* me, Unit const* victim) : _me(me), _victim(victim) {}
-
- bool operator() (WorldObject* target) const
- {
- if (target == _victim && _me->GetThreatMgr().GetThreatListSize() > 1)
- return true;
-
- if (target->GetTypeId() != TYPEID_PLAYER)
- return true;
-
- return false;
- }
-
-private:
- Creature* _me;
- Unit const* _victim;
-};
-
-class spell_ulduar_stone_grip_cast_target : public SpellScriptLoader
-{
-public:
- spell_ulduar_stone_grip_cast_target() : SpellScriptLoader("spell_ulduar_stone_grip_cast_target") { }
-
- class spell_ulduar_stone_grip_cast_target_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_ulduar_stone_grip_cast_target_SpellScript);
-
- bool Load() override
- {
- if (GetCaster()->GetTypeId() != TYPEID_UNIT)
- return false;
- return true;
- }
-
- void FilterTargetsInitial(std::list& targets)
- {
- // Remove "main tank" and non-player targets
- targets.remove_if (StoneGripTargetSelector(GetCaster()->ToCreature(), GetCaster()->GetVictim()));
- // Maximum affected targets per difficulty mode
- uint32 maxTargets = 1;
- if (GetSpellInfo()->Id == 63981)
- maxTargets = 3;
-
- // Return a random amount of targets based on maxTargets
- while (maxTargets < targets.size())
- {
- std::list::iterator itr = targets.begin();
- advance(itr, urand(0, targets.size() - 1));
- targets.erase(itr);
- }
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ulduar_stone_grip_cast_target_SpellScript::FilterTargetsInitial, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_ulduar_stone_grip_cast_target_SpellScript();
- }
-};
-
-class spell_ulduar_stone_grip : public SpellScriptLoader
-{
-public:
- spell_ulduar_stone_grip() : SpellScriptLoader("spell_ulduar_stone_grip") { }
-
- class spell_ulduar_stone_grip_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_ulduar_stone_grip_AuraScript);
-
- void OnRemoveStun(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
- {
- if (Player* owner = GetOwner()->ToPlayer())
- owner->RemoveAurasDueToSpell(aurEff->GetAmount());
- }
-
- void Register() override
- {
- OnEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_AuraScript::OnRemoveStun, EFFECT_2, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_ulduar_stone_grip_AuraScript();
- }
-};
-
-class spell_ulduar_squeezed_lifeless : public SpellScriptLoader
-{
-public:
- spell_ulduar_squeezed_lifeless() : SpellScriptLoader("spell_ulduar_squeezed_lifeless") { }
-
- class spell_ulduar_squeezed_lifeless_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_ulduar_squeezed_lifeless_SpellScript);
-
- void HandleInstaKill(SpellEffIndex /*effIndex*/)
- {
- if (!GetHitPlayer() || !GetHitPlayer()->GetVehicle())
- return;
-
- // Hack to set correct position is in _ExitVehicle()
- GetHitPlayer()->ExitVehicle();
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_ulduar_squeezed_lifeless_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_ulduar_squeezed_lifeless_SpellScript();
- }
-};
-
-class spell_kologarn_stone_shout : public SpellScriptLoader
-{
-public:
- spell_kologarn_stone_shout() : SpellScriptLoader("spell_kologarn_stone_shout") { }
-
- class spell_kologarn_stone_shout_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_kologarn_stone_shout_AuraScript);
-
- void OnPeriodic(AuraEffect const* /*aurEff*/)
- {
- uint32 triggerSpellId = GetSpellInfo()->Effects[EFFECT_0].TriggerSpell;
- if (Unit* caster = GetCaster())
- caster->CastSpell(caster, triggerSpellId, false);
- }
-
- void Register() override
- {
- if (m_scriptSpellId == SPELL_STONE_SHOUT_10 || m_scriptSpellId == SPELL_STONE_SHOUT_25)
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_kologarn_stone_shout_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_kologarn_stone_shout_AuraScript();
- }
-
- class spell_kologarn_stone_shout_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_kologarn_stone_shout_SpellScript);
-
- void FilterTargets(std::list& targets)
- {
- targets.remove_if (PlayerOrPetCheck());
- }
-
- void Register() override
- {
- if (m_scriptSpellId != SPELL_STONE_SHOUT_10 && m_scriptSpellId != SPELL_STONE_SHOUT_25)
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kologarn_stone_shout_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_kologarn_stone_shout_SpellScript();
- }
-};
-
-class achievement_kologarn_looks_could_kill : public AchievementCriteriaScript
-{
-public:
- achievement_kologarn_looks_could_kill() : AchievementCriteriaScript("achievement_kologarn_looks_could_kill") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- if (target)
- if (InstanceScript* instance = target->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN)))
- return cr->AI()->GetData(DATA_KOLOGARN_LOOKS_ACHIEV);
-
- return false;
- }
-};
-
-class achievement_kologarn_rubble_and_roll : public AchievementCriteriaScript
-{
-public:
- achievement_kologarn_rubble_and_roll() : AchievementCriteriaScript("achievement_kologarn_rubble_and_roll") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- if (target)
- if (InstanceScript* instance = target->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN)))
- return cr->AI()->GetData(DATA_KOLOGARN_RUBBLE_ACHIEV);
-
- return false;
- }
-};
-
-class achievement_kologarn_with_open_arms : public AchievementCriteriaScript
-{
-public:
- achievement_kologarn_with_open_arms() : AchievementCriteriaScript("achievement_kologarn_with_open_arms") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- if (target)
- if (InstanceScript* instance = target->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN)))
- return cr->AI()->GetData(DATA_KOLOGARN_ARMS_ACHIEV);
-
- return false;
- }
-};
-
void AddSC_boss_kologarn()
{
// Npcs
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.h
new file mode 100644
index 00000000000000..1b52988a9678e0
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.h
@@ -0,0 +1,876 @@
+#ifndef BOSS_KOLOGARN_H_
+#define BOSS_KOLOGARN_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "SpellAuraEffects.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "Vehicle.h"
+#include "ulduar.h"
+
+enum KologarnSays
+{
+ SAY_AGGRO = 0,
+ SAY_SLAY = 1,
+ SAY_LEFT_ARM_GONE = 2,
+ SAY_RIGHT_ARM_GONE = 3,
+ SAY_SHOCKWAVE = 4,
+ SAY_GRAB_PLAYER = 5,
+ SAY_DEATH = 6,
+ SAY_BERSERK = 7,
+ EMOTE_STONE_GRIP = 8,
+ EMOTE_EYES = 9
+};
+
+enum KologarnSpells
+{
+ SPELL_KOLOGARN_REDUCE_PARRY = 64651,
+
+ // BASIC
+ SPELL_OVERHEAD_SMASH_10 = 63356,
+ SPELL_OVERHEAD_SMASH_25 = 64003,
+ SPELL_ONEARMED_OVERHEAD_SMASH_10 = 63573,
+ SPELL_ONEARMED_OVERHEAD_SMASH_25 = 64006,
+ SPELL_PETRIFYING_BREATH_10 = 62030,
+ SPELL_PETRIFYING_BREATH_25 = 63980,
+ SPELL_STONE_SHOUT_10 = 63716,
+ SPELL_STONE_SHOUT_25 = 64005,
+
+ // EYEBEAM
+ SPELL_FOCUSED_EYEBEAM_SUMMON = 63342,
+ SPELL_FOCUSED_EYEBEAM_10 = 63347,
+ SPELL_FOCUSED_EYEBEAM_25 = 63977,
+ SPELL_FOCUSED_EYEBEAM_RIGHT = 63702,
+ SPELL_FOCUSED_EYEBEAM_LEFT = 63676,
+
+ // ARMS
+ SPELL_ARM_DEAD_10 = 63629,
+ SPELL_ARM_DEAD_25 = 63979,
+ SPELL_RUBBLE_FALL_10 = 63821,
+ SPELL_RUBBLE_FALL_25 = 64001,
+ SPELL_ARM_RESPAWN_VISUAL = 64753,
+
+ // LEFT ARM
+ SPELL_ARM_SWEEP_10 = 63766,
+ SPELL_ARM_SWEEP_25 = 63983,
+
+ // RIGHT ARM
+ SPELL_STONE_GRIP_10 = 62166,
+ SPELL_STONE_GRIP_25 = 63981,
+ SPELL_RIDE_RIGHT_ARM_10 = 62056,
+ SPELL_RIDE_RIGHT_ARM_25 = 63985,
+
+ // RUBBLE TRASH
+ SPELL_RUBBLE_ATTACK_10 = 63818,
+ SPELL_RUBBLE_ATTACK_25 = 63978,
+};
+
+#define SPELL_PETRIFYING_BREATH RAID_MODE(SPELL_PETRIFYING_BREATH_10, SPELL_PETRIFYING_BREATH_25)
+#define SPELL_OVERHEAD_SMASH RAID_MODE(SPELL_OVERHEAD_SMASH_10, SPELL_OVERHEAD_SMASH_25)
+#define SPELL_ONEARMED_OVERHEAD_SMASH RAID_MODE(SPELL_ONEARMED_OVERHEAD_SMASH_10, SPELL_ONEARMED_OVERHEAD_SMASH_25)
+#define SPELL_ARM_DEAD RAID_MODE(SPELL_ARM_DEAD_10, SPELL_ARM_DEAD_25)
+#define SPELL_ARM_SWEEP RAID_MODE(SPELL_ARM_SWEEP_10, SPELL_ARM_SWEEP_25)
+#define SPELL_STONE_GRIP RAID_MODE(SPELL_STONE_GRIP_10, SPELL_STONE_GRIP_25)
+#define SPELL_FOCUSED_EYEBEAM RAID_MODE(SPELL_FOCUSED_EYEBEAM_10, SPELL_FOCUSED_EYEBEAM_25)
+#define SPELL_RUBBLE_FALL RAID_MODE(SPELL_RUBBLE_FALL_10, SPELL_RUBBLE_FALL_25)
+#define SPELL_RUBBLE_ATTACK RAID_MODE(SPELL_RUBBLE_ATTACK_10, SPELL_RUBBLE_ATTACK_25)
+#define SPELL_RIDE_RIGHT_ARM RAID_MODE(SPELL_RIDE_RIGHT_ARM_10, SPELL_RIDE_RIGHT_ARM_25)
+#define SPELL_STONE_SHOUT RAID_MODE(SPELL_STONE_SHOUT_10, SPELL_STONE_SHOUT_25)
+
+enum KologarnEvents
+{
+ EVENT_SMASH = 1,
+ EVENT_GRIP = 2,
+ EVENT_SWEEP = 3,
+ EVENT_RESTORE_ARM_LEFT = 4,
+ EVENT_RESTORE_ARM_RIGHT = 5,
+ EVENT_FOCUSED_EYEBEAM = 6,
+ EVENT_STONE_SHOUT = 7,
+ EVENT_PREPARE_BREATH = 8, // Kologarn can't cast breath on pull
+};
+
+enum KologarnNPCs
+{
+ NPC_LEFT_ARM = 32933,
+ NPC_RIGHT_ARM = 32934,
+ NPC_SWEEP_TRIGGER = 33661,
+ NPC_EYE_LEFT = 33632,
+ NPC_EYE_RIGHT = 33802,
+ NPC_RUBBLE_TRIGGER = 33809,
+ NPC_RUBBLE_SUMMON = 33768,
+};
+
+enum KologarnSounds
+{
+ SOUND_AGGRO = 15586,
+ SOUND_SLAY1 = 15587,
+ SOUND_SLAY2 = 15588,
+ SOUND_LARM_GONE = 15589,
+ SOUND_RARM_GONE = 15590,
+ SOUND_SHOCKWAVE = 15591,
+ SOUND_GRIP = 15592,
+ SOUND_DEATH = 15593,
+ SOUND_BERSERK = 15594,
+};
+
+enum Misc
+{
+ ACHIEVEMENT_DISARMED_CRITERIA = 21687,
+
+ DATA_KOLOGARN_LOOKS_ACHIEV = 55,
+ DATA_KOLOGARN_RUBBLE_ACHIEV = 56,
+ DATA_KOLOGARN_ARMS_ACHIEV = 57,
+};
+
+class boss_kologarn : public CreatureScript
+{
+public:
+ boss_kologarn() : CreatureScript("boss_kologarn") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_kologarnAI : public ScriptedAI
+ {
+ boss_kologarnAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me), breathReady(false)
+ {
+ m_pInstance = me->GetInstanceScript();
+ eyebeamTarget = nullptr;
+ assert(vehicle);
+ me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
+ }
+
+ InstanceScript* m_pInstance;
+
+ Vehicle* vehicle;
+ ObjectGuid _left, _right;
+ EventMap events;
+ SummonList summons;
+
+ Unit* eyebeamTarget;
+
+ bool _looksAchievement, breathReady;
+ uint8 _rubbleAchievement;
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER && me->GetExactDist2d(who) < 45.0f && me->getStandState() == UNIT_STAND_STATE_SUBMERGED)
+ {
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ if (Unit* arm = ObjectAccessor::GetCreature(*me, _left))
+ arm->CastSpell(arm, SPELL_ARM_RESPAWN_VISUAL, true);
+ if (Unit* arm = ObjectAccessor::GetCreature(*me, _right))
+ arm->CastSpell(arm, SPELL_ARM_RESPAWN_VISUAL, true);
+ }
+
+ if (me->GetExactDist2d(who) < 30.0f)
+ ScriptedAI::MoveInLineOfSight(who);
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ if (!_EnterEvadeMode(why))
+ return;
+ Reset();
+ me->setActive(false);
+ }
+
+ void AttachLeftArm()
+ {
+ if (Unit* arm = ObjectAccessor::GetCreature(*me, _left))
+ arm->SetHealth(arm->GetMaxHealth());
+ else if (Creature* accessory = me->SummonCreature(NPC_LEFT_ARM, *me, TEMPSUMMON_MANUAL_DESPAWN))
+ {
+ accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
+ if (!me->HandleSpellClick(accessory, 0))
+ accessory->DespawnOrUnsummon();
+ else
+ {
+ _left = accessory->GetGUID();
+ accessory->SetOrientation(M_PI);
+ accessory->CastSpell(accessory, SPELL_ARM_RESPAWN_VISUAL, true);
+ }
+ }
+ }
+
+ void AttachRightArm()
+ {
+ if (Unit* arm = ObjectAccessor::GetCreature(*me, _right))
+ arm->SetHealth(arm->GetMaxHealth());
+ else if (Creature* accessory = me->SummonCreature(NPC_RIGHT_ARM, *me, TEMPSUMMON_MANUAL_DESPAWN))
+ {
+ accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
+ if (!me->HandleSpellClick(accessory, 1))
+ accessory->DespawnOrUnsummon();
+ else
+ {
+ _right = accessory->GetGUID();
+ accessory->SetOrientation(M_PI);
+ accessory->CastSpell(accessory, SPELL_ARM_RESPAWN_VISUAL, true);
+ }
+ }
+ }
+
+ void Reset() override
+ {
+ _rubbleAchievement = 0;
+ _looksAchievement = true;
+
+ me->SetDisableGravity(true);
+ me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
+ me->DisableRotate(true);
+
+ events.Reset();
+ summons.DespawnAll();
+
+ if (m_pInstance)
+ {
+ m_pInstance->SetData(TYPE_KOLOGARN, NOT_STARTED);
+
+ // Open the door inside Kologarn chamber
+ if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS)))
+ door->SetGoState(GO_STATE_ACTIVE);
+ }
+
+ AttachLeftArm();
+ AttachRightArm();
+
+ // Reset breath on pull
+ breathReady = false;
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == DATA_KOLOGARN_LOOKS_ACHIEV)
+ _looksAchievement = false;
+ if (param == DATA_KOLOGARN_RUBBLE_ACHIEV)
+ {
+ // Means arm died
+ if (m_pInstance && (!_left || !_right))
+ m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_DISARMED_CRITERIA);
+
+ ++_rubbleAchievement;
+ }
+ }
+
+ uint32 GetData(uint32 param) const override
+ {
+ if (param == DATA_KOLOGARN_LOOKS_ACHIEV)
+ return _looksAchievement;
+ else if (param == DATA_KOLOGARN_RUBBLE_ACHIEV)
+ return (_rubbleAchievement >= 5);
+ else if (param == DATA_KOLOGARN_ARMS_ACHIEV)
+ return !_rubbleAchievement;
+
+ return 0;
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ me->Attack(who, true);
+ }
+
+ void JustSummoned(Creature* cr) override
+ {
+ if (cr->GetEntry() != NPC_LEFT_ARM && cr->GetEntry() != NPC_RIGHT_ARM)
+ summons.Summon(cr);
+ }
+
+ void JustDied(Unit*) override
+ {
+ summons.DespawnAll();
+ me->StopMoving();
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_KOLOGARN, DONE);
+
+ Talk(SAY_DEATH);
+
+ if (m_pInstance)
+ {
+ // Open the door inside Kologarn chamber
+ if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS)))
+ door->SetGoState(GO_STATE_ACTIVE);
+ }
+
+ if (GameObject* bridge = me->FindNearestGameObject(GO_KOLOGARN_BRIDGE, 100))
+ bridge->SetGoState(GO_STATE_READY);
+
+ // Summon Chest
+ if (GameObject* go = me->SummonGameObject(RAID_MODE(GO_KOLOGARN_CHEST, GO_KOLOGARN_CHEST_HERO), 1839.62f, -35.98f, 448.81f, 3.6f, 0, 0, 0, 0, 7 * 86400))
+ {
+ me->RemoveGameObject(go, false);
+ go->SetSpellId(1); // hack to make it despawn
+ go->ReplaceAllGameObjectFlags((GameObjectFlags)0);
+ go->SetLootRecipient(me);
+ }
+ if (Creature* arm = ObjectAccessor::GetCreature(*me, _left))
+ arm->DespawnOrUnsummon(3000); // visual
+ if (Creature* arm = ObjectAccessor::GetCreature(*me, _right))
+ arm->DespawnOrUnsummon(3000); // visual
+ }
+
+ void KilledUnit(Unit*) override
+ {
+ if (!urand(0, 2))
+ return;
+
+ Talk(SAY_SLAY);
+ }
+
+ void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
+ {
+ if (!me->IsAlive())
+ return;
+
+ if (!apply)
+ {
+ // left arm
+ if (who->GetGUID() == _left)
+ {
+ _left.Clear();
+ if (me->IsInCombat())
+ {
+ Talk(SAY_LEFT_ARM_GONE);
+ events.ScheduleEvent(EVENT_RESTORE_ARM_LEFT, 50s);
+ }
+ }
+ else
+ {
+ _right.Clear();
+ if (me->IsInCombat())
+ {
+ Talk(SAY_RIGHT_ARM_GONE);
+ events.ScheduleEvent(EVENT_RESTORE_ARM_RIGHT, 50s);
+ }
+ }
+
+ me->CastSpell(me, SPELL_ARM_DEAD, true);
+ if (!_right && !_left)
+ events.ScheduleEvent(EVENT_STONE_SHOUT, 5s);
+ }
+ }
+
+ void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (who && who->GetEntry() == me->GetEntry() && me->GetHealth())
+ {
+ damage = std::min(damage, me->GetHealth() - 1);
+ me->LowerPlayerDamageReq(damage);
+ }
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_KOLOGARN, IN_PROGRESS);
+
+ events.ScheduleEvent(EVENT_SMASH, 8s);
+ events.ScheduleEvent(EVENT_SWEEP, 17s);
+ events.ScheduleEvent(EVENT_GRIP, 15s);
+ events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 10s);
+ events.ScheduleEvent(EVENT_PREPARE_BREATH, 3s);
+ //events.ScheduleEvent(EVENT_ENRAGE, x); no info
+
+ Talk(SAY_AGGRO);
+ me->setActive(true);
+
+ // Close the door inside Kologarn chamber
+ if (m_pInstance)
+ {
+ if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS)))
+ {
+ door->SetGoState(GO_STATE_READY);
+ }
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_PREPARE_BREATH:
+ breathReady = true;
+ break;
+ case EVENT_STONE_SHOUT:
+ if (_left || _right)
+ {
+ return;
+ }
+
+ me->CastSpell(me->GetVictim(), SPELL_STONE_SHOUT, false);
+ events.ScheduleEvent(EVENT_STONE_SHOUT, 2s);
+ break;
+ case EVENT_SMASH:
+ if (_left && _right)
+ me->CastSpell(me->GetVictim(), SPELL_OVERHEAD_SMASH, false);
+ else if (_left || _right)
+ me->CastSpell(me->GetVictim(), SPELL_ONEARMED_OVERHEAD_SMASH, false);
+
+ events.DelayEvents(1s);
+ events.ScheduleEvent(EVENT_SMASH, 14s);
+ return;
+ case EVENT_SWEEP:
+ if (_left)
+ {
+ if (Creature* cr = me->FindNearestCreature(NPC_SWEEP_TRIGGER, 300))
+ cr->CastSpell(cr, SPELL_ARM_SWEEP, false);
+
+ if (urand(0, 1))
+ Talk(SAY_SHOCKWAVE);
+ }
+
+ events.DelayEvents(1s);
+ events.ScheduleEvent(EVENT_SWEEP, 17s);
+ return;
+ case EVENT_GRIP:
+ events.ScheduleEvent(EVENT_GRIP, 25s);
+ if (!_right)
+ break;
+
+ me->CastSpell(me, SPELL_STONE_GRIP, false);
+ Talk(SAY_GRAB_PLAYER);
+ Talk(EMOTE_STONE_GRIP);
+ return;
+ case EVENT_FOCUSED_EYEBEAM:
+ {
+ events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 20s);
+
+ if ((eyebeamTarget = SelectTarget(SelectTargetMethod::MinDistance, 0, 0, true)))
+ {
+ me->CastSpell(eyebeamTarget, SPELL_FOCUSED_EYEBEAM_SUMMON, false);
+ }
+
+ Talk(EMOTE_EYES);
+ return;
+ }
+ case EVENT_RESTORE_ARM_LEFT:
+ // shouldn't happen
+ AttachLeftArm();
+ return;
+ case EVENT_RESTORE_ARM_RIGHT:
+ // shouldn't happen
+ AttachRightArm();
+ return;
+ }
+
+ //Make sure our attack is ready and we aren't currently casting before checking distance
+ if (me->isAttackReady() && me->GetVictim()) // victim could die by a spell (IMPORTANT!!!) and kologarn entered evade mode
+ {
+ //If we are within range melee the target
+ if (me->IsWithinMeleeRange(me->GetVictim()))
+ {
+ me->AttackerStateUpdate(me->GetVictim());
+ me->resetAttackTimer();
+ return;
+ }
+ else if (Unit* tgt = me->SelectNearbyTarget())
+ {
+ me->AttackerStateUpdate(tgt);
+ me->resetAttackTimer();
+ return;
+ }
+
+ if (breathReady)
+ me->CastSpell(me->GetVictim(), SPELL_PETRIFYING_BREATH, false);
+ me->resetAttackTimer();
+ }
+ }
+ };
+};
+
+// also used for left arm, all functions except JustDied wont be used by left arm
+class boss_kologarn_arms : public CreatureScript
+{
+public:
+ boss_kologarn_arms() : CreatureScript("boss_kologarn_arms") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_kologarn_armsAI : public ScriptedAI
+ {
+ boss_kologarn_armsAI(Creature* c) : ScriptedAI(c) { }
+
+ int32 _damageDone;
+ bool _combatStarted;
+
+ void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override {}
+ void MoveInLineOfSight(Unit*) override {}
+ void AttackStart(Unit*) override {}
+ void UpdateAI(uint32 /*diff*/) override {}
+
+ void Reset() override
+ {
+ _combatStarted = false;
+ _damageDone = 0;
+ }
+
+ void PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool apply) override
+ {
+ if (!apply)
+ _damageDone = 0;
+ else
+ {
+ //who->ClearUnitState(UNIT_STATE_ONVEHICLE);
+ if (!_damageDone)
+ _damageDone = RAID_MODE(80000, 380000);
+ }
+ }
+
+ void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (!_combatStarted)
+ if (InstanceScript* instance = me->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*me, instance->GetGuidData(TYPE_KOLOGARN)))
+ {
+ _combatStarted = true;
+ if (!cr->IsInCombat() && who)
+ cr->AI()->AttackStart(who);
+ }
+
+ if (_damageDone > 0)
+ {
+ _damageDone -= damage;
+ if (_damageDone <= 0 || damage >= me->GetHealth())
+ me->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE);
+ }
+ }
+
+ void JustDied(Unit*) override
+ {
+ float x, y, z;
+ // left arm
+ if( me->GetEntry() == NPC_LEFT_ARM )
+ {
+ x = 1776.97f;
+ y = -44.8396f;
+ z = 448.888f;
+ }
+ else
+ {
+ x = 1777.82f;
+ y = -3.50803f;
+ z = 448.888f;
+ }
+
+ if (Creature* cr = me->SummonTrigger(x, y, z, 0, 5000))
+ {
+ cr->CastSpell(cr, SPELL_RUBBLE_FALL, true);
+
+ if (me->GetInstanceScript())
+ if (Creature* kologarn = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN)))
+ for (uint8 i = 0; i < 5; ++i)
+ if (Creature* cr2 = kologarn->SummonCreature(NPC_RUBBLE_SUMMON, cr->GetPositionX() + irand(-5, 5), cr->GetPositionY() + irand(-5, 5), cr->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000))
+ {
+ cr2->SetInCombatWithZone();
+ if (Unit* target = SelectTargetFromPlayerList(100))
+ cr2->AI()->AttackStart(target);
+ }
+ }
+
+ if (me->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN)))
+ cr->AI()->DoAction(DATA_KOLOGARN_RUBBLE_ACHIEV);
+
+ me->ExitVehicle();
+ }
+ };
+};
+
+class boss_kologarn_eyebeam : public CreatureScript
+{
+public:
+ boss_kologarn_eyebeam() : CreatureScript("boss_kologarn_eyebeam") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+ struct boss_kologarn_eyebeamAI : public ScriptedAI
+ {
+ boss_kologarn_eyebeamAI(Creature* c) : ScriptedAI(c), _timer(1), _damaged(false), justSpawned(true)
+ {
+ m_pInstance = (InstanceScript*)c->GetInstanceScript();
+ }
+
+ InstanceScript* m_pInstance;
+ uint32 _timer;
+ bool _damaged, justSpawned;
+
+ void DamageDealt(Unit* /*victim*/, uint32& damage, DamageEffectType /*damageType*/) override
+ {
+ if (damage > 0 && !_damaged && me->GetInstanceScript())
+ {
+ _damaged = true;
+ if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_KOLOGARN)))
+ cr->AI()->DoAction(DATA_KOLOGARN_LOOKS_ACHIEV);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (justSpawned)
+ {
+ me->DespawnOrUnsummon(10000);
+ if (Creature* cr = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(TYPE_KOLOGARN)))
+ {
+ me->CastSpell(cr, me->GetEntry() == NPC_EYE_LEFT ? SPELL_FOCUSED_EYEBEAM_LEFT : SPELL_FOCUSED_EYEBEAM_RIGHT, true);
+ }
+ me->CastSpell(me, SPELL_FOCUSED_EYEBEAM, true);
+ justSpawned = false;
+ }
+ if (_timer)
+ {
+ _timer += diff;
+ if (_timer >= 2000)
+ {
+ me->CastSpell(me, (me->GetMap()->Is25ManRaid() ? SPELL_FOCUSED_EYEBEAM_25 : SPELL_FOCUSED_EYEBEAM_10), true);
+ _timer = 0;
+ }
+ }
+ }
+ };
+};
+
+// predicate function to select non main tank target
+class StoneGripTargetSelector
+{
+public:
+ StoneGripTargetSelector(Creature* me, Unit const* victim) : _me(me), _victim(victim) {}
+
+ bool operator() (WorldObject* target) const
+ {
+ if (target == _victim && _me->GetThreatMgr().GetThreatListSize() > 1)
+ return true;
+
+ if (target->GetTypeId() != TYPEID_PLAYER)
+ return true;
+
+ return false;
+ }
+
+private:
+ Creature* _me;
+ Unit const* _victim;
+};
+
+class spell_ulduar_stone_grip_cast_target : public SpellScriptLoader
+{
+public:
+ spell_ulduar_stone_grip_cast_target() : SpellScriptLoader("spell_ulduar_stone_grip_cast_target") { }
+
+ class spell_ulduar_stone_grip_cast_target_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_ulduar_stone_grip_cast_target_SpellScript);
+
+ bool Load() override
+ {
+ if (GetCaster()->GetTypeId() != TYPEID_UNIT)
+ return false;
+ return true;
+ }
+
+ void FilterTargetsInitial(std::list& targets)
+ {
+ // Remove "main tank" and non-player targets
+ targets.remove_if (StoneGripTargetSelector(GetCaster()->ToCreature(), GetCaster()->GetVictim()));
+ // Maximum affected targets per difficulty mode
+ uint32 maxTargets = 1;
+ if (GetSpellInfo()->Id == 63981)
+ maxTargets = 3;
+
+ // Return a random amount of targets based on maxTargets
+ while (maxTargets < targets.size())
+ {
+ std::list::iterator itr = targets.begin();
+ advance(itr, urand(0, targets.size() - 1));
+ targets.erase(itr);
+ }
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_ulduar_stone_grip_cast_target_SpellScript::FilterTargetsInitial, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_ulduar_stone_grip_cast_target_SpellScript();
+ }
+};
+
+class spell_ulduar_stone_grip : public SpellScriptLoader
+{
+public:
+ spell_ulduar_stone_grip() : SpellScriptLoader("spell_ulduar_stone_grip") { }
+
+ class spell_ulduar_stone_grip_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_ulduar_stone_grip_AuraScript);
+
+ void OnRemoveStun(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
+ {
+ if (Player* owner = GetOwner()->ToPlayer())
+ owner->RemoveAurasDueToSpell(aurEff->GetAmount());
+ }
+
+ void Register() override
+ {
+ OnEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_AuraScript::OnRemoveStun, EFFECT_2, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_ulduar_stone_grip_AuraScript();
+ }
+};
+
+class spell_ulduar_squeezed_lifeless : public SpellScriptLoader
+{
+public:
+ spell_ulduar_squeezed_lifeless() : SpellScriptLoader("spell_ulduar_squeezed_lifeless") { }
+
+ class spell_ulduar_squeezed_lifeless_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_ulduar_squeezed_lifeless_SpellScript);
+
+ void HandleInstaKill(SpellEffIndex /*effIndex*/)
+ {
+ if (!GetHitPlayer() || !GetHitPlayer()->GetVehicle())
+ return;
+
+ // Hack to set correct position is in _ExitVehicle()
+ GetHitPlayer()->ExitVehicle();
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_ulduar_squeezed_lifeless_SpellScript::HandleInstaKill, EFFECT_1, SPELL_EFFECT_INSTAKILL);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_ulduar_squeezed_lifeless_SpellScript();
+ }
+};
+
+class spell_kologarn_stone_shout : public SpellScriptLoader
+{
+public:
+ spell_kologarn_stone_shout() : SpellScriptLoader("spell_kologarn_stone_shout") { }
+
+ class spell_kologarn_stone_shout_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_kologarn_stone_shout_AuraScript);
+
+ void OnPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ uint32 triggerSpellId = GetSpellInfo()->Effects[EFFECT_0].TriggerSpell;
+ if (Unit* caster = GetCaster())
+ caster->CastSpell(caster, triggerSpellId, false);
+ }
+
+ void Register() override
+ {
+ if (m_scriptSpellId == SPELL_STONE_SHOUT_10 || m_scriptSpellId == SPELL_STONE_SHOUT_25)
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_kologarn_stone_shout_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_kologarn_stone_shout_AuraScript();
+ }
+
+ class spell_kologarn_stone_shout_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_kologarn_stone_shout_SpellScript);
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove_if (PlayerOrPetCheck());
+ }
+
+ void Register() override
+ {
+ if (m_scriptSpellId != SPELL_STONE_SHOUT_10 && m_scriptSpellId != SPELL_STONE_SHOUT_25)
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kologarn_stone_shout_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_kologarn_stone_shout_SpellScript();
+ }
+};
+
+class achievement_kologarn_looks_could_kill : public AchievementCriteriaScript
+{
+public:
+ achievement_kologarn_looks_could_kill() : AchievementCriteriaScript("achievement_kologarn_looks_could_kill") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ if (target)
+ if (InstanceScript* instance = target->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN)))
+ return cr->AI()->GetData(DATA_KOLOGARN_LOOKS_ACHIEV);
+
+ return false;
+ }
+};
+
+class achievement_kologarn_rubble_and_roll : public AchievementCriteriaScript
+{
+public:
+ achievement_kologarn_rubble_and_roll() : AchievementCriteriaScript("achievement_kologarn_rubble_and_roll") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ if (target)
+ if (InstanceScript* instance = target->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN)))
+ return cr->AI()->GetData(DATA_KOLOGARN_RUBBLE_ACHIEV);
+
+ return false;
+ }
+};
+
+class achievement_kologarn_with_open_arms : public AchievementCriteriaScript
+{
+public:
+ achievement_kologarn_with_open_arms() : AchievementCriteriaScript("achievement_kologarn_with_open_arms") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ if (target)
+ if (InstanceScript* instance = target->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_KOLOGARN)))
+ return cr->AI()->GetData(DATA_KOLOGARN_ARMS_ACHIEV);
+
+ return false;
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
index 00ba652b45403a..c38896286e45e5 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_mimiron.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "GameObjectScript.h"
@@ -30,2462 +31,6 @@
#include "Vehicle.h"
#include "ulduar.h"
-enum SpellData
-{
- SPELL_BERSERK = 64238,
-
- // PHASE 1:
- SPELL_NAPALM_SHELL_25 = 65026,
- SPELL_NAPALM_SHELL_10 = 63666,
-
- SPELL_PLASMA_BLAST_25 = 64529,
- SPELL_PLASMA_BLAST_10 = 62997,
-
- SPELL_SHOCK_BLAST = 63631,
-
- SPELL_PROXIMITY_MINES = 63027,
- NPC_PROXIMITY_MINE = 34362,
- SPELL_MINE_EXPLOSION_25 = 63009,
- SPELL_MINE_EXPLOSION_10 = 66351,
- SPELL_SUMMON_PROXIMITY_MINE = 65347,
-
- // PHASE 2:
- SPELL_HEAT_WAVE = 64533,
-
- SPELL_ROCKET_STRIKE_AURA = 64064,
- NPC_ROCKET_VISUAL = 34050,
- NPC_ROCKET_STRIKE_N = 34047,
-
- SPELL_RAPID_BURST = 63382,
- SPELL_RAPID_BURST_DAMAGE_25_1 = 64531,
- SPELL_RAPID_BURST_DAMAGE_25_2 = 64532,
- SPELL_RAPID_BURST_DAMAGE_10_1 = 63387,
- SPELL_RAPID_BURST_DAMAGE_10_2 = 64019,
- SPELL_SUMMON_BURST_TARGET = 64840,
-
- SPELL_SPINNING_UP = 63414,
-
- // PHASE 3:
- SPELL_PLASMA_BALL_25 = 64535,
- SPELL_PLASMA_BALL_10 = 63689,
-
- SPELL_MAGNETIC_CORE = 64436,
- SPELL_SPINNING = 64438,
-
- SPELL_SUMMON_BOMB_BOT = 63811,
- SPELL_BB_EXPLODE = 63801,
-
- SPELL_BEAM_GREEN = 63295,
- SPELL_BEAM_YELLOW = 63292,
- SPELL_BEAM_BLUE = 63294,
-
- // PHASE 4:
- SPELL_HAND_PULSE_10_R = 64352,
- SPELL_HAND_PULSE_25_R = 64537,
- SPELL_HAND_PULSE_10_L = 64348,
- SPELL_HAND_PULSE_25_L = 64536,
-
- SPELL_SELF_REPAIR = 64383,
- SPELL_SLEEP = 64394,
-};
-
-enum NPCs
-{
- //NPC_MIMIRON = 33350,
- NPC_LEVIATHAN_MKII = 33432,
- NPC_LEVIATHAN_MKII_CANNON = 34071,
- NPC_VX001 = 33651,
- NPC_AERIAL_COMMAND_UNIT = 33670,
- NPC_COMPUTER = 34143,
- NPC_BOMB_BOT = 33836,
- NPC_BOT_SUMMON_TRIGGER = 33856,
- NPC_ASSAULT_BOT = 34057,
- NPC_JUNK_BOT = 33855,
- NPC_MAGNETIC_CORE = 34068,
-};
-
-enum GOs
-{
- //GO_MIMIRON_ELEVATOR = 194749,
- GO_DOOR_1 = 194776,
- GO_DOOR_2 = 194774,
- GO_DOOR_3 = 194775,
- GO_BUTTON = 194739,
- // pads: 194740-48
-};
-
-enum HardMode
-{
- SPELL_EMERGENCY_MODE = 64582,
- SPELL_SELF_DESTRUCT = 64610,
-
- SPELL_SUMMON_FLAMES_INITIAL = 64563,
- NPC_FLAMES_INITIAL = 34363,
- SPELL_SUMMON_FLAMES_SPREAD = 64564,
- NPC_FLAMES_SPREAD = 34121,
- SPELL_FLAMES_AURA = 64561,
-
- SPELL_VX001_FROST_BOMB = 64623,
- SPELL_FROST_BOMB_VISUAL_AURA = 64624,
- SPELL_SUMMON_FROST_BOMB = 64627,
- NPC_FROST_BOMB = 34149,
- SPELL_FROST_BOMB_EXPLOSION_10 = 64626,
- SPELL_FROST_BOMB_EXPLOSION_25 = 65333,
-
- SPELL_FLAME_SUPPRESSANT_10yd = 65192,
- SPELL_FLAME_SUPPRESSANT_50000yd = 64570,
-
- SPELL_WATER_SPRAY = 64619,
- SPELL_DEAFENING_SIREN = 64616,
- NPC_EMERGENCY_FIRE_BOT = 34147,
-
- SPELL_ENTER_VEHICLE_0 = 63112,
- SPELL_ENTER_VEHICLE_1 = 63313,
- SPELL_ENTER_VEHICLE_2 = 63314,
- SPELL_ENTER_VEHICLE_4 = 63316,
-};
-
-enum EVENTS
-{
- // Mimiron:
- EVENT_SIT_LMK2 = 1,
- EVENT_SIT_LMK2_INTERVAL = 2,
- EVENT_LMK2_RETREAT_INTERVAL = 7,
- EVENT_ELEVATOR_INTERVAL_1 = 8,
- EVENT_ELEVATOR_INTERVAL_2 = 9,
- EVENT_SITTING_ON_VX001 = 10,
- EVENT_ENTER_VX001 = 11,
- EVENT_EMOTE_VX001 = 12,
- EVENT_VX001_START_FIGHT = 13,
- EVENT_ELEVATOR_INTERVAL_0 = 14,
- EVENT_GET_OUT_VX001 = 21,
- EVENT_SAY_VX001_DEAD = 22,
- EVENT_ENTER_ACU = 23,
- EVENT_SAY_ACU_ACTIVATE = 24,
- EVENT_ACU_START_ATTACK = 25,
- EVENT_VX001_EMOTESTATE_DEATH = 26,
- EVENT_SAY_ACU_DEAD = 31,
- EVENT_LEVIATHAN_COME_CLOSER = 32,
- EVENT_VX001_EMOTE_JUMP = 33,
- EVENT_LEVIATHAN_RIDE_MIDDLE = 34,
- EVENT_JOIN_TOGETHER = 342,
- EVENT_JOIN_ACU = 35,
- EVENT_START_PHASE4 = 36,
- EVENT_FINISH = 50,
- EVENT_SAY_VOLTRON_DEAD = 51,
- EVENT_DISAPPEAR = 52,
- EVENT_BERSERK = 53,
- EVENT_BERSERK_2 = 54,
-
- // Leviathan:
- EVENT_SPELL_NAPALM_SHELL = 3,
- EVENT_SPELL_PLASMA_BLAST = 4,
- EVENT_SPELL_SHOCK_BLAST = 5,
- EVENT_PROXIMITY_MINES_1 = 6,
-
- // VX001:
- EVENT_SPELL_HEAT_WAVE = 15,
- EVENT_SPELL_ROCKET_STRIKE = 16,
- EVENT_REINSTALL_ROCKETS = 17,
- EVENT_SPELL_RAPID_BURST = 18,
- EVENT_SPELL_RAPID_BURST_INTERVAL = 19,
- EVENT_SPELL_SPINNING_UP = 20,
- EVENT_HAND_PULSE = 37,
-
- // ACU:
- EVENT_SPELL_PLASMA_BALL = 27,
- EVENT_SUMMON_BOMB_BOT = 28,
- EVENT_BOMB_BOT_CHASE = 29,
- EVENT_BOMB_BOT_RELOCATE = 30,
- EVENT_SUMMON_ASSAULT_BOT = 40,
- EVENT_SUMMON_JUNK_BOT = 41,
- EVENT_MAGNETIC_CORE_PULL_DOWN = 42,
- EVENT_MAGNETIC_CORE_FREE = 43,
- EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE = 44,
-
- // Hard mode:
- EVENT_COMPUTER_SAY_INITIATED = 60,
- EVENT_COMPUTER_SAY_MINUTES = 61,
- EVENT_MIMIRON_SAY_HARDMODE = 62,
- EVENT_SPAWN_FLAMES_INITIAL = 63,
- EVENT_FLAMES_SPREAD = 64,
- EVENT_FLAME_SUPPRESSION_50000 = 65,
- EVENT_FLAME_SUPPRESSION_10 = 66,
- EVENT_FROST_BOMB = 67,
- EVENT_SUMMON_EMERGENCY_FIRE_BOTS = 68,
- EVENT_EMERGENCY_BOT_CHECK = 69,
- EVENT_EMERGENCY_BOT_ATTACK = 70,
-};
-
-#define SPELL_NAPALM_SHELL RAID_MODE(SPELL_NAPALM_SHELL_10, SPELL_NAPALM_SHELL_25)
-#define SPELL_PLASMA_BLAST RAID_MODE(SPELL_PLASMA_BLAST_10, SPELL_PLASMA_BLAST_25)
-#define SPELL_MINE_EXPLOSION RAID_MODE(SPELL_MINE_EXPLOSION_10, SPELL_MINE_EXPLOSION_25)
-#define SPELL_PLASMA_BALL RAID_MODE(SPELL_PLASMA_BALL_10, SPELL_PLASMA_BALL_25)
-#define SPELL_HAND_PULSE_R RAID_MODE(SPELL_HAND_PULSE_10_R, SPELL_HAND_PULSE_25_R)
-#define SPELL_HAND_PULSE_L RAID_MODE(SPELL_HAND_PULSE_10_L, SPELL_HAND_PULSE_25_L)
-#define SPELL_FROST_BOMB_EXPLOSION RAID_MODE(SPELL_FROST_BOMB_EXPLOSION_10, SPELL_FROST_BOMB_EXPLOSION_25)
-
-enum Texts
-{
- // Mimiron
- SAY_AGGRO = 0, // Unused
- SAY_HARDMODE_ON = 1,
- SAY_MKII_ACTIVATE = 2,
- SAY_MKII_SLAY = 3,
- SAY_MKII_DEATH = 4,
- SAY_VX001_ACTIVATE = 5,
- SAY_VX001_SLAY = 6,
- SAY_VX001_DEATH = 7,
- SAY_AERIAL_ACTIVATE = 8,
- SAY_AERIAL_SLAY = 9,
- SAY_AERIAL_DEATH = 10,
- SAY_V07TRON_ACTIVATE = 11,
- SAY_V07TRON_SLAY = 12,
- SAY_V07TRON_DEATH = 13,
- SAY_BERSERK = 14,
-
- // MK II
- EMOTE_PLASMA_BLAST = 0,
-
- // Computer (Hardmode countdown)
- TALK_COMPUTER_INITIATED = 0,
- TALK_COMPUTER_TERMINATED = 1,
- TALK_COMPUTER_TEN = 2,
- TALK_COMPUTER_NINE = 3,
- TALK_COMPUTER_EIGHT = 4,
- TALK_COMPUTER_SEVEN = 5,
- TALK_COMPUTER_SIX = 6,
- TALK_COMPUTER_FIVE = 7,
- TALK_COMPUTER_FOUR = 8,
- TALK_COMPUTER_THREE = 9,
- TALK_COMPUTER_TWO = 10,
- TALK_COMPUTER_ONE = 11,
- TALK_COMPUTER_ZERO = 12,
-};
-
-#define GetMimiron() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_MIMIRON))
-#define GetLMK2() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_LEVIATHAN_MKII))
-#define GetVX001() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_VX001))
-#define GetACU() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_ACU))
-
-class boss_mimiron : public CreatureScript
-{
-public:
- boss_mimiron() : CreatureScript("boss_mimiron") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_mimironAI : public ScriptedAI
- {
- boss_mimironAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
- {
- pInstance = me->GetInstanceScript();
- if (!me->IsAlive())
- if (pInstance)
- pInstance->SetData(TYPE_MIMIRON, DONE);
- bIsEvading = false;
- }
-
- InstanceScript* pInstance;
- EventMap events;
- SummonList summons;
- bool bIsEvading;
- bool hardmode;
- bool berserk;
- bool bAchievProximityMine;
- bool bAchievBombBot;
- bool bAchievRocketStrike;
- uint32 allowedFlameSpreadTime;
- bool changeAllowedFlameSpreadTime;
- uint8 minutesTalkNum;
- uint32 outofCombatTimer;
-
- void Reset() override
- {
- hardmode = false;
- berserk = false;
- bAchievProximityMine = false;
- bAchievBombBot = false;
- bAchievRocketStrike = false;
- allowedFlameSpreadTime = 0;
- outofCombatTimer = 0;
- changeAllowedFlameSpreadTime = false;
- ResetGameObjects();
- events.Reset();
- summons.DespawnAll();
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
-
- if (pInstance && pInstance->GetData(TYPE_MIMIRON) != DONE)
- pInstance->SetData(TYPE_MIMIRON, NOT_STARTED);
- }
-
- void AttackStart(Unit* who) override
- {
- if (who)
- me->Attack(who, true); // skip following
- }
-
- void JustReachedHome() override
- {
- me->setActive(false);
- ScriptedAI::JustReachedHome();
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- me->setActive(true);
- DoZoneInCombat();
- me->RemoveAllAuras();
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- events.Reset();
-
- if (Creature* c = GetLMK2())
- {
- if (c->IsInEvadeMode())
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
- if (!c->IsAlive())
- c->Respawn();
-
- me->EnterVehicle(c, 1);
- }
- else
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
- CloseDoorAndButton();
-
- if (!hardmode)
- {
- Talk(SAY_MKII_ACTIVATE);
- events.ScheduleEvent(EVENT_SIT_LMK2, 6s);
- events.ScheduleEvent(EVENT_BERSERK, 15min);
- }
- else
- {
- events.ScheduleEvent(EVENT_MIMIRON_SAY_HARDMODE, 7s);
- events.ScheduleEvent(EVENT_BERSERK, Is25ManRaid() ? 10min : 8min);
-
- events.ScheduleEvent(EVENT_COMPUTER_SAY_INITIATED, 0ms);
- events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, 3s);
- minutesTalkNum = Is25ManRaid() ? TALK_COMPUTER_TEN : TALK_COMPUTER_EIGHT;
- for (uint32 i = 0; i < uint32(TALK_COMPUTER_ZERO - minutesTalkNum - 1); ++i)
- events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, (i + 1)*MINUTE * IN_MILLISECONDS);
- events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, (TALK_COMPUTER_ZERO - minutesTalkNum)*MINUTE * IN_MILLISECONDS + 6000);
- }
-
- // ensure LMK2 is at proper position
- if (pInstance)
- if (Creature* LMK2 = GetLMK2())
- {
- LMK2->UpdatePosition(LMK2->GetHomePosition(), true);
- LMK2->StopMovingOnCurrentPos();
- }
-
- if (pInstance && pInstance->GetData(TYPE_MIMIRON) != DONE)
- pInstance->SetData(TYPE_MIMIRON, IN_PROGRESS);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!me->IsInCombat())
- {
- outofCombatTimer += diff;
- if (outofCombatTimer >= 10000)
- {
- outofCombatTimer = 0;
- if (Creature* c = GetLMK2())
- me->CastSpell(c, RAND(SPELL_ENTER_VEHICLE_0, SPELL_ENTER_VEHICLE_1, SPELL_ENTER_VEHICLE_2, SPELL_ENTER_VEHICLE_4), true);
- }
- return;
- }
-
- Position p = me->GetHomePosition();
- if (me->GetExactDist(&p) > 80.0f || !SelectTargetFromPlayerList(150.0f))
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
-
- events.Update(diff);
-
- switch( events.ExecuteEvent() )
- {
- case 0:
- break;
- case EVENT_COMPUTER_SAY_INITIATED:
- if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) )
- computer->AI()->Talk(TALK_COMPUTER_INITIATED);
- break;
- case EVENT_COMPUTER_SAY_MINUTES:
- if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) )
- computer->AI()->Talk(minutesTalkNum++);
- break;
- case EVENT_MIMIRON_SAY_HARDMODE:
- Talk(SAY_HARDMODE_ON);
- events.ScheduleEvent(EVENT_SPAWN_FLAMES_INITIAL, 0ms);
- events.ScheduleEvent(EVENT_SIT_LMK2, 4s);
- break;
- case EVENT_SPAWN_FLAMES_INITIAL:
- {
- if (changeAllowedFlameSpreadTime)
- allowedFlameSpreadTime = GameTime::GetGameTime().count();
-
- std::vector pg;
- Map::PlayerList const& pl = me->GetMap()->GetPlayers();
- for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
- if( Player* plr = itr->GetSource() )
- if( plr->IsAlive() && plr->GetExactDist2d(me) < 150.0f && !plr->IsGameMaster() )
- pg.push_back(plr);
-
- for( uint8 i = 0; i < 3; ++i )
- if( !pg.empty() )
- {
- uint8 index = urand(0, pg.size() - 1);
- Player* player = pg[index];
- float angle = rand_norm() * 2 * M_PI;
- float z = 364.35f;
- if (!player->IsWithinLOS(player->GetPositionX() + cos(angle) * 5.0f, player->GetPositionY() + std::sin(angle) * 5.0f, z))
- {
- angle = player->GetAngle(2744.65f, 2569.46f);
- }
- me->CastSpell(player->GetPositionX() + cos(angle) * 5.0f, player->GetPositionY() + std::sin(angle) * 5.0f, z, SPELL_SUMMON_FLAMES_INITIAL, true);
- pg.erase(pg.begin() + index);
- }
-
- events.Repeat(30s);
- }
- break;
- case EVENT_BERSERK:
- berserk = true;
- Talk(SAY_BERSERK);
- if( hardmode )
- me->SummonCreature(33576, 2744.78f, 2569.47f, 364.32f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 120000);
- events.ScheduleEvent(EVENT_BERSERK_2, 0ms);
- break;
- case EVENT_BERSERK_2:
- {
- Creature* VX001 = nullptr;
- Creature* LMK2 = nullptr;
- Creature* ACU = nullptr;
- if ((VX001 = GetVX001()))
- VX001->CastSpell(VX001, SPELL_BERSERK, true);
- if ((LMK2 = GetLMK2()))
- LMK2->CastSpell(LMK2, SPELL_BERSERK, true);
- if ((ACU = GetACU()))
- ACU->CastSpell(ACU, SPELL_BERSERK, true);
- events.Repeat(30s);
- }
- break;
- case EVENT_SIT_LMK2:
- if(Creature* LMK2 = GetLMK2())
- {
- me->EnterVehicle(LMK2, 6);
- events.ScheduleEvent(EVENT_SIT_LMK2_INTERVAL, 2s);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_SIT_LMK2_INTERVAL:
- if (Creature* LMK2 = GetLMK2())
- {
- if (hardmode)
- {
- LMK2->CastSpell(LMK2, SPELL_EMERGENCY_MODE, true);
- if( Vehicle* veh = LMK2->GetVehicleKit() )
- if( Unit* cannon = veh->GetPassenger(3) )
- cannon->CastSpell(cannon, SPELL_EMERGENCY_MODE, true);
- }
- LMK2->AI()->SetData(1, 1);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_LMK2_RETREAT_INTERVAL:
- if (Creature* LMK2 = GetLMK2())
- {
- me->EnterVehicle(LMK2, 1);
- Talk(SAY_MKII_DEATH);
- LMK2->SetFacingTo(3.58f);
- events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_0, 6s);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_ELEVATOR_INTERVAL_0:
- if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 100.0f) )
- {
- elevator->SetLootState(GO_READY);
- elevator->UseDoorOrButton(0, false);
- elevator->EnableCollision(false);
- }
- events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_1, 6s);
- break;
- case EVENT_ELEVATOR_INTERVAL_1:
- if(me->SummonCreature(NPC_VX001, 2744.65f, 2569.46f, 364.40f, 3.14f, TEMPSUMMON_MANUAL_DESPAWN))
- {
- if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 100.0f) )
- {
- elevator->SetLootState(GO_READY);
- elevator->UseDoorOrButton(0, true);
- elevator->EnableCollision(false);
- }
- events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_2, 18s);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_ELEVATOR_INTERVAL_2:
- if (Creature* VX001 = GetVX001())
- {
- me->EnterVehicle(VX001, 0);
- events.ScheduleEvent(EVENT_SITTING_ON_VX001, 4s);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_SITTING_ON_VX001:
- Talk(SAY_VX001_ACTIVATE);
- events.ScheduleEvent(EVENT_ENTER_VX001, 5s);
- break;
- case EVENT_ENTER_VX001:
- if( Creature* VX001 = GetVX001() )
- {
- me->EnterVehicle(VX001, 1);
- events.ScheduleEvent(EVENT_EMOTE_VX001, 2s);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_EMOTE_VX001:
- if( Creature* VX001 = GetVX001() )
- {
- VX001->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
- events.ScheduleEvent(EVENT_VX001_START_FIGHT, 1750ms);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_VX001_START_FIGHT:
- if( Creature* VX001 = GetVX001() )
- {
- if( hardmode )
- VX001->CastSpell(VX001, SPELL_EMERGENCY_MODE, true);
- VX001->AI()->SetData(1, 2);
- me->SetInCombatWithZone();
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_VX001_EMOTESTATE_DEATH:
- if( Creature* VX001 = GetVX001() )
- {
- VX001->HandleEmoteCommand(EMOTE_STATE_DROWNED);
- VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DROWNED);
- events.ScheduleEvent(EVENT_GET_OUT_VX001, 2500ms);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_GET_OUT_VX001:
- if( Creature* VX001 = GetVX001() )
- if( Creature* ACU = me->SummonCreature(NPC_AERIAL_COMMAND_UNIT, 2743.91f, 2568.78f, 391.34f, M_PI, TEMPSUMMON_MANUAL_DESPAWN) )
- {
- me->EnterVehicle(VX001, 4);
- float speed = ACU->GetDistance(2737.75f, 2574.22f, 381.34f) / 2.0f;
- ACU->MonsterMoveWithSpeed(2737.75f, 2574.22f, 381.34f, speed);
- ACU->SetPosition(2737.75f, 2574.22f, 381.34f, M_PI);
- events.ScheduleEvent(EVENT_SAY_VX001_DEAD, 2s);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_SAY_VX001_DEAD:
- changeAllowedFlameSpreadTime = true;
- Talk(SAY_VX001_DEATH);
- events.ScheduleEvent(EVENT_ENTER_ACU, 7s);
- break;
- case EVENT_ENTER_ACU:
- if( Creature* ACU = GetACU() )
- {
- me->EnterVehicle(ACU, 0);
- events.ScheduleEvent(EVENT_SAY_ACU_ACTIVATE, 6s);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_SAY_ACU_ACTIVATE:
- Talk(SAY_AERIAL_ACTIVATE);
- events.ScheduleEvent(EVENT_ACU_START_ATTACK, 4s);
- break;
- case EVENT_ACU_START_ATTACK:
- if( Creature* ACU = GetACU() )
- {
- if( hardmode )
- ACU->CastSpell(ACU, SPELL_EMERGENCY_MODE, true);
- ACU->AI()->SetData(1, 3);
- me->SetInCombatWithZone();
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_SAY_ACU_DEAD:
- Talk(SAY_AERIAL_DEATH);
- events.ScheduleEvent(EVENT_LEVIATHAN_COME_CLOSER, 5s);
- break;
- case EVENT_LEVIATHAN_COME_CLOSER:
- if (Creature* LMK2 = GetLMK2())
- {
- LMK2->GetMotionMaster()->MoveCharge(2755.77f, 2574.95f, 364.31f, 21.0f);
- events.ScheduleEvent(EVENT_VX001_EMOTE_JUMP, 4s);
- break;
- }
- EnterEvadeMode(EVADE_REASON_OTHER);
- break;
- case EVENT_VX001_EMOTE_JUMP:
- {
- Creature* LMK2 = GetLMK2();
- Creature* VX001 = GetVX001();
- if( !VX001 || !LMK2 )
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
-
- VX001->SendMeleeAttackStop();
- VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_02);
- VX001->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_02);
- events.ScheduleEvent(EVENT_LEVIATHAN_RIDE_MIDDLE, 4800ms);
- }
- break;
- case EVENT_LEVIATHAN_RIDE_MIDDLE:
- {
- Creature* VX001 = GetVX001();
- Creature* LMK2 = GetLMK2();
- if( !VX001 || !LMK2 )
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
-
- LMK2->GetMotionMaster()->MoveCharge(2744.65f, 2569.46f, 364.31f, 21.0f);
- VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_CUSTOM_SPELL_01);
- VX001->HandleEmoteCommand(EMOTE_STATE_CUSTOM_SPELL_01);
- VX001->EnterVehicle(LMK2, 3);
- events.ScheduleEvent(EVENT_JOIN_TOGETHER, 3s);
- }
- break;
- case EVENT_JOIN_TOGETHER:
- {
- Creature* ACU = GetACU();
- Creature* VX001 = GetVX001();
- if( !VX001 || !ACU )
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
-
- ACU->SetDisableGravity(false);
- ACU->EnterVehicle(VX001, 3);
- me->EnterVehicle(VX001, 1);
- Talk(SAY_V07TRON_ACTIVATE);
- events.ScheduleEvent(EVENT_START_PHASE4, 10s);
- }
- break;
- case EVENT_START_PHASE4:
- {
- Creature* VX001 = GetVX001();
- Creature* LMK2 = GetLMK2();
- Creature* ACU = GetACU();
- if( !VX001 || !LMK2 || !ACU )
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
-
- LMK2->AI()->SetData(1, 4);
- VX001->AI()->SetData(1, 4);
- ACU->AI()->SetData(1, 4);
- LMK2->CastSpell(LMK2, SPELL_SELF_REPAIR, true); //LMK2->SetHealth( LMK2->GetMaxHealth()/2 );
- VX001->CastSpell(VX001, SPELL_SELF_REPAIR, true); //VX001->SetHealth( VX001->GetMaxHealth()/2 );
- ACU->CastSpell(ACU, SPELL_SELF_REPAIR, true); //ACU->SetHealth( ACU->GetMaxHealth()/2 );
- if( hardmode )
- {
- LMK2->CastSpell(LMK2, SPELL_EMERGENCY_MODE, true);
- VX001->CastSpell(VX001, SPELL_EMERGENCY_MODE, true);
- ACU->CastSpell(ACU, SPELL_EMERGENCY_MODE, true);
- }
- me->SetInCombatWithZone();
- }
- break;
- case EVENT_FINISH:
- {
- Creature* LMK2 = GetLMK2();
- Creature* VX001 = GetVX001();
- Creature* ACU = GetACU();
-
- if (!VX001 || !LMK2 || !ACU)
- return;
-
- LMK2->GetMotionMaster()->Clear();
- LMK2->StopMoving();
- LMK2->InterruptNonMeleeSpells(false);
- LMK2->AttackStop();
- LMK2->AI()->SetData(1, 0);
- LMK2->DespawnOrUnsummon(7000);
- LMK2->SetReactState(REACT_PASSIVE);
- VX001->InterruptNonMeleeSpells(false);
- VX001->AttackStop();
- VX001->AI()->SetData(1, 0);
- VX001->DespawnOrUnsummon(7000);
- VX001->SetReactState(REACT_PASSIVE);
- ACU->InterruptNonMeleeSpells(false);
- ACU->AttackStop();
- ACU->AI()->SetData(1, 0);
- ACU->DespawnOrUnsummon(7000);
- ACU->SetReactState(REACT_PASSIVE);
-
- Position exitPos = me->GetPosition();
- me->_ExitVehicle(&exitPos);
- me->AttackStop();
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK);
- me->GetMotionMaster()->Clear();
- summons.DoAction(1337); // despawn summons of summons
- summons.DespawnEntry(NPC_FLAMES_INITIAL);
- summons.DespawnEntry(33576);
-
- float angle = VX001->GetOrientation();
- float v_x = me->GetPositionX() + cos(angle) * 10.0f;
- float v_y = me->GetPositionY() + std::sin(angle) * 10.0f;
- me->GetMotionMaster()->MoveJump(v_x, v_y, 364.32f, 7.0f, 7.0f);
-
- if( pInstance )
- for( uint16 i = 0; i < 3; ++i )
- if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) )
- if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) )
- if( door->GetGoState() != GO_STATE_ACTIVE )
- {
- door->SetLootState(GO_READY);
- door->UseDoorOrButton(0, false);
- }
-
- if (pInstance)
- pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_LEVIATHAN_MKII, 1, me);
-
- if (hardmode)
- if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) )
- computer->AI()->Talk(TALK_COMPUTER_TERMINATED);
-
- events.Reset();
- events.ScheduleEvent(EVENT_SAY_VOLTRON_DEAD, 6s);
- }
- break;
- case EVENT_SAY_VOLTRON_DEAD:
- Talk(SAY_V07TRON_DEATH);
- // spawn chest
- if (uint32 chestId = (hardmode ? RAID_MODE(GO_MIMIRON_CHEST_HARD, GO_MIMIRON_CHEST_HERO_HARD) : RAID_MODE(GO_MIMIRON_CHEST, GO_MIMIRON_CHEST_HERO)))
- {
- if (GameObject* go = me->SummonGameObject(chestId, 2744.65f, 2569.46f, 364.397f, 0, 0, 0, 0, 0, 0))
- {
- go->ReplaceAllGameObjectFlags((GameObjectFlags)0);
- go->SetLootRecipient(me->GetMap());
- }
- }
- events.ScheduleEvent(EVENT_DISAPPEAR, 15s);
- break;
- case EVENT_DISAPPEAR:
- if( pInstance )
- pInstance->SetData(TYPE_MIMIRON, DONE);
- summons.DespawnAll();
- me->DespawnOrUnsummon();
- break;
- }
- }
-
- void MoveInLineOfSight(Unit* /*mover*/) override {}
-
- void EnterEvadeMode(EvadeReason why) override
- {
- if (bIsEvading)
- return;
- bIsEvading = true;
-
- if (Creature* c = GetLMK2())
- {
- c->AI()->EnterEvadeMode(why);
- }
- if (Creature* c = GetVX001())
- {
- c->AI()->EnterEvadeMode(why);
- c->DespawnOrUnsummon();
- }
- if (Creature* c = GetACU())
- {
- c->AI()->EnterEvadeMode(why);
- c->DespawnOrUnsummon();
- }
-
- summons.DoAction(1337); // despawn summons of summons
-
- me->RemoveAllAuras();
- me->ExitVehicle();
- ScriptedAI::EnterEvadeMode(why);
-
- bIsEvading = false;
- }
-
- void JustSummoned(Creature* s) override
- {
- summons.Summon(s);
- }
-
- void SummonedCreatureDespawn(Creature* s) override
- {
- summons.Despawn(s);
- }
-
- void ResetGameObjects()
- {
- if( pInstance )
- for( uint16 i = 0; i < 3; ++i )
- if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) )
- if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) )
- if( door->GetGoState() != GO_STATE_ACTIVE )
- {
- door->SetLootState(GO_READY);
- door->UseDoorOrButton(0, false);
- }
-
- if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 200.0f) )
- {
- if( elevator->GetGoState() != GO_STATE_ACTIVE )
- {
- elevator->SetLootState(GO_READY);
- elevator->SetByteValue(GAMEOBJECT_BYTES_1, 0, GO_STATE_ACTIVE);
- }
- elevator->EnableCollision(false);
- }
-
- if( GameObject* button = me->FindNearestGameObject(GO_BUTTON, 200.0f) )
- if( button->GetGoState() != GO_STATE_READY )
- {
- button->SetLootState(GO_READY);
- button->UseDoorOrButton(0, false);
- button->RemoveGameObjectFlag(GO_FLAG_IN_USE);
- }
- }
-
- void CloseDoorAndButton()
- {
- if( pInstance )
- for( uint16 i = 0; i < 3; ++i )
- if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) )
- if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) )
- if( door->GetGoState() != GO_STATE_READY )
- {
- door->SetLootState(GO_READY);
- door->UseDoorOrButton(0, false);
- }
-
- if( GameObject* button = me->FindNearestGameObject(GO_BUTTON, 200.0f) )
- if( button->GetGoState() != GO_STATE_ACTIVE )
- {
- button->SetLootState(GO_READY);
- button->UseDoorOrButton(0, false);
- }
- }
-
- void SetData(uint32 /*id*/, uint32 value) override
- {
- switch (value) // end of phase 1-3, 4-6 for voltron
- {
- case 1:
- events.ScheduleEvent(EVENT_LMK2_RETREAT_INTERVAL, 5s);
- break;
- case 2:
- events.ScheduleEvent(EVENT_VX001_EMOTESTATE_DEATH, 2500ms);
- break;
- case 3:
- events.ScheduleEvent(EVENT_SAY_ACU_DEAD, 5s);
- break;
- case 4:
- case 5:
- case 6:
- {
- Creature* LMK2 = GetLMK2();
- Creature* VX001 = GetVX001();
- Creature* ACU = GetACU();
- if (!LMK2 || !VX001 || !ACU)
- {
- EnterEvadeMode(EVADE_REASON_OTHER);
- return;
- }
-
- Spell* s1 = LMK2->GetCurrentSpell(CURRENT_GENERIC_SPELL);
- Spell* s2 = VX001->GetCurrentSpell(CURRENT_GENERIC_SPELL);
- Spell* s3 = ACU->GetCurrentSpell(CURRENT_GENERIC_SPELL);
- if (s1 && s2 && s3 && s1->GetSpellInfo()->Id == SPELL_SELF_REPAIR && s2->GetSpellInfo()->Id == SPELL_SELF_REPAIR && s3->GetSpellInfo()->Id == SPELL_SELF_REPAIR)
- events.ScheduleEvent(EVENT_FINISH, 0ms);
- }
- break;
- case 7:
- hardmode = true;
- break;
- case 11:
- bAchievProximityMine = true;
- break;
- case 12:
- bAchievBombBot = true;
- break;
- case 13:
- bAchievRocketStrike = true;
- break;
- }
- }
-
- uint32 GetData(uint32 id) const override
- {
- switch (id)
- {
- case 1:
- return (hardmode ? 1 : 0);
- case 2:
- return (berserk ? 1 : 0);
- case 10:
- return allowedFlameSpreadTime;
- case 11:
- return (bAchievProximityMine ? 1 : 0);
- case 12:
- return (bAchievBombBot ? 1 : 0);
- case 13:
- return (bAchievRocketStrike ? 1 : 0);
- }
- return 0;
- }
- };
-};
-
-class npc_ulduar_leviathan_mkii : public CreatureScript
-{
-public:
- npc_ulduar_leviathan_mkii() : CreatureScript("npc_ulduar_leviathan_mkii") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_leviathan_mkiiAI : public ScriptedAI
- {
- npc_ulduar_leviathan_mkiiAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- pInstance = me->GetInstanceScript();
- bIsEvading = false;
- }
-
- InstanceScript* pInstance;
- EventMap events;
- bool bIsEvading;
- uint8 Phase;
-
- void Reset() override
- {
- Phase = 0;
- if (Unit* c = GetS3())
- c->ExitVehicle(); // this should never happen!
- if (Creature* c = me->SummonCreature(NPC_LEVIATHAN_MKII_CANNON, *me, TEMPSUMMON_MANUAL_DESPAWN))
- c->EnterVehicle(me, 3);
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetReactState(REACT_AGGRESSIVE);
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
-
- events.Reset();
- }
-
- void SetData(uint32 id, uint32 value) override
- {
- if (id == 1) // setting phase to start fighting
- {
- switch (value)
- {
- case 0:
- Phase = 0;
- events.Reset();
- break;
- case 1:
- Phase = 1;
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- if (Unit* target = SelectTargetFromPlayerList(75.0f))
- AttackStart(target);
- DoZoneInCombat();
- events.Reset();
- events.ScheduleEvent(EVENT_SPELL_NAPALM_SHELL, 3s);
- events.ScheduleEvent(EVENT_SPELL_PLASMA_BLAST, 10s);
- events.ScheduleEvent(EVENT_SPELL_SHOCK_BLAST, 20s);
- events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 6s);
- if (Creature* c = GetMimiron())
- if (c->AI()->GetData(1))
- events.ScheduleEvent(EVENT_FLAME_SUPPRESSION_50000, 60s);
- break;
- case 4:
- me->SetReactState(REACT_AGGRESSIVE);
- DoResetThreatList();
- Phase = 4;
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- if (Unit* target = SelectTargetFromPlayerList(75.0f))
- AttackStart(target);
- DoZoneInCombat();
- events.Reset();
- events.ScheduleEvent(EVENT_SPELL_SHOCK_BLAST, 20s);
- events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 6s);
- break;
- }
- }
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (damage >= me->GetHealth() || me->GetHealth() < 15000)
- {
- damage = 0;
- if (me->GetReactState() == REACT_PASSIVE)
- return;
- me->SetReactState(REACT_PASSIVE);
- if (Phase == 1)
- {
- if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
- {
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->GetMotionMaster()->Clear();
- me->AttackStop();
- me->SetReactState(REACT_PASSIVE);
- SetData(1, 0);
- me->InterruptNonMeleeSpells(false);
- me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
- if (Unit* cannon = GetS3())
- cannon->ExitVehicle();
- me->GetMotionMaster()->MoveCharge(2795.076f, 2598.616f, 364.32f, 21.0f);
- if (Creature* c = GetMimiron())
- c->AI()->SetData(0, 1);
- }
- }
- else if (Phase == 4)
- {
- if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
- {
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->InterruptNonMeleeSpells(false);
- me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
- me->CastSpell(me, SPELL_SELF_REPAIR, false);
- if (Creature* c = GetMimiron())
- {
- if (c->AI()->GetData(1))
- me->CastSpell(me, SPELL_EMERGENCY_MODE, true);
- if (c->AI()->GetData(2))
- me->CastSpell(me, SPELL_BERSERK, true);
- c->AI()->SetData(0, 4);
- }
- }
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
-
- if (!me->HasUnitState(UNIT_STATE_CASTING))
- DoMeleeAttackIfReady();
-
- Unit* cannon = GetS3();
- if (!cannon || cannon->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CASTING) || me->HasAuraType(SPELL_AURA_MOD_SILENCE))
- return;
-
- switch (events.ExecuteEvent())
- {
- case 0:
- break;
- case EVENT_SPELL_NAPALM_SHELL:
- {
- Player* pTarget = nullptr;
- std::vector pList;
- Map::PlayerList const& pl = me->GetMap()->GetPlayers();
- for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
- if (Player* plr = itr->GetSource())
- if( plr->IsAlive() && plr->GetDistance2d(me) > 15.0f )
- pList.push_back(plr);
-
- if (!pList.empty())
- pTarget = pList[urand(0, pList.size() - 1)];
- else
- pTarget = (Player*)SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true);
-
- if( pTarget )
- cannon->CastSpell(pTarget, SPELL_NAPALM_SHELL, false);
-
- events.Repeat(14s);
- }
- break;
- case EVENT_SPELL_PLASMA_BLAST:
- if (Unit* victim = me->GetVictim())
- {
- Talk(EMOTE_PLASMA_BLAST);
- cannon->CastSpell(victim, SPELL_PLASMA_BLAST, false);
- }
- events.Repeat(22s);
- break;
- case EVENT_SPELL_SHOCK_BLAST:
- me->CastSpell(me->GetVictim(), SPELL_SHOCK_BLAST, false);
- events.Repeat(30s);
- events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 8s);
- break;
- case EVENT_PROXIMITY_MINES_1:
- for (uint8 i = 0; i < 10; ++i)
- {
- me->CastSpell(me, SPELL_SUMMON_PROXIMITY_MINE, true);
- }
- break;
- case EVENT_FLAME_SUPPRESSION_50000:
- me->CastSpell(me, SPELL_FLAME_SUPPRESSANT_50000yd, false);
- break;
- }
- }
-
- void MoveInLineOfSight(Unit* /*mover*/) override {}
-
- void KilledUnit(Unit* who) override
- {
- if (who->GetTypeId() == TYPEID_PLAYER)
- if (Creature* c = GetMimiron())
- {
- if (Phase == 1)
- {
- c->AI()->Talk(SAY_MKII_SLAY);
- }
- else
- {
- c->AI()->Talk(SAY_V07TRON_SLAY);
- }
- }
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- if (bIsEvading)
- return;
- bIsEvading = true;
-
- me->RemoveAllAuras();
- me->ExitVehicle();
- ScriptedAI::EnterEvadeMode();
-
- if (Creature* mimiron = GetMimiron())
- mimiron->AI()->EnterEvadeMode(why);
-
- bIsEvading = false;
- }
-
- void PassengerBoarded(Unit* p, int8 /*seat*/, bool apply) override
- {
- if (p->GetEntry() == NPC_LEVIATHAN_MKII_CANNON && !apply)
- {
- Unit::Kill(p, p);
- p->ToCreature()->DespawnOrUnsummon(6000);
- }
- }
-
- Unit* GetS3()
- {
- if (Vehicle* vk = me->GetVehicleKit())
- if (Unit* cannon = vk->GetPassenger(3))
- return cannon;
-
- return 0;
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if( spell->Id == SPELL_SELF_REPAIR )
- {
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetReactState(REACT_AGGRESSIVE);
- }
- }
- };
-};
-
-class npc_ulduar_vx001 : public CreatureScript
-{
-public:
- npc_ulduar_vx001() : CreatureScript("npc_ulduar_vx001") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_vx001AI : public ScriptedAI
- {
- npc_ulduar_vx001AI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- pInstance = me->GetInstanceScript();
- bIsEvading = false;
- }
-
- InstanceScript* pInstance;
- EventMap events;
- bool bIsEvading;
- uint8 Phase;
- bool fighting;
- bool leftarm;
- uint32 spinningUpOrientation;
- uint16 spinningUpTimer;
-
- void Reset() override
- {
- Phase = 0;
- fighting = false;
- leftarm = false;
- spinningUpTimer = 0;
- me->SetRegeneratingHealth(false);
- events.Reset();
- }
-
- void AttackStart(Unit* /*who*/) override {}
-
- void SetData(uint32 id, uint32 value) override
- {
- if (id == 1) // setting phase to start fighting
- {
- switch (value)
- {
- case 0:
- Phase = 0;
- fighting = false;
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
- events.Reset();
- break;
- case 2:
- Phase = 2;
- fighting = true;
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_SPELL_CAST_OMNI);
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- events.Reset();
- events.ScheduleEvent(EVENT_SPELL_HEAT_WAVE, 10s);
- events.ScheduleEvent(EVENT_SPELL_ROCKET_STRIKE, 16s);
- events.ScheduleEvent(EVENT_SPELL_RAPID_BURST, 0ms);
- events.ScheduleEvent(EVENT_SPELL_SPINNING_UP, 30s);
- events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 3s);
- if (Creature* c = GetMimiron())
- if (c->AI()->GetData(1))
- {
- events.ScheduleEvent(EVENT_FLAME_SUPPRESSION_10, 7s);
- events.ScheduleEvent(EVENT_FROST_BOMB, 1s);
- }
- break;
- case 4:
- Phase = 4;
- fighting = true;
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- events.Reset();
- events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 3s);
- events.ScheduleEvent(EVENT_SPELL_ROCKET_STRIKE, 16s);
- events.ScheduleEvent(EVENT_HAND_PULSE, 1ms);
- events.ScheduleEvent(EVENT_SPELL_SPINNING_UP, 30s);
- if (Creature* c = GetMimiron())
- if (c->AI()->GetData(1))
- events.ScheduleEvent(EVENT_FROST_BOMB, 1s);
- break;
- }
- }
- }
-
- uint32 GetData(uint32 /*id*/) const override
- {
- return spinningUpOrientation;
- }
-
- void DoAction(int32 action) override
- {
- if (action == 1337)
- if( Vehicle* vk = me->GetVehicleKit() )
- for (uint8 i = 0; i < 2; ++i)
- if (Unit* r = vk->GetPassenger(5 + i))
- if (r->GetTypeId() == TYPEID_UNIT)
- r->ToCreature()->DespawnOrUnsummon(1);
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (damage >= me->GetHealth() || me->GetHealth() < 15000)
- {
- damage = 0;
- if (me->GetReactState() == REACT_PASSIVE)
- return;
- me->SetReactState(REACT_PASSIVE);
- if (Phase == 2)
- {
- if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
- {
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- SetData(1, 0);
- me->InterruptNonMeleeSpells(false);
- me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
- me->SendMeleeAttackStop();
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_06);
- me->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_06);
- if (Creature* c = GetMimiron())
- c->AI()->SetData(0, 2);
- }
- }
- else if (Phase == 4)
- {
- if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
- {
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->InterruptNonMeleeSpells(false);
- me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
- me->CastSpell(me, SPELL_SELF_REPAIR, false);
- if (Creature* c = GetMimiron())
- {
- if (c->AI()->GetData(1))
- me->CastSpell(me, SPELL_EMERGENCY_MODE, true);
- if (c->AI()->GetData(2))
- me->CastSpell(me, SPELL_BERSERK, true);
- c->AI()->SetData(0, 5);
- }
- }
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!fighting)
- return;
-
- events.Update(diff);
-
- if (spinningUpTimer) // executed about a second after starting casting to ensure players can see the correct direction
- {
- if (spinningUpTimer <= diff)
- {
- float angle = (spinningUpOrientation * 2 * M_PI) / 100.0f;
- me->SetFacingTo(angle);
-
- spinningUpTimer = 0;
- }
- else
- spinningUpTimer -= diff;
- }
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case 0:
- break;
- case EVENT_SPELL_HEAT_WAVE:
- me->CastSpell(me, SPELL_HEAT_WAVE, true);
- events.Repeat(10s);
- break;
- case EVENT_SPELL_ROCKET_STRIKE:
- if( Vehicle* vk = me->GetVehicleKit() )
- {
- for( int i = 0; i < (Phase / 2); ++i )
- {
- uint8 index = (Phase == 2 ? rand() % 2 : i);
- if( Unit* r = vk->GetPassenger(5 + index) )
- if (Player* temp = SelectTargetFromPlayerList(100.0f))
- {
- if( Creature* trigger = me->SummonCreature(NPC_ROCKET_STRIKE_N, temp->GetPositionX(), temp->GetPositionY(), temp->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 6000) )
- trigger->CastSpell(trigger, SPELL_ROCKET_STRIKE_AURA, true);
- Position exitPos = r->GetPosition();
- exitPos.m_positionX += cos(me->GetOrientation()) * 2.35f;
- exitPos.m_positionY += std::sin(me->GetOrientation()) * 2.35f;
- exitPos.m_positionZ += 2.0f * Phase;
- r->_ExitVehicle(&exitPos);
- me->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE, r->GetGUID());
- if (r->GetTypeId() == TYPEID_UNIT)
- r->ToCreature()->AI()->SetData(0, 0);
- }
- }
- events.Repeat(20s);
- events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 10s);
- }
- break;
- case EVENT_REINSTALL_ROCKETS:
- if (Vehicle* vk = me->GetVehicleKit())
- {
- for (uint8 i = 5; i <= 6; ++i)
- if (!vk->GetPassenger(i))
- if (TempSummon* accessory = me->SummonCreature(NPC_ROCKET_VISUAL, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 4.0f, me->GetOrientation(), TEMPSUMMON_MANUAL_DESPAWN))
- if (!me->HandleSpellClick(accessory, i))
- accessory->UnSummon();
- }
- break;
- case EVENT_SPELL_RAPID_BURST:
- if (Player* p = SelectTargetFromPlayerList(80.0f))
- {
- me->CastSpell(p, SPELL_RAPID_BURST, true);
- me->SetFacingToObject(p);
- }
- events.Repeat(3200ms);
- break;
- case EVENT_HAND_PULSE:
- if (Player* p = SelectTargetFromPlayerList(80.0f))
- {
- me->SetFacingToObject(p);
- if (Unit* vb = me->GetVehicleBase())
- {
- vb->SendMeleeAttackStop();
- vb->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
-
- if( !leftarm )
- {
- vb->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_03);
- me->CastSpell(p, SPELL_HAND_PULSE_R, false);
- }
- else
- {
- vb->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_04);
- me->CastSpell(p, SPELL_HAND_PULSE_L, false);
- }
- }
-
- leftarm = !leftarm;
- }
- events.Repeat(1750ms);
- break;
- case EVENT_SPELL_SPINNING_UP:
- events.Repeat(45s);
- if (Player* p = SelectTargetFromPlayerList(80.0f))
- {
- float angle = me->GetAngle(p);
-
- spinningUpOrientation = (uint32)((angle * 100.0f) / (2 * M_PI));
- spinningUpTimer = 1500;
- me->SetFacingTo(angle);
- me->CastSpell(p, SPELL_SPINNING_UP, true);
- if (Unit* vehicle = me->GetVehicleBase())
- {
- vehicle->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_CUSTOM_SPELL_01);
- vehicle->HandleEmoteCommand(EMOTE_STATE_CUSTOM_SPELL_01);
- }
- events.RescheduleEvent((Phase == 2 ? EVENT_SPELL_RAPID_BURST : EVENT_HAND_PULSE), 14s + 500ms);
- }
- break;
- case EVENT_FLAME_SUPPRESSION_10:
- me->CastSpell(me, SPELL_FLAME_SUPPRESSANT_10yd, false);
- events.Repeat(10s);
- break;
- case EVENT_FROST_BOMB:
- me->CastCustomSpell(SPELL_VX001_FROST_BOMB, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false);
- events.Repeat(45s);
- break;
- }
- }
-
- void MoveInLineOfSight(Unit* /*mover*/) override {}
-
- void KilledUnit(Unit* who) override
- {
- if (who->GetTypeId() == TYPEID_PLAYER)
- if (Creature* c = GetMimiron())
- {
- if (Phase == 2)
- {
- c->AI()->Talk(SAY_VX001_SLAY);
- }
- else
- {
- c->AI()->Talk(SAY_V07TRON_SLAY);
- }
- }
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- if (bIsEvading)
- return;
- bIsEvading = true;
-
- me->RemoveAllAuras();
- me->ExitVehicle();
- _EnterEvadeMode();
- Reset();
- if (Creature* mimiron = GetMimiron())
- mimiron->AI()->EnterEvadeMode(why);
-
- bIsEvading = false;
- }
-
- void PassengerBoarded(Unit* p, int8 /*seat*/, bool apply) override
- {
- if (p->GetEntry() == NPC_ROCKET_VISUAL && !apply)
- p->ToCreature()->DespawnOrUnsummon(8000);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if( spell->Id == SPELL_SELF_REPAIR )
- {
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetReactState(REACT_AGGRESSIVE);
- }
- }
- };
-};
-
-class npc_ulduar_aerial_command_unit : public CreatureScript
-{
-public:
- npc_ulduar_aerial_command_unit() : CreatureScript("npc_ulduar_aerial_command_unit") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_aerial_command_unitAI : public ScriptedAI
- {
- npc_ulduar_aerial_command_unitAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
- {
- pInstance = me->GetInstanceScript();
- bIsEvading = false;
- immobilized = false;
- me->SetDisableGravity(true);
- }
-
- InstanceScript* pInstance;
- EventMap events;
- SummonList summons;
- bool bIsEvading;
- uint8 Phase;
- bool immobilized;
-
- void Reset() override
- {
- Phase = 0;
- events.Reset();
- summons.DespawnAll();
- }
-
- void AttackStart(Unit* who) override
- {
- if (who)
- me->Attack(who, true); // skip following
- }
-
- void SetData(uint32 id, uint32 value) override
- {
- if (id == 1) // setting phase to start fighting
- {
- switch (value)
- {
- case 0:
- Phase = 0;
- events.Reset();
- immobilized = false;
- break;
- case 3:
- Phase = 3;
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- if (Unit* target = SelectTargetFromPlayerList(75.0f))
- AttackStart(target);
- DoZoneInCombat();
- events.Reset();
- events.ScheduleEvent(EVENT_SPELL_PLASMA_BALL, 0ms);
- events.ScheduleEvent(EVENT_SUMMON_BOMB_BOT, 15s);
- events.ScheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 1s);
- events.ScheduleEvent(EVENT_SUMMON_JUNK_BOT, 10s);
- if (Creature* c = GetMimiron())
- if (c->AI()->GetData(1))
- events.ScheduleEvent(EVENT_SUMMON_EMERGENCY_FIRE_BOTS, 0ms);
- break;
- case 4:
- me->SetReactState(REACT_AGGRESSIVE);
- DoResetThreatList();
- Phase = 4;
- me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- if (Unit* target = SelectTargetFromPlayerList(75.0f))
- AttackStart(target);
- DoZoneInCombat();
- events.Reset();
- events.ScheduleEvent(EVENT_SPELL_PLASMA_BALL, 0ms);
- }
- }
- else if (id == 2 && !immobilized && Phase == 3) // magnetic core
- {
- immobilized = true;
- events.ScheduleEvent(EVENT_MAGNETIC_CORE_PULL_DOWN, 2s);
- }
- }
-
- void DoAction(int32 param) override
- {
- if (param == 1337)
- summons.DespawnAll();
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (damage >= me->GetHealth() || me->GetHealth() < 15000)
- {
- damage = 0;
- if (me->GetReactState() == REACT_PASSIVE)
- return;
- me->SetReactState(REACT_PASSIVE);
- if (Phase == 3)
- {
- if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
- {
- me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
- me->GetMotionMaster()->Clear();
- me->StopMoving();
- me->AttackStop();
- me->SetReactState(REACT_PASSIVE);
- SetData(1, 0);
- me->InterruptNonMeleeSpells(false);
- me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
-
- me->MonsterMoveWithSpeed(2744.65f, 2569.46f, 381.34f, me->GetDistance(2744.65f, 2569.46f, 381.34f));
- me->UpdatePosition(2744.65f, 2569.46f, 381.34f, M_PI, false);
-
- if (Creature* c = GetMimiron())
- c->AI()->SetData(0, 3);
- }
- }
- else if (Phase == 4)
- {
- if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
- {
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->InterruptNonMeleeSpells(false);
- me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
- me->CastSpell(me, SPELL_SELF_REPAIR, false);
- if (Creature* c = GetMimiron())
- {
- if (c->AI()->GetData(1))
- me->CastSpell(me, SPELL_EMERGENCY_MODE, true);
- if (c->AI()->GetData(2))
- me->CastSpell(me, SPELL_BERSERK, true);
- c->AI()->SetData(0, 6);
- }
- }
- }
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- // following :D
- if( Phase == 3 && !immobilized )
- if( Unit* victim = me->GetVictim() )
- if( me->GetExactDist2d(victim) > 25.0f )
- {
- float angle = victim->GetAngle(me->GetPositionX(), me->GetPositionY());
- me->SetOrientation( me->GetAngle(victim->GetPositionX(), victim->GetPositionY()) );
- float x = victim->GetPositionX() + 15.0f * cos(angle);
- float y = victim->GetPositionY() + 15.0f * std::sin(angle);
-
- // check if there's magnetic core in line of movement
- Creature* mc = nullptr;
- std::list cl;
- me->GetCreaturesWithEntryInRange(cl, me->GetExactDist2d(victim), NPC_MAGNETIC_CORE);
- for( std::list::iterator itr = cl.begin(); itr != cl.end(); ++itr )
- {
- if ((*itr)->IsInBetween(me, victim, 4.0f) && (*itr)->GetExactDist2d(victim) >= 10.0f) // don't come very close just because there's a magnetic core
- {
- x = (*itr)->GetPositionX();
- y = (*itr)->GetPositionY();
- mc = (*itr);
- break;
- }
- }
-
- float speed = me->GetExactDist(x, y, 381.34f);
- me->MonsterMoveWithSpeed(x, y, 381.34f, speed);
- me->UpdatePosition(x, y, 381.34f, me->GetAngle(victim), false);
- if (mc)
- {
- mc->AI()->SetData(0, 0);
- SetData(2, 1);
- }
- }
-
- events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case 0:
- break;
- case EVENT_SPELL_PLASMA_BALL:
- if( !immobilized )
- {
- if (Phase == 3)
- {
- if( Unit* victim = me->GetVictim() )
- me->CastSpell(victim, SPELL_PLASMA_BALL, false);
- }
- else
- {
- if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 27.5f, true))
- {
- me->SetFacingToObject(victim);
- me->CastSpell(victim, SPELL_PLASMA_BALL, false);
- }
- }
- }
- events.Repeat(3s);
- break;
- case EVENT_SUMMON_BOMB_BOT:
- if( !immobilized )
- me->CastSpell(me, SPELL_SUMMON_BOMB_BOT, false);
- events.Repeat(15s);
- break;
- case EVENT_SUMMON_ASSAULT_BOT:
- if( GameObject* pad = me->FindNearestGameObject(RAND(194742, 194746, 194745), 200.0f) )
- if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_TIMED_DESPAWN, 15000))
- trigger->AI()->DoAction(2);
- events.Repeat(30s);
- break;
- case EVENT_SUMMON_JUNK_BOT:
- if( GameObject* pad = me->FindNearestGameObject(RAND(194741, 194744, 194747), 200.0f) )
- if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_TIMED_DESPAWN, 15000))
- trigger->AI()->DoAction(1);
- events.Repeat(10s);
- break;
- case EVENT_SUMMON_EMERGENCY_FIRE_BOTS:
- {
- uint32 ids[3] = {194740, 194743, 194748};
- for( uint8 i = 0; i < 3; ++i )
- if( GameObject* pad = me->FindNearestGameObject(ids[i], 200.0f) )
- if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_MANUAL_DESPAWN))
- trigger->AI()->DoAction(3);
- events.Repeat(45s);
- }
- break;
- case EVENT_MAGNETIC_CORE_PULL_DOWN:
- me->CastSpell(me, SPELL_MAGNETIC_CORE, true);
- me->CastSpell(me, SPELL_SPINNING, true);
- me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 365.34f, me->GetExactDist(me->GetPositionX(), me->GetPositionY(), 365.34f));
- me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), 365.34f, me->GetOrientation(), false);
- events.ScheduleEvent(EVENT_MAGNETIC_CORE_FREE, 20s);
- break;
- case EVENT_MAGNETIC_CORE_FREE:
- me->RemoveAura(SPELL_SPINNING);
- me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 381.34f, me->GetDistance(me->GetPositionX(), me->GetPositionY(), 381.34f));
- me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), 381.34f, me->GetOrientation(), false);
- events.ScheduleEvent(EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE, 1s);
- break;
- case EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE:
- immobilized = false;
- break;
- }
- }
-
- void MoveInLineOfSight(Unit* /*mover*/) override {}
-
- void KilledUnit(Unit* who) override
- {
- if (who->GetTypeId() == TYPEID_PLAYER)
- if (Creature* c = GetMimiron())
- {
- if (Phase == 3)
- {
- c->AI()->Talk(SAY_AERIAL_SLAY);
- }
- else
- {
- c->AI()->Talk(SAY_V07TRON_SLAY);
- }
- }
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- if (bIsEvading)
- return;
- bIsEvading = true;
-
- me->RemoveAllAuras();
- me->ExitVehicle();
- _EnterEvadeMode();
- Reset();
- if (Creature* mimiron = GetMimiron())
- mimiron->AI()->EnterEvadeMode(why);
-
- bIsEvading = false;
- }
-
- void JustSummoned(Creature* s) override
- {
- summons.Summon(s);
- if (s->GetEntry() == NPC_BOMB_BOT)
- s->m_positionZ = 364.34f;
- }
-
- void SummonedCreatureDespawn(Creature* s) override
- {
- summons.Despawn(s);
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if( spell->Id == SPELL_SELF_REPAIR )
- {
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetReactState(REACT_AGGRESSIVE);
- }
- }
- };
-};
-
-class npc_ulduar_proximity_mine : public CreatureScript
-{
-public:
- npc_ulduar_proximity_mine() : CreatureScript("npc_ulduar_proximity_mine") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_proximity_mineAI : public ScriptedAI
- {
- npc_ulduar_proximity_mineAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- exploded = false;
- timer = 2500;
- timer2 = 35000;
- }
-
- bool exploded;
- uint16 timer;
- uint16 timer2;
-
- void AttackStart(Unit* /*who*/) override {}
- void MoveInLineOfSight(Unit* /*who*/) override {}
- bool CanAIAttack(Unit const* /*target*/) const override { return false; }
-
- void SpellHitTarget(Unit* target, SpellInfo const* spell) override
- {
- if (target && spell && target->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_MINE_EXPLOSION)
- if (InstanceScript* pInstance = me->GetInstanceScript())
- if (Creature* c = GetMimiron())
- c->AI()->SetData(0, 11);
- }
-
- // MoveInLineOfSight is checked every few yards, can't use it
- void UpdateAI(uint32 diff) override
- {
- if (timer2 <= diff)
- {
- timer2 = 35000;
- if (!exploded)
- {
- exploded = true;
- me->CastSpell(me, SPELL_MINE_EXPLOSION, false);
- }
- }
- else
- timer2 -= diff;
-
- if (timer <= diff)
- {
- timer = 500;
- if (!exploded && SelectTargetFromPlayerList(1.9f))
- {
- exploded = true;
- me->CastSpell(me, SPELL_MINE_EXPLOSION, false);
- }
- }
- else
- timer -= diff;
- }
- };
-};
-
-class npc_ulduar_mimiron_rocket : public CreatureScript
-{
-public:
- npc_ulduar_mimiron_rocket() : CreatureScript("npc_ulduar_mimiron_rocket") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_mimiron_rocketAI : public NullCreatureAI
- {
- npc_ulduar_mimiron_rocketAI(Creature* pCreature) : NullCreatureAI(pCreature) {}
-
- void InitializeAI() override
- {
- if (!me->isDead())
- Reset();
- }
-
- void Reset() override
- {
- me->SetCanFly(true);
- me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING);
- me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
- }
-
- void SetData(uint32 /*id*/, uint32 /*value*/) override
- {
- me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 100.0f, false, true);
- }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- if (!me->GetVehicle())
- {
- me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN) + 0.4f, false);
- me->SetSpeed(MOVE_FLIGHT, me->GetSpeedRate(MOVE_RUN), false);
- }
- }
- };
-};
-
-class npc_ulduar_magnetic_core : public CreatureScript
-{
-public:
- npc_ulduar_magnetic_core() : CreatureScript("npc_ulduar_magnetic_core") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_magnetic_coreAI : public NullCreatureAI
- {
- npc_ulduar_magnetic_coreAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- pInstance = me->GetInstanceScript();
- if (Creature* c = GetACU())
- if (c->GetExactDist2d(me) <= 10.0f)
- {
- me->SendMonsterMove(c->GetPositionX(), c->GetPositionY(), 364.313f, 1);
- me->UpdatePosition(c->GetPositionX(), c->GetPositionY(), 364.313f, me->GetOrientation(), true);
- me->StopMovingOnCurrentPos();
- c->AI()->SetData(2, 1);
- despawnTimer = 20000;
- return;
- }
- despawnTimer = 60000;
- }
-
- InstanceScript* pInstance;
- uint16 despawnTimer;
-
- void SetData(uint32 /*id*/, uint32 /*value*/) override
- {
- despawnTimer = 20000;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (despawnTimer <= diff)
- {
- despawnTimer = 60000;
- me->DespawnOrUnsummon(1);
- }
- else
- despawnTimer -= diff;
- }
- };
-};
-
-class npc_ulduar_bot_summon_trigger : public CreatureScript
-{
-public:
- npc_ulduar_bot_summon_trigger() : CreatureScript("npc_ulduar_bot_summon_trigger") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_bot_summon_triggerAI : public NullCreatureAI
- {
- npc_ulduar_bot_summon_triggerAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
-
- uint32 timer;
- uint8 option;
-
- void Reset() override
- {
- timer = 8000;
- option = 0;
- }
-
- void DoAction(int32 param) override
- {
- switch( param )
- {
- case 1:
- me->CastSpell(me, SPELL_BEAM_GREEN, true);
- option = 1;
- break;
- case 2:
- me->CastSpell(me, SPELL_BEAM_YELLOW, true);
- option = 2;
- break;
- case 3:
- me->CastSpell(me, SPELL_BEAM_BLUE, true);
- option = 3;
- break;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if( timer <= diff )
- {
- uint32 option_npcid[3] = {NPC_JUNK_BOT, NPC_ASSAULT_BOT, NPC_EMERGENCY_FIRE_BOT};
- InstanceScript* pInstance = me->GetInstanceScript();
- if (Creature* ACU = GetACU()) // ACU summons for easy removing
- if( Creature* bot = ACU->SummonCreature( option_npcid[option - 1], *me, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 25000 ) )
- {
- if( option < 3 )
- bot->SetInCombatWithZone();
- if (Creature* m = GetMimiron())
- if (m->AI()->GetData(1)) // hardmode
- bot->CastSpell(bot, SPELL_EMERGENCY_MODE, true);
- }
-
- me->DespawnOrUnsummon(500);
- timer = 99999;
- }
- else
- timer -= diff;
- }
- };
-};
-
-class spell_mimiron_rapid_burst : public SpellScriptLoader
-{
-public:
- spell_mimiron_rapid_burst() : SpellScriptLoader("spell_mimiron_rapid_burst") { }
-
- class spell_mimiron_rapid_burst_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_mimiron_rapid_burst_AuraScript)
-
- void HandleEffectPeriodic(AuraEffect const* aurEff)
- {
- if (Unit* c = GetCaster())
- {
- uint32 id = ( c->GetMap()->Is25ManRaid() ? ((aurEff->GetTickNumber() % 2) ? SPELL_RAPID_BURST_DAMAGE_25_2 : SPELL_RAPID_BURST_DAMAGE_25_1) : ((aurEff->GetTickNumber() % 2) ? SPELL_RAPID_BURST_DAMAGE_10_2 : SPELL_RAPID_BURST_DAMAGE_10_1) );
- c->CastSpell((Unit*)nullptr, id, true);
- }
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_rapid_burst_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_mimiron_rapid_burst_AuraScript();
- }
-};
-
-class spell_mimiron_p3wx2_laser_barrage : public SpellScriptLoader
-{
-public:
- spell_mimiron_p3wx2_laser_barrage() : SpellScriptLoader("spell_mimiron_p3wx2_laser_barrage") { }
-
- class spell_mimiron_p3wx2_laser_barrage_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_mimiron_p3wx2_laser_barrage_AuraScript)
-
- uint32 lastMSTime;
- float lastOrientation;
-
- bool Load() override
- {
- lastMSTime = GameTime::GetGameTimeMS().count();
- lastOrientation = -1.0f;
- return true;
- }
-
- void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
- {
- if (Unit* c = GetCaster())
- {
- if (c->GetTypeId() != TYPEID_UNIT)
- return;
- uint32 diff = getMSTimeDiff(lastMSTime, GameTime::GetGameTimeMS().count());
- if (lastOrientation == -1.0f)
- {
- lastOrientation = (c->ToCreature()->AI()->GetData(0) * 2 * M_PI) / 100.0f;
- diff = 0;
- }
- float new_o = Position::NormalizeOrientation(lastOrientation - (M_PI / 60) * (diff / 250.0f));
- lastMSTime = GameTime::GetGameTimeMS().count();
- lastOrientation = new_o;
- c->SetFacingTo(new_o);
-
- c->CastSpell((Unit*)nullptr, 63297, true);
- c->CastSpell((Unit*)nullptr, 64042, true);
- }
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_p3wx2_laser_barrage_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_mimiron_p3wx2_laser_barrage_AuraScript();
- }
-};
-
-class go_ulduar_do_not_push_this_button : public GameObjectScript
-{
-public:
- go_ulduar_do_not_push_this_button() : GameObjectScript("go_ulduar_do_not_push_this_button") { }
-
- bool OnGossipHello(Player* player, GameObject* go) override
- {
- if(!player || !go)
- return true;
-
- if (InstanceScript* instance = go->GetInstanceScript())
- {
- if(instance->GetData(TYPE_MIMIRON) != NOT_STARTED)
- return false;
-
- if (Creature* c = ObjectAccessor::GetCreature(*go, instance->GetGuidData(TYPE_MIMIRON)))
- {
- c->AI()->SetData(0, 7);
- c->AI()->AttackStart(player);
- }
- }
-
- return false;
- }
-};
-
-class npc_ulduar_flames_initial : public CreatureScript
-{
-public:
- npc_ulduar_flames_initial() : CreatureScript("npc_ulduar_flames_initial") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_flames_initialAI : public NullCreatureAI
- {
- npc_ulduar_flames_initialAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- CreateTime = GameTime::GetGameTime().count();
- events.Reset();
- events.ScheduleEvent(EVENT_FLAMES_SPREAD, 5750ms);
- if( Creature* flame = me->SummonCreature(NPC_FLAMES_SPREAD, me->GetPositionX(), me->GetPositionY(), 364.32f, 0.0f) )
- {
- FlameList.push_back(flame->GetGUID());
- flame->CastSpell(flame, SPELL_FLAMES_AURA, true);
- }
- }
-
- GuidList FlameList;
- EventMap events;
- uint32 CreateTime;
-
- void DoAction(int32 action) override
- {
- if (action == 1337)
- RemoveAll();
- }
-
- void SpreadFlame(float x, float y)
- {
- if( Creature* flame = me->SummonCreature(NPC_FLAMES_SPREAD, x, y, 364.32f, 0.0f) )
- {
- FlameList.push_back(flame->GetGUID());
- if (Creature* c = me->FindNearestCreature(NPC_FLAMES_SPREAD, 10.0f))
- if (c->GetExactDist2d(flame->GetPositionX(), flame->GetPositionY()) <= 4.0f)
- return;
- flame->CastSpell(flame, SPELL_FLAMES_AURA, true);
- }
- }
-
- void RemoveFlame(ObjectGuid guid)
- {
- FlameList.remove(guid);
- }
-
- void RemoveAll()
- {
- for (ObjectGuid const& guid : FlameList)
- if (Creature* c = ObjectAccessor::GetCreature(*me, guid))
- c->DespawnOrUnsummon();
- FlameList.clear();
- me->DespawnOrUnsummon();
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (InstanceScript* pInstance = me->GetInstanceScript())
- if (pInstance->GetData(TYPE_MIMIRON) != IN_PROGRESS)
- {
- RemoveAll();
- return;
- }
-
- events.Update(diff);
-
- switch( events.ExecuteEvent() )
- {
- case 0:
- break;
- case EVENT_FLAMES_SPREAD:
- {
- if( FlameList.empty() )
- {
- me->DespawnOrUnsummon();
- return;
- }
-
- if (InstanceScript* pInstance = me->GetInstanceScript())
- if (Creature* mimiron = GetMimiron())
- if (CreateTime < mimiron->AI()->GetData(10))
- {
- break;
- }
-
- Creature* last = ObjectAccessor::GetCreature(*me, FlameList.back());
- if( last )
- {
- float prevdist = 100.0f;
- Player* target = nullptr;
-
- Map::PlayerList const& pl = me->GetMap()->GetPlayers();
- for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
- if( Player* plr = itr->GetSource() )
- if( plr->IsAlive() && plr->GetExactDist2d(last) < prevdist && !plr->IsGameMaster() )
- {
- target = plr;
- prevdist = plr->GetExactDist2d(last);
- }
-
- if (target && prevdist >= 4.0f) // no need to spread when player is standing in fire, check distance
- {
- float angle = last->GetAngle(target->GetPositionX(), target->GetPositionY()) - M_PI / 8 + rand_norm() * 2 * M_PI / 8;
- SpreadFlame(last->GetPositionX() + 7.0f * cos(angle), last->GetPositionY() + 7.0f * std::sin(angle));
- }
- }
-
- events.Repeat(5750ms);
- }
- break;
- }
- }
- };
-};
-
-class npc_ulduar_flames_spread : public CreatureScript
-{
-public:
- npc_ulduar_flames_spread() : CreatureScript("npc_ulduar_flames_spread") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_flames_spreadAI : public NullCreatureAI
- {
- npc_ulduar_flames_spreadAI(Creature* pCreature) : NullCreatureAI(pCreature) {}
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- switch( spell->Id )
- {
- case SPELL_FROST_BOMB_EXPLOSION_10:
- case SPELL_FROST_BOMB_EXPLOSION_25:
- case SPELL_FLAME_SUPPRESSANT_10yd:
- case SPELL_FLAME_SUPPRESSANT_50000yd:
- case SPELL_WATER_SPRAY:
- {
- if (me->IsSummon())
- if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit())
- if (Creature* c = summoner->ToCreature())
- if (c->AI())
- CAST_AI(npc_ulduar_flames_initial::npc_ulduar_flames_initialAI, c->AI())->RemoveFlame(me->GetGUID());
-
- me->RemoveAllAuras();
- me->DespawnOrUnsummon(2500);
- }
- break;
- case SPELL_VX001_FROST_BOMB:
- me->CastSpell(me, SPELL_SUMMON_FROST_BOMB, true);
- break;
- }
- }
- };
-};
-
-class npc_ulduar_emergency_fire_bot : public CreatureScript
-{
-public:
- npc_ulduar_emergency_fire_bot() : CreatureScript("npc_ulduar_emergency_fire_bot") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_emergency_fire_botAI : public ScriptedAI
- {
- npc_ulduar_emergency_fire_botAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- events.Reset();
- events.ScheduleEvent(EVENT_EMERGENCY_BOT_CHECK, 1s);
- }
-
- EventMap events;
-
- void MoveInLineOfSight(Unit*) override {}
- void AttackStart(Unit*) override {}
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type == POINT_MOTION_TYPE && id == 1)
- events.ScheduleEvent(EVENT_EMERGENCY_BOT_ATTACK, 0ms);
- }
-
- void UpdateAI(uint32 diff) override
- {
- events.Update(diff);
- switch( events.ExecuteEvent() )
- {
- case 0:
- break;
- case EVENT_EMERGENCY_BOT_CHECK:
- events.Repeat(15s);
- if (Creature* flame = me->FindNearestCreature(NPC_FLAMES_SPREAD, 150.0f, true))
- {
- me->SetOrientation(me->GetAngle(flame->GetPositionX(), flame->GetPositionY()));
- float dist = me->GetExactDist2d(flame);
- if (dist <= 5.0f)
- events.ScheduleEvent(EVENT_EMERGENCY_BOT_ATTACK, 0ms);
- else
- me->GetMotionMaster()->MovePoint(1, me->GetPositionX() + (dist - 5.0f)*cos(me->GetOrientation()), me->GetPositionY() + (dist - 5.0f)*sin(me->GetOrientation()), 364.32f);
- }
- break;
- case EVENT_EMERGENCY_BOT_ATTACK:
- me->CastSpell((Unit*)nullptr, SPELL_WATER_SPRAY, false);
- events.RescheduleEvent(EVENT_EMERGENCY_BOT_CHECK, 5s);
- break;
- }
- }
- };
-};
-
-class npc_ulduar_rocket_strike_trigger : public CreatureScript
-{
-public:
- npc_ulduar_rocket_strike_trigger() : CreatureScript("npc_ulduar_rocket_strike_trigger") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_rocket_strike_triggerAI : public NullCreatureAI
- {
- npc_ulduar_rocket_strike_triggerAI(Creature* pCreature) : NullCreatureAI(pCreature) {}
-
- void SpellHitTarget(Unit* target, SpellInfo const* spell) override
- {
- if (!target || !spell)
- return;
- if (spell->Id == 63041)
- {
- if (target->GetEntry() == NPC_ASSAULT_BOT)
- me->CastSpell(me, 65040, true); // achievement Not-So-Friendly Fire
- else if (target->GetTypeId() == TYPEID_PLAYER)
- if (InstanceScript* pInstance = me->GetInstanceScript())
- if (Creature* c = GetMimiron())
- c->AI()->SetData(0, 13);
- }
- }
- };
-};
-
-class achievement_mimiron_firefighter : public AchievementCriteriaScript
-{
-public:
- achievement_mimiron_firefighter() : AchievementCriteriaScript("achievement_mimiron_firefighter") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1);
- }
-};
-
-class achievement_mimiron_set_up_us_the_bomb_11 : public AchievementCriteriaScript
-{
-public:
- achievement_mimiron_set_up_us_the_bomb_11() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_11") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(11);
- }
-};
-
-class achievement_mimiron_set_up_us_the_bomb_12 : public AchievementCriteriaScript
-{
-public:
- achievement_mimiron_set_up_us_the_bomb_12() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_12") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(12);
- }
-};
-
-class achievement_mimiron_set_up_us_the_bomb_13 : public AchievementCriteriaScript
-{
-public:
- achievement_mimiron_set_up_us_the_bomb_13() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_13") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(13);
- }
-};
-
void AddSC_boss_mimiron()
{
new boss_mimiron();
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.h
new file mode 100644
index 00000000000000..55f9bf4c4f66d1
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.h
@@ -0,0 +1,2475 @@
+#ifndef BOSS_MIMIRON_H_
+#define BOSS_MIMIRON_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "GameObjectScript.h"
+#include "GameTime.h"
+#include "MapMgr.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "Spell.h"
+#include "SpellAuraEffects.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "Vehicle.h"
+#include "ulduar.h"
+
+enum SpellData
+{
+ SPELL_BERSERK = 64238,
+
+ // PHASE 1:
+ SPELL_NAPALM_SHELL_25 = 65026,
+ SPELL_NAPALM_SHELL_10 = 63666,
+
+ SPELL_PLASMA_BLAST_25 = 64529,
+ SPELL_PLASMA_BLAST_10 = 62997,
+
+ SPELL_SHOCK_BLAST = 63631,
+
+ SPELL_PROXIMITY_MINES = 63027,
+ NPC_PROXIMITY_MINE = 34362,
+ SPELL_MINE_EXPLOSION_25 = 63009,
+ SPELL_MINE_EXPLOSION_10 = 66351,
+ SPELL_SUMMON_PROXIMITY_MINE = 65347,
+
+ // PHASE 2:
+ SPELL_HEAT_WAVE = 64533,
+
+ SPELL_ROCKET_STRIKE_AURA = 64064,
+ NPC_ROCKET_VISUAL = 34050,
+ NPC_ROCKET_STRIKE_N = 34047,
+
+ SPELL_RAPID_BURST = 63382,
+ SPELL_RAPID_BURST_DAMAGE_25_1 = 64531,
+ SPELL_RAPID_BURST_DAMAGE_25_2 = 64532,
+ SPELL_RAPID_BURST_DAMAGE_10_1 = 63387,
+ SPELL_RAPID_BURST_DAMAGE_10_2 = 64019,
+ SPELL_SUMMON_BURST_TARGET = 64840,
+
+ SPELL_SPINNING_UP = 63414,
+
+ // PHASE 3:
+ SPELL_PLASMA_BALL_25 = 64535,
+ SPELL_PLASMA_BALL_10 = 63689,
+
+ SPELL_MAGNETIC_CORE = 64436,
+ SPELL_SPINNING = 64438,
+
+ SPELL_SUMMON_BOMB_BOT = 63811,
+ SPELL_BB_EXPLODE = 63801,
+
+ SPELL_BEAM_GREEN = 63295,
+ SPELL_BEAM_YELLOW = 63292,
+ SPELL_BEAM_BLUE = 63294,
+
+ // PHASE 4:
+ SPELL_HAND_PULSE_10_R = 64352,
+ SPELL_HAND_PULSE_25_R = 64537,
+ SPELL_HAND_PULSE_10_L = 64348,
+ SPELL_HAND_PULSE_25_L = 64536,
+
+ SPELL_SELF_REPAIR = 64383,
+ SPELL_SLEEP = 64394,
+};
+
+enum NPCs
+{
+ //NPC_MIMIRON = 33350,
+ NPC_LEVIATHAN_MKII = 33432,
+ NPC_LEVIATHAN_MKII_CANNON = 34071,
+ NPC_VX001 = 33651,
+ NPC_AERIAL_COMMAND_UNIT = 33670,
+ NPC_COMPUTER = 34143,
+ NPC_BOMB_BOT = 33836,
+ NPC_BOT_SUMMON_TRIGGER = 33856,
+ NPC_ASSAULT_BOT = 34057,
+ NPC_JUNK_BOT = 33855,
+ NPC_MAGNETIC_CORE = 34068,
+};
+
+enum GOs
+{
+ //GO_MIMIRON_ELEVATOR = 194749,
+ GO_DOOR_1 = 194776,
+ GO_DOOR_2 = 194774,
+ GO_DOOR_3 = 194775,
+ GO_BUTTON = 194739,
+ // pads: 194740-48
+};
+
+enum HardMode
+{
+ SPELL_EMERGENCY_MODE = 64582,
+ SPELL_SELF_DESTRUCT = 64610,
+
+ SPELL_SUMMON_FLAMES_INITIAL = 64563,
+ NPC_FLAMES_INITIAL = 34363,
+ SPELL_SUMMON_FLAMES_SPREAD = 64564,
+ NPC_FLAMES_SPREAD = 34121,
+ SPELL_FLAMES_AURA = 64561,
+
+ SPELL_VX001_FROST_BOMB = 64623,
+ SPELL_FROST_BOMB_VISUAL_AURA = 64624,
+ SPELL_SUMMON_FROST_BOMB = 64627,
+ NPC_FROST_BOMB = 34149,
+ SPELL_FROST_BOMB_EXPLOSION_10 = 64626,
+ SPELL_FROST_BOMB_EXPLOSION_25 = 65333,
+
+ SPELL_FLAME_SUPPRESSANT_10yd = 65192,
+ SPELL_FLAME_SUPPRESSANT_50000yd = 64570,
+
+ SPELL_WATER_SPRAY = 64619,
+ SPELL_DEAFENING_SIREN = 64616,
+ NPC_EMERGENCY_FIRE_BOT = 34147,
+
+ SPELL_ENTER_VEHICLE_0 = 63112,
+ SPELL_ENTER_VEHICLE_1 = 63313,
+ SPELL_ENTER_VEHICLE_2 = 63314,
+ SPELL_ENTER_VEHICLE_4 = 63316,
+};
+
+enum EVENTS
+{
+ // Mimiron:
+ EVENT_SIT_LMK2 = 1,
+ EVENT_SIT_LMK2_INTERVAL = 2,
+ EVENT_LMK2_RETREAT_INTERVAL = 7,
+ EVENT_ELEVATOR_INTERVAL_1 = 8,
+ EVENT_ELEVATOR_INTERVAL_2 = 9,
+ EVENT_SITTING_ON_VX001 = 10,
+ EVENT_ENTER_VX001 = 11,
+ EVENT_EMOTE_VX001 = 12,
+ EVENT_VX001_START_FIGHT = 13,
+ EVENT_ELEVATOR_INTERVAL_0 = 14,
+ EVENT_GET_OUT_VX001 = 21,
+ EVENT_SAY_VX001_DEAD = 22,
+ EVENT_ENTER_ACU = 23,
+ EVENT_SAY_ACU_ACTIVATE = 24,
+ EVENT_ACU_START_ATTACK = 25,
+ EVENT_VX001_EMOTESTATE_DEATH = 26,
+ EVENT_SAY_ACU_DEAD = 31,
+ EVENT_LEVIATHAN_COME_CLOSER = 32,
+ EVENT_VX001_EMOTE_JUMP = 33,
+ EVENT_LEVIATHAN_RIDE_MIDDLE = 34,
+ EVENT_JOIN_TOGETHER = 342,
+ EVENT_JOIN_ACU = 35,
+ EVENT_START_PHASE4 = 36,
+ EVENT_FINISH = 50,
+ EVENT_SAY_VOLTRON_DEAD = 51,
+ EVENT_DISAPPEAR = 52,
+ EVENT_BERSERK = 53,
+ EVENT_BERSERK_2 = 54,
+
+ // Leviathan:
+ EVENT_SPELL_NAPALM_SHELL = 3,
+ EVENT_SPELL_PLASMA_BLAST = 4,
+ EVENT_SPELL_SHOCK_BLAST = 5,
+ EVENT_PROXIMITY_MINES_1 = 6,
+
+ // VX001:
+ EVENT_SPELL_HEAT_WAVE = 15,
+ EVENT_SPELL_ROCKET_STRIKE = 16,
+ EVENT_REINSTALL_ROCKETS = 17,
+ EVENT_SPELL_RAPID_BURST = 18,
+ EVENT_SPELL_RAPID_BURST_INTERVAL = 19,
+ EVENT_SPELL_SPINNING_UP = 20,
+ EVENT_HAND_PULSE = 37,
+
+ // ACU:
+ EVENT_SPELL_PLASMA_BALL = 27,
+ EVENT_SUMMON_BOMB_BOT = 28,
+ EVENT_BOMB_BOT_CHASE = 29,
+ EVENT_BOMB_BOT_RELOCATE = 30,
+ EVENT_SUMMON_ASSAULT_BOT = 40,
+ EVENT_SUMMON_JUNK_BOT = 41,
+ EVENT_MAGNETIC_CORE_PULL_DOWN = 42,
+ EVENT_MAGNETIC_CORE_FREE = 43,
+ EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE = 44,
+
+ // Hard mode:
+ EVENT_COMPUTER_SAY_INITIATED = 60,
+ EVENT_COMPUTER_SAY_MINUTES = 61,
+ EVENT_MIMIRON_SAY_HARDMODE = 62,
+ EVENT_SPAWN_FLAMES_INITIAL = 63,
+ EVENT_FLAMES_SPREAD = 64,
+ EVENT_FLAME_SUPPRESSION_50000 = 65,
+ EVENT_FLAME_SUPPRESSION_10 = 66,
+ EVENT_FROST_BOMB = 67,
+ EVENT_SUMMON_EMERGENCY_FIRE_BOTS = 68,
+ EVENT_EMERGENCY_BOT_CHECK = 69,
+ EVENT_EMERGENCY_BOT_ATTACK = 70,
+};
+
+#define SPELL_NAPALM_SHELL RAID_MODE(SPELL_NAPALM_SHELL_10, SPELL_NAPALM_SHELL_25)
+#define SPELL_PLASMA_BLAST RAID_MODE(SPELL_PLASMA_BLAST_10, SPELL_PLASMA_BLAST_25)
+#define SPELL_MINE_EXPLOSION RAID_MODE(SPELL_MINE_EXPLOSION_10, SPELL_MINE_EXPLOSION_25)
+#define SPELL_PLASMA_BALL RAID_MODE(SPELL_PLASMA_BALL_10, SPELL_PLASMA_BALL_25)
+#define SPELL_HAND_PULSE_R RAID_MODE(SPELL_HAND_PULSE_10_R, SPELL_HAND_PULSE_25_R)
+#define SPELL_HAND_PULSE_L RAID_MODE(SPELL_HAND_PULSE_10_L, SPELL_HAND_PULSE_25_L)
+#define SPELL_FROST_BOMB_EXPLOSION RAID_MODE(SPELL_FROST_BOMB_EXPLOSION_10, SPELL_FROST_BOMB_EXPLOSION_25)
+
+enum Texts
+{
+ // Mimiron
+ SAY_AGGRO = 0, // Unused
+ SAY_HARDMODE_ON = 1,
+ SAY_MKII_ACTIVATE = 2,
+ SAY_MKII_SLAY = 3,
+ SAY_MKII_DEATH = 4,
+ SAY_VX001_ACTIVATE = 5,
+ SAY_VX001_SLAY = 6,
+ SAY_VX001_DEATH = 7,
+ SAY_AERIAL_ACTIVATE = 8,
+ SAY_AERIAL_SLAY = 9,
+ SAY_AERIAL_DEATH = 10,
+ SAY_V07TRON_ACTIVATE = 11,
+ SAY_V07TRON_SLAY = 12,
+ SAY_V07TRON_DEATH = 13,
+ SAY_BERSERK = 14,
+
+ // MK II
+ EMOTE_PLASMA_BLAST = 0,
+
+ // Computer (Hardmode countdown)
+ TALK_COMPUTER_INITIATED = 0,
+ TALK_COMPUTER_TERMINATED = 1,
+ TALK_COMPUTER_TEN = 2,
+ TALK_COMPUTER_NINE = 3,
+ TALK_COMPUTER_EIGHT = 4,
+ TALK_COMPUTER_SEVEN = 5,
+ TALK_COMPUTER_SIX = 6,
+ TALK_COMPUTER_FIVE = 7,
+ TALK_COMPUTER_FOUR = 8,
+ TALK_COMPUTER_THREE = 9,
+ TALK_COMPUTER_TWO = 10,
+ TALK_COMPUTER_ONE = 11,
+ TALK_COMPUTER_ZERO = 12,
+};
+
+#define GetMimiron() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_MIMIRON))
+#define GetLMK2() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_LEVIATHAN_MKII))
+#define GetVX001() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_VX001))
+#define GetACU() ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_MIMIRON_ACU))
+
+class boss_mimiron : public CreatureScript
+{
+public:
+ boss_mimiron() : CreatureScript("boss_mimiron") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_mimironAI : public ScriptedAI
+ {
+ boss_mimironAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
+ {
+ pInstance = me->GetInstanceScript();
+ if (!me->IsAlive())
+ if (pInstance)
+ pInstance->SetData(TYPE_MIMIRON, DONE);
+ bIsEvading = false;
+ }
+
+ InstanceScript* pInstance;
+ EventMap events;
+ SummonList summons;
+ bool bIsEvading;
+ bool hardmode;
+ bool berserk;
+ bool bAchievProximityMine;
+ bool bAchievBombBot;
+ bool bAchievRocketStrike;
+ uint32 allowedFlameSpreadTime;
+ bool changeAllowedFlameSpreadTime;
+ uint8 minutesTalkNum;
+ uint32 outofCombatTimer;
+
+ void Reset() override
+ {
+ hardmode = false;
+ berserk = false;
+ bAchievProximityMine = false;
+ bAchievBombBot = false;
+ bAchievRocketStrike = false;
+ allowedFlameSpreadTime = 0;
+ outofCombatTimer = 0;
+ changeAllowedFlameSpreadTime = false;
+ ResetGameObjects();
+ events.Reset();
+ summons.DespawnAll();
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+
+ if (pInstance && pInstance->GetData(TYPE_MIMIRON) != DONE)
+ pInstance->SetData(TYPE_MIMIRON, NOT_STARTED);
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ if (who)
+ me->Attack(who, true); // skip following
+ }
+
+ void JustReachedHome() override
+ {
+ me->setActive(false);
+ ScriptedAI::JustReachedHome();
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ me->setActive(true);
+ DoZoneInCombat();
+ me->RemoveAllAuras();
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ events.Reset();
+
+ if (Creature* c = GetLMK2())
+ {
+ if (c->IsInEvadeMode())
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+ if (!c->IsAlive())
+ c->Respawn();
+
+ me->EnterVehicle(c, 1);
+ }
+ else
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+ CloseDoorAndButton();
+
+ if (!hardmode)
+ {
+ Talk(SAY_MKII_ACTIVATE);
+ events.ScheduleEvent(EVENT_SIT_LMK2, 6s);
+ events.ScheduleEvent(EVENT_BERSERK, 15min);
+ }
+ else
+ {
+ events.ScheduleEvent(EVENT_MIMIRON_SAY_HARDMODE, 7s);
+ events.ScheduleEvent(EVENT_BERSERK, Is25ManRaid() ? 10min : 8min);
+
+ events.ScheduleEvent(EVENT_COMPUTER_SAY_INITIATED, 0ms);
+ events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, 3s);
+ minutesTalkNum = Is25ManRaid() ? TALK_COMPUTER_TEN : TALK_COMPUTER_EIGHT;
+ for (uint32 i = 0; i < uint32(TALK_COMPUTER_ZERO - minutesTalkNum - 1); ++i)
+ events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, (i + 1)*MINUTE * IN_MILLISECONDS);
+ events.ScheduleEvent(EVENT_COMPUTER_SAY_MINUTES, (TALK_COMPUTER_ZERO - minutesTalkNum)*MINUTE * IN_MILLISECONDS + 6000);
+ }
+
+ // ensure LMK2 is at proper position
+ if (pInstance)
+ if (Creature* LMK2 = GetLMK2())
+ {
+ LMK2->UpdatePosition(LMK2->GetHomePosition(), true);
+ LMK2->StopMovingOnCurrentPos();
+ }
+
+ if (pInstance && pInstance->GetData(TYPE_MIMIRON) != DONE)
+ pInstance->SetData(TYPE_MIMIRON, IN_PROGRESS);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!me->IsInCombat())
+ {
+ outofCombatTimer += diff;
+ if (outofCombatTimer >= 10000)
+ {
+ outofCombatTimer = 0;
+ if (Creature* c = GetLMK2())
+ me->CastSpell(c, RAND(SPELL_ENTER_VEHICLE_0, SPELL_ENTER_VEHICLE_1, SPELL_ENTER_VEHICLE_2, SPELL_ENTER_VEHICLE_4), true);
+ }
+ return;
+ }
+
+ Position p = me->GetHomePosition();
+ if (me->GetExactDist(&p) > 80.0f || !SelectTargetFromPlayerList(150.0f))
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+
+ events.Update(diff);
+
+ switch( events.ExecuteEvent() )
+ {
+ case 0:
+ break;
+ case EVENT_COMPUTER_SAY_INITIATED:
+ if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) )
+ computer->AI()->Talk(TALK_COMPUTER_INITIATED);
+ break;
+ case EVENT_COMPUTER_SAY_MINUTES:
+ if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) )
+ computer->AI()->Talk(minutesTalkNum++);
+ break;
+ case EVENT_MIMIRON_SAY_HARDMODE:
+ Talk(SAY_HARDMODE_ON);
+ events.ScheduleEvent(EVENT_SPAWN_FLAMES_INITIAL, 0ms);
+ events.ScheduleEvent(EVENT_SIT_LMK2, 4s);
+ break;
+ case EVENT_SPAWN_FLAMES_INITIAL:
+ {
+ if (changeAllowedFlameSpreadTime)
+ allowedFlameSpreadTime = GameTime::GetGameTime().count();
+
+ std::vector pg;
+ Map::PlayerList const& pl = me->GetMap()->GetPlayers();
+ for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
+ if( Player* plr = itr->GetSource() )
+ if( plr->IsAlive() && plr->GetExactDist2d(me) < 150.0f && !plr->IsGameMaster() )
+ pg.push_back(plr);
+
+ for( uint8 i = 0; i < 3; ++i )
+ if( !pg.empty() )
+ {
+ uint8 index = urand(0, pg.size() - 1);
+ Player* player = pg[index];
+ float angle = rand_norm() * 2 * M_PI;
+ float z = 364.35f;
+ if (!player->IsWithinLOS(player->GetPositionX() + cos(angle) * 5.0f, player->GetPositionY() + std::sin(angle) * 5.0f, z))
+ {
+ angle = player->GetAngle(2744.65f, 2569.46f);
+ }
+ me->CastSpell(player->GetPositionX() + cos(angle) * 5.0f, player->GetPositionY() + std::sin(angle) * 5.0f, z, SPELL_SUMMON_FLAMES_INITIAL, true);
+ pg.erase(pg.begin() + index);
+ }
+
+ events.Repeat(30s);
+ }
+ break;
+ case EVENT_BERSERK:
+ berserk = true;
+ Talk(SAY_BERSERK);
+ if( hardmode )
+ me->SummonCreature(33576, 2744.78f, 2569.47f, 364.32f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 120000);
+ events.ScheduleEvent(EVENT_BERSERK_2, 0ms);
+ break;
+ case EVENT_BERSERK_2:
+ {
+ Creature* VX001 = nullptr;
+ Creature* LMK2 = nullptr;
+ Creature* ACU = nullptr;
+ if ((VX001 = GetVX001()))
+ VX001->CastSpell(VX001, SPELL_BERSERK, true);
+ if ((LMK2 = GetLMK2()))
+ LMK2->CastSpell(LMK2, SPELL_BERSERK, true);
+ if ((ACU = GetACU()))
+ ACU->CastSpell(ACU, SPELL_BERSERK, true);
+ events.Repeat(30s);
+ }
+ break;
+ case EVENT_SIT_LMK2:
+ if(Creature* LMK2 = GetLMK2())
+ {
+ me->EnterVehicle(LMK2, 6);
+ events.ScheduleEvent(EVENT_SIT_LMK2_INTERVAL, 2s);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_SIT_LMK2_INTERVAL:
+ if (Creature* LMK2 = GetLMK2())
+ {
+ if (hardmode)
+ {
+ LMK2->CastSpell(LMK2, SPELL_EMERGENCY_MODE, true);
+ if( Vehicle* veh = LMK2->GetVehicleKit() )
+ if( Unit* cannon = veh->GetPassenger(3) )
+ cannon->CastSpell(cannon, SPELL_EMERGENCY_MODE, true);
+ }
+ LMK2->AI()->SetData(1, 1);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_LMK2_RETREAT_INTERVAL:
+ if (Creature* LMK2 = GetLMK2())
+ {
+ me->EnterVehicle(LMK2, 1);
+ Talk(SAY_MKII_DEATH);
+ LMK2->SetFacingTo(3.58f);
+ events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_0, 6s);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_ELEVATOR_INTERVAL_0:
+ if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 100.0f) )
+ {
+ elevator->SetLootState(GO_READY);
+ elevator->UseDoorOrButton(0, false);
+ elevator->EnableCollision(false);
+ }
+ events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_1, 6s);
+ break;
+ case EVENT_ELEVATOR_INTERVAL_1:
+ if(me->SummonCreature(NPC_VX001, 2744.65f, 2569.46f, 364.40f, 3.14f, TEMPSUMMON_MANUAL_DESPAWN))
+ {
+ if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 100.0f) )
+ {
+ elevator->SetLootState(GO_READY);
+ elevator->UseDoorOrButton(0, true);
+ elevator->EnableCollision(false);
+ }
+ events.ScheduleEvent(EVENT_ELEVATOR_INTERVAL_2, 18s);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_ELEVATOR_INTERVAL_2:
+ if (Creature* VX001 = GetVX001())
+ {
+ me->EnterVehicle(VX001, 0);
+ events.ScheduleEvent(EVENT_SITTING_ON_VX001, 4s);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_SITTING_ON_VX001:
+ Talk(SAY_VX001_ACTIVATE);
+ events.ScheduleEvent(EVENT_ENTER_VX001, 5s);
+ break;
+ case EVENT_ENTER_VX001:
+ if( Creature* VX001 = GetVX001() )
+ {
+ me->EnterVehicle(VX001, 1);
+ events.ScheduleEvent(EVENT_EMOTE_VX001, 2s);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_EMOTE_VX001:
+ if( Creature* VX001 = GetVX001() )
+ {
+ VX001->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
+ events.ScheduleEvent(EVENT_VX001_START_FIGHT, 1750ms);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_VX001_START_FIGHT:
+ if( Creature* VX001 = GetVX001() )
+ {
+ if( hardmode )
+ VX001->CastSpell(VX001, SPELL_EMERGENCY_MODE, true);
+ VX001->AI()->SetData(1, 2);
+ me->SetInCombatWithZone();
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_VX001_EMOTESTATE_DEATH:
+ if( Creature* VX001 = GetVX001() )
+ {
+ VX001->HandleEmoteCommand(EMOTE_STATE_DROWNED);
+ VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DROWNED);
+ events.ScheduleEvent(EVENT_GET_OUT_VX001, 2500ms);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_GET_OUT_VX001:
+ if( Creature* VX001 = GetVX001() )
+ if( Creature* ACU = me->SummonCreature(NPC_AERIAL_COMMAND_UNIT, 2743.91f, 2568.78f, 391.34f, M_PI, TEMPSUMMON_MANUAL_DESPAWN) )
+ {
+ me->EnterVehicle(VX001, 4);
+ float speed = ACU->GetDistance(2737.75f, 2574.22f, 381.34f) / 2.0f;
+ ACU->MonsterMoveWithSpeed(2737.75f, 2574.22f, 381.34f, speed);
+ ACU->SetPosition(2737.75f, 2574.22f, 381.34f, M_PI);
+ events.ScheduleEvent(EVENT_SAY_VX001_DEAD, 2s);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_SAY_VX001_DEAD:
+ changeAllowedFlameSpreadTime = true;
+ Talk(SAY_VX001_DEATH);
+ events.ScheduleEvent(EVENT_ENTER_ACU, 7s);
+ break;
+ case EVENT_ENTER_ACU:
+ if( Creature* ACU = GetACU() )
+ {
+ me->EnterVehicle(ACU, 0);
+ events.ScheduleEvent(EVENT_SAY_ACU_ACTIVATE, 6s);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_SAY_ACU_ACTIVATE:
+ Talk(SAY_AERIAL_ACTIVATE);
+ events.ScheduleEvent(EVENT_ACU_START_ATTACK, 4s);
+ break;
+ case EVENT_ACU_START_ATTACK:
+ if( Creature* ACU = GetACU() )
+ {
+ if( hardmode )
+ ACU->CastSpell(ACU, SPELL_EMERGENCY_MODE, true);
+ ACU->AI()->SetData(1, 3);
+ me->SetInCombatWithZone();
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_SAY_ACU_DEAD:
+ Talk(SAY_AERIAL_DEATH);
+ events.ScheduleEvent(EVENT_LEVIATHAN_COME_CLOSER, 5s);
+ break;
+ case EVENT_LEVIATHAN_COME_CLOSER:
+ if (Creature* LMK2 = GetLMK2())
+ {
+ LMK2->GetMotionMaster()->MoveCharge(2755.77f, 2574.95f, 364.31f, 21.0f);
+ events.ScheduleEvent(EVENT_VX001_EMOTE_JUMP, 4s);
+ break;
+ }
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ break;
+ case EVENT_VX001_EMOTE_JUMP:
+ {
+ Creature* LMK2 = GetLMK2();
+ Creature* VX001 = GetVX001();
+ if( !VX001 || !LMK2 )
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+
+ VX001->SendMeleeAttackStop();
+ VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_02);
+ VX001->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_02);
+ events.ScheduleEvent(EVENT_LEVIATHAN_RIDE_MIDDLE, 4800ms);
+ }
+ break;
+ case EVENT_LEVIATHAN_RIDE_MIDDLE:
+ {
+ Creature* VX001 = GetVX001();
+ Creature* LMK2 = GetLMK2();
+ if( !VX001 || !LMK2 )
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+
+ LMK2->GetMotionMaster()->MoveCharge(2744.65f, 2569.46f, 364.31f, 21.0f);
+ VX001->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_CUSTOM_SPELL_01);
+ VX001->HandleEmoteCommand(EMOTE_STATE_CUSTOM_SPELL_01);
+ VX001->EnterVehicle(LMK2, 3);
+ events.ScheduleEvent(EVENT_JOIN_TOGETHER, 3s);
+ }
+ break;
+ case EVENT_JOIN_TOGETHER:
+ {
+ Creature* ACU = GetACU();
+ Creature* VX001 = GetVX001();
+ if( !VX001 || !ACU )
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+
+ ACU->SetDisableGravity(false);
+ ACU->EnterVehicle(VX001, 3);
+ me->EnterVehicle(VX001, 1);
+ Talk(SAY_V07TRON_ACTIVATE);
+ events.ScheduleEvent(EVENT_START_PHASE4, 10s);
+ }
+ break;
+ case EVENT_START_PHASE4:
+ {
+ Creature* VX001 = GetVX001();
+ Creature* LMK2 = GetLMK2();
+ Creature* ACU = GetACU();
+ if( !VX001 || !LMK2 || !ACU )
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+
+ LMK2->AI()->SetData(1, 4);
+ VX001->AI()->SetData(1, 4);
+ ACU->AI()->SetData(1, 4);
+ LMK2->CastSpell(LMK2, SPELL_SELF_REPAIR, true); //LMK2->SetHealth( LMK2->GetMaxHealth()/2 );
+ VX001->CastSpell(VX001, SPELL_SELF_REPAIR, true); //VX001->SetHealth( VX001->GetMaxHealth()/2 );
+ ACU->CastSpell(ACU, SPELL_SELF_REPAIR, true); //ACU->SetHealth( ACU->GetMaxHealth()/2 );
+ if( hardmode )
+ {
+ LMK2->CastSpell(LMK2, SPELL_EMERGENCY_MODE, true);
+ VX001->CastSpell(VX001, SPELL_EMERGENCY_MODE, true);
+ ACU->CastSpell(ACU, SPELL_EMERGENCY_MODE, true);
+ }
+ me->SetInCombatWithZone();
+ }
+ break;
+ case EVENT_FINISH:
+ {
+ Creature* LMK2 = GetLMK2();
+ Creature* VX001 = GetVX001();
+ Creature* ACU = GetACU();
+
+ if (!VX001 || !LMK2 || !ACU)
+ return;
+
+ LMK2->GetMotionMaster()->Clear();
+ LMK2->StopMoving();
+ LMK2->InterruptNonMeleeSpells(false);
+ LMK2->AttackStop();
+ LMK2->AI()->SetData(1, 0);
+ LMK2->DespawnOrUnsummon(7000);
+ LMK2->SetReactState(REACT_PASSIVE);
+ VX001->InterruptNonMeleeSpells(false);
+ VX001->AttackStop();
+ VX001->AI()->SetData(1, 0);
+ VX001->DespawnOrUnsummon(7000);
+ VX001->SetReactState(REACT_PASSIVE);
+ ACU->InterruptNonMeleeSpells(false);
+ ACU->AttackStop();
+ ACU->AI()->SetData(1, 0);
+ ACU->DespawnOrUnsummon(7000);
+ ACU->SetReactState(REACT_PASSIVE);
+
+ Position exitPos = me->GetPosition();
+ me->_ExitVehicle(&exitPos);
+ me->AttackStop();
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK);
+ me->GetMotionMaster()->Clear();
+ summons.DoAction(1337); // despawn summons of summons
+ summons.DespawnEntry(NPC_FLAMES_INITIAL);
+ summons.DespawnEntry(33576);
+
+ float angle = VX001->GetOrientation();
+ float v_x = me->GetPositionX() + cos(angle) * 10.0f;
+ float v_y = me->GetPositionY() + std::sin(angle) * 10.0f;
+ me->GetMotionMaster()->MoveJump(v_x, v_y, 364.32f, 7.0f, 7.0f);
+
+ if( pInstance )
+ for( uint16 i = 0; i < 3; ++i )
+ if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) )
+ if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) )
+ if( door->GetGoState() != GO_STATE_ACTIVE )
+ {
+ door->SetLootState(GO_READY);
+ door->UseDoorOrButton(0, false);
+ }
+
+ if (pInstance)
+ pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_LEVIATHAN_MKII, 1, me);
+
+ if (hardmode)
+ if( Creature* computer = me->SummonCreature(NPC_COMPUTER, 2746.7f, 2569.44f, 410.39f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 1000) )
+ computer->AI()->Talk(TALK_COMPUTER_TERMINATED);
+
+ events.Reset();
+ events.ScheduleEvent(EVENT_SAY_VOLTRON_DEAD, 6s);
+ }
+ break;
+ case EVENT_SAY_VOLTRON_DEAD:
+ Talk(SAY_V07TRON_DEATH);
+ // spawn chest
+ if (uint32 chestId = (hardmode ? RAID_MODE(GO_MIMIRON_CHEST_HARD, GO_MIMIRON_CHEST_HERO_HARD) : RAID_MODE(GO_MIMIRON_CHEST, GO_MIMIRON_CHEST_HERO)))
+ {
+ if (GameObject* go = me->SummonGameObject(chestId, 2744.65f, 2569.46f, 364.397f, 0, 0, 0, 0, 0, 0))
+ {
+ go->ReplaceAllGameObjectFlags((GameObjectFlags)0);
+ go->SetLootRecipient(me->GetMap());
+ }
+ }
+ events.ScheduleEvent(EVENT_DISAPPEAR, 15s);
+ break;
+ case EVENT_DISAPPEAR:
+ if( pInstance )
+ pInstance->SetData(TYPE_MIMIRON, DONE);
+ summons.DespawnAll();
+ me->DespawnOrUnsummon();
+ break;
+ }
+ }
+
+ void MoveInLineOfSight(Unit* /*mover*/) override {}
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ if (bIsEvading)
+ return;
+ bIsEvading = true;
+
+ if (Creature* c = GetLMK2())
+ {
+ c->AI()->EnterEvadeMode(why);
+ }
+ if (Creature* c = GetVX001())
+ {
+ c->AI()->EnterEvadeMode(why);
+ c->DespawnOrUnsummon();
+ }
+ if (Creature* c = GetACU())
+ {
+ c->AI()->EnterEvadeMode(why);
+ c->DespawnOrUnsummon();
+ }
+
+ summons.DoAction(1337); // despawn summons of summons
+
+ me->RemoveAllAuras();
+ me->ExitVehicle();
+ ScriptedAI::EnterEvadeMode(why);
+
+ bIsEvading = false;
+ }
+
+ void JustSummoned(Creature* s) override
+ {
+ summons.Summon(s);
+ }
+
+ void SummonedCreatureDespawn(Creature* s) override
+ {
+ summons.Despawn(s);
+ }
+
+ void ResetGameObjects()
+ {
+ if( pInstance )
+ for( uint16 i = 0; i < 3; ++i )
+ if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) )
+ if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) )
+ if( door->GetGoState() != GO_STATE_ACTIVE )
+ {
+ door->SetLootState(GO_READY);
+ door->UseDoorOrButton(0, false);
+ }
+
+ if( GameObject* elevator = me->FindNearestGameObject(GO_MIMIRON_ELEVATOR, 200.0f) )
+ {
+ if( elevator->GetGoState() != GO_STATE_ACTIVE )
+ {
+ elevator->SetLootState(GO_READY);
+ elevator->SetByteValue(GAMEOBJECT_BYTES_1, 0, GO_STATE_ACTIVE);
+ }
+ elevator->EnableCollision(false);
+ }
+
+ if( GameObject* button = me->FindNearestGameObject(GO_BUTTON, 200.0f) )
+ if( button->GetGoState() != GO_STATE_READY )
+ {
+ button->SetLootState(GO_READY);
+ button->UseDoorOrButton(0, false);
+ button->RemoveGameObjectFlag(GO_FLAG_IN_USE);
+ }
+ }
+
+ void CloseDoorAndButton()
+ {
+ if( pInstance )
+ for( uint16 i = 0; i < 3; ++i )
+ if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) )
+ if( GameObject* door = ObjectAccessor::GetGameObject(*me, guid) )
+ if( door->GetGoState() != GO_STATE_READY )
+ {
+ door->SetLootState(GO_READY);
+ door->UseDoorOrButton(0, false);
+ }
+
+ if( GameObject* button = me->FindNearestGameObject(GO_BUTTON, 200.0f) )
+ if( button->GetGoState() != GO_STATE_ACTIVE )
+ {
+ button->SetLootState(GO_READY);
+ button->UseDoorOrButton(0, false);
+ }
+ }
+
+ void SetData(uint32 /*id*/, uint32 value) override
+ {
+ switch (value) // end of phase 1-3, 4-6 for voltron
+ {
+ case 1:
+ events.ScheduleEvent(EVENT_LMK2_RETREAT_INTERVAL, 5s);
+ break;
+ case 2:
+ events.ScheduleEvent(EVENT_VX001_EMOTESTATE_DEATH, 2500ms);
+ break;
+ case 3:
+ events.ScheduleEvent(EVENT_SAY_ACU_DEAD, 5s);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ {
+ Creature* LMK2 = GetLMK2();
+ Creature* VX001 = GetVX001();
+ Creature* ACU = GetACU();
+ if (!LMK2 || !VX001 || !ACU)
+ {
+ EnterEvadeMode(EVADE_REASON_OTHER);
+ return;
+ }
+
+ Spell* s1 = LMK2->GetCurrentSpell(CURRENT_GENERIC_SPELL);
+ Spell* s2 = VX001->GetCurrentSpell(CURRENT_GENERIC_SPELL);
+ Spell* s3 = ACU->GetCurrentSpell(CURRENT_GENERIC_SPELL);
+ if (s1 && s2 && s3 && s1->GetSpellInfo()->Id == SPELL_SELF_REPAIR && s2->GetSpellInfo()->Id == SPELL_SELF_REPAIR && s3->GetSpellInfo()->Id == SPELL_SELF_REPAIR)
+ events.ScheduleEvent(EVENT_FINISH, 0ms);
+ }
+ break;
+ case 7:
+ hardmode = true;
+ break;
+ case 11:
+ bAchievProximityMine = true;
+ break;
+ case 12:
+ bAchievBombBot = true;
+ break;
+ case 13:
+ bAchievRocketStrike = true;
+ break;
+ }
+ }
+
+ uint32 GetData(uint32 id) const override
+ {
+ switch (id)
+ {
+ case 1:
+ return (hardmode ? 1 : 0);
+ case 2:
+ return (berserk ? 1 : 0);
+ case 10:
+ return allowedFlameSpreadTime;
+ case 11:
+ return (bAchievProximityMine ? 1 : 0);
+ case 12:
+ return (bAchievBombBot ? 1 : 0);
+ case 13:
+ return (bAchievRocketStrike ? 1 : 0);
+ }
+ return 0;
+ }
+ };
+};
+
+class npc_ulduar_leviathan_mkii : public CreatureScript
+{
+public:
+ npc_ulduar_leviathan_mkii() : CreatureScript("npc_ulduar_leviathan_mkii") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_leviathan_mkiiAI : public ScriptedAI
+ {
+ npc_ulduar_leviathan_mkiiAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = me->GetInstanceScript();
+ bIsEvading = false;
+ }
+
+ InstanceScript* pInstance;
+ EventMap events;
+ bool bIsEvading;
+ uint8 Phase;
+
+ void Reset() override
+ {
+ Phase = 0;
+ if (Unit* c = GetS3())
+ c->ExitVehicle(); // this should never happen!
+ if (Creature* c = me->SummonCreature(NPC_LEVIATHAN_MKII_CANNON, *me, TEMPSUMMON_MANUAL_DESPAWN))
+ c->EnterVehicle(me, 3);
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
+
+ events.Reset();
+ }
+
+ void SetData(uint32 id, uint32 value) override
+ {
+ if (id == 1) // setting phase to start fighting
+ {
+ switch (value)
+ {
+ case 0:
+ Phase = 0;
+ events.Reset();
+ break;
+ case 1:
+ Phase = 1;
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ if (Unit* target = SelectTargetFromPlayerList(75.0f))
+ AttackStart(target);
+ DoZoneInCombat();
+ events.Reset();
+ events.ScheduleEvent(EVENT_SPELL_NAPALM_SHELL, 3s);
+ events.ScheduleEvent(EVENT_SPELL_PLASMA_BLAST, 10s);
+ events.ScheduleEvent(EVENT_SPELL_SHOCK_BLAST, 20s);
+ events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 6s);
+ if (Creature* c = GetMimiron())
+ if (c->AI()->GetData(1))
+ events.ScheduleEvent(EVENT_FLAME_SUPPRESSION_50000, 60s);
+ break;
+ case 4:
+ me->SetReactState(REACT_AGGRESSIVE);
+ DoResetThreatList();
+ Phase = 4;
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ if (Unit* target = SelectTargetFromPlayerList(75.0f))
+ AttackStart(target);
+ DoZoneInCombat();
+ events.Reset();
+ events.ScheduleEvent(EVENT_SPELL_SHOCK_BLAST, 20s);
+ events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 6s);
+ break;
+ }
+ }
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (damage >= me->GetHealth() || me->GetHealth() < 15000)
+ {
+ damage = 0;
+ if (me->GetReactState() == REACT_PASSIVE)
+ return;
+ me->SetReactState(REACT_PASSIVE);
+ if (Phase == 1)
+ {
+ if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
+ {
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ me->GetMotionMaster()->Clear();
+ me->AttackStop();
+ me->SetReactState(REACT_PASSIVE);
+ SetData(1, 0);
+ me->InterruptNonMeleeSpells(false);
+ me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
+ if (Unit* cannon = GetS3())
+ cannon->ExitVehicle();
+ me->GetMotionMaster()->MoveCharge(2795.076f, 2598.616f, 364.32f, 21.0f);
+ if (Creature* c = GetMimiron())
+ c->AI()->SetData(0, 1);
+ }
+ }
+ else if (Phase == 4)
+ {
+ if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
+ {
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->InterruptNonMeleeSpells(false);
+ me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
+ me->CastSpell(me, SPELL_SELF_REPAIR, false);
+ if (Creature* c = GetMimiron())
+ {
+ if (c->AI()->GetData(1))
+ me->CastSpell(me, SPELL_EMERGENCY_MODE, true);
+ if (c->AI()->GetData(2))
+ me->CastSpell(me, SPELL_BERSERK, true);
+ c->AI()->SetData(0, 4);
+ }
+ }
+ }
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (!me->HasUnitState(UNIT_STATE_CASTING))
+ DoMeleeAttackIfReady();
+
+ Unit* cannon = GetS3();
+ if (!cannon || cannon->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CASTING) || me->HasAuraType(SPELL_AURA_MOD_SILENCE))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case 0:
+ break;
+ case EVENT_SPELL_NAPALM_SHELL:
+ {
+ Player* pTarget = nullptr;
+ std::vector pList;
+ Map::PlayerList const& pl = me->GetMap()->GetPlayers();
+ for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
+ if (Player* plr = itr->GetSource())
+ if( plr->IsAlive() && plr->GetDistance2d(me) > 15.0f )
+ pList.push_back(plr);
+
+ if (!pList.empty())
+ pTarget = pList[urand(0, pList.size() - 1)];
+ else
+ pTarget = (Player*)SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true);
+
+ if( pTarget )
+ cannon->CastSpell(pTarget, SPELL_NAPALM_SHELL, false);
+
+ events.Repeat(14s);
+ }
+ break;
+ case EVENT_SPELL_PLASMA_BLAST:
+ if (Unit* victim = me->GetVictim())
+ {
+ Talk(EMOTE_PLASMA_BLAST);
+ cannon->CastSpell(victim, SPELL_PLASMA_BLAST, false);
+ }
+ events.Repeat(22s);
+ break;
+ case EVENT_SPELL_SHOCK_BLAST:
+ me->CastSpell(me->GetVictim(), SPELL_SHOCK_BLAST, false);
+ events.Repeat(30s);
+ events.ScheduleEvent(EVENT_PROXIMITY_MINES_1, 8s);
+ break;
+ case EVENT_PROXIMITY_MINES_1:
+ for (uint8 i = 0; i < 10; ++i)
+ {
+ me->CastSpell(me, SPELL_SUMMON_PROXIMITY_MINE, true);
+ }
+ break;
+ case EVENT_FLAME_SUPPRESSION_50000:
+ me->CastSpell(me, SPELL_FLAME_SUPPRESSANT_50000yd, false);
+ break;
+ }
+ }
+
+ void MoveInLineOfSight(Unit* /*mover*/) override {}
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ if (Creature* c = GetMimiron())
+ {
+ if (Phase == 1)
+ {
+ c->AI()->Talk(SAY_MKII_SLAY);
+ }
+ else
+ {
+ c->AI()->Talk(SAY_V07TRON_SLAY);
+ }
+ }
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ if (bIsEvading)
+ return;
+ bIsEvading = true;
+
+ me->RemoveAllAuras();
+ me->ExitVehicle();
+ ScriptedAI::EnterEvadeMode();
+
+ if (Creature* mimiron = GetMimiron())
+ mimiron->AI()->EnterEvadeMode(why);
+
+ bIsEvading = false;
+ }
+
+ void PassengerBoarded(Unit* p, int8 /*seat*/, bool apply) override
+ {
+ if (p->GetEntry() == NPC_LEVIATHAN_MKII_CANNON && !apply)
+ {
+ Unit::Kill(p, p);
+ p->ToCreature()->DespawnOrUnsummon(6000);
+ }
+ }
+
+ Unit* GetS3()
+ {
+ if (Vehicle* vk = me->GetVehicleKit())
+ if (Unit* cannon = vk->GetPassenger(3))
+ return cannon;
+
+ return 0;
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if( spell->Id == SPELL_SELF_REPAIR )
+ {
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ }
+ }
+ };
+};
+
+class npc_ulduar_vx001 : public CreatureScript
+{
+public:
+ npc_ulduar_vx001() : CreatureScript("npc_ulduar_vx001") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_vx001AI : public ScriptedAI
+ {
+ npc_ulduar_vx001AI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = me->GetInstanceScript();
+ bIsEvading = false;
+ }
+
+ InstanceScript* pInstance;
+ EventMap events;
+ bool bIsEvading;
+ uint8 Phase;
+ bool fighting;
+ bool leftarm;
+ uint32 spinningUpOrientation;
+ uint16 spinningUpTimer;
+
+ void Reset() override
+ {
+ Phase = 0;
+ fighting = false;
+ leftarm = false;
+ spinningUpTimer = 0;
+ me->SetRegeneratingHealth(false);
+ events.Reset();
+ }
+
+ void AttackStart(Unit* /*who*/) override {}
+
+ void SetData(uint32 id, uint32 value) override
+ {
+ if (id == 1) // setting phase to start fighting
+ {
+ switch (value)
+ {
+ case 0:
+ Phase = 0;
+ fighting = false;
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
+ events.Reset();
+ break;
+ case 2:
+ Phase = 2;
+ fighting = true;
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_SPELL_CAST_OMNI);
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ events.Reset();
+ events.ScheduleEvent(EVENT_SPELL_HEAT_WAVE, 10s);
+ events.ScheduleEvent(EVENT_SPELL_ROCKET_STRIKE, 16s);
+ events.ScheduleEvent(EVENT_SPELL_RAPID_BURST, 0ms);
+ events.ScheduleEvent(EVENT_SPELL_SPINNING_UP, 30s);
+ events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 3s);
+ if (Creature* c = GetMimiron())
+ if (c->AI()->GetData(1))
+ {
+ events.ScheduleEvent(EVENT_FLAME_SUPPRESSION_10, 7s);
+ events.ScheduleEvent(EVENT_FROST_BOMB, 1s);
+ }
+ break;
+ case 4:
+ Phase = 4;
+ fighting = true;
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ events.Reset();
+ events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 3s);
+ events.ScheduleEvent(EVENT_SPELL_ROCKET_STRIKE, 16s);
+ events.ScheduleEvent(EVENT_HAND_PULSE, 1ms);
+ events.ScheduleEvent(EVENT_SPELL_SPINNING_UP, 30s);
+ if (Creature* c = GetMimiron())
+ if (c->AI()->GetData(1))
+ events.ScheduleEvent(EVENT_FROST_BOMB, 1s);
+ break;
+ }
+ }
+ }
+
+ uint32 GetData(uint32 /*id*/) const override
+ {
+ return spinningUpOrientation;
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == 1337)
+ if( Vehicle* vk = me->GetVehicleKit() )
+ for (uint8 i = 0; i < 2; ++i)
+ if (Unit* r = vk->GetPassenger(5 + i))
+ if (r->GetTypeId() == TYPEID_UNIT)
+ r->ToCreature()->DespawnOrUnsummon(1);
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (damage >= me->GetHealth() || me->GetHealth() < 15000)
+ {
+ damage = 0;
+ if (me->GetReactState() == REACT_PASSIVE)
+ return;
+ me->SetReactState(REACT_PASSIVE);
+ if (Phase == 2)
+ {
+ if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
+ {
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ SetData(1, 0);
+ me->InterruptNonMeleeSpells(false);
+ me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
+ me->SendMeleeAttackStop();
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_CUSTOM_SPELL_06);
+ me->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_06);
+ if (Creature* c = GetMimiron())
+ c->AI()->SetData(0, 2);
+ }
+ }
+ else if (Phase == 4)
+ {
+ if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
+ {
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->InterruptNonMeleeSpells(false);
+ me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
+ me->CastSpell(me, SPELL_SELF_REPAIR, false);
+ if (Creature* c = GetMimiron())
+ {
+ if (c->AI()->GetData(1))
+ me->CastSpell(me, SPELL_EMERGENCY_MODE, true);
+ if (c->AI()->GetData(2))
+ me->CastSpell(me, SPELL_BERSERK, true);
+ c->AI()->SetData(0, 5);
+ }
+ }
+ }
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!fighting)
+ return;
+
+ events.Update(diff);
+
+ if (spinningUpTimer) // executed about a second after starting casting to ensure players can see the correct direction
+ {
+ if (spinningUpTimer <= diff)
+ {
+ float angle = (spinningUpOrientation * 2 * M_PI) / 100.0f;
+ me->SetFacingTo(angle);
+
+ spinningUpTimer = 0;
+ }
+ else
+ spinningUpTimer -= diff;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case 0:
+ break;
+ case EVENT_SPELL_HEAT_WAVE:
+ me->CastSpell(me, SPELL_HEAT_WAVE, true);
+ events.Repeat(10s);
+ break;
+ case EVENT_SPELL_ROCKET_STRIKE:
+ if( Vehicle* vk = me->GetVehicleKit() )
+ {
+ for( int i = 0; i < (Phase / 2); ++i )
+ {
+ uint8 index = (Phase == 2 ? rand() % 2 : i);
+ if( Unit* r = vk->GetPassenger(5 + index) )
+ if (Player* temp = SelectTargetFromPlayerList(100.0f))
+ {
+ if( Creature* trigger = me->SummonCreature(NPC_ROCKET_STRIKE_N, temp->GetPositionX(), temp->GetPositionY(), temp->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 6000) )
+ trigger->CastSpell(trigger, SPELL_ROCKET_STRIKE_AURA, true);
+ Position exitPos = r->GetPosition();
+ exitPos.m_positionX += cos(me->GetOrientation()) * 2.35f;
+ exitPos.m_positionY += std::sin(me->GetOrientation()) * 2.35f;
+ exitPos.m_positionZ += 2.0f * Phase;
+ r->_ExitVehicle(&exitPos);
+ me->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE, r->GetGUID());
+ if (r->GetTypeId() == TYPEID_UNIT)
+ r->ToCreature()->AI()->SetData(0, 0);
+ }
+ }
+ events.Repeat(20s);
+ events.ScheduleEvent(EVENT_REINSTALL_ROCKETS, 10s);
+ }
+ break;
+ case EVENT_REINSTALL_ROCKETS:
+ if (Vehicle* vk = me->GetVehicleKit())
+ {
+ for (uint8 i = 5; i <= 6; ++i)
+ if (!vk->GetPassenger(i))
+ if (TempSummon* accessory = me->SummonCreature(NPC_ROCKET_VISUAL, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 4.0f, me->GetOrientation(), TEMPSUMMON_MANUAL_DESPAWN))
+ if (!me->HandleSpellClick(accessory, i))
+ accessory->UnSummon();
+ }
+ break;
+ case EVENT_SPELL_RAPID_BURST:
+ if (Player* p = SelectTargetFromPlayerList(80.0f))
+ {
+ me->CastSpell(p, SPELL_RAPID_BURST, true);
+ me->SetFacingToObject(p);
+ }
+ events.Repeat(3200ms);
+ break;
+ case EVENT_HAND_PULSE:
+ if (Player* p = SelectTargetFromPlayerList(80.0f))
+ {
+ me->SetFacingToObject(p);
+ if (Unit* vb = me->GetVehicleBase())
+ {
+ vb->SendMeleeAttackStop();
+ vb->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
+
+ if( !leftarm )
+ {
+ vb->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_03);
+ me->CastSpell(p, SPELL_HAND_PULSE_R, false);
+ }
+ else
+ {
+ vb->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_04);
+ me->CastSpell(p, SPELL_HAND_PULSE_L, false);
+ }
+ }
+
+ leftarm = !leftarm;
+ }
+ events.Repeat(1750ms);
+ break;
+ case EVENT_SPELL_SPINNING_UP:
+ events.Repeat(45s);
+ if (Player* p = SelectTargetFromPlayerList(80.0f))
+ {
+ float angle = me->GetAngle(p);
+
+ spinningUpOrientation = (uint32)((angle * 100.0f) / (2 * M_PI));
+ spinningUpTimer = 1500;
+ me->SetFacingTo(angle);
+ me->CastSpell(p, SPELL_SPINNING_UP, true);
+ if (Unit* vehicle = me->GetVehicleBase())
+ {
+ vehicle->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_CUSTOM_SPELL_01);
+ vehicle->HandleEmoteCommand(EMOTE_STATE_CUSTOM_SPELL_01);
+ }
+ events.RescheduleEvent((Phase == 2 ? EVENT_SPELL_RAPID_BURST : EVENT_HAND_PULSE), 14s + 500ms);
+ }
+ break;
+ case EVENT_FLAME_SUPPRESSION_10:
+ me->CastSpell(me, SPELL_FLAME_SUPPRESSANT_10yd, false);
+ events.Repeat(10s);
+ break;
+ case EVENT_FROST_BOMB:
+ me->CastCustomSpell(SPELL_VX001_FROST_BOMB, SPELLVALUE_MAX_TARGETS, 1, (Unit*)nullptr, false);
+ events.Repeat(45s);
+ break;
+ }
+ }
+
+ void MoveInLineOfSight(Unit* /*mover*/) override {}
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ if (Creature* c = GetMimiron())
+ {
+ if (Phase == 2)
+ {
+ c->AI()->Talk(SAY_VX001_SLAY);
+ }
+ else
+ {
+ c->AI()->Talk(SAY_V07TRON_SLAY);
+ }
+ }
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ if (bIsEvading)
+ return;
+ bIsEvading = true;
+
+ me->RemoveAllAuras();
+ me->ExitVehicle();
+ _EnterEvadeMode();
+ Reset();
+ if (Creature* mimiron = GetMimiron())
+ mimiron->AI()->EnterEvadeMode(why);
+
+ bIsEvading = false;
+ }
+
+ void PassengerBoarded(Unit* p, int8 /*seat*/, bool apply) override
+ {
+ if (p->GetEntry() == NPC_ROCKET_VISUAL && !apply)
+ p->ToCreature()->DespawnOrUnsummon(8000);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if( spell->Id == SPELL_SELF_REPAIR )
+ {
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ }
+ }
+ };
+};
+
+class npc_ulduar_aerial_command_unit : public CreatureScript
+{
+public:
+ npc_ulduar_aerial_command_unit() : CreatureScript("npc_ulduar_aerial_command_unit") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_aerial_command_unitAI : public ScriptedAI
+ {
+ npc_ulduar_aerial_command_unitAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
+ {
+ pInstance = me->GetInstanceScript();
+ bIsEvading = false;
+ immobilized = false;
+ me->SetDisableGravity(true);
+ }
+
+ InstanceScript* pInstance;
+ EventMap events;
+ SummonList summons;
+ bool bIsEvading;
+ uint8 Phase;
+ bool immobilized;
+
+ void Reset() override
+ {
+ Phase = 0;
+ events.Reset();
+ summons.DespawnAll();
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ if (who)
+ me->Attack(who, true); // skip following
+ }
+
+ void SetData(uint32 id, uint32 value) override
+ {
+ if (id == 1) // setting phase to start fighting
+ {
+ switch (value)
+ {
+ case 0:
+ Phase = 0;
+ events.Reset();
+ immobilized = false;
+ break;
+ case 3:
+ Phase = 3;
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ if (Unit* target = SelectTargetFromPlayerList(75.0f))
+ AttackStart(target);
+ DoZoneInCombat();
+ events.Reset();
+ events.ScheduleEvent(EVENT_SPELL_PLASMA_BALL, 0ms);
+ events.ScheduleEvent(EVENT_SUMMON_BOMB_BOT, 15s);
+ events.ScheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 1s);
+ events.ScheduleEvent(EVENT_SUMMON_JUNK_BOT, 10s);
+ if (Creature* c = GetMimiron())
+ if (c->AI()->GetData(1))
+ events.ScheduleEvent(EVENT_SUMMON_EMERGENCY_FIRE_BOTS, 0ms);
+ break;
+ case 4:
+ me->SetReactState(REACT_AGGRESSIVE);
+ DoResetThreatList();
+ Phase = 4;
+ me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ if (Unit* target = SelectTargetFromPlayerList(75.0f))
+ AttackStart(target);
+ DoZoneInCombat();
+ events.Reset();
+ events.ScheduleEvent(EVENT_SPELL_PLASMA_BALL, 0ms);
+ }
+ }
+ else if (id == 2 && !immobilized && Phase == 3) // magnetic core
+ {
+ immobilized = true;
+ events.ScheduleEvent(EVENT_MAGNETIC_CORE_PULL_DOWN, 2s);
+ }
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == 1337)
+ summons.DespawnAll();
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (damage >= me->GetHealth() || me->GetHealth() < 15000)
+ {
+ damage = 0;
+ if (me->GetReactState() == REACT_PASSIVE)
+ return;
+ me->SetReactState(REACT_PASSIVE);
+ if (Phase == 3)
+ {
+ if (!me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
+ {
+ me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
+ me->GetMotionMaster()->Clear();
+ me->StopMoving();
+ me->AttackStop();
+ me->SetReactState(REACT_PASSIVE);
+ SetData(1, 0);
+ me->InterruptNonMeleeSpells(false);
+ me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
+
+ me->MonsterMoveWithSpeed(2744.65f, 2569.46f, 381.34f, me->GetDistance(2744.65f, 2569.46f, 381.34f));
+ me->UpdatePosition(2744.65f, 2569.46f, 381.34f, M_PI, false);
+
+ if (Creature* c = GetMimiron())
+ c->AI()->SetData(0, 3);
+ }
+ }
+ else if (Phase == 4)
+ {
+ if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
+ {
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->InterruptNonMeleeSpells(false);
+ me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE);
+ me->CastSpell(me, SPELL_SELF_REPAIR, false);
+ if (Creature* c = GetMimiron())
+ {
+ if (c->AI()->GetData(1))
+ me->CastSpell(me, SPELL_EMERGENCY_MODE, true);
+ if (c->AI()->GetData(2))
+ me->CastSpell(me, SPELL_BERSERK, true);
+ c->AI()->SetData(0, 6);
+ }
+ }
+ }
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ // following :D
+ if( Phase == 3 && !immobilized )
+ if( Unit* victim = me->GetVictim() )
+ if( me->GetExactDist2d(victim) > 25.0f )
+ {
+ float angle = victim->GetAngle(me->GetPositionX(), me->GetPositionY());
+ me->SetOrientation( me->GetAngle(victim->GetPositionX(), victim->GetPositionY()) );
+ float x = victim->GetPositionX() + 15.0f * cos(angle);
+ float y = victim->GetPositionY() + 15.0f * std::sin(angle);
+
+ // check if there's magnetic core in line of movement
+ Creature* mc = nullptr;
+ std::list cl;
+ me->GetCreaturesWithEntryInRange(cl, me->GetExactDist2d(victim), NPC_MAGNETIC_CORE);
+ for( std::list::iterator itr = cl.begin(); itr != cl.end(); ++itr )
+ {
+ if ((*itr)->IsInBetween(me, victim, 4.0f) && (*itr)->GetExactDist2d(victim) >= 10.0f) // don't come very close just because there's a magnetic core
+ {
+ x = (*itr)->GetPositionX();
+ y = (*itr)->GetPositionY();
+ mc = (*itr);
+ break;
+ }
+ }
+
+ float speed = me->GetExactDist(x, y, 381.34f);
+ me->MonsterMoveWithSpeed(x, y, 381.34f, speed);
+ me->UpdatePosition(x, y, 381.34f, me->GetAngle(victim), false);
+ if (mc)
+ {
+ mc->AI()->SetData(0, 0);
+ SetData(2, 1);
+ }
+ }
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case 0:
+ break;
+ case EVENT_SPELL_PLASMA_BALL:
+ if( !immobilized )
+ {
+ if (Phase == 3)
+ {
+ if( Unit* victim = me->GetVictim() )
+ me->CastSpell(victim, SPELL_PLASMA_BALL, false);
+ }
+ else
+ {
+ if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 27.5f, true))
+ {
+ me->SetFacingToObject(victim);
+ me->CastSpell(victim, SPELL_PLASMA_BALL, false);
+ }
+ }
+ }
+ events.Repeat(3s);
+ break;
+ case EVENT_SUMMON_BOMB_BOT:
+ if( !immobilized )
+ me->CastSpell(me, SPELL_SUMMON_BOMB_BOT, false);
+ events.Repeat(15s);
+ break;
+ case EVENT_SUMMON_ASSAULT_BOT:
+ if( GameObject* pad = me->FindNearestGameObject(RAND(194742, 194746, 194745), 200.0f) )
+ if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_TIMED_DESPAWN, 15000))
+ trigger->AI()->DoAction(2);
+ events.Repeat(30s);
+ break;
+ case EVENT_SUMMON_JUNK_BOT:
+ if( GameObject* pad = me->FindNearestGameObject(RAND(194741, 194744, 194747), 200.0f) )
+ if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_TIMED_DESPAWN, 15000))
+ trigger->AI()->DoAction(1);
+ events.Repeat(10s);
+ break;
+ case EVENT_SUMMON_EMERGENCY_FIRE_BOTS:
+ {
+ uint32 ids[3] = {194740, 194743, 194748};
+ for( uint8 i = 0; i < 3; ++i )
+ if( GameObject* pad = me->FindNearestGameObject(ids[i], 200.0f) )
+ if (Creature* trigger = me->SummonCreature(NPC_BOT_SUMMON_TRIGGER, *pad, TEMPSUMMON_MANUAL_DESPAWN))
+ trigger->AI()->DoAction(3);
+ events.Repeat(45s);
+ }
+ break;
+ case EVENT_MAGNETIC_CORE_PULL_DOWN:
+ me->CastSpell(me, SPELL_MAGNETIC_CORE, true);
+ me->CastSpell(me, SPELL_SPINNING, true);
+ me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 365.34f, me->GetExactDist(me->GetPositionX(), me->GetPositionY(), 365.34f));
+ me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), 365.34f, me->GetOrientation(), false);
+ events.ScheduleEvent(EVENT_MAGNETIC_CORE_FREE, 20s);
+ break;
+ case EVENT_MAGNETIC_CORE_FREE:
+ me->RemoveAura(SPELL_SPINNING);
+ me->MonsterMoveWithSpeed(me->GetPositionX(), me->GetPositionY(), 381.34f, me->GetDistance(me->GetPositionX(), me->GetPositionY(), 381.34f));
+ me->UpdatePosition(me->GetPositionX(), me->GetPositionY(), 381.34f, me->GetOrientation(), false);
+ events.ScheduleEvent(EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE, 1s);
+ break;
+ case EVENT_MAGNETIC_CORE_REMOVE_IMMOBILIZE:
+ immobilized = false;
+ break;
+ }
+ }
+
+ void MoveInLineOfSight(Unit* /*mover*/) override {}
+
+ void KilledUnit(Unit* who) override
+ {
+ if (who->GetTypeId() == TYPEID_PLAYER)
+ if (Creature* c = GetMimiron())
+ {
+ if (Phase == 3)
+ {
+ c->AI()->Talk(SAY_AERIAL_SLAY);
+ }
+ else
+ {
+ c->AI()->Talk(SAY_V07TRON_SLAY);
+ }
+ }
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ if (bIsEvading)
+ return;
+ bIsEvading = true;
+
+ me->RemoveAllAuras();
+ me->ExitVehicle();
+ _EnterEvadeMode();
+ Reset();
+ if (Creature* mimiron = GetMimiron())
+ mimiron->AI()->EnterEvadeMode(why);
+
+ bIsEvading = false;
+ }
+
+ void JustSummoned(Creature* s) override
+ {
+ summons.Summon(s);
+ if (s->GetEntry() == NPC_BOMB_BOT)
+ s->m_positionZ = 364.34f;
+ }
+
+ void SummonedCreatureDespawn(Creature* s) override
+ {
+ summons.Despawn(s);
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if( spell->Id == SPELL_SELF_REPAIR )
+ {
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ }
+ }
+ };
+};
+
+class npc_ulduar_proximity_mine : public CreatureScript
+{
+public:
+ npc_ulduar_proximity_mine() : CreatureScript("npc_ulduar_proximity_mine") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_proximity_mineAI : public ScriptedAI
+ {
+ npc_ulduar_proximity_mineAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ exploded = false;
+ timer = 2500;
+ timer2 = 35000;
+ }
+
+ bool exploded;
+ uint16 timer;
+ uint16 timer2;
+
+ void AttackStart(Unit* /*who*/) override {}
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+ bool CanAIAttack(Unit const* /*target*/) const override { return false; }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override
+ {
+ if (target && spell && target->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_MINE_EXPLOSION)
+ if (InstanceScript* pInstance = me->GetInstanceScript())
+ if (Creature* c = GetMimiron())
+ c->AI()->SetData(0, 11);
+ }
+
+ // MoveInLineOfSight is checked every few yards, can't use it
+ void UpdateAI(uint32 diff) override
+ {
+ if (timer2 <= diff)
+ {
+ timer2 = 35000;
+ if (!exploded)
+ {
+ exploded = true;
+ me->CastSpell(me, SPELL_MINE_EXPLOSION, false);
+ }
+ }
+ else
+ timer2 -= diff;
+
+ if (timer <= diff)
+ {
+ timer = 500;
+ if (!exploded && SelectTargetFromPlayerList(1.9f))
+ {
+ exploded = true;
+ me->CastSpell(me, SPELL_MINE_EXPLOSION, false);
+ }
+ }
+ else
+ timer -= diff;
+ }
+ };
+};
+
+class npc_ulduar_mimiron_rocket : public CreatureScript
+{
+public:
+ npc_ulduar_mimiron_rocket() : CreatureScript("npc_ulduar_mimiron_rocket") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_mimiron_rocketAI : public NullCreatureAI
+ {
+ npc_ulduar_mimiron_rocketAI(Creature* pCreature) : NullCreatureAI(pCreature) {}
+
+ void InitializeAI() override
+ {
+ if (!me->isDead())
+ Reset();
+ }
+
+ void Reset() override
+ {
+ me->SetCanFly(true);
+ me->AddUnitMovementFlag(MOVEMENTFLAG_FLYING);
+ me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
+ }
+
+ void SetData(uint32 /*id*/, uint32 /*value*/) override
+ {
+ me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 100.0f, false, true);
+ }
+
+ void UpdateAI(uint32 /*diff*/) override
+ {
+ if (!me->GetVehicle())
+ {
+ me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN) + 0.4f, false);
+ me->SetSpeed(MOVE_FLIGHT, me->GetSpeedRate(MOVE_RUN), false);
+ }
+ }
+ };
+};
+
+class npc_ulduar_magnetic_core : public CreatureScript
+{
+public:
+ npc_ulduar_magnetic_core() : CreatureScript("npc_ulduar_magnetic_core") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_magnetic_coreAI : public NullCreatureAI
+ {
+ npc_ulduar_magnetic_coreAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ pInstance = me->GetInstanceScript();
+ if (Creature* c = GetACU())
+ if (c->GetExactDist2d(me) <= 10.0f)
+ {
+ me->SendMonsterMove(c->GetPositionX(), c->GetPositionY(), 364.313f, 1);
+ me->UpdatePosition(c->GetPositionX(), c->GetPositionY(), 364.313f, me->GetOrientation(), true);
+ me->StopMovingOnCurrentPos();
+ c->AI()->SetData(2, 1);
+ despawnTimer = 20000;
+ return;
+ }
+ despawnTimer = 60000;
+ }
+
+ InstanceScript* pInstance;
+ uint16 despawnTimer;
+
+ void SetData(uint32 /*id*/, uint32 /*value*/) override
+ {
+ despawnTimer = 20000;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (despawnTimer <= diff)
+ {
+ despawnTimer = 60000;
+ me->DespawnOrUnsummon(1);
+ }
+ else
+ despawnTimer -= diff;
+ }
+ };
+};
+
+class npc_ulduar_bot_summon_trigger : public CreatureScript
+{
+public:
+ npc_ulduar_bot_summon_trigger() : CreatureScript("npc_ulduar_bot_summon_trigger") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_bot_summon_triggerAI : public NullCreatureAI
+ {
+ npc_ulduar_bot_summon_triggerAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
+
+ uint32 timer;
+ uint8 option;
+
+ void Reset() override
+ {
+ timer = 8000;
+ option = 0;
+ }
+
+ void DoAction(int32 param) override
+ {
+ switch( param )
+ {
+ case 1:
+ me->CastSpell(me, SPELL_BEAM_GREEN, true);
+ option = 1;
+ break;
+ case 2:
+ me->CastSpell(me, SPELL_BEAM_YELLOW, true);
+ option = 2;
+ break;
+ case 3:
+ me->CastSpell(me, SPELL_BEAM_BLUE, true);
+ option = 3;
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if( timer <= diff )
+ {
+ uint32 option_npcid[3] = {NPC_JUNK_BOT, NPC_ASSAULT_BOT, NPC_EMERGENCY_FIRE_BOT};
+ InstanceScript* pInstance = me->GetInstanceScript();
+ if (Creature* ACU = GetACU()) // ACU summons for easy removing
+ if( Creature* bot = ACU->SummonCreature( option_npcid[option - 1], *me, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 25000 ) )
+ {
+ if( option < 3 )
+ bot->SetInCombatWithZone();
+ if (Creature* m = GetMimiron())
+ if (m->AI()->GetData(1)) // hardmode
+ bot->CastSpell(bot, SPELL_EMERGENCY_MODE, true);
+ }
+
+ me->DespawnOrUnsummon(500);
+ timer = 99999;
+ }
+ else
+ timer -= diff;
+ }
+ };
+};
+
+class spell_mimiron_rapid_burst : public SpellScriptLoader
+{
+public:
+ spell_mimiron_rapid_burst() : SpellScriptLoader("spell_mimiron_rapid_burst") { }
+
+ class spell_mimiron_rapid_burst_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mimiron_rapid_burst_AuraScript)
+
+ void HandleEffectPeriodic(AuraEffect const* aurEff)
+ {
+ if (Unit* c = GetCaster())
+ {
+ uint32 id = ( c->GetMap()->Is25ManRaid() ? ((aurEff->GetTickNumber() % 2) ? SPELL_RAPID_BURST_DAMAGE_25_2 : SPELL_RAPID_BURST_DAMAGE_25_1) : ((aurEff->GetTickNumber() % 2) ? SPELL_RAPID_BURST_DAMAGE_10_2 : SPELL_RAPID_BURST_DAMAGE_10_1) );
+ c->CastSpell((Unit*)nullptr, id, true);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_rapid_burst_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mimiron_rapid_burst_AuraScript();
+ }
+};
+
+class spell_mimiron_p3wx2_laser_barrage : public SpellScriptLoader
+{
+public:
+ spell_mimiron_p3wx2_laser_barrage() : SpellScriptLoader("spell_mimiron_p3wx2_laser_barrage") { }
+
+ class spell_mimiron_p3wx2_laser_barrage_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mimiron_p3wx2_laser_barrage_AuraScript)
+
+ uint32 lastMSTime;
+ float lastOrientation;
+
+ bool Load() override
+ {
+ lastMSTime = GameTime::GetGameTimeMS().count();
+ lastOrientation = -1.0f;
+ return true;
+ }
+
+ void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ if (Unit* c = GetCaster())
+ {
+ if (c->GetTypeId() != TYPEID_UNIT)
+ return;
+ uint32 diff = getMSTimeDiff(lastMSTime, GameTime::GetGameTimeMS().count());
+ if (lastOrientation == -1.0f)
+ {
+ lastOrientation = (c->ToCreature()->AI()->GetData(0) * 2 * M_PI) / 100.0f;
+ diff = 0;
+ }
+ float new_o = Position::NormalizeOrientation(lastOrientation - (M_PI / 60) * (diff / 250.0f));
+ lastMSTime = GameTime::GetGameTimeMS().count();
+ lastOrientation = new_o;
+ c->SetFacingTo(new_o);
+
+ c->CastSpell((Unit*)nullptr, 63297, true);
+ c->CastSpell((Unit*)nullptr, 64042, true);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_p3wx2_laser_barrage_AuraScript::HandleEffectPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_mimiron_p3wx2_laser_barrage_AuraScript();
+ }
+};
+
+class go_ulduar_do_not_push_this_button : public GameObjectScript
+{
+public:
+ go_ulduar_do_not_push_this_button() : GameObjectScript("go_ulduar_do_not_push_this_button") { }
+
+ bool OnGossipHello(Player* player, GameObject* go) override
+ {
+ if(!player || !go)
+ return true;
+
+ if (InstanceScript* instance = go->GetInstanceScript())
+ {
+ if(instance->GetData(TYPE_MIMIRON) != NOT_STARTED)
+ return false;
+
+ if (Creature* c = ObjectAccessor::GetCreature(*go, instance->GetGuidData(TYPE_MIMIRON)))
+ {
+ c->AI()->SetData(0, 7);
+ c->AI()->AttackStart(player);
+ }
+ }
+
+ return false;
+ }
+};
+
+class npc_ulduar_flames_initial : public CreatureScript
+{
+public:
+ npc_ulduar_flames_initial() : CreatureScript("npc_ulduar_flames_initial") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_flames_initialAI : public NullCreatureAI
+ {
+ npc_ulduar_flames_initialAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ CreateTime = GameTime::GetGameTime().count();
+ events.Reset();
+ events.ScheduleEvent(EVENT_FLAMES_SPREAD, 5750ms);
+ if( Creature* flame = me->SummonCreature(NPC_FLAMES_SPREAD, me->GetPositionX(), me->GetPositionY(), 364.32f, 0.0f) )
+ {
+ FlameList.push_back(flame->GetGUID());
+ flame->CastSpell(flame, SPELL_FLAMES_AURA, true);
+ }
+ }
+
+ GuidList FlameList;
+ EventMap events;
+ uint32 CreateTime;
+
+ void DoAction(int32 action) override
+ {
+ if (action == 1337)
+ RemoveAll();
+ }
+
+ void SpreadFlame(float x, float y)
+ {
+ if( Creature* flame = me->SummonCreature(NPC_FLAMES_SPREAD, x, y, 364.32f, 0.0f) )
+ {
+ FlameList.push_back(flame->GetGUID());
+ if (Creature* c = me->FindNearestCreature(NPC_FLAMES_SPREAD, 10.0f))
+ if (c->GetExactDist2d(flame->GetPositionX(), flame->GetPositionY()) <= 4.0f)
+ return;
+ flame->CastSpell(flame, SPELL_FLAMES_AURA, true);
+ }
+ }
+
+ void RemoveFlame(ObjectGuid guid)
+ {
+ FlameList.remove(guid);
+ }
+
+ void RemoveAll()
+ {
+ for (ObjectGuid const& guid : FlameList)
+ if (Creature* c = ObjectAccessor::GetCreature(*me, guid))
+ c->DespawnOrUnsummon();
+ FlameList.clear();
+ me->DespawnOrUnsummon();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (InstanceScript* pInstance = me->GetInstanceScript())
+ if (pInstance->GetData(TYPE_MIMIRON) != IN_PROGRESS)
+ {
+ RemoveAll();
+ return;
+ }
+
+ events.Update(diff);
+
+ switch( events.ExecuteEvent() )
+ {
+ case 0:
+ break;
+ case EVENT_FLAMES_SPREAD:
+ {
+ if( FlameList.empty() )
+ {
+ me->DespawnOrUnsummon();
+ return;
+ }
+
+ if (InstanceScript* pInstance = me->GetInstanceScript())
+ if (Creature* mimiron = GetMimiron())
+ if (CreateTime < mimiron->AI()->GetData(10))
+ {
+ break;
+ }
+
+ Creature* last = ObjectAccessor::GetCreature(*me, FlameList.back());
+ if( last )
+ {
+ float prevdist = 100.0f;
+ Player* target = nullptr;
+
+ Map::PlayerList const& pl = me->GetMap()->GetPlayers();
+ for( Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr )
+ if( Player* plr = itr->GetSource() )
+ if( plr->IsAlive() && plr->GetExactDist2d(last) < prevdist && !plr->IsGameMaster() )
+ {
+ target = plr;
+ prevdist = plr->GetExactDist2d(last);
+ }
+
+ if (target && prevdist >= 4.0f) // no need to spread when player is standing in fire, check distance
+ {
+ float angle = last->GetAngle(target->GetPositionX(), target->GetPositionY()) - M_PI / 8 + rand_norm() * 2 * M_PI / 8;
+ SpreadFlame(last->GetPositionX() + 7.0f * cos(angle), last->GetPositionY() + 7.0f * std::sin(angle));
+ }
+ }
+
+ events.Repeat(5750ms);
+ }
+ break;
+ }
+ }
+ };
+};
+
+class npc_ulduar_flames_spread : public CreatureScript
+{
+public:
+ npc_ulduar_flames_spread() : CreatureScript("npc_ulduar_flames_spread") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_flames_spreadAI : public NullCreatureAI
+ {
+ npc_ulduar_flames_spreadAI(Creature* pCreature) : NullCreatureAI(pCreature) {}
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ switch( spell->Id )
+ {
+ case SPELL_FROST_BOMB_EXPLOSION_10:
+ case SPELL_FROST_BOMB_EXPLOSION_25:
+ case SPELL_FLAME_SUPPRESSANT_10yd:
+ case SPELL_FLAME_SUPPRESSANT_50000yd:
+ case SPELL_WATER_SPRAY:
+ {
+ if (me->IsSummon())
+ if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit())
+ if (Creature* c = summoner->ToCreature())
+ if (c->AI())
+ CAST_AI(npc_ulduar_flames_initial::npc_ulduar_flames_initialAI, c->AI())->RemoveFlame(me->GetGUID());
+
+ me->RemoveAllAuras();
+ me->DespawnOrUnsummon(2500);
+ }
+ break;
+ case SPELL_VX001_FROST_BOMB:
+ me->CastSpell(me, SPELL_SUMMON_FROST_BOMB, true);
+ break;
+ }
+ }
+ };
+};
+
+class npc_ulduar_emergency_fire_bot : public CreatureScript
+{
+public:
+ npc_ulduar_emergency_fire_bot() : CreatureScript("npc_ulduar_emergency_fire_bot") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_emergency_fire_botAI : public ScriptedAI
+ {
+ npc_ulduar_emergency_fire_botAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ events.Reset();
+ events.ScheduleEvent(EVENT_EMERGENCY_BOT_CHECK, 1s);
+ }
+
+ EventMap events;
+
+ void MoveInLineOfSight(Unit*) override {}
+ void AttackStart(Unit*) override {}
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type == POINT_MOTION_TYPE && id == 1)
+ events.ScheduleEvent(EVENT_EMERGENCY_BOT_ATTACK, 0ms);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+ switch( events.ExecuteEvent() )
+ {
+ case 0:
+ break;
+ case EVENT_EMERGENCY_BOT_CHECK:
+ events.Repeat(15s);
+ if (Creature* flame = me->FindNearestCreature(NPC_FLAMES_SPREAD, 150.0f, true))
+ {
+ me->SetOrientation(me->GetAngle(flame->GetPositionX(), flame->GetPositionY()));
+ float dist = me->GetExactDist2d(flame);
+ if (dist <= 5.0f)
+ events.ScheduleEvent(EVENT_EMERGENCY_BOT_ATTACK, 0ms);
+ else
+ me->GetMotionMaster()->MovePoint(1, me->GetPositionX() + (dist - 5.0f)*cos(me->GetOrientation()), me->GetPositionY() + (dist - 5.0f)*sin(me->GetOrientation()), 364.32f);
+ }
+ break;
+ case EVENT_EMERGENCY_BOT_ATTACK:
+ me->CastSpell((Unit*)nullptr, SPELL_WATER_SPRAY, false);
+ events.RescheduleEvent(EVENT_EMERGENCY_BOT_CHECK, 5s);
+ break;
+ }
+ }
+ };
+};
+
+class npc_ulduar_rocket_strike_trigger : public CreatureScript
+{
+public:
+ npc_ulduar_rocket_strike_trigger() : CreatureScript("npc_ulduar_rocket_strike_trigger") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_rocket_strike_triggerAI : public NullCreatureAI
+ {
+ npc_ulduar_rocket_strike_triggerAI(Creature* pCreature) : NullCreatureAI(pCreature) {}
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override
+ {
+ if (!target || !spell)
+ return;
+ if (spell->Id == 63041)
+ {
+ if (target->GetEntry() == NPC_ASSAULT_BOT)
+ me->CastSpell(me, 65040, true); // achievement Not-So-Friendly Fire
+ else if (target->GetTypeId() == TYPEID_PLAYER)
+ if (InstanceScript* pInstance = me->GetInstanceScript())
+ if (Creature* c = GetMimiron())
+ c->AI()->SetData(0, 13);
+ }
+ }
+ };
+};
+
+class achievement_mimiron_firefighter : public AchievementCriteriaScript
+{
+public:
+ achievement_mimiron_firefighter() : AchievementCriteriaScript("achievement_mimiron_firefighter") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->AI()->GetData(1);
+ }
+};
+
+class achievement_mimiron_set_up_us_the_bomb_11 : public AchievementCriteriaScript
+{
+public:
+ achievement_mimiron_set_up_us_the_bomb_11() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_11") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(11);
+ }
+};
+
+class achievement_mimiron_set_up_us_the_bomb_12 : public AchievementCriteriaScript
+{
+public:
+ achievement_mimiron_set_up_us_the_bomb_12() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_12") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(12);
+ }
+};
+
+class achievement_mimiron_set_up_us_the_bomb_13 : public AchievementCriteriaScript
+{
+public:
+ achievement_mimiron_set_up_us_the_bomb_13() : AchievementCriteriaScript("achievement_mimiron_set_up_us_the_bomb_13") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_MIMIRON && target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->AI()->GetData(13);
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp
index c92f5db29cf2e3..c4a1d9e7cf5a73 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_razorscale.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "GameObjectScript.h"
@@ -27,1147 +28,6 @@
#include "WaypointMgr.h"
#include "ulduar.h"
-enum Spells
-{
- // Razorscale
- SPELL_FLAMEBUFFET_10 = 64016,
- SPELL_FLAMEBUFFET_25 = 64023,
- SPELL_FIREBALL = 63815,
- SPELL_WINGBUFFET = 62666,
- SPELL_FLAMEBREATH_10 = 63317,
- SPELL_FLAMEBREATH_25 = 64021,
- SPELL_FUSEARMOR = 64771,
- SPELL_FUSED_ARMOR = 64774, // Applied on 5th stack of SPELL_FUSEARMOR
- SPELL_DEVOURINGFLAME = 63236,
- SPELL_BERSERK = 47008,
-
- // Haproons
- SPELL_CHAIN_1 = 49679,
- SPELL_CHAIN_2 = 49682,
- SPELL_CHAIN_3 = 49683,
- SPELL_CHAIN_4 = 49684,
- SPELL_LAUNCH_CHAIN = 62505,
-
- // Dark Rune Sentinel
- SPELL_WHIRLWIND = 63808,
- SPELL_BATTLE_SHOUT_10 = 46763,
- SPELL_BATTLE_SHOUT_25 = 64062,
-
- // Dark Rune Guardian
- SPELL_STORMSTRIKE_DMG = 65971,
- SPELL_STORMSTRIKE_DEBUFF = 64757,
-
- // Dark Rune Watcher
- SPELL_LIGHTINGBOLT_10 = 63809,
- SPELL_LIGHTINGBOLT_25 = 64696,
- SPELL_CHAINLIGHTNING_10 = 64758,
- SPELL_CHAINLIGHTNING_25 = 64759,
-};
-
-#define SPELL_FLAMEBUFFET RAID_MODE(SPELL_FLAMEBUFFET_10, SPELL_FLAMEBUFFET_25)
-#define SPELL_FLAMEBREATH RAID_MODE(SPELL_FLAMEBREATH_10, SPELL_FLAMEBREATH_25)
-#define SPELL_BATTLE_SHOUT RAID_MODE(SPELL_BATTLE_SHOUT_10, SPELL_BATTLE_SHOUT_25)
-#define SPELL_LIGHTINGBOLT RAID_MODE(SPELL_LIGHTINGBOLT_10, SPELL_LIGHTINGBOLT_25)
-#define SPELL_CHAINLIGHTNING RAID_MODE(SPELL_CHAINLIGHTNING_10, SPELL_CHAINLIGHTNING_25)
-#define REQ_CHAIN_COUNT RAID_MODE(2, 4)
-
-enum NPCs
-{
- NPC_DARK_RUNE_SENTINEL = 33846,
- NPC_DARK_RUNE_GUARDIAN = 33388,
- NPC_DARK_RUNE_WATCHER = 33453,
- NPC_EXPEDITION_ENGINEER = 33287,
- NPC_EXPEDITION_COMMANDER = 33210,
- NPC_RAZORSCALE_CONTROLLER = 33233, // Trigger Creature
-};
-
-enum GOs
-{
- GO_DRILL = 195305,
- GO_HARPOON_GUN_1 = 194519,
- GO_HARPOON_GUN_2 = 194541,
- GO_HARPOON_GUN_3 = 194542,
- GO_HARPOON_GUN_4 = 194543,
- GO_BROKEN_HARPOON = 194565,
-};
-
-enum eEvents
-{
- EVENT_NONE = 0,
- EVENT_COMMANDER_SAY_AGGRO,
- EVENT_EE_SAY_MOVE_OUT,
- EVENT_ENRAGE,
- EVENT_SPELL_FIREBALL,
- EVENT_SPELL_DEVOURING_FLAME,
- EVENT_SUMMON_MOLE_MACHINES,
- EVENT_SUMMON_ADDS,
- EVENT_WARN_DEEP_BREATH,
- EVENT_PHASE2_FLAME_BREATH,
- EVENT_FLY_UP,
- EVENT_RESUME_FIXING,
- EVENT_SPELL_FLAME_BREATH,
- EVENT_SPELL_DEVOURING_FLAME_GROUND,
- EVENT_SPELL_FUSE_ARMOR,
- EVENT_SPELL_FLAME_BUFFET,
-};
-
-enum Texts
-{
- // Razorscale
- EMOTE_PERMA_GROUND = 0,
- EMOTE_BREATH = 1,
- EMOTE_BERSERK = 2,
-
- // Expedition Commander
- SAY_COMMANDER_AGGRO = 0,
- SAY_COMMANDER_GROUND_PHASE = 1,
- SAY_COMMANDER_ENGINEERS_DEAD = 2, // Should be called when all engineers are dead, currently unused
-
- // Expedition Engineer
- SAY_EE_AGGRO = 0,
- SAY_EE_START_REPAIR = 1,
- SAY_EE_REBUILD_TURRETS = 2,
-
- // Harpoon
- EMOTE_HARPOON = 0,
-};
-
-enum Misc
-{
- POINT_RAZORSCALE_INIT = 1,
- REPAIR_POINTS = 25,
-
- // Expedition Commander Gossip
- GOSSIP_MENU_START_ENCOUNTER = 10314,
- NPC_TEXT_COMMANDER = 40100,
-};
-
-const Position CORDS_GROUND = {588.0f, -166.0f, 391.1f};
-const Position CORDS_AIR = {588.0f, -178.0f, 490.0f};
-
-class boss_razorscale : public CreatureScript
-{
-public:
- boss_razorscale() : CreatureScript("boss_razorscale") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_razorscaleAI : public ScriptedAI
- {
- boss_razorscaleAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
- {
- pInstance = me->GetInstanceScript();
- startPath = true;
- }
-
- InstanceScript* pInstance;
- EventMap events;
- SummonList summons;
- ObjectGuid ExpeditionEngineerGUIDs[3];
- ObjectGuid CommanderGUID;
- float cords[4][2];
- bool bGroundPhase;
- bool startPath;
- uint8 flyTimes;
-
- void InitializeAI() override
- {
- me->SetDisableGravity(true);
- me->setActive(true);
- Reset();
- }
-
- void Reset() override
- {
- events.Reset();
- summons.DespawnAll();
-
- for (uint8 i = 0; i < 3; ++i)
- ExpeditionEngineerGUIDs[i].Clear();
-
- // Show gossip icon if previously hidden
- if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID))
- if (!commander->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP))
- commander->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
-
- CommanderGUID.Clear();
- bGroundPhase = false;
- flyTimes = 0;
-
- if( pInstance )
- pInstance->SetData(TYPE_RAZORSCALE, NOT_STARTED);
- }
-
- void AttackStart(Unit* who) override
- {
- if (who && me->Attack(who, true) && bGroundPhase)
- me->GetMotionMaster()->MoveChase(who);
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- me->SetInCombatWithZone();
- events.Reset();
- events.ScheduleEvent(EVENT_COMMANDER_SAY_AGGRO, 5s);
- events.ScheduleEvent(EVENT_EE_SAY_MOVE_OUT, 10s);
- events.ScheduleEvent(EVENT_ENRAGE, 10min);
- events.ScheduleEvent(EVENT_SPELL_FIREBALL, 6s);
- events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME, 13s);
- events.ScheduleEvent(EVENT_SUMMON_MOLE_MACHINES, 11s);
-
- std::list eeList;
- me->GetCreaturesWithEntryInRange(eeList, 300.0f, NPC_EXPEDITION_ENGINEER);
- uint8 i = 0;
- for( std::list::iterator itr = eeList.begin(); itr != eeList.end(); ++itr )
- {
- if( i > 2 )
- break;
- ExpeditionEngineerGUIDs[i] = (*itr)->GetGUID();
- if (!i)
- (*itr)->AI()->Talk(SAY_EE_AGGRO);
- ++i;
- }
- if (Creature* c = me->FindNearestCreature(NPC_EXPEDITION_COMMANDER, 300.0f, true))
- CommanderGUID = c->GetGUID();
-
- if( pInstance )
- pInstance->SetData(TYPE_RAZORSCALE, IN_PROGRESS);
- }
-
- void JustDied(Unit* /*Killer*/) override
- {
- summons.DespawnAll();
-
- if( pInstance )
- pInstance->SetData(TYPE_RAZORSCALE, DONE);
- }
-
- void SpellHit(Unit* caster, SpellInfo const* spell) override
- {
- if (!caster || !pInstance)
- return;
-
- switch (spell->Id)
- {
- case SPELL_LAUNCH_CHAIN:
- {
- uint32 spellId = SPELL_CHAIN_4;
-
- if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1))
- {
- spellId = SPELL_CHAIN_1;
- }
- else if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_2))
- {
- spellId = SPELL_CHAIN_2;
- }
- else if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_3))
- {
- spellId = SPELL_CHAIN_3;
- }
-
- caster->CastSpell(me, spellId, true);
- }
- break;
- case SPELL_CHAIN_1:
- case SPELL_CHAIN_2:
- case SPELL_CHAIN_3:
- case SPELL_CHAIN_4:
- {
- uint8 count = 0;
- if( me->HasAura(SPELL_CHAIN_1) )
- count++;
- if( me->HasAura(SPELL_CHAIN_3) )
- count++;
- if (RAID_MODE(0, 1))
- {
- if( me->HasAura(SPELL_CHAIN_2) )
- count++;
- if( me->HasAura(SPELL_CHAIN_4) )
- count++;
- }
- if( count >= REQ_CHAIN_COUNT )
- {
- if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID))
- commander->AI()->Talk(SAY_COMMANDER_GROUND_PHASE);
-
- me->InterruptNonMeleeSpells(true);
- events.CancelEvent(EVENT_SPELL_FIREBALL);
- events.CancelEvent(EVENT_SPELL_DEVOURING_FLAME);
- events.CancelEvent(EVENT_SUMMON_MOLE_MACHINES);
- me->SetTarget();
- me->SendMeleeAttackStop(me->GetVictim());
- me->GetMotionMaster()->MoveLand(0, CORDS_GROUND, 25.0f);
- }
- }
- break;
- }
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
- {
- if (me->GetPositionZ() > 440.0f) // protection, razorscale is attackable (so harpoons can hit him, etc.), but should not receive dmg while in air
- damage = 0;
- else if (!bGroundPhase && ((me->GetHealth() * 100) / me->GetMaxHealth() < 50) && me->HasAura(62794)) // already below 50%, but still in chains and stunned
- events.RescheduleEvent(EVENT_WARN_DEEP_BREATH, 0ms);
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type == POINT_MOTION_TYPE && id == POINT_RAZORSCALE_INIT)
- {
- me->SetFacingTo(1.6f);
- return;
- }
- else if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized() && !me->IsInCombat())
- {
- startPath = true;
- return;
- }
-
- if (type != EFFECT_MOTION_TYPE)
- return;
- if (id == 0) // landed
- {
- me->SetControlled(true, UNIT_STATE_ROOT);
- me->DisableRotate(true);
- me->SetOrientation((float)(M_PI + 0.01) / 2);
- me->SetFacingTo(M_PI / 2);
- me->SetDisableGravity(false);
- me->CastSpell(me, 62794, true);
- events.ScheduleEvent(EVENT_WARN_DEEP_BREATH, 30s);
- }
- else if (id == 1) // flied up
- {
- events.ScheduleEvent(EVENT_SPELL_FIREBALL, 2s);
- events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME, 4s);
- events.ScheduleEvent(EVENT_SUMMON_MOLE_MACHINES, 5s);
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (startPath)
- {
- me->StopMoving();
- startPath = false;
- if (WaypointPath const* i_path = sWaypointMgr->GetPath(me->GetWaypointPath()))
- {
- Movement::PointsArray pathPoints;
- pathPoints.push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
- for (uint8 i = 0; i < i_path->size(); ++i)
- {
- WaypointData const* node = i_path->at(i);
- pathPoints.push_back(G3D::Vector3(node->x, node->y, node->z));
- }
- me->GetMotionMaster()->MoveSplinePath(&pathPoints);
- }
- }
-
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case 0:
- break;
- case EVENT_ENRAGE:
- Talk(EMOTE_BERSERK);
- me->CastSpell(me, SPELL_BERSERK, true);
- break;
- case EVENT_COMMANDER_SAY_AGGRO:
- if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID))
- commander->AI()->Talk(SAY_COMMANDER_AGGRO);
- break;
- case EVENT_EE_SAY_MOVE_OUT:
- for (uint8 i = 0; i < 3; ++i)
- if (Creature* c = ObjectAccessor::GetCreature(*me, ExpeditionEngineerGUIDs[i]))
- {
- if (!i)
- c->AI()->Talk(SAY_EE_START_REPAIR);
- c->AI()->SetData(1, 0); // start repairing
- }
- break;
- case EVENT_SPELL_FIREBALL:
- if( Unit* pTarget = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, true) )
- me->CastSpell(pTarget, SPELL_FIREBALL, false);
- events.Repeat(4s);
- break;
- case EVENT_SPELL_DEVOURING_FLAME:
- if( Unit* pTarget = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, true) )
- me->CastSpell(pTarget, SPELL_DEVOURINGFLAME, false);
- events.Repeat(13s);
- break;
- case EVENT_SUMMON_MOLE_MACHINES:
- {
- memset(cords, '\0', sizeof(cords));
- uint8 num = RAID_MODE( urand(2, 3), urand(2, 4) );
- for( int i = 0; i < num; ++i )
- {
- // X: (550, 625) Y: (-185, -230)
- cords[i][0] = urand(550, 625);
- cords[i][1] = -230 + rand() % 45;
- if( GameObject* drill = me->SummonGameObject(GO_DRILL, cords[i][0], cords[i][1], 391.1f, M_PI / 4, 0.0f, 0.0f, 0.0f, 0.0f, 8) )
- {
- //drill->SetGoAnimProgress(0);
- //drill->SetLootState(GO_READY);
- //drill->UseDoorOrButton(8);
- //drill->SetGoState(GO_STATE_READY);
- drill->SetGoState(GO_STATE_ACTIVE);
- drill->SetGoAnimProgress(0);
- }
- }
- events.Repeat(45s);
- events.RescheduleEvent(EVENT_SUMMON_ADDS, 4s);
- }
- break;
- case EVENT_SUMMON_ADDS:
- for( int i = 0; i < 4; ++i )
- {
- if( !cords[i][0] )
- break;
-
- uint8 opt;
- uint8 r = urand(1, 100);
- if( r <= 30 ) opt = 1;
- else if( r <= 65 ) opt = 2;
- else opt = 3;
-
- for( int j = 0; j < 4; ++j )
- {
- float x = cords[i][0] + 4.0f * cos(j * M_PI / 2);
- float y = cords[i][1] + 4.0f * std::sin(j * M_PI / 2);
-
- uint32 npc_entry = 0;
- switch( opt )
- {
- case 1:
- if( j == 1 ) npc_entry = NPC_DARK_RUNE_SENTINEL;
- break;
- case 2:
- switch( j )
- {
- case 1:
- npc_entry = NPC_DARK_RUNE_WATCHER;
- break;
- case 2:
- npc_entry = NPC_DARK_RUNE_GUARDIAN;
- break;
- }
- break;
- default: // case 3:
- switch( j )
- {
- case 1:
- npc_entry = NPC_DARK_RUNE_WATCHER;
- break;
- case 2:
- npc_entry = NPC_DARK_RUNE_GUARDIAN;
- break;
- case 3:
- npc_entry = NPC_DARK_RUNE_GUARDIAN;
- break;
- }
- break;
- }
-
- if( npc_entry )
- if (Creature* c = me->SummonCreature(npc_entry, x, y, 391.1f, j * M_PI / 2, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
- DoZoneInCombat(c);
- }
- }
- break;
- case EVENT_WARN_DEEP_BREATH:
- Talk(EMOTE_BREATH);
- me->RemoveAura(62794);
- events.ScheduleEvent(EVENT_PHASE2_FLAME_BREATH, 2500ms);
- break;
- case EVENT_PHASE2_FLAME_BREATH:
- me->CastSpell(me, SPELL_FLAMEBREATH, true);
- events.ScheduleEvent(EVENT_FLY_UP, 2s);
- break;
- case EVENT_FLY_UP:
- me->SetInCombatWithZone(); // just in case
- if (pInstance)
- for( int i = 0; i < 4; ++i )
- if( ObjectGuid guid = pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i) )
- if( Creature* hfs = ObjectAccessor::GetCreature(*me, guid) )
- {
- me->SummonCreature(34188, hfs->GetPositionX(), hfs->GetPositionY(), hfs->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 22000);
- hfs->AI()->SetData(1, 0);
- }
-
- me->RemoveAura(SPELL_LAUNCH_CHAIN);
- me->RemoveAura(SPELL_CHAIN_1);
- me->RemoveAura(SPELL_CHAIN_3);
- if (RAID_MODE(0, 1))
- {
- me->RemoveAura(SPELL_CHAIN_2);
- me->RemoveAura(SPELL_CHAIN_4);
- }
- me->CastSpell(me, SPELL_WINGBUFFET, true);
-
- if( (me->GetHealth() * 100) / me->GetMaxHealth() < 50 ) // start phase 3
- {
- Talk(EMOTE_PERMA_GROUND);
- me->SetControlled(false, UNIT_STATE_ROOT);
- me->DisableRotate(false);
- DoResetThreatList();
- Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0, true);
- if (!target)
- target = me->SelectNearestPlayer(200.0f);
- if (target)
- {
- AttackStart(target);
- me->GetMotionMaster()->MoveChase(target);
- }
- bGroundPhase = true;
- events.CancelEvent(EVENT_SPELL_FIREBALL);
- events.CancelEvent(EVENT_SPELL_DEVOURING_FLAME);
- events.CancelEvent(EVENT_SUMMON_MOLE_MACHINES);
-
- events.ScheduleEvent(EVENT_SPELL_FLAME_BREATH, 20s);
- events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME_GROUND, 5s);
- events.ScheduleEvent(EVENT_SPELL_FUSE_ARMOR, 10s);
- events.ScheduleEvent(EVENT_SPELL_FLAME_BUFFET, 3s);
-
- break;
- }
- else
- {
- ++flyTimes;
- me->SetControlled(false, UNIT_STATE_ROOT);
- me->DisableRotate(false);
- me->SendMeleeAttackStop(me->GetVictim());
- me->GetMotionMaster()->MoveIdle();
- me->StopMoving();
- me->SetDisableGravity(true);
- me->GetMotionMaster()->MoveTakeoff(1, CORDS_AIR, 25.0f);
- events.ScheduleEvent(EVENT_RESUME_FIXING, 22s);
- }
-
- break;
- case EVENT_RESUME_FIXING:
- for (uint8 i = 0; i < 3; ++i)
- if (Creature* c = ObjectAccessor::GetCreature(*me, ExpeditionEngineerGUIDs[i]))
- {
- if (!i)
- c->AI()->Talk(SAY_EE_REBUILD_TURRETS);
- c->AI()->SetData(1, 0); // start repairing
- }
- break;
- case EVENT_SPELL_FLAME_BREATH:
- me->CastSpell(me->GetVictim(), SPELL_FLAMEBREATH, false);
- events.Repeat(20s);
- break;
- case EVENT_SPELL_DEVOURING_FLAME_GROUND:
- me->CastSpell(me->GetVictim(), SPELL_DEVOURINGFLAME, false);
- events.Repeat(13s);
- break;
- case EVENT_SPELL_FUSE_ARMOR:
- if (Unit* victim = me->GetVictim())
- if (me->IsWithinMeleeRange(victim))
- {
- me->CastSpell(victim, SPELL_FUSEARMOR, false);
- if (Aura* aur = victim->GetAura(SPELL_FUSEARMOR))
- if (aur->GetStackAmount() == 5)
- victim->CastSpell(victim, SPELL_FUSED_ARMOR, true);
- events.Repeat(10s);
- break;
- }
- events.Repeat(2s);
- break;
- case EVENT_SPELL_FLAME_BUFFET:
- me->CastSpell(me->GetVictim(), SPELL_FLAMEBUFFET, false);
- events.Repeat(7s);
- break;
- }
-
- if (bGroundPhase)
- DoMeleeAttackIfReady();
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override {}
-
- void JustReachedHome() override
- {
- startPath = true;
- }
-
- void JustSummoned(Creature* s) override
- {
- summons.Summon(s);
- }
-
- uint32 GetData(uint32 id) const override
- {
- if (id == 1)
- return (flyTimes <= 1 ? 1 : 0);
- return 0;
- }
-
- void KilledUnit(Unit* victim) override
- {
- if (victim && victim->GetEntry() == NPC_DARK_RUNE_GUARDIAN)
- if (pInstance)
- pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_DARK_RUNE_GUARDIAN, 1, me);
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- me->SetDisableGravity(true);
- me->SetControlled(false, UNIT_STATE_ROOT);
- me->DisableRotate(false);
- ScriptedAI::EnterEvadeMode(why);
- }
- };
-};
-
-class npc_ulduar_expedition_commander : public CreatureScript
-{
-public:
- npc_ulduar_expedition_commander() : CreatureScript("npc_ulduar_expedition_commander") { }
-
- bool OnGossipHello(Player* player, Creature* creature) override
- {
- if (!player || !creature)
- return true;
-
- InstanceScript* instance = creature->GetInstanceScript();
- if (!instance)
- return true;
-
- if (instance->GetData(TYPE_RAZORSCALE) == DONE)
- return true;
-
- Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE));
- if (!razorscale || razorscale->IsInCombat())
- return true;
-
- AddGossipItemFor(player, GOSSIP_MENU_START_ENCOUNTER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
- SendGossipMenuFor(player, NPC_TEXT_COMMANDER, creature);
- return true;
- }
-
- bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 uiAction) override
- {
- if (!player || !creature)
- return true;
-
- if (uiAction == GOSSIP_ACTION_INFO_DEF + 1)
- {
- InstanceScript* instance = creature->GetInstanceScript();
- if (!instance || instance->GetData(TYPE_RAZORSCALE) == DONE)
- return true;
-
- Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE));
- if (razorscale && !razorscale->IsInCombat())
- {
- // Do not show gossip icon if encounter is in progress
- creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
-
- // reset npcs NPC_HARPOON_FIRE_STATE
- for (uint8 i = 0; i < 4; ++i)
- if (Creature* hfs = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i)))
- hfs->AI()->SetData(1, 0);
-
- if (razorscale->AI())
- {
- razorscale->AI()->AttackStart(player);
- razorscale->GetMotionMaster()->MoveIdle();
- razorscale->GetMotionMaster()->MovePoint(POINT_RAZORSCALE_INIT, 588.0f, -178.0f, 490.0f, false, false);
- }
- }
- }
-
- player->PlayerTalkClass->SendCloseGossip();
- return true;
- }
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetUlduarAI(creature);
- }
-
- struct npc_ulduar_expedition_commanderAI : public NullCreatureAI
- {
- npc_ulduar_expedition_commanderAI(Creature* creature) : NullCreatureAI(creature)
- {
- _instance = creature->GetInstanceScript();
- _introSpoken = _instance->GetData(TYPE_RAZORSCALE) == DONE;
- me->SetReactState(REACT_AGGRESSIVE);
- }
-
- void MoveInLineOfSight(Unit* who) override
- {
- if (_introSpoken)
- return;
-
- if (who->GetTypeId() != TYPEID_PLAYER || me->GetExactDist2d(who) > 15.0f)
- return;
-
- _introSpoken = true;
- //Talk(SAY_COMMANDER_INTRO); // No source leads to showing any text messages, perhaps only SOUND ID 15647 is played?
- }
-
- private:
- InstanceScript* _instance;
- bool _introSpoken;
- };
-};
-
-class npc_ulduar_harpoonfirestate : public CreatureScript
-{
-public:
- npc_ulduar_harpoonfirestate() : CreatureScript("npc_ulduar_harpoonfirestate") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_harpoonfirestateAI : public NullCreatureAI
- {
- npc_ulduar_harpoonfirestateAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- pInstance = me->GetInstanceScript();
- }
-
- InstanceScript* pInstance;
- uint8 repairPoints;
-
- void Reset() override
- {
- repairPoints = 0;
- }
-
- uint32 GetHarpoonGunIdForThisHFS()
- {
- if (pInstance)
- {
- if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1) )
- return GO_HARPOON_GUN_1;
- else if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_2) )
- return GO_HARPOON_GUN_2;
- else if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_3) )
- return GO_HARPOON_GUN_3;
- else
- return GO_HARPOON_GUN_4;
- }
- return 0;
- }
-
- void SetData(uint32 id, uint32 value) override
- {
- switch (id)
- {
- case 1: // cleanup at the start of the fight
- if (pInstance)
- {
- uint32 h_entry = GetHarpoonGunIdForThisHFS();
- if( GameObject* wh = me->FindNearestGameObject(h_entry, 5.0f) )
- {
- wh->SetRespawnTime(0);
- wh->Delete();
- }
- if( GameObject* bh = me->FindNearestGameObject(GO_BROKEN_HARPOON, 5.0f) )
- if (bh->GetPhaseMask() != 1)
- bh->SetPhaseMask(1, true);
- }
- Reset();
- break;
- case 2: // repairing
- if (repairPoints < REPAIR_POINTS)
- {
- if (++repairPoints >= REPAIR_POINTS)
- {
- if( GameObject* bh = me->FindNearestGameObject(GO_BROKEN_HARPOON, 4.0f) )
- bh->SetPhaseMask(2, true);
- if( GameObject* wh = me->SummonGameObject(GetHarpoonGunIdForThisHFS(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 3 * M_PI / 2, 0.0f, 0.0f, 0.0f, 0.0f, 0) )
- {
- me->RemoveGameObject(wh, false);
- if (Creature* cr = me->SummonCreature(NPC_RAZORSCALE_CONTROLLER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 5000))
- cr->AI()->Talk(EMOTE_HARPOON);
- }
- }
- }
- break;
- case 3: // shoot
- if (pInstance)
- {
- Creature* razorscale = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_RAZORSCALE));
- if (!razorscale)
- return;
- if (!razorscale->HasAura(value))
- me->CastSpell(razorscale, SPELL_LAUNCH_CHAIN, true);
- }
- break;
- }
- }
-
- uint32 GetData(uint32 id) const override
- {
- switch (id)
- {
- case 2:
- return (repairPoints >= REPAIR_POINTS ? 1 : 0);
- }
- return 0;
- }
- };
-};
-
-class npc_ulduar_expedition_engineer : public CreatureScript
-{
-public:
- npc_ulduar_expedition_engineer() : CreatureScript("npc_ulduar_expedition_engineer") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_expedition_engineerAI : public NullCreatureAI
- {
- npc_ulduar_expedition_engineerAI(Creature* pCreature) : NullCreatureAI(pCreature)
- {
- pInstance = me->GetInstanceScript();
- }
-
- InstanceScript* pInstance;
- bool working;
- uint16 timer;
- ObjectGuid fixingGUID;
-
- void Reset() override
- {
- working = false;
- timer = 0;
- fixingGUID.Clear();
- }
-
- void SetData(uint32 id, uint32 /*value*/) override
- {
- switch (id)
- {
- case 1: // start/resume repairing
- working = true;
- timer = 0;
- fixingGUID.Clear();
- break;
- case 2: // stop repairing
- Reset();
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND);
- me->GetMotionMaster()->MoveTargetedHome();
- break;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (working)
- {
- if (timer <= diff)
- {
- timer = 3000;
-
- if (fixingGUID)
- {
- if (Creature* c = ObjectAccessor::GetCreature(*me, fixingGUID))
- if (me->GetExactDist2dSq(c) <= 25.0f)
- {
- if( me->GetUInt32Value(UNIT_NPC_EMOTESTATE) != EMOTE_STATE_WORK )
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_WORK);
-
- if (std::fabs(me->GetOrientation() - me->GetAngle(c)) > M_PI / 4)
- me->SetFacingToObject(c);
-
- c->AI()->SetData(2, 0);
- if (c->AI()->GetData(2))
- fixingGUID.Clear();
- }
- }
-
- if (!fixingGUID)
- {
- Creature* razorscale = nullptr;
- if( ObjectGuid rsGUID = pInstance->GetGuidData(TYPE_RAZORSCALE) )
- razorscale = ObjectAccessor::GetCreature(*me, rsGUID);
-
- if( !razorscale || !razorscale->IsInCombat() )
- {
- Reset();
- me->GetMotionMaster()->MoveTargetedHome();
- return;
- }
-
- for( int i = 0; i < 4; ++i )
- if( ObjectGuid fs_GUID = pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i) )
- if( Creature* fs = ObjectAccessor::GetCreature(*me, fs_GUID) )
- if (!fs->AI()->GetData(2))
- {
- float a = rand_norm() * M_PI;
- me->GetMotionMaster()->MovePoint(0, fs->GetPositionX() + 3.0f * cos(a), fs->GetPositionY() + 3.0f * std::sin(a), fs->GetPositionZ());
- fixingGUID = fs->GetGUID();
- return;
- }
-
- Reset(); // all harpoons repaired
- me->GetMotionMaster()->MoveTargetedHome();
- }
- }
- else
- timer -= diff;
- }
- else if (me->GetUInt32Value(UNIT_NPC_EMOTESTATE) == EMOTE_STATE_WORK)
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND);
- }
- };
-};
-
-class go_ulduar_working_harpoon : public GameObjectScript
-{
-public:
- go_ulduar_working_harpoon() : GameObjectScript("go_ulduar_working_harpoon") { }
-
- bool OnGossipHello(Player* user, GameObject* go) override
- {
- if( !user || !go )
- return true;
-
- InstanceScript* pInstance = go->GetInstanceScript();
- if( !pInstance )
- return true;
-
- Creature* rs = nullptr;
- if( ObjectGuid rsGUID = pInstance->GetGuidData(TYPE_RAZORSCALE) )
- rs = ObjectAccessor::GetCreature(*go, rsGUID);
-
- if( !rs || !rs->IsInCombat() )
- {
- go->SetRespawnTime(0);
- go->Delete();
- return true;
- }
-
- uint32 npc = 0;
- uint32 spell = 0;
- switch( go->GetEntry() )
- {
- case GO_HARPOON_GUN_1:
- npc = DATA_HARPOON_FIRE_STATE_1;
- spell = SPELL_CHAIN_1;
- break;
- case GO_HARPOON_GUN_2:
- npc = DATA_HARPOON_FIRE_STATE_2;
- spell = SPELL_CHAIN_2;
- break;
- case GO_HARPOON_GUN_3:
- npc = DATA_HARPOON_FIRE_STATE_3;
- spell = SPELL_CHAIN_3;
- break;
- case GO_HARPOON_GUN_4:
- npc = DATA_HARPOON_FIRE_STATE_4;
- spell = SPELL_CHAIN_4;
- break;
- }
-
- if( ObjectGuid g = pInstance->GetGuidData(npc) )
- if( Creature* hfs = ObjectAccessor::GetCreature(*go, g) )
- hfs->AI()->SetData(3, spell);
-
- go->SetLootState(GO_JUST_DEACTIVATED);
- return true;
- }
-};
-
-class npc_ulduar_dark_rune_guardian : public CreatureScript
-{
-public:
- npc_ulduar_dark_rune_guardian() : CreatureScript("npc_ulduar_dark_rune_guardian") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_dark_rune_guardianAI : public ScriptedAI
- {
- npc_ulduar_dark_rune_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- uint32 timer2;
-
- void Reset() override
- {
- timer2 = 6000;
- }
-
- bool CanAIAttack(Unit const* target) const override
- {
- return target && target->GetEntry() != NPC_RAZORSCALE;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if( !UpdateVictim() )
- return;
-
- if (timer2 <= diff) timer2 = 0;
- else timer2 -= diff;
- if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()))
- {
- me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DMG, true);
- me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DMG, true); // cast the same twice cus second one requires setting offhand damage
- me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DEBUFF, true);
- timer2 = urand(8000, 10000);
- return;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class npc_ulduar_dark_rune_watcher : public CreatureScript
-{
-public:
- npc_ulduar_dark_rune_watcher() : CreatureScript("npc_ulduar_dark_rune_watcher") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_dark_rune_watcherAI : public ScriptedAI
- {
- npc_ulduar_dark_rune_watcherAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- uint32 timer1;
- uint32 timer2;
-
- void Reset() override
- {
- timer1 = 6000;
- timer2 = 2000;
- }
-
- bool CanAIAttack(Unit const* target) const override
- {
- return target && target->GetEntry() != NPC_RAZORSCALE;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if( !UpdateVictim() )
- return;
-
- if( timer1 <= diff )
- {
- me->CastSpell(me->GetVictim(), SPELL_CHAINLIGHTNING, false);
- timer1 = urand(10000, 12000);
- return;
- }
- else
- timer1 -= diff;
-
- if (timer2 <= diff)
- {
- me->CastSpell(me->GetVictim(), SPELL_LIGHTINGBOLT, false);
- timer2 = 4000;
- return;
- }
- else
- timer2 -= diff;
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class npc_ulduar_dark_rune_sentinel : public CreatureScript
-{
-public:
- npc_ulduar_dark_rune_sentinel() : CreatureScript("npc_ulduar_dark_rune_sentinel") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_ulduar_dark_rune_sentinelAI : public ScriptedAI
- {
- npc_ulduar_dark_rune_sentinelAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- uint32 timer1;
- uint32 timer2;
-
- void Reset() override
- {
- timer1 = urand(1000, 2000);
- timer2 = 6000;
- }
-
- bool CanAIAttack(Unit const* target) const override
- {
- return target && target->GetEntry() != NPC_RAZORSCALE;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if( !UpdateVictim() )
- return;
-
- if( timer1 <= diff )
- {
- me->CastSpell(me, SPELL_BATTLE_SHOUT, false);
- timer1 = urand(15000, 20000);
- }
- else
- timer1 -= diff;
-
- if (timer2 <= diff) timer2 = 0;
- else timer2 -= diff;
- if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()))
- {
- me->CastSpell(me, SPELL_WHIRLWIND, false);
- timer2 = urand(10000, 12000);
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class achievement_quick_shave : public AchievementCriteriaScript
-{
-public:
- achievement_quick_shave() : AchievementCriteriaScript("achievement_quick_shave") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetTypeId() == TYPEID_UNIT && target->GetEntry() == NPC_RAZORSCALE && target->ToCreature()->AI()->GetData(1);
- }
-};
-
-class achievement_iron_dwarf_medium_rare : public AchievementCriteriaScript
-{
-public:
- achievement_iron_dwarf_medium_rare() : AchievementCriteriaScript("achievement_iron_dwarf_medium_rare") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- return target && target->GetEntry() == NPC_RAZORSCALE;
- }
-};
-
void AddSC_boss_razorscale()
{
new boss_razorscale();
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.h
new file mode 100644
index 00000000000000..22360225823474
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.h
@@ -0,0 +1,1157 @@
+#ifndef BOSS_RAZORSCALE_H_
+#define BOSS_RAZORSCALE_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "GameObjectScript.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "ScriptedGossip.h"
+#include "SpellAuras.h"
+#include "SpellScript.h"
+#include "WaypointMgr.h"
+#include "ulduar.h"
+
+enum Spells
+{
+ // Razorscale
+ SPELL_FLAMEBUFFET_10 = 64016,
+ SPELL_FLAMEBUFFET_25 = 64023,
+ SPELL_FIREBALL = 63815,
+ SPELL_WINGBUFFET = 62666,
+ SPELL_FLAMEBREATH_10 = 63317,
+ SPELL_FLAMEBREATH_25 = 64021,
+ SPELL_FUSEARMOR = 64771,
+ SPELL_FUSED_ARMOR = 64774, // Applied on 5th stack of SPELL_FUSEARMOR
+ SPELL_DEVOURINGFLAME = 63236,
+ SPELL_BERSERK = 47008,
+
+ // Haproons
+ SPELL_CHAIN_1 = 49679,
+ SPELL_CHAIN_2 = 49682,
+ SPELL_CHAIN_3 = 49683,
+ SPELL_CHAIN_4 = 49684,
+ SPELL_LAUNCH_CHAIN = 62505,
+
+ // Dark Rune Sentinel
+ SPELL_WHIRLWIND = 63808,
+ SPELL_BATTLE_SHOUT_10 = 46763,
+ SPELL_BATTLE_SHOUT_25 = 64062,
+
+ // Dark Rune Guardian
+ SPELL_STORMSTRIKE_DMG = 65971,
+ SPELL_STORMSTRIKE_DEBUFF = 64757,
+
+ // Dark Rune Watcher
+ SPELL_LIGHTINGBOLT_10 = 63809,
+ SPELL_LIGHTINGBOLT_25 = 64696,
+ SPELL_CHAINLIGHTNING_10 = 64758,
+ SPELL_CHAINLIGHTNING_25 = 64759,
+};
+
+#define SPELL_FLAMEBUFFET RAID_MODE(SPELL_FLAMEBUFFET_10, SPELL_FLAMEBUFFET_25)
+#define SPELL_FLAMEBREATH RAID_MODE(SPELL_FLAMEBREATH_10, SPELL_FLAMEBREATH_25)
+#define SPELL_BATTLE_SHOUT RAID_MODE(SPELL_BATTLE_SHOUT_10, SPELL_BATTLE_SHOUT_25)
+#define SPELL_LIGHTINGBOLT RAID_MODE(SPELL_LIGHTINGBOLT_10, SPELL_LIGHTINGBOLT_25)
+#define SPELL_CHAINLIGHTNING RAID_MODE(SPELL_CHAINLIGHTNING_10, SPELL_CHAINLIGHTNING_25)
+#define REQ_CHAIN_COUNT RAID_MODE(2, 4)
+
+enum NPCs
+{
+ NPC_DARK_RUNE_SENTINEL = 33846,
+ NPC_DARK_RUNE_GUARDIAN = 33388,
+ NPC_DARK_RUNE_WATCHER = 33453,
+ NPC_EXPEDITION_ENGINEER = 33287,
+ NPC_EXPEDITION_COMMANDER = 33210,
+ NPC_RAZORSCALE_CONTROLLER = 33233, // Trigger Creature
+};
+
+enum GOs
+{
+ GO_DRILL = 195305,
+ GO_HARPOON_GUN_1 = 194519,
+ GO_HARPOON_GUN_2 = 194541,
+ GO_HARPOON_GUN_3 = 194542,
+ GO_HARPOON_GUN_4 = 194543,
+ GO_BROKEN_HARPOON = 194565,
+};
+
+enum eEvents
+{
+ EVENT_NONE = 0,
+ EVENT_COMMANDER_SAY_AGGRO,
+ EVENT_EE_SAY_MOVE_OUT,
+ EVENT_ENRAGE,
+ EVENT_SPELL_FIREBALL,
+ EVENT_SPELL_DEVOURING_FLAME,
+ EVENT_SUMMON_MOLE_MACHINES,
+ EVENT_SUMMON_ADDS,
+ EVENT_WARN_DEEP_BREATH,
+ EVENT_PHASE2_FLAME_BREATH,
+ EVENT_FLY_UP,
+ EVENT_RESUME_FIXING,
+ EVENT_SPELL_FLAME_BREATH,
+ EVENT_SPELL_DEVOURING_FLAME_GROUND,
+ EVENT_SPELL_FUSE_ARMOR,
+ EVENT_SPELL_FLAME_BUFFET,
+};
+
+enum Texts
+{
+ // Razorscale
+ EMOTE_PERMA_GROUND = 0,
+ EMOTE_BREATH = 1,
+ EMOTE_BERSERK = 2,
+
+ // Expedition Commander
+ SAY_COMMANDER_AGGRO = 0,
+ SAY_COMMANDER_GROUND_PHASE = 1,
+ SAY_COMMANDER_ENGINEERS_DEAD = 2, // Should be called when all engineers are dead, currently unused
+
+ // Expedition Engineer
+ SAY_EE_AGGRO = 0,
+ SAY_EE_START_REPAIR = 1,
+ SAY_EE_REBUILD_TURRETS = 2,
+
+ // Harpoon
+ EMOTE_HARPOON = 0,
+};
+
+enum Misc
+{
+ POINT_RAZORSCALE_INIT = 1,
+ REPAIR_POINTS = 25,
+
+ // Expedition Commander Gossip
+ GOSSIP_MENU_START_ENCOUNTER = 10314,
+ NPC_TEXT_COMMANDER = 40100,
+};
+
+const Position CORDS_GROUND = {588.0f, -166.0f, 391.1f};
+const Position CORDS_AIR = {588.0f, -178.0f, 490.0f};
+
+class boss_razorscale : public CreatureScript
+{
+public:
+ boss_razorscale() : CreatureScript("boss_razorscale") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_razorscaleAI : public ScriptedAI
+ {
+ boss_razorscaleAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
+ {
+ pInstance = me->GetInstanceScript();
+ startPath = true;
+ }
+
+ InstanceScript* pInstance;
+ EventMap events;
+ SummonList summons;
+ ObjectGuid ExpeditionEngineerGUIDs[3];
+ ObjectGuid CommanderGUID;
+ float cords[4][2];
+ bool bGroundPhase;
+ bool startPath;
+ uint8 flyTimes;
+
+ void InitializeAI() override
+ {
+ me->SetDisableGravity(true);
+ me->setActive(true);
+ Reset();
+ }
+
+ void Reset() override
+ {
+ events.Reset();
+ summons.DespawnAll();
+
+ for (uint8 i = 0; i < 3; ++i)
+ ExpeditionEngineerGUIDs[i].Clear();
+
+ // Show gossip icon if previously hidden
+ if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID))
+ if (!commander->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP))
+ commander->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
+
+ CommanderGUID.Clear();
+ bGroundPhase = false;
+ flyTimes = 0;
+
+ if( pInstance )
+ pInstance->SetData(TYPE_RAZORSCALE, NOT_STARTED);
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ if (who && me->Attack(who, true) && bGroundPhase)
+ me->GetMotionMaster()->MoveChase(who);
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ me->SetInCombatWithZone();
+ events.Reset();
+ events.ScheduleEvent(EVENT_COMMANDER_SAY_AGGRO, 5s);
+ events.ScheduleEvent(EVENT_EE_SAY_MOVE_OUT, 10s);
+ events.ScheduleEvent(EVENT_ENRAGE, 10min);
+ events.ScheduleEvent(EVENT_SPELL_FIREBALL, 6s);
+ events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME, 13s);
+ events.ScheduleEvent(EVENT_SUMMON_MOLE_MACHINES, 11s);
+
+ std::list eeList;
+ me->GetCreaturesWithEntryInRange(eeList, 300.0f, NPC_EXPEDITION_ENGINEER);
+ uint8 i = 0;
+ for( std::list::iterator itr = eeList.begin(); itr != eeList.end(); ++itr )
+ {
+ if( i > 2 )
+ break;
+ ExpeditionEngineerGUIDs[i] = (*itr)->GetGUID();
+ if (!i)
+ (*itr)->AI()->Talk(SAY_EE_AGGRO);
+ ++i;
+ }
+ if (Creature* c = me->FindNearestCreature(NPC_EXPEDITION_COMMANDER, 300.0f, true))
+ CommanderGUID = c->GetGUID();
+
+ if( pInstance )
+ pInstance->SetData(TYPE_RAZORSCALE, IN_PROGRESS);
+ }
+
+ void JustDied(Unit* /*Killer*/) override
+ {
+ summons.DespawnAll();
+
+ if( pInstance )
+ pInstance->SetData(TYPE_RAZORSCALE, DONE);
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ if (!caster || !pInstance)
+ return;
+
+ switch (spell->Id)
+ {
+ case SPELL_LAUNCH_CHAIN:
+ {
+ uint32 spellId = SPELL_CHAIN_4;
+
+ if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1))
+ {
+ spellId = SPELL_CHAIN_1;
+ }
+ else if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_2))
+ {
+ spellId = SPELL_CHAIN_2;
+ }
+ else if (caster->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_3))
+ {
+ spellId = SPELL_CHAIN_3;
+ }
+
+ caster->CastSpell(me, spellId, true);
+ }
+ break;
+ case SPELL_CHAIN_1:
+ case SPELL_CHAIN_2:
+ case SPELL_CHAIN_3:
+ case SPELL_CHAIN_4:
+ {
+ uint8 count = 0;
+ if( me->HasAura(SPELL_CHAIN_1) )
+ count++;
+ if( me->HasAura(SPELL_CHAIN_3) )
+ count++;
+ if (RAID_MODE(0, 1))
+ {
+ if( me->HasAura(SPELL_CHAIN_2) )
+ count++;
+ if( me->HasAura(SPELL_CHAIN_4) )
+ count++;
+ }
+ if( count >= REQ_CHAIN_COUNT )
+ {
+ if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID))
+ commander->AI()->Talk(SAY_COMMANDER_GROUND_PHASE);
+
+ me->InterruptNonMeleeSpells(true);
+ events.CancelEvent(EVENT_SPELL_FIREBALL);
+ events.CancelEvent(EVENT_SPELL_DEVOURING_FLAME);
+ events.CancelEvent(EVENT_SUMMON_MOLE_MACHINES);
+ me->SetTarget();
+ me->SendMeleeAttackStop(me->GetVictim());
+ me->GetMotionMaster()->MoveLand(0, CORDS_GROUND, 25.0f);
+ }
+ }
+ break;
+ }
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
+ {
+ if (me->GetPositionZ() > 440.0f) // protection, razorscale is attackable (so harpoons can hit him, etc.), but should not receive dmg while in air
+ damage = 0;
+ else if (!bGroundPhase && ((me->GetHealth() * 100) / me->GetMaxHealth() < 50) && me->HasAura(62794)) // already below 50%, but still in chains and stunned
+ events.RescheduleEvent(EVENT_WARN_DEEP_BREATH, 0ms);
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type == POINT_MOTION_TYPE && id == POINT_RAZORSCALE_INIT)
+ {
+ me->SetFacingTo(1.6f);
+ return;
+ }
+ else if (type == ESCORT_MOTION_TYPE && me->movespline->Finalized() && !me->IsInCombat())
+ {
+ startPath = true;
+ return;
+ }
+
+ if (type != EFFECT_MOTION_TYPE)
+ return;
+ if (id == 0) // landed
+ {
+ me->SetControlled(true, UNIT_STATE_ROOT);
+ me->DisableRotate(true);
+ me->SetOrientation((float)(M_PI + 0.01) / 2);
+ me->SetFacingTo(M_PI / 2);
+ me->SetDisableGravity(false);
+ me->CastSpell(me, 62794, true);
+ events.ScheduleEvent(EVENT_WARN_DEEP_BREATH, 30s);
+ }
+ else if (id == 1) // flied up
+ {
+ events.ScheduleEvent(EVENT_SPELL_FIREBALL, 2s);
+ events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME, 4s);
+ events.ScheduleEvent(EVENT_SUMMON_MOLE_MACHINES, 5s);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (startPath)
+ {
+ me->StopMoving();
+ startPath = false;
+ if (WaypointPath const* i_path = sWaypointMgr->GetPath(me->GetWaypointPath()))
+ {
+ Movement::PointsArray pathPoints;
+ pathPoints.push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
+ for (uint8 i = 0; i < i_path->size(); ++i)
+ {
+ WaypointData const* node = i_path->at(i);
+ pathPoints.push_back(G3D::Vector3(node->x, node->y, node->z));
+ }
+ me->GetMotionMaster()->MoveSplinePath(&pathPoints);
+ }
+ }
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case 0:
+ break;
+ case EVENT_ENRAGE:
+ Talk(EMOTE_BERSERK);
+ me->CastSpell(me, SPELL_BERSERK, true);
+ break;
+ case EVENT_COMMANDER_SAY_AGGRO:
+ if (Creature* commander = ObjectAccessor::GetCreature(*me, CommanderGUID))
+ commander->AI()->Talk(SAY_COMMANDER_AGGRO);
+ break;
+ case EVENT_EE_SAY_MOVE_OUT:
+ for (uint8 i = 0; i < 3; ++i)
+ if (Creature* c = ObjectAccessor::GetCreature(*me, ExpeditionEngineerGUIDs[i]))
+ {
+ if (!i)
+ c->AI()->Talk(SAY_EE_START_REPAIR);
+ c->AI()->SetData(1, 0); // start repairing
+ }
+ break;
+ case EVENT_SPELL_FIREBALL:
+ if( Unit* pTarget = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, true) )
+ me->CastSpell(pTarget, SPELL_FIREBALL, false);
+ events.Repeat(4s);
+ break;
+ case EVENT_SPELL_DEVOURING_FLAME:
+ if( Unit* pTarget = SelectTarget(SelectTargetMethod::Random, 0, 200.0f, true) )
+ me->CastSpell(pTarget, SPELL_DEVOURINGFLAME, false);
+ events.Repeat(13s);
+ break;
+ case EVENT_SUMMON_MOLE_MACHINES:
+ {
+ memset(cords, '\0', sizeof(cords));
+ uint8 num = RAID_MODE( urand(2, 3), urand(2, 4) );
+ for( int i = 0; i < num; ++i )
+ {
+ // X: (550, 625) Y: (-185, -230)
+ cords[i][0] = urand(550, 625);
+ cords[i][1] = -230 + rand() % 45;
+ if( GameObject* drill = me->SummonGameObject(GO_DRILL, cords[i][0], cords[i][1], 391.1f, M_PI / 4, 0.0f, 0.0f, 0.0f, 0.0f, 8) )
+ {
+ //drill->SetGoAnimProgress(0);
+ //drill->SetLootState(GO_READY);
+ //drill->UseDoorOrButton(8);
+ //drill->SetGoState(GO_STATE_READY);
+ drill->SetGoState(GO_STATE_ACTIVE);
+ drill->SetGoAnimProgress(0);
+ }
+ }
+ events.Repeat(45s);
+ events.RescheduleEvent(EVENT_SUMMON_ADDS, 4s);
+ }
+ break;
+ case EVENT_SUMMON_ADDS:
+ for( int i = 0; i < 4; ++i )
+ {
+ if( !cords[i][0] )
+ break;
+
+ uint8 opt;
+ uint8 r = urand(1, 100);
+ if( r <= 30 ) opt = 1;
+ else if( r <= 65 ) opt = 2;
+ else opt = 3;
+
+ for( int j = 0; j < 4; ++j )
+ {
+ float x = cords[i][0] + 4.0f * cos(j * M_PI / 2);
+ float y = cords[i][1] + 4.0f * std::sin(j * M_PI / 2);
+
+ uint32 npc_entry = 0;
+ switch( opt )
+ {
+ case 1:
+ if( j == 1 ) npc_entry = NPC_DARK_RUNE_SENTINEL;
+ break;
+ case 2:
+ switch( j )
+ {
+ case 1:
+ npc_entry = NPC_DARK_RUNE_WATCHER;
+ break;
+ case 2:
+ npc_entry = NPC_DARK_RUNE_GUARDIAN;
+ break;
+ }
+ break;
+ default: // case 3:
+ switch( j )
+ {
+ case 1:
+ npc_entry = NPC_DARK_RUNE_WATCHER;
+ break;
+ case 2:
+ npc_entry = NPC_DARK_RUNE_GUARDIAN;
+ break;
+ case 3:
+ npc_entry = NPC_DARK_RUNE_GUARDIAN;
+ break;
+ }
+ break;
+ }
+
+ if( npc_entry )
+ if (Creature* c = me->SummonCreature(npc_entry, x, y, 391.1f, j * M_PI / 2, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000))
+ DoZoneInCombat(c);
+ }
+ }
+ break;
+ case EVENT_WARN_DEEP_BREATH:
+ Talk(EMOTE_BREATH);
+ me->RemoveAura(62794);
+ events.ScheduleEvent(EVENT_PHASE2_FLAME_BREATH, 2500ms);
+ break;
+ case EVENT_PHASE2_FLAME_BREATH:
+ me->CastSpell(me, SPELL_FLAMEBREATH, true);
+ events.ScheduleEvent(EVENT_FLY_UP, 2s);
+ break;
+ case EVENT_FLY_UP:
+ me->SetInCombatWithZone(); // just in case
+ if (pInstance)
+ for( int i = 0; i < 4; ++i )
+ if( ObjectGuid guid = pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i) )
+ if( Creature* hfs = ObjectAccessor::GetCreature(*me, guid) )
+ {
+ me->SummonCreature(34188, hfs->GetPositionX(), hfs->GetPositionY(), hfs->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 22000);
+ hfs->AI()->SetData(1, 0);
+ }
+
+ me->RemoveAura(SPELL_LAUNCH_CHAIN);
+ me->RemoveAura(SPELL_CHAIN_1);
+ me->RemoveAura(SPELL_CHAIN_3);
+ if (RAID_MODE(0, 1))
+ {
+ me->RemoveAura(SPELL_CHAIN_2);
+ me->RemoveAura(SPELL_CHAIN_4);
+ }
+ me->CastSpell(me, SPELL_WINGBUFFET, true);
+
+ if( (me->GetHealth() * 100) / me->GetMaxHealth() < 50 ) // start phase 3
+ {
+ Talk(EMOTE_PERMA_GROUND);
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->DisableRotate(false);
+ DoResetThreatList();
+ Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 0.0, true);
+ if (!target)
+ target = me->SelectNearestPlayer(200.0f);
+ if (target)
+ {
+ AttackStart(target);
+ me->GetMotionMaster()->MoveChase(target);
+ }
+ bGroundPhase = true;
+ events.CancelEvent(EVENT_SPELL_FIREBALL);
+ events.CancelEvent(EVENT_SPELL_DEVOURING_FLAME);
+ events.CancelEvent(EVENT_SUMMON_MOLE_MACHINES);
+
+ events.ScheduleEvent(EVENT_SPELL_FLAME_BREATH, 20s);
+ events.ScheduleEvent(EVENT_SPELL_DEVOURING_FLAME_GROUND, 5s);
+ events.ScheduleEvent(EVENT_SPELL_FUSE_ARMOR, 10s);
+ events.ScheduleEvent(EVENT_SPELL_FLAME_BUFFET, 3s);
+
+ break;
+ }
+ else
+ {
+ ++flyTimes;
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->DisableRotate(false);
+ me->SendMeleeAttackStop(me->GetVictim());
+ me->GetMotionMaster()->MoveIdle();
+ me->StopMoving();
+ me->SetDisableGravity(true);
+ me->GetMotionMaster()->MoveTakeoff(1, CORDS_AIR, 25.0f);
+ events.ScheduleEvent(EVENT_RESUME_FIXING, 22s);
+ }
+
+ break;
+ case EVENT_RESUME_FIXING:
+ for (uint8 i = 0; i < 3; ++i)
+ if (Creature* c = ObjectAccessor::GetCreature(*me, ExpeditionEngineerGUIDs[i]))
+ {
+ if (!i)
+ c->AI()->Talk(SAY_EE_REBUILD_TURRETS);
+ c->AI()->SetData(1, 0); // start repairing
+ }
+ break;
+ case EVENT_SPELL_FLAME_BREATH:
+ me->CastSpell(me->GetVictim(), SPELL_FLAMEBREATH, false);
+ events.Repeat(20s);
+ break;
+ case EVENT_SPELL_DEVOURING_FLAME_GROUND:
+ me->CastSpell(me->GetVictim(), SPELL_DEVOURINGFLAME, false);
+ events.Repeat(13s);
+ break;
+ case EVENT_SPELL_FUSE_ARMOR:
+ if (Unit* victim = me->GetVictim())
+ if (me->IsWithinMeleeRange(victim))
+ {
+ me->CastSpell(victim, SPELL_FUSEARMOR, false);
+ if (Aura* aur = victim->GetAura(SPELL_FUSEARMOR))
+ if (aur->GetStackAmount() == 5)
+ victim->CastSpell(victim, SPELL_FUSED_ARMOR, true);
+ events.Repeat(10s);
+ break;
+ }
+ events.Repeat(2s);
+ break;
+ case EVENT_SPELL_FLAME_BUFFET:
+ me->CastSpell(me->GetVictim(), SPELL_FLAMEBUFFET, false);
+ events.Repeat(7s);
+ break;
+ }
+
+ if (bGroundPhase)
+ DoMeleeAttackIfReady();
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+
+ void JustReachedHome() override
+ {
+ startPath = true;
+ }
+
+ void JustSummoned(Creature* s) override
+ {
+ summons.Summon(s);
+ }
+
+ uint32 GetData(uint32 id) const override
+ {
+ if (id == 1)
+ return (flyTimes <= 1 ? 1 : 0);
+ return 0;
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim && victim->GetEntry() == NPC_DARK_RUNE_GUARDIAN)
+ if (pInstance)
+ pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, NPC_DARK_RUNE_GUARDIAN, 1, me);
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ me->SetDisableGravity(true);
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->DisableRotate(false);
+ ScriptedAI::EnterEvadeMode(why);
+ }
+ };
+};
+
+class npc_ulduar_expedition_commander : public CreatureScript
+{
+public:
+ npc_ulduar_expedition_commander() : CreatureScript("npc_ulduar_expedition_commander") { }
+
+ bool OnGossipHello(Player* player, Creature* creature) override
+ {
+ if (!player || !creature)
+ return true;
+
+ InstanceScript* instance = creature->GetInstanceScript();
+ if (!instance)
+ return true;
+
+ if (instance->GetData(TYPE_RAZORSCALE) == DONE)
+ return true;
+
+ Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE));
+ if (!razorscale || razorscale->IsInCombat())
+ return true;
+
+ AddGossipItemFor(player, GOSSIP_MENU_START_ENCOUNTER, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
+ SendGossipMenuFor(player, NPC_TEXT_COMMANDER, creature);
+ return true;
+ }
+
+ bool OnGossipSelect(Player* player, Creature* creature, uint32 /*uiSender*/, uint32 uiAction) override
+ {
+ if (!player || !creature)
+ return true;
+
+ if (uiAction == GOSSIP_ACTION_INFO_DEF + 1)
+ {
+ InstanceScript* instance = creature->GetInstanceScript();
+ if (!instance || instance->GetData(TYPE_RAZORSCALE) == DONE)
+ return true;
+
+ Creature* razorscale = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(TYPE_RAZORSCALE));
+ if (razorscale && !razorscale->IsInCombat())
+ {
+ // Do not show gossip icon if encounter is in progress
+ creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
+
+ // reset npcs NPC_HARPOON_FIRE_STATE
+ for (uint8 i = 0; i < 4; ++i)
+ if (Creature* hfs = ObjectAccessor::GetCreature(*creature, instance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i)))
+ hfs->AI()->SetData(1, 0);
+
+ if (razorscale->AI())
+ {
+ razorscale->AI()->AttackStart(player);
+ razorscale->GetMotionMaster()->MoveIdle();
+ razorscale->GetMotionMaster()->MovePoint(POINT_RAZORSCALE_INIT, 588.0f, -178.0f, 490.0f, false, false);
+ }
+ }
+ }
+
+ player->PlayerTalkClass->SendCloseGossip();
+ return true;
+ }
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetUlduarAI(creature);
+ }
+
+ struct npc_ulduar_expedition_commanderAI : public NullCreatureAI
+ {
+ npc_ulduar_expedition_commanderAI(Creature* creature) : NullCreatureAI(creature)
+ {
+ _instance = creature->GetInstanceScript();
+ _introSpoken = _instance->GetData(TYPE_RAZORSCALE) == DONE;
+ me->SetReactState(REACT_AGGRESSIVE);
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (_introSpoken)
+ return;
+
+ if (who->GetTypeId() != TYPEID_PLAYER || me->GetExactDist2d(who) > 15.0f)
+ return;
+
+ _introSpoken = true;
+ //Talk(SAY_COMMANDER_INTRO); // No source leads to showing any text messages, perhaps only SOUND ID 15647 is played?
+ }
+
+ private:
+ InstanceScript* _instance;
+ bool _introSpoken;
+ };
+};
+
+class npc_ulduar_harpoonfirestate : public CreatureScript
+{
+public:
+ npc_ulduar_harpoonfirestate() : CreatureScript("npc_ulduar_harpoonfirestate") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_harpoonfirestateAI : public NullCreatureAI
+ {
+ npc_ulduar_harpoonfirestateAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ pInstance = me->GetInstanceScript();
+ }
+
+ InstanceScript* pInstance;
+ uint8 repairPoints;
+
+ void Reset() override
+ {
+ repairPoints = 0;
+ }
+
+ uint32 GetHarpoonGunIdForThisHFS()
+ {
+ if (pInstance)
+ {
+ if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1) )
+ return GO_HARPOON_GUN_1;
+ else if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_2) )
+ return GO_HARPOON_GUN_2;
+ else if( me->GetGUID() == pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_3) )
+ return GO_HARPOON_GUN_3;
+ else
+ return GO_HARPOON_GUN_4;
+ }
+ return 0;
+ }
+
+ void SetData(uint32 id, uint32 value) override
+ {
+ switch (id)
+ {
+ case 1: // cleanup at the start of the fight
+ if (pInstance)
+ {
+ uint32 h_entry = GetHarpoonGunIdForThisHFS();
+ if( GameObject* wh = me->FindNearestGameObject(h_entry, 5.0f) )
+ {
+ wh->SetRespawnTime(0);
+ wh->Delete();
+ }
+ if( GameObject* bh = me->FindNearestGameObject(GO_BROKEN_HARPOON, 5.0f) )
+ if (bh->GetPhaseMask() != 1)
+ bh->SetPhaseMask(1, true);
+ }
+ Reset();
+ break;
+ case 2: // repairing
+ if (repairPoints < REPAIR_POINTS)
+ {
+ if (++repairPoints >= REPAIR_POINTS)
+ {
+ if( GameObject* bh = me->FindNearestGameObject(GO_BROKEN_HARPOON, 4.0f) )
+ bh->SetPhaseMask(2, true);
+ if( GameObject* wh = me->SummonGameObject(GetHarpoonGunIdForThisHFS(), me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 3 * M_PI / 2, 0.0f, 0.0f, 0.0f, 0.0f, 0) )
+ {
+ me->RemoveGameObject(wh, false);
+ if (Creature* cr = me->SummonCreature(NPC_RAZORSCALE_CONTROLLER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 5000))
+ cr->AI()->Talk(EMOTE_HARPOON);
+ }
+ }
+ }
+ break;
+ case 3: // shoot
+ if (pInstance)
+ {
+ Creature* razorscale = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_RAZORSCALE));
+ if (!razorscale)
+ return;
+ if (!razorscale->HasAura(value))
+ me->CastSpell(razorscale, SPELL_LAUNCH_CHAIN, true);
+ }
+ break;
+ }
+ }
+
+ uint32 GetData(uint32 id) const override
+ {
+ switch (id)
+ {
+ case 2:
+ return (repairPoints >= REPAIR_POINTS ? 1 : 0);
+ }
+ return 0;
+ }
+ };
+};
+
+class npc_ulduar_expedition_engineer : public CreatureScript
+{
+public:
+ npc_ulduar_expedition_engineer() : CreatureScript("npc_ulduar_expedition_engineer") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_expedition_engineerAI : public NullCreatureAI
+ {
+ npc_ulduar_expedition_engineerAI(Creature* pCreature) : NullCreatureAI(pCreature)
+ {
+ pInstance = me->GetInstanceScript();
+ }
+
+ InstanceScript* pInstance;
+ bool working;
+ uint16 timer;
+ ObjectGuid fixingGUID;
+
+ void Reset() override
+ {
+ working = false;
+ timer = 0;
+ fixingGUID.Clear();
+ }
+
+ void SetData(uint32 id, uint32 /*value*/) override
+ {
+ switch (id)
+ {
+ case 1: // start/resume repairing
+ working = true;
+ timer = 0;
+ fixingGUID.Clear();
+ break;
+ case 2: // stop repairing
+ Reset();
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND);
+ me->GetMotionMaster()->MoveTargetedHome();
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (working)
+ {
+ if (timer <= diff)
+ {
+ timer = 3000;
+
+ if (fixingGUID)
+ {
+ if (Creature* c = ObjectAccessor::GetCreature(*me, fixingGUID))
+ if (me->GetExactDist2dSq(c) <= 25.0f)
+ {
+ if( me->GetUInt32Value(UNIT_NPC_EMOTESTATE) != EMOTE_STATE_WORK )
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_WORK);
+
+ if (std::fabs(me->GetOrientation() - me->GetAngle(c)) > M_PI / 4)
+ me->SetFacingToObject(c);
+
+ c->AI()->SetData(2, 0);
+ if (c->AI()->GetData(2))
+ fixingGUID.Clear();
+ }
+ }
+
+ if (!fixingGUID)
+ {
+ Creature* razorscale = nullptr;
+ if( ObjectGuid rsGUID = pInstance->GetGuidData(TYPE_RAZORSCALE) )
+ razorscale = ObjectAccessor::GetCreature(*me, rsGUID);
+
+ if( !razorscale || !razorscale->IsInCombat() )
+ {
+ Reset();
+ me->GetMotionMaster()->MoveTargetedHome();
+ return;
+ }
+
+ for( int i = 0; i < 4; ++i )
+ if( ObjectGuid fs_GUID = pInstance->GetGuidData(DATA_HARPOON_FIRE_STATE_1 + i) )
+ if( Creature* fs = ObjectAccessor::GetCreature(*me, fs_GUID) )
+ if (!fs->AI()->GetData(2))
+ {
+ float a = rand_norm() * M_PI;
+ me->GetMotionMaster()->MovePoint(0, fs->GetPositionX() + 3.0f * cos(a), fs->GetPositionY() + 3.0f * std::sin(a), fs->GetPositionZ());
+ fixingGUID = fs->GetGUID();
+ return;
+ }
+
+ Reset(); // all harpoons repaired
+ me->GetMotionMaster()->MoveTargetedHome();
+ }
+ }
+ else
+ timer -= diff;
+ }
+ else if (me->GetUInt32Value(UNIT_NPC_EMOTESTATE) == EMOTE_STATE_WORK)
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND);
+ }
+ };
+};
+
+class go_ulduar_working_harpoon : public GameObjectScript
+{
+public:
+ go_ulduar_working_harpoon() : GameObjectScript("go_ulduar_working_harpoon") { }
+
+ bool OnGossipHello(Player* user, GameObject* go) override
+ {
+ if( !user || !go )
+ return true;
+
+ InstanceScript* pInstance = go->GetInstanceScript();
+ if( !pInstance )
+ return true;
+
+ Creature* rs = nullptr;
+ if( ObjectGuid rsGUID = pInstance->GetGuidData(TYPE_RAZORSCALE) )
+ rs = ObjectAccessor::GetCreature(*go, rsGUID);
+
+ if( !rs || !rs->IsInCombat() )
+ {
+ go->SetRespawnTime(0);
+ go->Delete();
+ return true;
+ }
+
+ uint32 npc = 0;
+ uint32 spell = 0;
+ switch( go->GetEntry() )
+ {
+ case GO_HARPOON_GUN_1:
+ npc = DATA_HARPOON_FIRE_STATE_1;
+ spell = SPELL_CHAIN_1;
+ break;
+ case GO_HARPOON_GUN_2:
+ npc = DATA_HARPOON_FIRE_STATE_2;
+ spell = SPELL_CHAIN_2;
+ break;
+ case GO_HARPOON_GUN_3:
+ npc = DATA_HARPOON_FIRE_STATE_3;
+ spell = SPELL_CHAIN_3;
+ break;
+ case GO_HARPOON_GUN_4:
+ npc = DATA_HARPOON_FIRE_STATE_4;
+ spell = SPELL_CHAIN_4;
+ break;
+ }
+
+ if( ObjectGuid g = pInstance->GetGuidData(npc) )
+ if( Creature* hfs = ObjectAccessor::GetCreature(*go, g) )
+ hfs->AI()->SetData(3, spell);
+
+ go->SetLootState(GO_JUST_DEACTIVATED);
+ return true;
+ }
+};
+
+class npc_ulduar_dark_rune_guardian : public CreatureScript
+{
+public:
+ npc_ulduar_dark_rune_guardian() : CreatureScript("npc_ulduar_dark_rune_guardian") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_dark_rune_guardianAI : public ScriptedAI
+ {
+ npc_ulduar_dark_rune_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ uint32 timer2;
+
+ void Reset() override
+ {
+ timer2 = 6000;
+ }
+
+ bool CanAIAttack(Unit const* target) const override
+ {
+ return target && target->GetEntry() != NPC_RAZORSCALE;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if( !UpdateVictim() )
+ return;
+
+ if (timer2 <= diff) timer2 = 0;
+ else timer2 -= diff;
+ if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()))
+ {
+ me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DMG, true);
+ me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DMG, true); // cast the same twice cus second one requires setting offhand damage
+ me->CastSpell(me->GetVictim(), SPELL_STORMSTRIKE_DEBUFF, true);
+ timer2 = urand(8000, 10000);
+ return;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class npc_ulduar_dark_rune_watcher : public CreatureScript
+{
+public:
+ npc_ulduar_dark_rune_watcher() : CreatureScript("npc_ulduar_dark_rune_watcher") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_dark_rune_watcherAI : public ScriptedAI
+ {
+ npc_ulduar_dark_rune_watcherAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ uint32 timer1;
+ uint32 timer2;
+
+ void Reset() override
+ {
+ timer1 = 6000;
+ timer2 = 2000;
+ }
+
+ bool CanAIAttack(Unit const* target) const override
+ {
+ return target && target->GetEntry() != NPC_RAZORSCALE;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if( !UpdateVictim() )
+ return;
+
+ if( timer1 <= diff )
+ {
+ me->CastSpell(me->GetVictim(), SPELL_CHAINLIGHTNING, false);
+ timer1 = urand(10000, 12000);
+ return;
+ }
+ else
+ timer1 -= diff;
+
+ if (timer2 <= diff)
+ {
+ me->CastSpell(me->GetVictim(), SPELL_LIGHTINGBOLT, false);
+ timer2 = 4000;
+ return;
+ }
+ else
+ timer2 -= diff;
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class npc_ulduar_dark_rune_sentinel : public CreatureScript
+{
+public:
+ npc_ulduar_dark_rune_sentinel() : CreatureScript("npc_ulduar_dark_rune_sentinel") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_ulduar_dark_rune_sentinelAI : public ScriptedAI
+ {
+ npc_ulduar_dark_rune_sentinelAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ uint32 timer1;
+ uint32 timer2;
+
+ void Reset() override
+ {
+ timer1 = urand(1000, 2000);
+ timer2 = 6000;
+ }
+
+ bool CanAIAttack(Unit const* target) const override
+ {
+ return target && target->GetEntry() != NPC_RAZORSCALE;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if( !UpdateVictim() )
+ return;
+
+ if( timer1 <= diff )
+ {
+ me->CastSpell(me, SPELL_BATTLE_SHOUT, false);
+ timer1 = urand(15000, 20000);
+ }
+ else
+ timer1 -= diff;
+
+ if (timer2 <= diff) timer2 = 0;
+ else timer2 -= diff;
+ if (timer2 == 0 && me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()))
+ {
+ me->CastSpell(me, SPELL_WHIRLWIND, false);
+ timer2 = urand(10000, 12000);
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class achievement_quick_shave : public AchievementCriteriaScript
+{
+public:
+ achievement_quick_shave() : AchievementCriteriaScript("achievement_quick_shave") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetTypeId() == TYPEID_UNIT && target->GetEntry() == NPC_RAZORSCALE && target->ToCreature()->AI()->GetData(1);
+ }
+};
+
+class achievement_iron_dwarf_medium_rare : public AchievementCriteriaScript
+{
+public:
+ achievement_iron_dwarf_medium_rare() : AchievementCriteriaScript("achievement_iron_dwarf_medium_rare") {}
+
+ bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
+ {
+ return target && target->GetEntry() == NPC_RAZORSCALE;
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp
index 5894409bef73f0..c85ed2d4c2971a 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_thorim.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "GameObjectScript.h"
@@ -27,1787 +28,6 @@
#include "SpellScriptLoader.h"
#include "ulduar.h"
-enum ThorimSpells
-{
- // THORIM
- SPELL_LIGHTNING_DESTRUCTION = 62393,
- SPELL_SHEATH_OF_LIGHTNING = 62276,
- SPELL_STORMHAMMER = 62042,
- SPELL_BERSERK_FRIENDS = 62560,
- SPELL_CHAIN_LIGHTNING_10 = 62131,
- SPELL_CHAIN_LIGHTNING_25 = 64390,
- SPELL_UNBALANCING_STRIKE = 62130,
- SPELL_BERSERK = 26662,
-
- SPELL_CHARGE_ORB = 62016,
- SPELL_LIGHTNING_PILLAR_P1 = 63238,
-
- SPELL_LIGHTNING_ORB_VISUAL = 62186,
- SPELL_LIGHTNING_CHARGE_DAMAGE = 62466,
- SPELL_LIGHTNING_CHARGE_BUFF = 62279,
- SPELL_LIGHTNING_PILLAR_P2 = 62976,
- SPELL_LIGHTNING_ORB_CHARGER = 62278,
-
- // SIF
- SPELL_TOUCH_OF_DOMINION = 62507,
- SPELL_SIF_TRANSFORM = 64778,
- SPELL_SIF_CHANNEL_HOLOGRAM = 64324,
- SPELL_FROSTBOLT = 62601,
- SPELL_FROSTBOLT_VALLEY = 62604,
- SPELL_BLIZZARD_10 = 62577,
- SPELL_BLIZZARD_25 = 62603,
- SPELL_FROST_NOVA = 62605,
-
- // DARK RUNE ACOLYTE
- SPELL_GREATER_HEAL_10 = 62334,
- SPELL_GREATER_HEAL_25 = 62442,
- SPELL_HOLY_SMITE_10 = 62335,
- SPELL_HOLY_SMITE_25 = 62443,
- SPELL_RENEW_10 = 62333,
- SPELL_RENEW_25 = 62441,
-
- // CAPTURED MERCENARY SOLDIER
- SPELL_BARBED_SHOT = 62318,
- SPELL_WING_CLIP = 40652,
- SPELL_SHOOT = 16496,
-
- // CAPTURED MERCENARY CAPTAIN
- SPELL_DEVASTATE = 62317,
- SPELL_HEROIC_STRIKE = 62444,
-
- // JORMUNGAR BEHEMOTH
- SPELL_ACID_BREATH_10 = 62315,
- SPELL_ACID_BREATH_25 = 62415,
- SPELL_SWEEP_10 = 62316,
- SPELL_SWEEP_25 = 62417,
-
- // IRON RING GUARD
- SPELL_IMPALE_10 = 62331,
- SPELL_IMPALE_25 = 62418,
- SPELL_WHIRLING_TRIP = 64151,
-
- // IRON HONOR GUARD
- SPELL_SHIELD_SMASH_10 = 62332,
- SPELL_SHIELD_SMASH_25 = 62420,
- SPELL_CLEAVE = 42724,
- SPELL_HAMSTRING = 48639,
-
- // DARK RUNE WARBRINGER
- SPELL_AURA_OF_CELERITY = 62320,
- SPELL_RUNIC_STRIKE = 62322,
-
- // DARK RUNE EVOKER
- SPELL_RUNIC_LIGHTNING_10 = 62327,
- SPELL_RUNIC_LIGHTNING_25 = 62445,
- SPELL_RUNIC_MENDING_10 = 62328,
- SPELL_RUNIC_MENDING_25 = 62446,
- SPELL_RUNIC_SHIELD_10 = 62321,
- SPELL_RUNIC_SHIELD_25 = 62529,
-
- // DARK RUNE CHAMPION
- SPELL_CHARGE = 32323,
- SPELL_MORTAL_STRIKE = 35054,
- SPELL_WHIRLWIND = 15578,
-
- // DARK RUNE COMMONER
- SPELL_LOW_BLOW = 62326,
- SPELL_PUMMEL = 38313,
-
- // RUNIC COLOSSUS
- SPELL_COLOSSUS_CHARGE_10 = 62613,
- SPELL_COLOSSUS_CHARGE_25 = 62614,
- SPELL_RUNIC_BARRIER = 62338,
- SPELL_SMASH = 62339,
- SPELL_RUNIC_SMASH_LEFT = 62057,
- SPELL_RUNIC_SMASH_RIGHT = 62058,
- SPELL_RUNIC_SMASH_DAMAGE = 62465,
-
- // ANCIENT RUNE GIANT
- SPELL_RUNE_DETONATION = 62526,
- SPELL_RUNIC_FORTIFICATION = 62942,
- SPELL_STOMP_10 = 62411,
- SPELL_STOMP_25 = 62413,
-
- // TRAPS
- SPELL_LIGHTNING_FIELD = 64972,
- SPELL_PARALYTIC_FIELD_FIRST = 62241,
- SPELL_PARALYTIC_FIELD_SECOND = 63540,
-};
-
-#define SPELL_GREATER_HEAL RAID_MODE(SPELL_GREATER_HEAL_10, SPELL_GREATER_HEAL_25)
-#define SPELL_HOLY_SMITE RAID_MODE(SPELL_HOLY_SMITE_10, SPELL_HOLY_SMITE_25)
-#define SPELL_RENEW RAID_MODE(SPELL_RENEW_10, SPELL_RENEW_25)
-#define SPELL_ACID_BREATH RAID_MODE(SPELL_ACID_BREATH_10, SPELL_ACID_BREATH_25)
-#define SPELL_SWEEP RAID_MODE(SPELL_SWEEP_10, SPELL_SWEEP_25)
-#define SPELL_IMPALE RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25)
-#define SPELL_COLOSSUS_CHARGE RAID_MODE(SPELL_COLOSSUS_CHARGE_10, SPELL_COLOSSUS_CHARGE_25)
-#define SPELL_STOMP RAID_MODE(SPELL_STOMP_10, SPELL_STOMP_25)
-#define SPELL_SHIELD_SMASH RAID_MODE(SPELL_SHIELD_SMASH_10, SPELL_SHIELD_SMASH_25)
-#define SPELL_RUNIC_LIGHTNING RAID_MODE(SPELL_RUNIC_LIGHTNING_10, SPELL_RUNIC_LIGHTNING_25)
-#define SPELL_RUNIC_MENDING RAID_MODE(SPELL_RUNIC_MENDING_10, SPELL_RUNIC_MENDING_25)
-#define SPELL_RUNIC_SHIELD RAID_MODE(SPELL_RUNIC_SHIELD_10, SPELL_RUNIC_SHIELD_25)
-#define SPELL_CHAIN_LIGHTNING RAID_MODE(SPELL_CHAIN_LIGHTNING_10, SPELL_CHAIN_LIGHTNING_25)
-
-enum ThormNPCandGOs : uint32
-{
- // ARENA INIT
- NPC_DARK_RUNE_ACOLYTE_I = 32886,
- NPC_CAPTURED_MERCENARY_SOLDIER_ALLY = 32885,
- NPC_CAPTURED_MERCENARY_SOLDIER_HORDE = 32883,
- NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY = 32908,
- NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE = 32907,
- NPC_JORMUNGAR_BEHEMOT = 32882,
-
- // ARENA PHASE
- NPC_DARK_RUNE_WARBRINGER = 32877,
- NPC_DARK_RUNE_EVOKER = 32878,
- NPC_DARK_RUNE_CHAMPION = 32876,
- NPC_DARK_RUNE_COMMONER = 32904,
-
- // GAUNTLET
- NPC_IRON_RING_GUARD = 32874,
- NPC_RUNIC_COLOSSUS = 32872,
- NPC_ANCIENT_RUNE_GIANT = 32873,
- NPC_DARK_RUNE_ACOLYTE_G = 33110,
- NPC_IRON_HONOR_GUARD = 32875,
-
- // TRIGGERS
- NPC_LIGHTNING_ORB = 33138,
- NPC_THUNDER_ORB = 33378,
- NPC_PILLAR = 32892,
- NPC_SIF_BLIZZARD = 32879,
-
- NPC_SIF = 33196,
-};
-
-enum ThorimEvents
-{
- EVENT_THORIM_START_PHASE1 = 1,
- EVENT_THORIM_STORMHAMMER = 2,
- EVENT_THORIM_CHARGE_ORB = 3,
- EVENT_THORIM_LIGHTNING_ORB = 4,
- EVENT_THORIM_NOT_REACH_IN_TIME = 5,
- EVENT_THORIM_FILL_ARENA = 6,
- EVENT_THORIM_UNBALANCING_STRIKE = 7,
- EVENT_THORIM_LIGHTNING_CHARGE = 8,
- EVENT_THORIM_CHAIN_LIGHTNING = 9,
- EVENT_THORIM_BERSERK = 10,
- EVENT_THORIM_AGGRO = 11,
- EVENT_THORIM_AGGRO2 = 12,
- EVENT_THORIM_OUTRO1 = 13,
- EVENT_THORIM_OUTRO2 = 14,
- EVENT_THORIM_OUTRO3 = 15,
-
- EVENT_DR_ACOLYTE_GH = 20,
- EVENT_DR_ACOLYTE_HS = 21,
- EVENT_DR_ACOLYTE_R = 22,
-
- EVENT_CM_SOLDIER_BS = 30,
- EVENT_CM_SOLDIER_S = 31,
- EVENT_CM_SOLDIER_WC = 32,
-
- EVENT_CM_CAPTAIN_D = 40,
- EVENT_CM_CAPTAIN_HC = 41,
-
- EVENT_JB_ACID_BREATH = 50,
- EVENT_JB_SWEEP = 51,
-
- EVENT_IR_GUARD_IMPALE = 60,
- EVENT_IR_GUARD_WHIRL = 61,
-
- EVENT_RC_RUNIC_BARRIER = 70,
- EVENT_RC_SMASH = 71,
- EVENT_RC_RUNIC_SMASH = 72,
- EVENT_RC_RUNIC_SMASH_TRIGGER = 73,
- EVENT_RC_CHARGE = 74,
-
- EVENT_ARG_RD = 80,
- EVENT_ARG_RF = 81,
- EVENT_ARG_STOMP = 82,
- EVENT_ARG_SPAWN = 83,
-
- EVENT_IH_GUARD_CLEAVE = 90,
- EVENT_IH_GUARD_HAMSTRING = 91,
- EVENT_IH_GUARD_SHIELD_SMASH = 92,
-
- EVENT_SIF_START_TALK = 100,
- EVENT_SIF_JOIN_TALK = 101,
- EVENT_SIF_FINISH_DOMINION = 102,
- EVENT_SIF_FROSTBOLT_VALLEY = 103,
- EVENT_SIF_BLIZZARD = 104,
- EVENT_SIF_FROST_NOVA_START = 105,
- EVENT_SIF_FROST_NOVA_CAST = 106,
-
- EVENT_DR_WARBRINGER_RS = 110,
-
- EVENT_DR_EVOKER_RL = 120,
- EVENT_DR_EVOKER_RM = 121,
- EVENT_DR_EVOKER_RS = 122,
-
- EVENT_DR_CHAMPION_WH = 130,
- EVENT_DR_CHAMPION_CH = 131,
- EVENT_DR_CHAMPION_MS = 132,
-
- EVENT_DR_COMMONER_PM = 140,
- EVENT_DR_COMMONER_LB = 141,
-};
-
-const Position ArenaNPCs[] =
-{
- {2178.5f, -300.2f, 441.97f, 2.5f},
- {2188.12f, -295.1f, 443.75, 2.5f},
- {2180.9f, -286.8f, 433.3f, 2.49f},
- {2193.2f, -280.6f, 443.14f, 2.79f},
- {2191.8f, -270.2f, 438.3f, 3.0f},
- {2186.84f, -238.5f, 439.7f, 3.4f},
- {2166.3f, -213.0f, 440.0f, 4.1f},
- {2100.5f, -213.5f, 441.66f, 5.4f},
- {2091.0f, -231.26f, 435.17f, 5.5f},
- {2083.2f, -239.2f, 438.77f, 5.85f},
- {2081.54f, -253.27f, 434.67f, 6.19f},
- {2077.65f, -272.73f, 439.12f, 0.15f},
- {2084.36f, -282.12f, 435.87f, 0.24f},
- {2087.46f, -298.71f, 440.5f, 0.59f}
-};
-
-enum Texts
-{
- // Thorim
- SAY_AGGRO_1 = 0,
- SAY_AGGRO_2 = 1,
- SAY_SPECIAL_1 = 2, // Unused
- SAY_SPECIAL_2 = 3,
- SAY_SPECIAL_3 = 4, // Unused
- SAY_JUMPDOWN = 5,
- SAY_SLAY = 6,
- SAY_BERSERK = 7,
- SAY_WIPE = 8,
- SAY_DEATH = 9,
- SAY_END_NORMAL_1 = 10,
- SAY_END_NORMAL_2 = 11,
- SAY_END_NORMAL_3 = 12,
- SAY_END_HARD_1 = 13,
- SAY_END_HARD_2 = 14,
- SAY_END_HARD_3 = 15,
-
- // Sif
- SAY_SIF_AGGRO = 0,
- SAY_SIF_HM_MISSED = 1,
- SAY_SIF_HM_REACHED = 2,
-
- // Ancient Rune Giant
- SAY_GIANT_RUNIC_MIGHT = 0,
-
- // Runic Colossus
- SAY_COLOSSUS_RUNIC_BARRIER = 0,
-};
-
-enum Misc
-{
- ACTION_START_TRASH_DIED = 1,
- ACTION_ALLOW_HIT = 2,
- ACTION_SIF_JOIN_FIGHT = 3,
- ACTION_SIF_START_TALK = 4,
- ACTION_SIF_START_DOMINION = 5,
- ACTION_SIF_TRANSFORM = 6,
- ACTION_IRON_HONOR_DIED = 7,
-
- EVENT_PHASE_START = 1,
- EVENT_PHASE_RING = 2,
- EVENT_PHASE_OUTRO = 3,
-
- DATA_HIT_BY_LIGHTNING = 1,
- DATA_LOSE_YOUR_ILLUSION = 2,
-};
-
-const Position Middle = {2134.68f, -263.13f, 419.44f, M_PI * 1.5f};
-
-const uint32 RollTable[3] = { 32877, 32878, 32876 };
-
-class boss_thorim : public CreatureScript
-{
-public:
- boss_thorim() : CreatureScript("boss_thorim") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorimAI : public ScriptedAI
- {
- boss_thorimAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
- {
- m_pInstance = pCreature->GetInstanceScript();
- if ((_encounterFinished = (!me->IsAlive())))
- if (m_pInstance)
- m_pInstance->SetData(TYPE_THORIM, DONE);
- }
-
- bool _isArenaEmpty;
- bool _encounterFinished;
- bool _spawnCommoners;
- bool _hardMode;
- bool _isHitAllowed;
- bool _isAlly;
- uint8 _trashCounter;
-
- InstanceScript* m_pInstance;
- EventMap events;
- SummonList summons;
-
- bool _hitByLightning;
-
- void DisableThorim(bool apply)
- {
- if (apply)
- {
- me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED);
- me->DisableRotate(true);
- me->AddUnitState(UNIT_STATE_ROOT);
- }
- else
- {
- me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED);
- me->DisableRotate(false);
- me->ClearUnitState(UNIT_STATE_ROOT);
- me->resetAttackTimer(BASE_ATTACK);
- }
- }
-
- GameObject* GetThorimObject(uint32 entry)
- {
- if (m_pInstance)
- return ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(entry));
- return nullptr;
- }
-
- void JustSummoned(Creature* cr) override { summons.Summon(cr); }
-
- void SpawnAllNPCs()
- {
- // Jormungar Behemoth 32882
- me->SummonCreature(NPC_JORMUNGAR_BEHEMOT, 2149.68f, -263.477f, 419.679f, 3.12102f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
-
- // Captured Mercenary Soldier 32885
- me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2127.24f, -251.309f, 419.793f, 5.89921f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
- me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2120.1f, -258.99f, 419.764f, 6.24828f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
- me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2123.32f, -254.771f, 419.789f, 6.17846f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
-
- // Captured Mercenary Captain 32908
- me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY : NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE, 2131.31f, -259.182f, 419.974f, 5.91667f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
-
- // Dark Rune Acolyte (arena) 32886
- me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_I, 2129.09f, -277.142f, 419.756f, 1.22173f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
-
- // Iron Ring Guard 32874
- me->SummonCreature(NPC_IRON_RING_GUARD, 2217.69f, -337.394f, 412.177f, 1.23918f);
- me->SummonCreature(NPC_IRON_RING_GUARD, 2218.38f, -297.505f, 412.176f, 1.02974f);
- me->SummonCreature(NPC_IRON_RING_GUARD, 2235.26f, -338.345f, 412.134f, 1.58979f);
- me->SummonCreature(NPC_IRON_RING_GUARD, 2235.07f, -297.985f, 412.134f, 1.61336f);
-
- // Dark Rune Acolyte (gauntlet) 33110
- me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2198.29f, -436.92f, 419.985f, 0.261799f);
- me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2227.58f, -308.303f, 412.134f, 1.59372f);
- me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2227.47f, -345.375f, 412.134f, 1.56622f);
-
- // Iron Honor Guard 32875
- me->SummonCreature(NPC_IRON_HONOR_GUARD, 2198.05f, -428.769f, 419.985f, 6.05629f);
- me->SummonCreature(NPC_IRON_HONOR_GUARD, 2220.31f, -436.22f, 412.26f, 1.06465f);
-
- // Runic Colossus 32872
- me->SummonCreature(NPC_RUNIC_COLOSSUS, 2227.5f, -396.179f, 412.176f, 1.79769f);
-
- // Ancient Rune Giant 32873
- me->SummonCreature(NPC_ANCIENT_RUNE_GIANT, 2134.57f, -440.318f, 438.331f, 0.226893f);
-
- // Sif 33196
- me->SummonCreature(NPC_SIF, 2147.86f, -301.2f, 438.246f, 2.488f);
- }
-
- void CloseDoors()
- {
- GameObject* go;
- if ((go = GetThorimObject(DATA_THORIM_LEVER)))
- {
- go->ReplaceAllGameObjectFlags((GameObjectFlags)48);
- go->SetGoState(GO_STATE_READY);
- }
- if ((go = GetThorimObject(DATA_THORIM_FIRST_DOORS)))
- go->SetGoState(GO_STATE_READY);
-
- if ((go = GetThorimObject(DATA_THORIM_SECOND_DOORS)))
- go->SetGoState(GO_STATE_READY);
-
- if ((go = GetThorimObject(DATA_THORIM_FENCE)))
- go->SetGoState(GO_STATE_ACTIVE);
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- DisableThorim(false);
- CreatureAI::EnterEvadeMode(why);
- }
-
- void Reset() override
- {
- if (m_pInstance && !_encounterFinished)
- m_pInstance->SetData(TYPE_THORIM, NOT_STARTED);
-
- events.Reset();
- events.SetPhase(0);
- summons.DespawnAll();
-
- _trashCounter = 0;
- _isAlly = true;
- _isHitAllowed = false;
- _spawnCommoners = false;
- _hardMode = false;
- _isArenaEmpty = false;
- _hitByLightning = false;
-
- if (Player* t = SelectTargetFromPlayerList(1000))
- if (t->GetTeamId() == TEAM_HORDE)
- _isAlly = false;
-
- SpawnAllNPCs();
-
- CloseDoors();
- DisableThorim(false);
- }
-
- uint32 GetData(uint32 param) const override
- {
- if (param == DATA_HIT_BY_LIGHTNING)
- return !_hitByLightning;
- if (param == DATA_LOSE_YOUR_ILLUSION)
- return _hardMode;
-
- return 0;
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_START_TRASH_DIED)
- {
- _trashCounter++;
- // activate levar
- if (_trashCounter >= 6)
- {
- if (GameObject* go = GetThorimObject(DATA_THORIM_LEVER))
- go->RemoveGameObjectFlag((GameObjectFlags)48);
-
- events.ScheduleEvent(EVENT_THORIM_AGGRO, 0ms);
- events.SetPhase(EVENT_PHASE_START);
- events.ScheduleEvent(EVENT_THORIM_START_PHASE1, 20s);
- _trashCounter = 0;
- }
- }
- else if (param == ACTION_ALLOW_HIT)
- _isHitAllowed = true;
- }
-
- void KilledUnit(Unit* victim) override
- {
- if (victim->GetTypeId() == TYPEID_PLAYER)
- Talk(SAY_SLAY);
- }
-
- void JustReachedHome() override { me->setActive(false); }
-
- void JustEngagedWith(Unit*) override
- {
- if (m_pInstance && !_encounterFinished)
- m_pInstance->SetData(TYPE_THORIM, IN_PROGRESS);
- me->setActive(true);
- DisableThorim(true);
- me->CastSpell(me, SPELL_SHEATH_OF_LIGHTNING, true);
- //me->CastSpell(me, SPELL_TOUCH_OF_DOMINION, true);
- }
-
- void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (who && _isHitAllowed && who->GetPositionZ() > 430 && who->GetTypeId() == TYPEID_PLAYER)
- {
- _isHitAllowed = false;
- DisableThorim(false);
-
- events.SetPhase(EVENT_PHASE_RING);
- events.ScheduleEvent(EVENT_THORIM_UNBALANCING_STRIKE, 8s, 0, EVENT_PHASE_RING);
- events.ScheduleEvent(EVENT_THORIM_LIGHTNING_CHARGE, 12s + 500ms, 0, EVENT_PHASE_RING);
- events.ScheduleEvent(EVENT_THORIM_CHAIN_LIGHTNING, 13s, 0, EVENT_PHASE_RING);
- events.ScheduleEvent(EVENT_THORIM_BERSERK, 5min, 0, EVENT_PHASE_RING);
-
- me->GetMotionMaster()->MoveChase(me->GetVictim());
- me->GetMotionMaster()->MoveJump(Middle.GetPositionX(), Middle.GetPositionY(), Middle.GetPositionZ(), 20, 20);
- me->RemoveAura(SPELL_SHEATH_OF_LIGHTNING);
-
- Talk(SAY_JUMPDOWN);
-
- // Hard Mode
- if (!me->HasAura(62565 /*TOUCH OF DOMINION TRIGGER*/))
- {
- if (m_pInstance)
- m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 64980 /*SIFFED ACHIEVEMENT*/);
-
- _hardMode = true;
- EntryCheckPredicate pred(NPC_SIF);
- summons.DoAction(ACTION_SIF_JOIN_FIGHT, pred);
- }
-
- DoResetThreatList();
- if (Player* player = GetArenaPlayer())
- me->AddThreat(player, 1000.0f);
- }
-
- if (damage >= me->GetHealth())
- {
- damage = 0;
- if (!_encounterFinished)
- {
- _encounterFinished = true;
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->SetFaction(FACTION_FRIENDLY);
- me->SetHealth(me->GetMaxHealth());
- me->CombatStop();
- me->RemoveAllAuras();
- events.Reset();
- DisableThorim(true);
-
- Talk(SAY_DEATH);
-
- events.SetPhase(EVENT_PHASE_OUTRO);
- events.ScheduleEvent(EVENT_THORIM_OUTRO1, 2s, 0, EVENT_PHASE_OUTRO);
-
- GameObject* go = nullptr;
- if ((go = GetThorimObject(DATA_THORIM_FENCE)))
- go->SetGoState(GO_STATE_ACTIVE);
-
- uint32 chestId = me->GetMap()->Is25ManRaid() ? GO_THORIM_CHEST_HERO : GO_THORIM_CHEST;
- if (_hardMode)
- chestId += 1; // hard mode offset
-
- if ((go = me->SummonGameObject(chestId, 2134.73f, -286.32f, 419.51f, 4.65f, 0, 0, 0, 0, 0)))
- {
- go->ReplaceAllGameObjectFlags((GameObjectFlags)0);
- go->SetLootRecipient(me->GetMap());
- }
-
- // Defeat credit
- if (m_pInstance)
- {
- me->CastSpell(me, 64985, true); // credit
- m_pInstance->SetData(TYPE_THORIM, DONE);
- }
- }
- }
- }
-
- void SpawnArenaNPCs()
- {
- Creature* cr;
- uint8 rnd;
- if (_spawnCommoners || urand(0, 2))
- _spawnCommoners = !_spawnCommoners;
-
- for (uint8 i = 0; i < (_spawnCommoners ? 7 : 2); ++i)
- {
- rnd = urand(0, 13);
- if ((cr = me->SummonCreature((_spawnCommoners ? NPC_DARK_RUNE_COMMONER : RollTable[urand(0, 2)]), ArenaNPCs[rnd], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000)))
- cr->GetMotionMaster()->MoveJump(
- Middle.GetPositionX() + urand(19, 24) * cos(Middle.GetAngle(cr)),
- Middle.GetPositionY() + urand(19, 24) * std::sin(Middle.GetAngle(cr)),
- Middle.GetPositionZ(), 20, 20);
- }
- }
-
- void SpellHit(Unit* caster, SpellInfo const* spellInfo) override
- {
- if (spellInfo->Id == SPELL_LIGHTNING_ORB_CHARGER)
- {
- me->SetOrientation(me->GetAngle(caster));
- me->CastSpell(caster, SPELL_LIGHTNING_CHARGE_DAMAGE, true);
- me->CastSpell(me, SPELL_LIGHTNING_CHARGE_BUFF, true);
- events.RescheduleEvent(EVENT_THORIM_LIGHTNING_CHARGE, 10s, 0, EVENT_PHASE_RING);
- }
- }
-
- void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
- {
- if (spellInfo->Id == SPELL_LIGHTNING_CHARGE_DAMAGE && target->GetTypeId() == TYPEID_PLAYER)
- _hitByLightning = true;
- }
-
- Player* GetArenaPlayer()
- {
- Map::PlayerList const& pList = me->GetMap()->GetPlayers();
- for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
- if (Player* p = itr->GetSource())
- if (p->GetPositionX() > 2085 && p->GetPositionX() < 2185 && p->GetPositionY() < -214 && p->GetPositionY() > -305 && p->IsAlive() && p->GetPositionZ() < 425)
- return p;
- return nullptr;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!_encounterFinished && !UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_THORIM_AGGRO:
- Talk(SAY_AGGRO_1);
- events.ScheduleEvent(EVENT_THORIM_AGGRO2, 9s);
-
- if (GameObject* go = GetThorimObject(DATA_THORIM_FENCE))
- go->SetGoState(GO_STATE_READY);
-
- break;
- case EVENT_THORIM_AGGRO2:
- {
- Talk(SAY_AGGRO_2);
-
- EntryCheckPredicate pred(NPC_SIF);
- summons.DoAction(ACTION_SIF_START_TALK, pred);
- break;
- }
- case EVENT_THORIM_START_PHASE1:
- {
- events.ScheduleEvent(EVENT_THORIM_STORMHAMMER, 8s, 0, EVENT_PHASE_START);
- events.ScheduleEvent(EVENT_THORIM_CHARGE_ORB, 14s, 0, EVENT_PHASE_START);
- events.ScheduleEvent(EVENT_THORIM_FILL_ARENA, 0ms, 0, EVENT_PHASE_START);
- events.ScheduleEvent(EVENT_THORIM_LIGHTNING_ORB, 5s, 0, EVENT_PHASE_START); // checked every 5 secs if there are players on arena
- events.ScheduleEvent(EVENT_THORIM_NOT_REACH_IN_TIME, 5min, 0, EVENT_PHASE_START);
-
- EntryCheckPredicate pred(NPC_SIF);
- summons.DoAction(ACTION_SIF_START_DOMINION, pred);
- break;
- }
- case EVENT_THORIM_STORMHAMMER:
- me->CastCustomSpell(SPELL_STORMHAMMER, SPELLVALUE_MAX_TARGETS, 1, me->GetVictim(), false);
- events.Repeat(16s);
- break;
- case EVENT_THORIM_CHARGE_ORB:
- me->CastCustomSpell(SPELL_CHARGE_ORB, SPELLVALUE_MAX_TARGETS, 1, me, false);
- events.Repeat(16s);
- break;
- case EVENT_THORIM_LIGHTNING_ORB:
- {
- if (GetArenaPlayer())
- {
- // Player found, repeat and return
- events.Repeat(5s);
- return;
- }
-
- // No players found
- Talk(SAY_WIPE);
- me->SummonCreature(NPC_LIGHTNING_ORB, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
-
- _isArenaEmpty = true;
- events.CancelEvent(EVENT_THORIM_NOT_REACH_IN_TIME);
- break;
- }
- case EVENT_THORIM_NOT_REACH_IN_TIME:
- _isArenaEmpty = true;
- events.CancelEvent(EVENT_THORIM_LIGHTNING_ORB);
- me->CastSpell(me, SPELL_BERSERK_FRIENDS, true);
- me->SummonCreature(NPC_LIGHTNING_ORB, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
- break;
- case EVENT_THORIM_FILL_ARENA:
- SpawnArenaNPCs();
- events.Repeat(10s);
- break;
- case EVENT_THORIM_UNBALANCING_STRIKE:
- me->CastSpell(me->GetVictim(), SPELL_UNBALANCING_STRIKE, false);
- events.Repeat(20s);
- break;
- case EVENT_THORIM_LIGHTNING_CHARGE:
- me->CastSpell(me, SPELL_LIGHTNING_PILLAR_P2, true);
- break;
- case EVENT_THORIM_CHAIN_LIGHTNING:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target, SPELL_CHAIN_LIGHTNING, false);
- events.Repeat(15s);
- break;
- case EVENT_THORIM_BERSERK:
- me->CastSpell(me, SPELL_BERSERK, true);
- Talk(SAY_BERSERK);
- break;
- case EVENT_THORIM_OUTRO1:
- if (_hardMode)
- {
- Talk(SAY_END_HARD_1);
- events.ScheduleEvent(EVENT_THORIM_OUTRO2, 5s, 0, 3);
- EntryCheckPredicate pred(NPC_SIF);
- summons.DoAction(ACTION_SIF_TRANSFORM, pred);
- }
- else
- {
- Talk(SAY_END_NORMAL_1);
- events.ScheduleEvent(EVENT_THORIM_OUTRO2, 9s, 0, 3);
- }
- break;
- case EVENT_THORIM_OUTRO2:
- if (_hardMode)
- {
- Talk(SAY_END_HARD_2);
- events.ScheduleEvent(EVENT_THORIM_OUTRO3, 12s, 0, 3);
- }
- else
- {
- Talk(SAY_END_NORMAL_2);
- events.ScheduleEvent(EVENT_THORIM_OUTRO3, 10s, 0, 3);
- }
- break;
- case EVENT_THORIM_OUTRO3:
- if (_hardMode)
- {
- Talk(SAY_END_HARD_3);
- }
- else
- {
- Talk(SAY_END_NORMAL_3);
- }
-
- // Defeat credit
- if (m_pInstance)
- m_pInstance->SetData(TYPE_THORIM, DONE);
-
- me->DespawnOrUnsummon(8000);
- break;
- }
-
- if (!_encounterFinished)
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_thorim_sif : public CreatureScript
-{
-public:
- boss_thorim_sif() : CreatureScript("boss_thorim_sif") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorim_sifAI : public ScriptedAI
- {
- boss_thorim_sifAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- void MoveInLineOfSight(Unit*) override {}
- void AttackStart(Unit*) override {}
-
- bool _allowCast;
- EventMap events;
-
- void Reset() override
- {
- events.Reset();
- me->SetReactState(REACT_PASSIVE);
- _allowCast = false;
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_SIF_START_TALK)
- events.ScheduleEvent(EVENT_SIF_START_TALK, 9s);
- else if (param == ACTION_SIF_START_DOMINION)
- {
- if (me->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM)))
- me->CastSpell(cr, SPELL_TOUCH_OF_DOMINION, false);
-
- events.ScheduleEvent(EVENT_SIF_FINISH_DOMINION, 150s);
- }
- else if (param == ACTION_SIF_JOIN_FIGHT)
- {
- me->InterruptNonMeleeSpells(false);
- events.ScheduleEvent(EVENT_SIF_JOIN_TALK, 9s);
- events.CancelEvent(EVENT_SIF_START_TALK);
- events.CancelEvent(EVENT_SIF_FINISH_DOMINION);
- }
- else if (param == ACTION_SIF_TRANSFORM)
- {
- me->CastSpell(me, SPELL_SIF_TRANSFORM, true);
- me->DespawnOrUnsummon(5000);
- events.Reset();
- _allowCast = false;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_SIF_FINISH_DOMINION:
- Talk(SAY_SIF_HM_MISSED);
- me->DespawnOrUnsummon(5000);
- break;
- case EVENT_SIF_START_TALK:
- Talk(SAY_SIF_AGGRO);
- break;
- case EVENT_SIF_JOIN_TALK:
- Talk(SAY_SIF_HM_REACHED);
- events.ScheduleEvent(EVENT_SIF_FROST_NOVA_START, 1s);
- events.ScheduleEvent(EVENT_SIF_FROSTBOLT_VALLEY, 11s);
- events.ScheduleEvent(EVENT_SIF_BLIZZARD, 15s);
- break;
- case EVENT_SIF_FROSTBOLT_VALLEY:
- me->CastSpell(me, SPELL_FROSTBOLT_VALLEY, false);
- events.Repeat(13s);
- return;
- case EVENT_SIF_BLIZZARD:
- me->SummonCreature(NPC_SIF_BLIZZARD, 2108.7f, -280.04f, 419.42f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000);
- events.Repeat(30s);
- return;
- case EVENT_SIF_FROST_NOVA_START:
- me->NearTeleportTo(2108 + urand(0, 42), -238 - irand(0, 46), 420.02f, me->GetAngle(&Middle));
- events.Repeat(20s);
- events.DelayEvents(5s);
- events.ScheduleEvent(EVENT_SIF_FROST_NOVA_CAST, 2500ms);
- _allowCast = false;
- return;
- case EVENT_SIF_FROST_NOVA_CAST:
- _allowCast = true;
- me->CastSpell(me, SPELL_FROST_NOVA, false);
- return;
- }
-
- // has casting check before event select (return in events)
- if (_allowCast)
- if (Player* target = SelectTargetFromPlayerList(70))
- {
- me->CastSpell(target, SPELL_FROSTBOLT, false);
- me->StopMoving();
- }
- }
- };
-};
-
-class boss_thorim_lightning_orb : public CreatureScript
-{
-public:
- boss_thorim_lightning_orb() : CreatureScript("boss_thorim_lightning_orb") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorim_lightning_orbAI : public npc_escortAI
- {
- boss_thorim_lightning_orbAI(Creature* pCreature) : npc_escortAI(pCreature)
- {
- InitWaypoint();
- Reset();
- Start(false, true);
- }
-
- uint32 Timer;
-
- void EnterEvadeMode(EvadeReason /*why*/) override {}
- void MoveInLineOfSight(Unit*) override {}
- void AttackStart(Unit*) override {}
-
- void InitWaypoint()
- {
- AddWaypoint(1, 2135, -304, 438.24f, 0);
- AddWaypoint(2, 2132, -441, 438.24f, 0);
- AddWaypoint(3, 2167, -442, 438.24f, 0);
- AddWaypoint(4, 2227, -432, 412.18f, 0);
- AddWaypoint(5, 2227, -263, 412.17f, 0);
- AddWaypoint(6, 2179, -262, 414.7f, 0);
- AddWaypoint(7, 2169, -261, 419.3f, 0);
- AddWaypoint(8, 2110, -251, 419.42f, 0);
- }
-
- void Reset() override
- {
- me->CastSpell(me, SPELL_LIGHTNING_DESTRUCTION, true);
- }
-
- void WaypointReached(uint32 /*point*/) override
- {
- }
- };
-};
-
-class boss_thorim_trap : public CreatureScript
-{
-public:
- boss_thorim_trap() : CreatureScript("boss_thorim_trap") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorim_trapAI : public NullCreatureAI
- {
- boss_thorim_trapAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
-
- uint32 _checkTimer;
-
- void Reset() override { _checkTimer = 1; }
- void UpdateAI(uint32 diff) override
- {
- if (_checkTimer)
- {
- _checkTimer += diff;
- if ((_checkTimer >= 1000 && _checkTimer < 10000) || _checkTimer >= 60000)
- {
- if (me->SelectNearbyTarget(nullptr, 12.0f))
- {
- me->CastSpell(me, SPELL_LIGHTNING_FIELD, true);
- me->CastSpell(me, (me->GetEntry() == 33054 /*NPC_THORIM_TRAP_BUNNY*/ ? SPELL_PARALYTIC_FIELD_FIRST : SPELL_PARALYTIC_FIELD_SECOND), true);
- _checkTimer = 10000;
- return;
- }
- _checkTimer = 1;
- }
- }
- }
- };
-};
-
-class boss_thorim_sif_blizzard : public CreatureScript
-{
-public:
- boss_thorim_sif_blizzard() : CreatureScript("boss_thorim_sif_blizzard") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorim_sif_blizzardAI : public npc_escortAI
- {
- boss_thorim_sif_blizzardAI(Creature* pCreature) : npc_escortAI(pCreature)
- {
- InitWaypoint();
- Reset();
- Start(false, true);
- SetDespawnAtEnd(false);
- }
-
- void MoveInLineOfSight(Unit* /*who*/) override {}
- void JustEngagedWith(Unit* /*who*/) override {}
- void AttackStart(Unit* /*who*/) override {}
-
- void InitWaypoint()
- {
- AddWaypoint(1, 2104.6f, -268.5f, 419.4f, 0);
- AddWaypoint(2, 2104.3f, -256.3f, 419.4f, 0);
- AddWaypoint(3, 2109.3f, -246.4f, 419.4f, 0);
- AddWaypoint(4, 2117.9f, -238.6f, 419.4f, 0);
- AddWaypoint(5, 2128.8f, -232.1f, 419.4f, 0);
- AddWaypoint(6, 2151.9f, -237.5f, 419.4f, 0);
- AddWaypoint(7, 2164.9f, -256.3f, 419.4f, 0);
- AddWaypoint(8, 2161.5f, -280.0f, 419.4f, 0);
- }
-
- void Reset() override
- {
- me->SetSpeed(MOVE_RUN, 1);
- me->SetSpeed(MOVE_WALK, 1);
- me->CastSpell(me, RAID_MODE(SPELL_BLIZZARD_10, SPELL_BLIZZARD_25), true);
- }
-
- void WaypointReached(uint32 /*point*/) override
- {
- }
- };
-};
-
-class boss_thorim_pillar : public CreatureScript
-{
-public:
- boss_thorim_pillar() : CreatureScript("boss_thorim_pillar") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorim_pillarAI : public NullCreatureAI
- {
- boss_thorim_pillarAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
-
- uint32 _resetTimer;
-
- void Reset() override
- {
- _resetTimer = 0;
- me->SetControlled(true, UNIT_STATE_STUNNED);
- me->SetDisableGravity(true);
- }
-
- void SpellHit(Unit*, SpellInfo const* spellInfo) override
- {
- if (spellInfo->Id == SPELL_CHARGE_ORB)
- me->CastSpell(me, SPELL_LIGHTNING_PILLAR_P1, true);
- else if (spellInfo->Id == SPELL_LIGHTNING_PILLAR_P2)
- {
- if (Creature* cr = me->FindNearestCreature(NPC_THUNDER_ORB, 100))
- cr->CastSpell(cr, SPELL_LIGHTNING_ORB_VISUAL, true);
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- _resetTimer += diff;
- if (_resetTimer >= 10000)
- Reset(); // _resetTimer set to 0
- }
- };
-};
-
-class boss_thorim_start_npcs : public CreatureScript
-{
-public:
- boss_thorim_start_npcs() : CreatureScript("boss_thorim_start_npcs") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorim_start_npcsAI : public ScriptedAI
- {
- boss_thorim_start_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- EventMap events;
- bool _isCaster;
- bool _playerAttack;
-
- void Reset() override
- {
- events.Reset();
- _isCaster = (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I);
- _playerAttack = false;
- if (me->GetEntry() != NPC_JORMUNGAR_BEHEMOT)
- if (Creature* cr = me->FindNearestCreature(NPC_JORMUNGAR_BEHEMOT, 30.0f))
- AttackStart(cr);
- }
-
- void DamageTaken(Unit* who, uint32&, DamageEffectType, SpellSchoolMask) override
- {
- if (!_playerAttack && who && (who->GetTypeId() == TYPEID_PLAYER || who->GetOwnerGUID().IsPlayer()))
- {
- if (me->GetInstanceScript())
- if (Creature* thorim = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM)))
- {
- if (!thorim->IsInCombat())
- {
- thorim->SetInCombatWithZone();
- thorim->AI()->AttackStart(who);
- }
- }
- _playerAttack = true;
- me->GetThreatMgr().ResetAllThreat();
- me->CallForHelp(40.0f);
- AttackStart(who);
- }
-
- if (!_playerAttack && me->HealthBelowPct(60))
- me->SetHealth(me->GetMaxHealth());
- }
-
- void JustDied(Unit*) override
- {
- if (me->GetInstanceScript())
- if (Creature* thorim = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM)))
- thorim->AI()->DoAction(ACTION_START_TRASH_DIED);
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- if (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I)
- {
- events.ScheduleEvent(EVENT_DR_ACOLYTE_GH, 10s);
- events.ScheduleEvent(EVENT_DR_ACOLYTE_HS, 5s);
- events.ScheduleEvent(EVENT_DR_ACOLYTE_R, 7s);
- }
- else if (me->GetEntry() == NPC_CAPTURED_MERCENARY_SOLDIER_ALLY || me->GetEntry() == NPC_CAPTURED_MERCENARY_SOLDIER_HORDE)
- {
- events.ScheduleEvent(EVENT_CM_SOLDIER_BS, 9s);
- events.ScheduleEvent(EVENT_CM_SOLDIER_WC, 5s);
- events.ScheduleEvent(EVENT_CM_SOLDIER_S, 0ms);
- }
- else if (me->GetEntry() == NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY || me->GetEntry() == NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE)
- {
- events.ScheduleEvent(EVENT_CM_CAPTAIN_D, 9s);
- events.ScheduleEvent(EVENT_CM_CAPTAIN_HC, 5s);
- }
- else if (me->GetEntry() == NPC_JORMUNGAR_BEHEMOT)
- {
- events.ScheduleEvent(EVENT_JB_ACID_BREATH, 12s);
- events.ScheduleEvent(EVENT_JB_SWEEP, 5s);
- }
-
- me->CallForHelp(10);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_DR_ACOLYTE_GH:
- if (HealthBelowPct(60))
- me->CastSpell(me, SPELL_GREATER_HEAL, false);
- else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 20))
- me->CastSpell(target, SPELL_GREATER_HEAL, false);
- events.Repeat(10s);
- break;
- case EVENT_DR_ACOLYTE_HS:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target, SPELL_HOLY_SMITE, false);
- events.Repeat(1600ms);
- break;
- case EVENT_DR_ACOLYTE_R:
- if (HealthBelowPct(75) && !me->HasAura(SPELL_RENEW))
- me->CastSpell(me, SPELL_GREATER_HEAL, false);
- else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 10))
- me->CastSpell(target, SPELL_RENEW, false);
- events.Repeat(7s);
- break;
- case EVENT_CM_SOLDIER_BS:
- me->CastSpell(me->GetVictim(), SPELL_BARBED_SHOT, false);
- events.Repeat(9s);
- break;
- case EVENT_CM_SOLDIER_WC:
- me->CastSpell(me->GetVictim(), SPELL_WING_CLIP, false);
- events.Repeat(5s);
- break;
- case EVENT_CM_SOLDIER_S:
- if (me->GetDistance(me->GetVictim()) > 8)
- me->CastSpell(me->GetVictim(), SPELL_SHOOT, false);
-
- events.Repeat(1500ms);
- break;
- case EVENT_CM_CAPTAIN_D:
- me->CastSpell(me->GetVictim(), SPELL_DEVASTATE, false);
- events.Repeat(9s);
- break;
- case EVENT_CM_CAPTAIN_HC:
- me->CastSpell(me->GetVictim(), SPELL_HEROIC_STRIKE, false);
- events.Repeat(5s);
- break;
- case EVENT_JB_ACID_BREATH:
- me->CastSpell(me->GetVictim(), SPELL_ACID_BREATH, false);
- events.Repeat(12s);
- break;
- case EVENT_JB_SWEEP:
- me->CastSpell(me->GetVictim(), SPELL_SWEEP, false);
- events.Repeat(5s);
- break;
- }
-
- if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10))
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_thorim_gauntlet_npcs : public CreatureScript
-{
-public:
- boss_thorim_gauntlet_npcs() : CreatureScript("boss_thorim_gauntlet_npcs") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorim_gauntlet_npcsAI : public ScriptedAI
- {
- boss_thorim_gauntlet_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- EventMap events;
- bool _isCaster;
-
- void Reset() override
- {
- events.Reset();
- _isCaster = (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_G);
- }
-
- void JustEngagedWith(Unit* /*who*/) override
- {
- if (me->GetEntry() == NPC_IRON_RING_GUARD)
- {
- events.ScheduleEvent(EVENT_IR_GUARD_IMPALE, 12s);
- events.ScheduleEvent(EVENT_IR_GUARD_WHIRL, 5s);
- }
- else if (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I)
- {
- events.ScheduleEvent(EVENT_DR_ACOLYTE_GH, 10s);
- events.ScheduleEvent(EVENT_DR_ACOLYTE_HS, 5s);
- events.ScheduleEvent(EVENT_DR_ACOLYTE_R, 7s);
- }
- else if (me->GetEntry() == NPC_IRON_HONOR_GUARD)
- {
- events.ScheduleEvent(EVENT_IH_GUARD_CLEAVE, 6s);
- events.ScheduleEvent(EVENT_IH_GUARD_HAMSTRING, 9s);
- events.ScheduleEvent(EVENT_IH_GUARD_SHIELD_SMASH, 15s);
-
- if (Creature* runeGiant = me->FindNearestCreature(NPC_ANCIENT_RUNE_GIANT, 200.0f))
- runeGiant->AI()->DoAction(ACTION_IRON_HONOR_DIED);
- }
-
- me->CallForHelp(25);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_IR_GUARD_IMPALE:
- me->CastSpell(me->GetVictim(), SPELL_IMPALE, false);
- events.Repeat(12s);
- break;
- case EVENT_IR_GUARD_WHIRL:
- me->CastSpell(me->GetVictim(), SPELL_WHIRLING_TRIP, false);
- events.Repeat(5s);
- break;
- case EVENT_DR_ACOLYTE_GH:
- if (HealthBelowPct(60))
- me->CastSpell(me, SPELL_GREATER_HEAL, false);
- else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 20))
- me->CastSpell(target, SPELL_GREATER_HEAL, false);
- events.Repeat(10s);
- break;
- case EVENT_DR_ACOLYTE_HS:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target, SPELL_HOLY_SMITE, false);
- events.Repeat(1600ms);
- break;
- case EVENT_DR_ACOLYTE_R:
- if (HealthBelowPct(75) && !me->HasAura(SPELL_RENEW))
- me->CastSpell(me, SPELL_GREATER_HEAL, false);
- else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 10))
- me->CastSpell(target, SPELL_RENEW, false);
- events.Repeat(7s);
- break;
- case EVENT_IH_GUARD_CLEAVE:
- me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false);
- events.Repeat(6s);
- break;
- case EVENT_IH_GUARD_HAMSTRING:
- me->CastSpell(me->GetVictim(), SPELL_HAMSTRING, false);
- events.Repeat(9s);
- break;
- case EVENT_IH_GUARD_SHIELD_SMASH:
- me->CastSpell(me->GetVictim(), SPELL_SHIELD_SMASH, false);
- events.Repeat(15s);
- break;
- }
-
- if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10))
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_thorim_runic_colossus : public CreatureScript
-{
-public:
- boss_thorim_runic_colossus() : CreatureScript("boss_thorim_runic_colossus") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorim_runic_colossusAI : public ScriptedAI
- {
- boss_thorim_runic_colossusAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- EventMap events;
- bool _leftHand;
- bool _checkTarget;
- float _nextTriggerPos;
- ObjectGuid _triggerLeftGUID[2], _triggerRightGUID[2];
-
- void Reset() override
- {
- _nextTriggerPos = 0.0f;
- _leftHand = false;
- _checkTarget = false;
- events.Reset();
- events.ScheduleEvent(EVENT_RC_RUNIC_SMASH, 0ms);
- Creature* c;
-
- if ((c = me->SummonCreature(33140, 2221, -385, me->GetPositionZ())))
- _triggerRightGUID[0] = c->GetGUID();
- if ((c = me->SummonCreature(33140, 2210, -385, me->GetPositionZ())))
- _triggerRightGUID[1] = c->GetGUID();
-
- if ((c = me->SummonCreature(33141, 2235, -385, me->GetPositionZ())))
- _triggerLeftGUID[0] = c->GetGUID();
- if ((c = me->SummonCreature(33141, 2246, -385, me->GetPositionZ())))
- _triggerLeftGUID[1] = c->GetGUID();
- }
-
- void JustDied(Unit*) override
- {
- if (me->GetInstanceScript())
- {
- if (GameObject* go = ObjectAccessor::GetGameObject(*me, me->GetInstanceScript()->GetGuidData(DATA_THORIM_FIRST_DOORS)))
- go->SetGoState(GO_STATE_ACTIVE);
-
- if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM)))
- cr->AI()->Talk(SAY_SPECIAL_2);
- }
- }
-
- void JustEngagedWith(Unit*) override
- {
- events.CancelEvent(EVENT_RC_RUNIC_SMASH);
- events.ScheduleEvent(EVENT_RC_RUNIC_BARRIER, 10s);
- events.ScheduleEvent(EVENT_RC_SMASH, 18s);
- events.ScheduleEvent(EVENT_RC_CHARGE, 15s);
-
- me->InterruptNonMeleeSpells(false);
- _checkTarget = true;
- }
-
- void SpellHit(Unit*, SpellInfo const* spellInfo) override
- {
- if (spellInfo->Id == SPELL_RUNIC_SMASH_LEFT || spellInfo->Id == SPELL_RUNIC_SMASH_RIGHT)
- {
- _leftHand = spellInfo->Id == SPELL_RUNIC_SMASH_LEFT;
- events.RescheduleEvent(EVENT_RC_RUNIC_SMASH_TRIGGER, 1s);
- }
- }
-
- void RunRunicSmash(bool cast)
- {
- if (Creature* cr = ObjectAccessor::GetCreature(*me, _leftHand ? _triggerLeftGUID[0] : _triggerRightGUID[0]) )
- {
- if (cast)
- cr->CastSpell(cr, SPELL_RUNIC_SMASH_DAMAGE, true);
- cr->SetPosition(_leftHand ? 2235.0f : 2221.0f, _nextTriggerPos, cr->GetPositionZ(), 0.0f);
- cr->StopMovingOnCurrentPos();
- }
- if( Creature* cr = ObjectAccessor::GetCreature(*me, _leftHand ? _triggerLeftGUID[1] : _triggerRightGUID[1]) )
- {
- if (cast)
- cr->CastSpell(cr, SPELL_RUNIC_SMASH_DAMAGE, true);
- cr->SetPosition(_leftHand ? 2246.0f : 2210.0f, _nextTriggerPos, cr->GetPositionZ(), 0.0f);
- cr->StopMovingOnCurrentPos();
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (_checkTarget && !UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_RC_RUNIC_SMASH_TRIGGER:
- _nextTriggerPos += 16.0f;
- if (_nextTriggerPos <= -260.0f)
- {
- events.RescheduleEvent(EVENT_RC_RUNIC_SMASH_TRIGGER, 500ms);
- }
-
- RunRunicSmash(true);
- break;
- case EVENT_RC_RUNIC_SMASH:
- if (urand(0, 1))
- me->CastSpell(me, SPELL_RUNIC_SMASH_LEFT, false);
- else
- me->CastSpell(me, SPELL_RUNIC_SMASH_RIGHT, false);
-
- _nextTriggerPos = -385.0f;
- RunRunicSmash(false);
- events.Repeat(11s);
- break;
- case EVENT_RC_RUNIC_BARRIER:
- me->CastSpell(me, SPELL_RUNIC_BARRIER, false);
- Talk(SAY_COLOSSUS_RUNIC_BARRIER);
- events.Repeat(20s);
- break;
- case EVENT_RC_SMASH:
- me->CastSpell(me->GetVictim(), SPELL_SMASH, false);
- events.Repeat(10s);
- break;
- case EVENT_RC_CHARGE:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target, SPELL_CHARGE, false);
- events.Repeat(15s);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_thorim_ancient_rune_giant : public CreatureScript
-{
-public:
- boss_thorim_ancient_rune_giant() : CreatureScript("boss_thorim_ancient_rune_giant") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorim_ancient_rune_giantAI : public ScriptedAI
- {
- boss_thorim_ancient_rune_giantAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- EventMap events;
- bool _isInCombat;
-
- void Reset() override
- {
- _isInCombat = false;
- events.Reset();
- }
-
- void JustEngagedWith(Unit*) override
- {
- _isInCombat = true;
- events.CancelEvent(EVENT_ARG_SPAWN);
- events.ScheduleEvent(EVENT_ARG_RD, 12s);
- events.ScheduleEvent(EVENT_ARG_STOMP, 8s);
-
- me->CastSpell(me, SPELL_RUNIC_FORTIFICATION, false);
- Talk(SAY_GIANT_RUNIC_MIGHT);
- }
-
- void JustDied(Unit*) override
- {
- if (InstanceScript* pInstance = me->GetInstanceScript())
- {
- if (GameObject* go = ObjectAccessor::GetGameObject(*me, pInstance->GetGuidData(DATA_THORIM_SECOND_DOORS)))
- go->SetGoState(GO_STATE_ACTIVE);
-
- if (Creature* thorim = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_THORIM)))
- thorim->AI()->DoAction(ACTION_ALLOW_HIT);
- }
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_IRON_HONOR_DIED)
- events.RescheduleEvent(EVENT_ARG_SPAWN, 20s);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (_isInCombat && !UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_ARG_RD:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target, SPELL_RUNE_DETONATION, false);
- events.Repeat(12s);
- break;
- case EVENT_ARG_STOMP:
- me->CastSpell(me->GetVictim(), SPELL_STOMP, false);
- events.Repeat(8s);
- break;
- case EVENT_ARG_SPAWN:
- if (Creature* cr = me->SummonCreature(NPC_IRON_HONOR_GUARD, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000))
- if (Unit* target = SelectTargetFromPlayerList(150.0f))
- cr->AI()->AttackStart(target);
- events.Repeat(10s);
- break;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class boss_thorim_arena_npcs : public CreatureScript
-{
-public:
- boss_thorim_arena_npcs() : CreatureScript("boss_thorim_arena_npcs") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_thorim_arena_npcsAI : public ScriptedAI
- {
- boss_thorim_arena_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- EventMap events;
- bool _isCaster;
-
- void Reset() override
- {
- _isCaster = (me->GetEntry() == NPC_DARK_RUNE_EVOKER);
- events.Reset();
- if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER)
- me->CastSpell(me, SPELL_AURA_OF_CELERITY, true);
- }
-
- void JustEngagedWith(Unit*) override
- {
- if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER)
- {
- events.ScheduleEvent(EVENT_DR_WARBRINGER_RS, 8s);
- }
- else if (me->GetEntry() == NPC_DARK_RUNE_EVOKER)
- {
- events.ScheduleEvent(EVENT_DR_EVOKER_RL, 2500ms);
- events.ScheduleEvent(EVENT_DR_EVOKER_RM, 4s);
- events.ScheduleEvent(EVENT_DR_EVOKER_RS, 10s);
- }
- else if (me->GetEntry() == NPC_DARK_RUNE_CHAMPION)
- {
- events.ScheduleEvent(EVENT_DR_CHAMPION_WH, 6s);
- events.ScheduleEvent(EVENT_DR_CHAMPION_CH, 12s);
- events.ScheduleEvent(EVENT_DR_CHAMPION_MS, 8s);
- }
- else if (me->GetEntry() == NPC_DARK_RUNE_COMMONER)
- {
- events.ScheduleEvent(EVENT_DR_COMMONER_LB, 5s);
- events.ScheduleEvent(EVENT_DR_COMMONER_PM, 6s);
- }
- }
-
- bool CanAIAttack(Unit const* target) const override
- {
- return target->GetPositionX() < 2180 && target->GetPositionZ() < 425;
- }
-
- bool SelectT()
- {
- Player* target = nullptr;
- Map::PlayerList const& pList = me->GetMap()->GetPlayers();
- uint8 num = urand(0, pList.getSize() - 1);
- uint8 count = 0;
- for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr, ++count)
- {
- if (itr->GetSource()->GetPositionX() > 2180 || !itr->GetSource()->IsAlive() || itr->GetSource()->GetPositionZ() > 425)
- continue;
-
- if (count <= num || !target)
- target = itr->GetSource();
- else
- break;
- }
-
- if (target)
- {
- AttackStart(target);
- me->AddThreat(target, 500.0f);
- if (me->GetEntry() == NPC_DARK_RUNE_EVOKER && urand(0, 1))
- me->CastSpell(me, SPELL_RUNIC_SHIELD, false);
- else if (me->GetEntry() == NPC_DARK_RUNE_CHAMPION && !urand(0, 2))
- me->CastSpell(target, SPELL_CHARGE, false);
- return true;
- }
- return false;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim() && !SelectT())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch (events.ExecuteEvent())
- {
- case EVENT_DR_WARBRINGER_RS:
- me->CastSpell(me->GetVictim(), SPELL_RUNIC_STRIKE, false);
- events.Repeat(8s);
- break;
- case EVENT_DR_EVOKER_RL:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target, SPELL_RUNIC_LIGHTNING, false);
- events.Repeat(2500ms);
- break;
- case EVENT_DR_EVOKER_RM:
- if (Unit* target = DoSelectLowestHpFriendly(40.0f, 15))
- me->CastSpell(target, SPELL_RUNIC_MENDING, false);
- else
- me->CastSpell(me, SPELL_RUNIC_MENDING, false);
- events.Repeat(4s);
- break;
- case EVENT_DR_EVOKER_RS:
- me->CastSpell(me, SPELL_RUNIC_SHIELD, false);
- events.Repeat(10s);
- break;
- case EVENT_DR_CHAMPION_CH:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- me->CastSpell(target, SPELL_CHARGE, false);
- events.Repeat(12s);
- break;
- case EVENT_DR_CHAMPION_WH:
- if (!me->HasUnitFlag(UNIT_FLAG_DISARMED))
- me->CastSpell(me, SPELL_WHIRLWIND, false);
- events.Repeat(6s);
- break;
- case EVENT_DR_CHAMPION_MS:
- me->CastSpell(me->GetVictim(), SPELL_MORTAL_STRIKE, false);
- events.Repeat(8s);
- break;
- case EVENT_DR_COMMONER_LB:
- me->CastSpell(me->GetVictim(), SPELL_LOW_BLOW, false);
- events.Repeat(5s);
- break;
- case EVENT_DR_COMMONER_PM:
- me->CastSpell(me->GetVictim(), SPELL_PUMMEL, false);
- events.Repeat(6s);
- break;
- }
-
- if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10))
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class go_thorim_lever : public GameObjectScript
-{
-public:
- go_thorim_lever() : GameObjectScript("go_thorim_lever") { }
-
- bool OnGossipHello(Player* pPlayer, GameObject* go) override
- {
- if (GameObject* g = pPlayer->FindNearestGameObject(GO_ARENA_LEVER_GATE, 50))
- g->UseDoorOrButton();
-
- go->UseDoorOrButton();
- return true;
- }
-};
-
-class spell_thorim_lightning_pillar_P2 : public SpellScriptLoader
-{
-public:
- spell_thorim_lightning_pillar_P2() : SpellScriptLoader("spell_thorim_lightning_pillar_P2") { }
-
- class spell_thorim_lightning_pillar_P2_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_thorim_lightning_pillar_P2_AuraScript);
-
- void OnPeriodic(AuraEffect const* aurEff)
- {
- PreventDefaultAction();
- if (Unit* caster = GetCaster())
- GetUnitOwner()->CastSpell(caster, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_thorim_lightning_pillar_P2_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_thorim_lightning_pillar_P2_AuraScript();
- }
-};
-
-class spell_thorim_trash_impale : public SpellScriptLoader
-{
-public:
- spell_thorim_trash_impale() : SpellScriptLoader("spell_thorim_trash_impale") { }
-
- class spell_thorim_trash_impale_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_thorim_trash_impale_AuraScript);
-
- void OnPeriodic(AuraEffect const* /*aurEff*/)
- {
- // deals damage until target is healed above 90%
- if (GetUnitOwner()->HealthAbovePct(90))
- SetDuration(0);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_thorim_trash_impale_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_thorim_trash_impale_AuraScript();
- }
-};
-
-class achievement_thorim_stand_in_the_lightning : public AchievementCriteriaScript
-{
-public:
- achievement_thorim_stand_in_the_lightning() : AchievementCriteriaScript("achievement_thorim_stand_in_the_lightning") {}
-
- bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override
- {
- if (InstanceScript* instance = player->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*player, instance->GetGuidData(TYPE_THORIM)))
- return cr->AI()->GetData(DATA_HIT_BY_LIGHTNING);
-
- return false;
- }
-};
-
-class achievement_thorim_lose_your_illusion : public AchievementCriteriaScript
-{
-public:
- achievement_thorim_lose_your_illusion() : AchievementCriteriaScript("achievement_thorim_lose_your_illusion") {}
-
- bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override
- {
- if (InstanceScript* instance = player->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*player, instance->GetGuidData(TYPE_THORIM)))
- return cr->AI()->GetData(DATA_LOSE_YOUR_ILLUSION);
-
- return false;
- }
-};
-
void AddSC_boss_thorim()
{
// Main encounter
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.h
new file mode 100644
index 00000000000000..96ba29d4a110de
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.h
@@ -0,0 +1,1797 @@
+#ifndef BOSS_THORIM_H_
+#define BOSS_THORIM_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "GameObjectScript.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "ScriptedEscortAI.h"
+#include "SpellAuraEffects.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "ulduar.h"
+
+enum ThorimSpells
+{
+ // THORIM
+ SPELL_LIGHTNING_DESTRUCTION = 62393,
+ SPELL_SHEATH_OF_LIGHTNING = 62276,
+ SPELL_STORMHAMMER = 62042,
+ SPELL_BERSERK_FRIENDS = 62560,
+ SPELL_CHAIN_LIGHTNING_10 = 62131,
+ SPELL_CHAIN_LIGHTNING_25 = 64390,
+ SPELL_UNBALANCING_STRIKE = 62130,
+ SPELL_BERSERK = 26662,
+
+ SPELL_CHARGE_ORB = 62016,
+ SPELL_LIGHTNING_PILLAR_P1 = 63238,
+
+ SPELL_LIGHTNING_ORB_VISUAL = 62186,
+ SPELL_LIGHTNING_CHARGE_DAMAGE = 62466,
+ SPELL_LIGHTNING_CHARGE_BUFF = 62279,
+ SPELL_LIGHTNING_PILLAR_P2 = 62976,
+ SPELL_LIGHTNING_ORB_CHARGER = 62278,
+
+ // SIF
+ SPELL_TOUCH_OF_DOMINION = 62507,
+ SPELL_SIF_TRANSFORM = 64778,
+ SPELL_SIF_CHANNEL_HOLOGRAM = 64324,
+ SPELL_FROSTBOLT = 62601,
+ SPELL_FROSTBOLT_VALLEY = 62604,
+ SPELL_BLIZZARD_10 = 62577,
+ SPELL_BLIZZARD_25 = 62603,
+ SPELL_FROST_NOVA = 62605,
+
+ // DARK RUNE ACOLYTE
+ SPELL_GREATER_HEAL_10 = 62334,
+ SPELL_GREATER_HEAL_25 = 62442,
+ SPELL_HOLY_SMITE_10 = 62335,
+ SPELL_HOLY_SMITE_25 = 62443,
+ SPELL_RENEW_10 = 62333,
+ SPELL_RENEW_25 = 62441,
+
+ // CAPTURED MERCENARY SOLDIER
+ SPELL_BARBED_SHOT = 62318,
+ SPELL_WING_CLIP = 40652,
+ SPELL_SHOOT = 16496,
+
+ // CAPTURED MERCENARY CAPTAIN
+ SPELL_DEVASTATE = 62317,
+ SPELL_HEROIC_STRIKE = 62444,
+
+ // JORMUNGAR BEHEMOTH
+ SPELL_ACID_BREATH_10 = 62315,
+ SPELL_ACID_BREATH_25 = 62415,
+ SPELL_SWEEP_10 = 62316,
+ SPELL_SWEEP_25 = 62417,
+
+ // IRON RING GUARD
+ SPELL_IMPALE_10 = 62331,
+ SPELL_IMPALE_25 = 62418,
+ SPELL_WHIRLING_TRIP = 64151,
+
+ // IRON HONOR GUARD
+ SPELL_SHIELD_SMASH_10 = 62332,
+ SPELL_SHIELD_SMASH_25 = 62420,
+ SPELL_CLEAVE = 42724,
+ SPELL_HAMSTRING = 48639,
+
+ // DARK RUNE WARBRINGER
+ SPELL_AURA_OF_CELERITY = 62320,
+ SPELL_RUNIC_STRIKE = 62322,
+
+ // DARK RUNE EVOKER
+ SPELL_RUNIC_LIGHTNING_10 = 62327,
+ SPELL_RUNIC_LIGHTNING_25 = 62445,
+ SPELL_RUNIC_MENDING_10 = 62328,
+ SPELL_RUNIC_MENDING_25 = 62446,
+ SPELL_RUNIC_SHIELD_10 = 62321,
+ SPELL_RUNIC_SHIELD_25 = 62529,
+
+ // DARK RUNE CHAMPION
+ SPELL_CHARGE = 32323,
+ SPELL_MORTAL_STRIKE = 35054,
+ SPELL_WHIRLWIND = 15578,
+
+ // DARK RUNE COMMONER
+ SPELL_LOW_BLOW = 62326,
+ SPELL_PUMMEL = 38313,
+
+ // RUNIC COLOSSUS
+ SPELL_COLOSSUS_CHARGE_10 = 62613,
+ SPELL_COLOSSUS_CHARGE_25 = 62614,
+ SPELL_RUNIC_BARRIER = 62338,
+ SPELL_SMASH = 62339,
+ SPELL_RUNIC_SMASH_LEFT = 62057,
+ SPELL_RUNIC_SMASH_RIGHT = 62058,
+ SPELL_RUNIC_SMASH_DAMAGE = 62465,
+
+ // ANCIENT RUNE GIANT
+ SPELL_RUNE_DETONATION = 62526,
+ SPELL_RUNIC_FORTIFICATION = 62942,
+ SPELL_STOMP_10 = 62411,
+ SPELL_STOMP_25 = 62413,
+
+ // TRAPS
+ SPELL_LIGHTNING_FIELD = 64972,
+ SPELL_PARALYTIC_FIELD_FIRST = 62241,
+ SPELL_PARALYTIC_FIELD_SECOND = 63540,
+};
+
+#define SPELL_GREATER_HEAL RAID_MODE(SPELL_GREATER_HEAL_10, SPELL_GREATER_HEAL_25)
+#define SPELL_HOLY_SMITE RAID_MODE(SPELL_HOLY_SMITE_10, SPELL_HOLY_SMITE_25)
+#define SPELL_RENEW RAID_MODE(SPELL_RENEW_10, SPELL_RENEW_25)
+#define SPELL_ACID_BREATH RAID_MODE(SPELL_ACID_BREATH_10, SPELL_ACID_BREATH_25)
+#define SPELL_SWEEP RAID_MODE(SPELL_SWEEP_10, SPELL_SWEEP_25)
+#define SPELL_IMPALE RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25)
+#define SPELL_COLOSSUS_CHARGE RAID_MODE(SPELL_COLOSSUS_CHARGE_10, SPELL_COLOSSUS_CHARGE_25)
+#define SPELL_STOMP RAID_MODE(SPELL_STOMP_10, SPELL_STOMP_25)
+#define SPELL_SHIELD_SMASH RAID_MODE(SPELL_SHIELD_SMASH_10, SPELL_SHIELD_SMASH_25)
+#define SPELL_RUNIC_LIGHTNING RAID_MODE(SPELL_RUNIC_LIGHTNING_10, SPELL_RUNIC_LIGHTNING_25)
+#define SPELL_RUNIC_MENDING RAID_MODE(SPELL_RUNIC_MENDING_10, SPELL_RUNIC_MENDING_25)
+#define SPELL_RUNIC_SHIELD RAID_MODE(SPELL_RUNIC_SHIELD_10, SPELL_RUNIC_SHIELD_25)
+#define SPELL_CHAIN_LIGHTNING RAID_MODE(SPELL_CHAIN_LIGHTNING_10, SPELL_CHAIN_LIGHTNING_25)
+
+enum ThormNPCandGOs : uint32
+{
+ // ARENA INIT
+ NPC_DARK_RUNE_ACOLYTE_I = 32886,
+ NPC_CAPTURED_MERCENARY_SOLDIER_ALLY = 32885,
+ NPC_CAPTURED_MERCENARY_SOLDIER_HORDE = 32883,
+ NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY = 32908,
+ NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE = 32907,
+ NPC_JORMUNGAR_BEHEMOT = 32882,
+
+ // ARENA PHASE
+ NPC_DARK_RUNE_WARBRINGER = 32877,
+ NPC_DARK_RUNE_EVOKER = 32878,
+ NPC_DARK_RUNE_CHAMPION = 32876,
+ NPC_DARK_RUNE_COMMONER = 32904,
+
+ // GAUNTLET
+ NPC_IRON_RING_GUARD = 32874,
+ NPC_RUNIC_COLOSSUS = 32872,
+ NPC_ANCIENT_RUNE_GIANT = 32873,
+ NPC_DARK_RUNE_ACOLYTE_G = 33110,
+ NPC_IRON_HONOR_GUARD = 32875,
+
+ // TRIGGERS
+ NPC_LIGHTNING_ORB = 33138,
+ NPC_THUNDER_ORB = 33378,
+ NPC_PILLAR = 32892,
+ NPC_SIF_BLIZZARD = 32879,
+
+ NPC_SIF = 33196,
+};
+
+enum ThorimEvents
+{
+ EVENT_THORIM_START_PHASE1 = 1,
+ EVENT_THORIM_STORMHAMMER = 2,
+ EVENT_THORIM_CHARGE_ORB = 3,
+ EVENT_THORIM_LIGHTNING_ORB = 4,
+ EVENT_THORIM_NOT_REACH_IN_TIME = 5,
+ EVENT_THORIM_FILL_ARENA = 6,
+ EVENT_THORIM_UNBALANCING_STRIKE = 7,
+ EVENT_THORIM_LIGHTNING_CHARGE = 8,
+ EVENT_THORIM_CHAIN_LIGHTNING = 9,
+ EVENT_THORIM_BERSERK = 10,
+ EVENT_THORIM_AGGRO = 11,
+ EVENT_THORIM_AGGRO2 = 12,
+ EVENT_THORIM_OUTRO1 = 13,
+ EVENT_THORIM_OUTRO2 = 14,
+ EVENT_THORIM_OUTRO3 = 15,
+
+ EVENT_DR_ACOLYTE_GH = 20,
+ EVENT_DR_ACOLYTE_HS = 21,
+ EVENT_DR_ACOLYTE_R = 22,
+
+ EVENT_CM_SOLDIER_BS = 30,
+ EVENT_CM_SOLDIER_S = 31,
+ EVENT_CM_SOLDIER_WC = 32,
+
+ EVENT_CM_CAPTAIN_D = 40,
+ EVENT_CM_CAPTAIN_HC = 41,
+
+ EVENT_JB_ACID_BREATH = 50,
+ EVENT_JB_SWEEP = 51,
+
+ EVENT_IR_GUARD_IMPALE = 60,
+ EVENT_IR_GUARD_WHIRL = 61,
+
+ EVENT_RC_RUNIC_BARRIER = 70,
+ EVENT_RC_SMASH = 71,
+ EVENT_RC_RUNIC_SMASH = 72,
+ EVENT_RC_RUNIC_SMASH_TRIGGER = 73,
+ EVENT_RC_CHARGE = 74,
+
+ EVENT_ARG_RD = 80,
+ EVENT_ARG_RF = 81,
+ EVENT_ARG_STOMP = 82,
+ EVENT_ARG_SPAWN = 83,
+
+ EVENT_IH_GUARD_CLEAVE = 90,
+ EVENT_IH_GUARD_HAMSTRING = 91,
+ EVENT_IH_GUARD_SHIELD_SMASH = 92,
+
+ EVENT_SIF_START_TALK = 100,
+ EVENT_SIF_JOIN_TALK = 101,
+ EVENT_SIF_FINISH_DOMINION = 102,
+ EVENT_SIF_FROSTBOLT_VALLEY = 103,
+ EVENT_SIF_BLIZZARD = 104,
+ EVENT_SIF_FROST_NOVA_START = 105,
+ EVENT_SIF_FROST_NOVA_CAST = 106,
+
+ EVENT_DR_WARBRINGER_RS = 110,
+
+ EVENT_DR_EVOKER_RL = 120,
+ EVENT_DR_EVOKER_RM = 121,
+ EVENT_DR_EVOKER_RS = 122,
+
+ EVENT_DR_CHAMPION_WH = 130,
+ EVENT_DR_CHAMPION_CH = 131,
+ EVENT_DR_CHAMPION_MS = 132,
+
+ EVENT_DR_COMMONER_PM = 140,
+ EVENT_DR_COMMONER_LB = 141,
+};
+
+const Position ArenaNPCs[] =
+{
+ {2178.5f, -300.2f, 441.97f, 2.5f},
+ {2188.12f, -295.1f, 443.75, 2.5f},
+ {2180.9f, -286.8f, 433.3f, 2.49f},
+ {2193.2f, -280.6f, 443.14f, 2.79f},
+ {2191.8f, -270.2f, 438.3f, 3.0f},
+ {2186.84f, -238.5f, 439.7f, 3.4f},
+ {2166.3f, -213.0f, 440.0f, 4.1f},
+ {2100.5f, -213.5f, 441.66f, 5.4f},
+ {2091.0f, -231.26f, 435.17f, 5.5f},
+ {2083.2f, -239.2f, 438.77f, 5.85f},
+ {2081.54f, -253.27f, 434.67f, 6.19f},
+ {2077.65f, -272.73f, 439.12f, 0.15f},
+ {2084.36f, -282.12f, 435.87f, 0.24f},
+ {2087.46f, -298.71f, 440.5f, 0.59f}
+};
+
+enum Texts
+{
+ // Thorim
+ SAY_AGGRO_1 = 0,
+ SAY_AGGRO_2 = 1,
+ SAY_SPECIAL_1 = 2, // Unused
+ SAY_SPECIAL_2 = 3,
+ SAY_SPECIAL_3 = 4, // Unused
+ SAY_JUMPDOWN = 5,
+ SAY_SLAY = 6,
+ SAY_BERSERK = 7,
+ SAY_WIPE = 8,
+ SAY_DEATH = 9,
+ SAY_END_NORMAL_1 = 10,
+ SAY_END_NORMAL_2 = 11,
+ SAY_END_NORMAL_3 = 12,
+ SAY_END_HARD_1 = 13,
+ SAY_END_HARD_2 = 14,
+ SAY_END_HARD_3 = 15,
+
+ // Sif
+ SAY_SIF_AGGRO = 0,
+ SAY_SIF_HM_MISSED = 1,
+ SAY_SIF_HM_REACHED = 2,
+
+ // Ancient Rune Giant
+ SAY_GIANT_RUNIC_MIGHT = 0,
+
+ // Runic Colossus
+ SAY_COLOSSUS_RUNIC_BARRIER = 0,
+};
+
+enum Misc
+{
+ ACTION_START_TRASH_DIED = 1,
+ ACTION_ALLOW_HIT = 2,
+ ACTION_SIF_JOIN_FIGHT = 3,
+ ACTION_SIF_START_TALK = 4,
+ ACTION_SIF_START_DOMINION = 5,
+ ACTION_SIF_TRANSFORM = 6,
+ ACTION_IRON_HONOR_DIED = 7,
+
+ EVENT_PHASE_START = 1,
+ EVENT_PHASE_RING = 2,
+ EVENT_PHASE_OUTRO = 3,
+
+ DATA_HIT_BY_LIGHTNING = 1,
+ DATA_LOSE_YOUR_ILLUSION = 2,
+};
+
+const Position Middle = {2134.68f, -263.13f, 419.44f, M_PI * 1.5f};
+
+const uint32 RollTable[3] = { 32877, 32878, 32876 };
+
+class boss_thorim : public CreatureScript
+{
+public:
+ boss_thorim() : CreatureScript("boss_thorim") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorimAI : public ScriptedAI
+ {
+ boss_thorimAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
+ {
+ m_pInstance = pCreature->GetInstanceScript();
+ if ((_encounterFinished = (!me->IsAlive())))
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_THORIM, DONE);
+ }
+
+ bool _isArenaEmpty;
+ bool _encounterFinished;
+ bool _spawnCommoners;
+ bool _hardMode;
+ bool _isHitAllowed;
+ bool _isAlly;
+ uint8 _trashCounter;
+
+ InstanceScript* m_pInstance;
+ EventMap events;
+ SummonList summons;
+
+ bool _hitByLightning;
+
+ void DisableThorim(bool apply)
+ {
+ if (apply)
+ {
+ me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED);
+ me->DisableRotate(true);
+ me->AddUnitState(UNIT_STATE_ROOT);
+ }
+ else
+ {
+ me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_PACIFIED);
+ me->DisableRotate(false);
+ me->ClearUnitState(UNIT_STATE_ROOT);
+ me->resetAttackTimer(BASE_ATTACK);
+ }
+ }
+
+ GameObject* GetThorimObject(uint32 entry)
+ {
+ if (m_pInstance)
+ return ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(entry));
+ return nullptr;
+ }
+
+ void JustSummoned(Creature* cr) override { summons.Summon(cr); }
+
+ void SpawnAllNPCs()
+ {
+ // Jormungar Behemoth 32882
+ me->SummonCreature(NPC_JORMUNGAR_BEHEMOT, 2149.68f, -263.477f, 419.679f, 3.12102f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
+
+ // Captured Mercenary Soldier 32885
+ me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2127.24f, -251.309f, 419.793f, 5.89921f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
+ me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2120.1f, -258.99f, 419.764f, 6.24828f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
+ me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_SOLDIER_ALLY : NPC_CAPTURED_MERCENARY_SOLDIER_HORDE, 2123.32f, -254.771f, 419.789f, 6.17846f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
+
+ // Captured Mercenary Captain 32908
+ me->SummonCreature(_isAlly ? NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY : NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE, 2131.31f, -259.182f, 419.974f, 5.91667f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
+
+ // Dark Rune Acolyte (arena) 32886
+ me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_I, 2129.09f, -277.142f, 419.756f, 1.22173f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
+
+ // Iron Ring Guard 32874
+ me->SummonCreature(NPC_IRON_RING_GUARD, 2217.69f, -337.394f, 412.177f, 1.23918f);
+ me->SummonCreature(NPC_IRON_RING_GUARD, 2218.38f, -297.505f, 412.176f, 1.02974f);
+ me->SummonCreature(NPC_IRON_RING_GUARD, 2235.26f, -338.345f, 412.134f, 1.58979f);
+ me->SummonCreature(NPC_IRON_RING_GUARD, 2235.07f, -297.985f, 412.134f, 1.61336f);
+
+ // Dark Rune Acolyte (gauntlet) 33110
+ me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2198.29f, -436.92f, 419.985f, 0.261799f);
+ me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2227.58f, -308.303f, 412.134f, 1.59372f);
+ me->SummonCreature(NPC_DARK_RUNE_ACOLYTE_G, 2227.47f, -345.375f, 412.134f, 1.56622f);
+
+ // Iron Honor Guard 32875
+ me->SummonCreature(NPC_IRON_HONOR_GUARD, 2198.05f, -428.769f, 419.985f, 6.05629f);
+ me->SummonCreature(NPC_IRON_HONOR_GUARD, 2220.31f, -436.22f, 412.26f, 1.06465f);
+
+ // Runic Colossus 32872
+ me->SummonCreature(NPC_RUNIC_COLOSSUS, 2227.5f, -396.179f, 412.176f, 1.79769f);
+
+ // Ancient Rune Giant 32873
+ me->SummonCreature(NPC_ANCIENT_RUNE_GIANT, 2134.57f, -440.318f, 438.331f, 0.226893f);
+
+ // Sif 33196
+ me->SummonCreature(NPC_SIF, 2147.86f, -301.2f, 438.246f, 2.488f);
+ }
+
+ void CloseDoors()
+ {
+ GameObject* go;
+ if ((go = GetThorimObject(DATA_THORIM_LEVER)))
+ {
+ go->ReplaceAllGameObjectFlags((GameObjectFlags)48);
+ go->SetGoState(GO_STATE_READY);
+ }
+ if ((go = GetThorimObject(DATA_THORIM_FIRST_DOORS)))
+ go->SetGoState(GO_STATE_READY);
+
+ if ((go = GetThorimObject(DATA_THORIM_SECOND_DOORS)))
+ go->SetGoState(GO_STATE_READY);
+
+ if ((go = GetThorimObject(DATA_THORIM_FENCE)))
+ go->SetGoState(GO_STATE_ACTIVE);
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ DisableThorim(false);
+ CreatureAI::EnterEvadeMode(why);
+ }
+
+ void Reset() override
+ {
+ if (m_pInstance && !_encounterFinished)
+ m_pInstance->SetData(TYPE_THORIM, NOT_STARTED);
+
+ events.Reset();
+ events.SetPhase(0);
+ summons.DespawnAll();
+
+ _trashCounter = 0;
+ _isAlly = true;
+ _isHitAllowed = false;
+ _spawnCommoners = false;
+ _hardMode = false;
+ _isArenaEmpty = false;
+ _hitByLightning = false;
+
+ if (Player* t = SelectTargetFromPlayerList(1000))
+ if (t->GetTeamId() == TEAM_HORDE)
+ _isAlly = false;
+
+ SpawnAllNPCs();
+
+ CloseDoors();
+ DisableThorim(false);
+ }
+
+ uint32 GetData(uint32 param) const override
+ {
+ if (param == DATA_HIT_BY_LIGHTNING)
+ return !_hitByLightning;
+ if (param == DATA_LOSE_YOUR_ILLUSION)
+ return _hardMode;
+
+ return 0;
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_START_TRASH_DIED)
+ {
+ _trashCounter++;
+ // activate levar
+ if (_trashCounter >= 6)
+ {
+ if (GameObject* go = GetThorimObject(DATA_THORIM_LEVER))
+ go->RemoveGameObjectFlag((GameObjectFlags)48);
+
+ events.ScheduleEvent(EVENT_THORIM_AGGRO, 0ms);
+ events.SetPhase(EVENT_PHASE_START);
+ events.ScheduleEvent(EVENT_THORIM_START_PHASE1, 20s);
+ _trashCounter = 0;
+ }
+ }
+ else if (param == ACTION_ALLOW_HIT)
+ _isHitAllowed = true;
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_SLAY);
+ }
+
+ void JustReachedHome() override { me->setActive(false); }
+
+ void JustEngagedWith(Unit*) override
+ {
+ if (m_pInstance && !_encounterFinished)
+ m_pInstance->SetData(TYPE_THORIM, IN_PROGRESS);
+ me->setActive(true);
+ DisableThorim(true);
+ me->CastSpell(me, SPELL_SHEATH_OF_LIGHTNING, true);
+ //me->CastSpell(me, SPELL_TOUCH_OF_DOMINION, true);
+ }
+
+ void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (who && _isHitAllowed && who->GetPositionZ() > 430 && who->GetTypeId() == TYPEID_PLAYER)
+ {
+ _isHitAllowed = false;
+ DisableThorim(false);
+
+ events.SetPhase(EVENT_PHASE_RING);
+ events.ScheduleEvent(EVENT_THORIM_UNBALANCING_STRIKE, 8s, 0, EVENT_PHASE_RING);
+ events.ScheduleEvent(EVENT_THORIM_LIGHTNING_CHARGE, 12s + 500ms, 0, EVENT_PHASE_RING);
+ events.ScheduleEvent(EVENT_THORIM_CHAIN_LIGHTNING, 13s, 0, EVENT_PHASE_RING);
+ events.ScheduleEvent(EVENT_THORIM_BERSERK, 5min, 0, EVENT_PHASE_RING);
+
+ me->GetMotionMaster()->MoveChase(me->GetVictim());
+ me->GetMotionMaster()->MoveJump(Middle.GetPositionX(), Middle.GetPositionY(), Middle.GetPositionZ(), 20, 20);
+ me->RemoveAura(SPELL_SHEATH_OF_LIGHTNING);
+
+ Talk(SAY_JUMPDOWN);
+
+ // Hard Mode
+ if (!me->HasAura(62565 /*TOUCH OF DOMINION TRIGGER*/))
+ {
+ if (m_pInstance)
+ m_pInstance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 64980 /*SIFFED ACHIEVEMENT*/);
+
+ _hardMode = true;
+ EntryCheckPredicate pred(NPC_SIF);
+ summons.DoAction(ACTION_SIF_JOIN_FIGHT, pred);
+ }
+
+ DoResetThreatList();
+ if (Player* player = GetArenaPlayer())
+ me->AddThreat(player, 1000.0f);
+ }
+
+ if (damage >= me->GetHealth())
+ {
+ damage = 0;
+ if (!_encounterFinished)
+ {
+ _encounterFinished = true;
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
+ me->SetFaction(FACTION_FRIENDLY);
+ me->SetHealth(me->GetMaxHealth());
+ me->CombatStop();
+ me->RemoveAllAuras();
+ events.Reset();
+ DisableThorim(true);
+
+ Talk(SAY_DEATH);
+
+ events.SetPhase(EVENT_PHASE_OUTRO);
+ events.ScheduleEvent(EVENT_THORIM_OUTRO1, 2s, 0, EVENT_PHASE_OUTRO);
+
+ GameObject* go = nullptr;
+ if ((go = GetThorimObject(DATA_THORIM_FENCE)))
+ go->SetGoState(GO_STATE_ACTIVE);
+
+ uint32 chestId = me->GetMap()->Is25ManRaid() ? GO_THORIM_CHEST_HERO : GO_THORIM_CHEST;
+ if (_hardMode)
+ chestId += 1; // hard mode offset
+
+ if ((go = me->SummonGameObject(chestId, 2134.73f, -286.32f, 419.51f, 4.65f, 0, 0, 0, 0, 0)))
+ {
+ go->ReplaceAllGameObjectFlags((GameObjectFlags)0);
+ go->SetLootRecipient(me->GetMap());
+ }
+
+ // Defeat credit
+ if (m_pInstance)
+ {
+ me->CastSpell(me, 64985, true); // credit
+ m_pInstance->SetData(TYPE_THORIM, DONE);
+ }
+ }
+ }
+ }
+
+ void SpawnArenaNPCs()
+ {
+ Creature* cr;
+ uint8 rnd;
+ if (_spawnCommoners || urand(0, 2))
+ _spawnCommoners = !_spawnCommoners;
+
+ for (uint8 i = 0; i < (_spawnCommoners ? 7 : 2); ++i)
+ {
+ rnd = urand(0, 13);
+ if ((cr = me->SummonCreature((_spawnCommoners ? NPC_DARK_RUNE_COMMONER : RollTable[urand(0, 2)]), ArenaNPCs[rnd], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000)))
+ cr->GetMotionMaster()->MoveJump(
+ Middle.GetPositionX() + urand(19, 24) * cos(Middle.GetAngle(cr)),
+ Middle.GetPositionY() + urand(19, 24) * std::sin(Middle.GetAngle(cr)),
+ Middle.GetPositionZ(), 20, 20);
+ }
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_LIGHTNING_ORB_CHARGER)
+ {
+ me->SetOrientation(me->GetAngle(caster));
+ me->CastSpell(caster, SPELL_LIGHTNING_CHARGE_DAMAGE, true);
+ me->CastSpell(me, SPELL_LIGHTNING_CHARGE_BUFF, true);
+ events.RescheduleEvent(EVENT_THORIM_LIGHTNING_CHARGE, 10s, 0, EVENT_PHASE_RING);
+ }
+ }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_LIGHTNING_CHARGE_DAMAGE && target->GetTypeId() == TYPEID_PLAYER)
+ _hitByLightning = true;
+ }
+
+ Player* GetArenaPlayer()
+ {
+ Map::PlayerList const& pList = me->GetMap()->GetPlayers();
+ for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
+ if (Player* p = itr->GetSource())
+ if (p->GetPositionX() > 2085 && p->GetPositionX() < 2185 && p->GetPositionY() < -214 && p->GetPositionY() > -305 && p->IsAlive() && p->GetPositionZ() < 425)
+ return p;
+ return nullptr;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!_encounterFinished && !UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_THORIM_AGGRO:
+ Talk(SAY_AGGRO_1);
+ events.ScheduleEvent(EVENT_THORIM_AGGRO2, 9s);
+
+ if (GameObject* go = GetThorimObject(DATA_THORIM_FENCE))
+ go->SetGoState(GO_STATE_READY);
+
+ break;
+ case EVENT_THORIM_AGGRO2:
+ {
+ Talk(SAY_AGGRO_2);
+
+ EntryCheckPredicate pred(NPC_SIF);
+ summons.DoAction(ACTION_SIF_START_TALK, pred);
+ break;
+ }
+ case EVENT_THORIM_START_PHASE1:
+ {
+ events.ScheduleEvent(EVENT_THORIM_STORMHAMMER, 8s, 0, EVENT_PHASE_START);
+ events.ScheduleEvent(EVENT_THORIM_CHARGE_ORB, 14s, 0, EVENT_PHASE_START);
+ events.ScheduleEvent(EVENT_THORIM_FILL_ARENA, 0ms, 0, EVENT_PHASE_START);
+ events.ScheduleEvent(EVENT_THORIM_LIGHTNING_ORB, 5s, 0, EVENT_PHASE_START); // checked every 5 secs if there are players on arena
+ events.ScheduleEvent(EVENT_THORIM_NOT_REACH_IN_TIME, 5min, 0, EVENT_PHASE_START);
+
+ EntryCheckPredicate pred(NPC_SIF);
+ summons.DoAction(ACTION_SIF_START_DOMINION, pred);
+ break;
+ }
+ case EVENT_THORIM_STORMHAMMER:
+ me->CastCustomSpell(SPELL_STORMHAMMER, SPELLVALUE_MAX_TARGETS, 1, me->GetVictim(), false);
+ events.Repeat(16s);
+ break;
+ case EVENT_THORIM_CHARGE_ORB:
+ me->CastCustomSpell(SPELL_CHARGE_ORB, SPELLVALUE_MAX_TARGETS, 1, me, false);
+ events.Repeat(16s);
+ break;
+ case EVENT_THORIM_LIGHTNING_ORB:
+ {
+ if (GetArenaPlayer())
+ {
+ // Player found, repeat and return
+ events.Repeat(5s);
+ return;
+ }
+
+ // No players found
+ Talk(SAY_WIPE);
+ me->SummonCreature(NPC_LIGHTNING_ORB, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
+
+ _isArenaEmpty = true;
+ events.CancelEvent(EVENT_THORIM_NOT_REACH_IN_TIME);
+ break;
+ }
+ case EVENT_THORIM_NOT_REACH_IN_TIME:
+ _isArenaEmpty = true;
+ events.CancelEvent(EVENT_THORIM_LIGHTNING_ORB);
+ me->CastSpell(me, SPELL_BERSERK_FRIENDS, true);
+ me->SummonCreature(NPC_LIGHTNING_ORB, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
+ break;
+ case EVENT_THORIM_FILL_ARENA:
+ SpawnArenaNPCs();
+ events.Repeat(10s);
+ break;
+ case EVENT_THORIM_UNBALANCING_STRIKE:
+ me->CastSpell(me->GetVictim(), SPELL_UNBALANCING_STRIKE, false);
+ events.Repeat(20s);
+ break;
+ case EVENT_THORIM_LIGHTNING_CHARGE:
+ me->CastSpell(me, SPELL_LIGHTNING_PILLAR_P2, true);
+ break;
+ case EVENT_THORIM_CHAIN_LIGHTNING:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target, SPELL_CHAIN_LIGHTNING, false);
+ events.Repeat(15s);
+ break;
+ case EVENT_THORIM_BERSERK:
+ me->CastSpell(me, SPELL_BERSERK, true);
+ Talk(SAY_BERSERK);
+ break;
+ case EVENT_THORIM_OUTRO1:
+ if (_hardMode)
+ {
+ Talk(SAY_END_HARD_1);
+ events.ScheduleEvent(EVENT_THORIM_OUTRO2, 5s, 0, 3);
+ EntryCheckPredicate pred(NPC_SIF);
+ summons.DoAction(ACTION_SIF_TRANSFORM, pred);
+ }
+ else
+ {
+ Talk(SAY_END_NORMAL_1);
+ events.ScheduleEvent(EVENT_THORIM_OUTRO2, 9s, 0, 3);
+ }
+ break;
+ case EVENT_THORIM_OUTRO2:
+ if (_hardMode)
+ {
+ Talk(SAY_END_HARD_2);
+ events.ScheduleEvent(EVENT_THORIM_OUTRO3, 12s, 0, 3);
+ }
+ else
+ {
+ Talk(SAY_END_NORMAL_2);
+ events.ScheduleEvent(EVENT_THORIM_OUTRO3, 10s, 0, 3);
+ }
+ break;
+ case EVENT_THORIM_OUTRO3:
+ if (_hardMode)
+ {
+ Talk(SAY_END_HARD_3);
+ }
+ else
+ {
+ Talk(SAY_END_NORMAL_3);
+ }
+
+ // Defeat credit
+ if (m_pInstance)
+ m_pInstance->SetData(TYPE_THORIM, DONE);
+
+ me->DespawnOrUnsummon(8000);
+ break;
+ }
+
+ if (!_encounterFinished)
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_thorim_sif : public CreatureScript
+{
+public:
+ boss_thorim_sif() : CreatureScript("boss_thorim_sif") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorim_sifAI : public ScriptedAI
+ {
+ boss_thorim_sifAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ void MoveInLineOfSight(Unit*) override {}
+ void AttackStart(Unit*) override {}
+
+ bool _allowCast;
+ EventMap events;
+
+ void Reset() override
+ {
+ events.Reset();
+ me->SetReactState(REACT_PASSIVE);
+ _allowCast = false;
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_SIF_START_TALK)
+ events.ScheduleEvent(EVENT_SIF_START_TALK, 9s);
+ else if (param == ACTION_SIF_START_DOMINION)
+ {
+ if (me->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM)))
+ me->CastSpell(cr, SPELL_TOUCH_OF_DOMINION, false);
+
+ events.ScheduleEvent(EVENT_SIF_FINISH_DOMINION, 150s);
+ }
+ else if (param == ACTION_SIF_JOIN_FIGHT)
+ {
+ me->InterruptNonMeleeSpells(false);
+ events.ScheduleEvent(EVENT_SIF_JOIN_TALK, 9s);
+ events.CancelEvent(EVENT_SIF_START_TALK);
+ events.CancelEvent(EVENT_SIF_FINISH_DOMINION);
+ }
+ else if (param == ACTION_SIF_TRANSFORM)
+ {
+ me->CastSpell(me, SPELL_SIF_TRANSFORM, true);
+ me->DespawnOrUnsummon(5000);
+ events.Reset();
+ _allowCast = false;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_SIF_FINISH_DOMINION:
+ Talk(SAY_SIF_HM_MISSED);
+ me->DespawnOrUnsummon(5000);
+ break;
+ case EVENT_SIF_START_TALK:
+ Talk(SAY_SIF_AGGRO);
+ break;
+ case EVENT_SIF_JOIN_TALK:
+ Talk(SAY_SIF_HM_REACHED);
+ events.ScheduleEvent(EVENT_SIF_FROST_NOVA_START, 1s);
+ events.ScheduleEvent(EVENT_SIF_FROSTBOLT_VALLEY, 11s);
+ events.ScheduleEvent(EVENT_SIF_BLIZZARD, 15s);
+ break;
+ case EVENT_SIF_FROSTBOLT_VALLEY:
+ me->CastSpell(me, SPELL_FROSTBOLT_VALLEY, false);
+ events.Repeat(13s);
+ return;
+ case EVENT_SIF_BLIZZARD:
+ me->SummonCreature(NPC_SIF_BLIZZARD, 2108.7f, -280.04f, 419.42f, 0, TEMPSUMMON_TIMED_DESPAWN, 30000);
+ events.Repeat(30s);
+ return;
+ case EVENT_SIF_FROST_NOVA_START:
+ me->NearTeleportTo(2108 + urand(0, 42), -238 - irand(0, 46), 420.02f, me->GetAngle(&Middle));
+ events.Repeat(20s);
+ events.DelayEvents(5s);
+ events.ScheduleEvent(EVENT_SIF_FROST_NOVA_CAST, 2500ms);
+ _allowCast = false;
+ return;
+ case EVENT_SIF_FROST_NOVA_CAST:
+ _allowCast = true;
+ me->CastSpell(me, SPELL_FROST_NOVA, false);
+ return;
+ }
+
+ // has casting check before event select (return in events)
+ if (_allowCast)
+ if (Player* target = SelectTargetFromPlayerList(70))
+ {
+ me->CastSpell(target, SPELL_FROSTBOLT, false);
+ me->StopMoving();
+ }
+ }
+ };
+};
+
+class boss_thorim_lightning_orb : public CreatureScript
+{
+public:
+ boss_thorim_lightning_orb() : CreatureScript("boss_thorim_lightning_orb") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorim_lightning_orbAI : public npc_escortAI
+ {
+ boss_thorim_lightning_orbAI(Creature* pCreature) : npc_escortAI(pCreature)
+ {
+ InitWaypoint();
+ Reset();
+ Start(false, true);
+ }
+
+ uint32 Timer;
+
+ void EnterEvadeMode(EvadeReason /*why*/) override {}
+ void MoveInLineOfSight(Unit*) override {}
+ void AttackStart(Unit*) override {}
+
+ void InitWaypoint()
+ {
+ AddWaypoint(1, 2135, -304, 438.24f, 0);
+ AddWaypoint(2, 2132, -441, 438.24f, 0);
+ AddWaypoint(3, 2167, -442, 438.24f, 0);
+ AddWaypoint(4, 2227, -432, 412.18f, 0);
+ AddWaypoint(5, 2227, -263, 412.17f, 0);
+ AddWaypoint(6, 2179, -262, 414.7f, 0);
+ AddWaypoint(7, 2169, -261, 419.3f, 0);
+ AddWaypoint(8, 2110, -251, 419.42f, 0);
+ }
+
+ void Reset() override
+ {
+ me->CastSpell(me, SPELL_LIGHTNING_DESTRUCTION, true);
+ }
+
+ void WaypointReached(uint32 /*point*/) override
+ {
+ }
+ };
+};
+
+class boss_thorim_trap : public CreatureScript
+{
+public:
+ boss_thorim_trap() : CreatureScript("boss_thorim_trap") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorim_trapAI : public NullCreatureAI
+ {
+ boss_thorim_trapAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
+
+ uint32 _checkTimer;
+
+ void Reset() override { _checkTimer = 1; }
+ void UpdateAI(uint32 diff) override
+ {
+ if (_checkTimer)
+ {
+ _checkTimer += diff;
+ if ((_checkTimer >= 1000 && _checkTimer < 10000) || _checkTimer >= 60000)
+ {
+ if (me->SelectNearbyTarget(nullptr, 12.0f))
+ {
+ me->CastSpell(me, SPELL_LIGHTNING_FIELD, true);
+ me->CastSpell(me, (me->GetEntry() == 33054 /*NPC_THORIM_TRAP_BUNNY*/ ? SPELL_PARALYTIC_FIELD_FIRST : SPELL_PARALYTIC_FIELD_SECOND), true);
+ _checkTimer = 10000;
+ return;
+ }
+ _checkTimer = 1;
+ }
+ }
+ }
+ };
+};
+
+class boss_thorim_sif_blizzard : public CreatureScript
+{
+public:
+ boss_thorim_sif_blizzard() : CreatureScript("boss_thorim_sif_blizzard") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorim_sif_blizzardAI : public npc_escortAI
+ {
+ boss_thorim_sif_blizzardAI(Creature* pCreature) : npc_escortAI(pCreature)
+ {
+ InitWaypoint();
+ Reset();
+ Start(false, true);
+ SetDespawnAtEnd(false);
+ }
+
+ void MoveInLineOfSight(Unit* /*who*/) override {}
+ void JustEngagedWith(Unit* /*who*/) override {}
+ void AttackStart(Unit* /*who*/) override {}
+
+ void InitWaypoint()
+ {
+ AddWaypoint(1, 2104.6f, -268.5f, 419.4f, 0);
+ AddWaypoint(2, 2104.3f, -256.3f, 419.4f, 0);
+ AddWaypoint(3, 2109.3f, -246.4f, 419.4f, 0);
+ AddWaypoint(4, 2117.9f, -238.6f, 419.4f, 0);
+ AddWaypoint(5, 2128.8f, -232.1f, 419.4f, 0);
+ AddWaypoint(6, 2151.9f, -237.5f, 419.4f, 0);
+ AddWaypoint(7, 2164.9f, -256.3f, 419.4f, 0);
+ AddWaypoint(8, 2161.5f, -280.0f, 419.4f, 0);
+ }
+
+ void Reset() override
+ {
+ me->SetSpeed(MOVE_RUN, 1);
+ me->SetSpeed(MOVE_WALK, 1);
+ me->CastSpell(me, RAID_MODE(SPELL_BLIZZARD_10, SPELL_BLIZZARD_25), true);
+ }
+
+ void WaypointReached(uint32 /*point*/) override
+ {
+ }
+ };
+};
+
+class boss_thorim_pillar : public CreatureScript
+{
+public:
+ boss_thorim_pillar() : CreatureScript("boss_thorim_pillar") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorim_pillarAI : public NullCreatureAI
+ {
+ boss_thorim_pillarAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
+
+ uint32 _resetTimer;
+
+ void Reset() override
+ {
+ _resetTimer = 0;
+ me->SetControlled(true, UNIT_STATE_STUNNED);
+ me->SetDisableGravity(true);
+ }
+
+ void SpellHit(Unit*, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_CHARGE_ORB)
+ me->CastSpell(me, SPELL_LIGHTNING_PILLAR_P1, true);
+ else if (spellInfo->Id == SPELL_LIGHTNING_PILLAR_P2)
+ {
+ if (Creature* cr = me->FindNearestCreature(NPC_THUNDER_ORB, 100))
+ cr->CastSpell(cr, SPELL_LIGHTNING_ORB_VISUAL, true);
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _resetTimer += diff;
+ if (_resetTimer >= 10000)
+ Reset(); // _resetTimer set to 0
+ }
+ };
+};
+
+class boss_thorim_start_npcs : public CreatureScript
+{
+public:
+ boss_thorim_start_npcs() : CreatureScript("boss_thorim_start_npcs") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorim_start_npcsAI : public ScriptedAI
+ {
+ boss_thorim_start_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ EventMap events;
+ bool _isCaster;
+ bool _playerAttack;
+
+ void Reset() override
+ {
+ events.Reset();
+ _isCaster = (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I);
+ _playerAttack = false;
+ if (me->GetEntry() != NPC_JORMUNGAR_BEHEMOT)
+ if (Creature* cr = me->FindNearestCreature(NPC_JORMUNGAR_BEHEMOT, 30.0f))
+ AttackStart(cr);
+ }
+
+ void DamageTaken(Unit* who, uint32&, DamageEffectType, SpellSchoolMask) override
+ {
+ if (!_playerAttack && who && (who->GetTypeId() == TYPEID_PLAYER || who->GetOwnerGUID().IsPlayer()))
+ {
+ if (me->GetInstanceScript())
+ if (Creature* thorim = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM)))
+ {
+ if (!thorim->IsInCombat())
+ {
+ thorim->SetInCombatWithZone();
+ thorim->AI()->AttackStart(who);
+ }
+ }
+ _playerAttack = true;
+ me->GetThreatMgr().ResetAllThreat();
+ me->CallForHelp(40.0f);
+ AttackStart(who);
+ }
+
+ if (!_playerAttack && me->HealthBelowPct(60))
+ me->SetHealth(me->GetMaxHealth());
+ }
+
+ void JustDied(Unit*) override
+ {
+ if (me->GetInstanceScript())
+ if (Creature* thorim = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM)))
+ thorim->AI()->DoAction(ACTION_START_TRASH_DIED);
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ if (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I)
+ {
+ events.ScheduleEvent(EVENT_DR_ACOLYTE_GH, 10s);
+ events.ScheduleEvent(EVENT_DR_ACOLYTE_HS, 5s);
+ events.ScheduleEvent(EVENT_DR_ACOLYTE_R, 7s);
+ }
+ else if (me->GetEntry() == NPC_CAPTURED_MERCENARY_SOLDIER_ALLY || me->GetEntry() == NPC_CAPTURED_MERCENARY_SOLDIER_HORDE)
+ {
+ events.ScheduleEvent(EVENT_CM_SOLDIER_BS, 9s);
+ events.ScheduleEvent(EVENT_CM_SOLDIER_WC, 5s);
+ events.ScheduleEvent(EVENT_CM_SOLDIER_S, 0ms);
+ }
+ else if (me->GetEntry() == NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY || me->GetEntry() == NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE)
+ {
+ events.ScheduleEvent(EVENT_CM_CAPTAIN_D, 9s);
+ events.ScheduleEvent(EVENT_CM_CAPTAIN_HC, 5s);
+ }
+ else if (me->GetEntry() == NPC_JORMUNGAR_BEHEMOT)
+ {
+ events.ScheduleEvent(EVENT_JB_ACID_BREATH, 12s);
+ events.ScheduleEvent(EVENT_JB_SWEEP, 5s);
+ }
+
+ me->CallForHelp(10);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_DR_ACOLYTE_GH:
+ if (HealthBelowPct(60))
+ me->CastSpell(me, SPELL_GREATER_HEAL, false);
+ else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 20))
+ me->CastSpell(target, SPELL_GREATER_HEAL, false);
+ events.Repeat(10s);
+ break;
+ case EVENT_DR_ACOLYTE_HS:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target, SPELL_HOLY_SMITE, false);
+ events.Repeat(1600ms);
+ break;
+ case EVENT_DR_ACOLYTE_R:
+ if (HealthBelowPct(75) && !me->HasAura(SPELL_RENEW))
+ me->CastSpell(me, SPELL_GREATER_HEAL, false);
+ else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 10))
+ me->CastSpell(target, SPELL_RENEW, false);
+ events.Repeat(7s);
+ break;
+ case EVENT_CM_SOLDIER_BS:
+ me->CastSpell(me->GetVictim(), SPELL_BARBED_SHOT, false);
+ events.Repeat(9s);
+ break;
+ case EVENT_CM_SOLDIER_WC:
+ me->CastSpell(me->GetVictim(), SPELL_WING_CLIP, false);
+ events.Repeat(5s);
+ break;
+ case EVENT_CM_SOLDIER_S:
+ if (me->GetDistance(me->GetVictim()) > 8)
+ me->CastSpell(me->GetVictim(), SPELL_SHOOT, false);
+
+ events.Repeat(1500ms);
+ break;
+ case EVENT_CM_CAPTAIN_D:
+ me->CastSpell(me->GetVictim(), SPELL_DEVASTATE, false);
+ events.Repeat(9s);
+ break;
+ case EVENT_CM_CAPTAIN_HC:
+ me->CastSpell(me->GetVictim(), SPELL_HEROIC_STRIKE, false);
+ events.Repeat(5s);
+ break;
+ case EVENT_JB_ACID_BREATH:
+ me->CastSpell(me->GetVictim(), SPELL_ACID_BREATH, false);
+ events.Repeat(12s);
+ break;
+ case EVENT_JB_SWEEP:
+ me->CastSpell(me->GetVictim(), SPELL_SWEEP, false);
+ events.Repeat(5s);
+ break;
+ }
+
+ if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10))
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_thorim_gauntlet_npcs : public CreatureScript
+{
+public:
+ boss_thorim_gauntlet_npcs() : CreatureScript("boss_thorim_gauntlet_npcs") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorim_gauntlet_npcsAI : public ScriptedAI
+ {
+ boss_thorim_gauntlet_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ EventMap events;
+ bool _isCaster;
+
+ void Reset() override
+ {
+ events.Reset();
+ _isCaster = (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_G);
+ }
+
+ void JustEngagedWith(Unit* /*who*/) override
+ {
+ if (me->GetEntry() == NPC_IRON_RING_GUARD)
+ {
+ events.ScheduleEvent(EVENT_IR_GUARD_IMPALE, 12s);
+ events.ScheduleEvent(EVENT_IR_GUARD_WHIRL, 5s);
+ }
+ else if (me->GetEntry() == NPC_DARK_RUNE_ACOLYTE_I)
+ {
+ events.ScheduleEvent(EVENT_DR_ACOLYTE_GH, 10s);
+ events.ScheduleEvent(EVENT_DR_ACOLYTE_HS, 5s);
+ events.ScheduleEvent(EVENT_DR_ACOLYTE_R, 7s);
+ }
+ else if (me->GetEntry() == NPC_IRON_HONOR_GUARD)
+ {
+ events.ScheduleEvent(EVENT_IH_GUARD_CLEAVE, 6s);
+ events.ScheduleEvent(EVENT_IH_GUARD_HAMSTRING, 9s);
+ events.ScheduleEvent(EVENT_IH_GUARD_SHIELD_SMASH, 15s);
+
+ if (Creature* runeGiant = me->FindNearestCreature(NPC_ANCIENT_RUNE_GIANT, 200.0f))
+ runeGiant->AI()->DoAction(ACTION_IRON_HONOR_DIED);
+ }
+
+ me->CallForHelp(25);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_IR_GUARD_IMPALE:
+ me->CastSpell(me->GetVictim(), SPELL_IMPALE, false);
+ events.Repeat(12s);
+ break;
+ case EVENT_IR_GUARD_WHIRL:
+ me->CastSpell(me->GetVictim(), SPELL_WHIRLING_TRIP, false);
+ events.Repeat(5s);
+ break;
+ case EVENT_DR_ACOLYTE_GH:
+ if (HealthBelowPct(60))
+ me->CastSpell(me, SPELL_GREATER_HEAL, false);
+ else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 20))
+ me->CastSpell(target, SPELL_GREATER_HEAL, false);
+ events.Repeat(10s);
+ break;
+ case EVENT_DR_ACOLYTE_HS:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target, SPELL_HOLY_SMITE, false);
+ events.Repeat(1600ms);
+ break;
+ case EVENT_DR_ACOLYTE_R:
+ if (HealthBelowPct(75) && !me->HasAura(SPELL_RENEW))
+ me->CastSpell(me, SPELL_GREATER_HEAL, false);
+ else if (Unit* target = DoSelectLowestHpFriendly(60.0f, 10))
+ me->CastSpell(target, SPELL_RENEW, false);
+ events.Repeat(7s);
+ break;
+ case EVENT_IH_GUARD_CLEAVE:
+ me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false);
+ events.Repeat(6s);
+ break;
+ case EVENT_IH_GUARD_HAMSTRING:
+ me->CastSpell(me->GetVictim(), SPELL_HAMSTRING, false);
+ events.Repeat(9s);
+ break;
+ case EVENT_IH_GUARD_SHIELD_SMASH:
+ me->CastSpell(me->GetVictim(), SPELL_SHIELD_SMASH, false);
+ events.Repeat(15s);
+ break;
+ }
+
+ if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10))
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_thorim_runic_colossus : public CreatureScript
+{
+public:
+ boss_thorim_runic_colossus() : CreatureScript("boss_thorim_runic_colossus") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorim_runic_colossusAI : public ScriptedAI
+ {
+ boss_thorim_runic_colossusAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ EventMap events;
+ bool _leftHand;
+ bool _checkTarget;
+ float _nextTriggerPos;
+ ObjectGuid _triggerLeftGUID[2], _triggerRightGUID[2];
+
+ void Reset() override
+ {
+ _nextTriggerPos = 0.0f;
+ _leftHand = false;
+ _checkTarget = false;
+ events.Reset();
+ events.ScheduleEvent(EVENT_RC_RUNIC_SMASH, 0ms);
+ Creature* c;
+
+ if ((c = me->SummonCreature(33140, 2221, -385, me->GetPositionZ())))
+ _triggerRightGUID[0] = c->GetGUID();
+ if ((c = me->SummonCreature(33140, 2210, -385, me->GetPositionZ())))
+ _triggerRightGUID[1] = c->GetGUID();
+
+ if ((c = me->SummonCreature(33141, 2235, -385, me->GetPositionZ())))
+ _triggerLeftGUID[0] = c->GetGUID();
+ if ((c = me->SummonCreature(33141, 2246, -385, me->GetPositionZ())))
+ _triggerLeftGUID[1] = c->GetGUID();
+ }
+
+ void JustDied(Unit*) override
+ {
+ if (me->GetInstanceScript())
+ {
+ if (GameObject* go = ObjectAccessor::GetGameObject(*me, me->GetInstanceScript()->GetGuidData(DATA_THORIM_FIRST_DOORS)))
+ go->SetGoState(GO_STATE_ACTIVE);
+
+ if (Creature* cr = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_THORIM)))
+ cr->AI()->Talk(SAY_SPECIAL_2);
+ }
+ }
+
+ void JustEngagedWith(Unit*) override
+ {
+ events.CancelEvent(EVENT_RC_RUNIC_SMASH);
+ events.ScheduleEvent(EVENT_RC_RUNIC_BARRIER, 10s);
+ events.ScheduleEvent(EVENT_RC_SMASH, 18s);
+ events.ScheduleEvent(EVENT_RC_CHARGE, 15s);
+
+ me->InterruptNonMeleeSpells(false);
+ _checkTarget = true;
+ }
+
+ void SpellHit(Unit*, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_RUNIC_SMASH_LEFT || spellInfo->Id == SPELL_RUNIC_SMASH_RIGHT)
+ {
+ _leftHand = spellInfo->Id == SPELL_RUNIC_SMASH_LEFT;
+ events.RescheduleEvent(EVENT_RC_RUNIC_SMASH_TRIGGER, 1s);
+ }
+ }
+
+ void RunRunicSmash(bool cast)
+ {
+ if (Creature* cr = ObjectAccessor::GetCreature(*me, _leftHand ? _triggerLeftGUID[0] : _triggerRightGUID[0]) )
+ {
+ if (cast)
+ cr->CastSpell(cr, SPELL_RUNIC_SMASH_DAMAGE, true);
+ cr->SetPosition(_leftHand ? 2235.0f : 2221.0f, _nextTriggerPos, cr->GetPositionZ(), 0.0f);
+ cr->StopMovingOnCurrentPos();
+ }
+ if( Creature* cr = ObjectAccessor::GetCreature(*me, _leftHand ? _triggerLeftGUID[1] : _triggerRightGUID[1]) )
+ {
+ if (cast)
+ cr->CastSpell(cr, SPELL_RUNIC_SMASH_DAMAGE, true);
+ cr->SetPosition(_leftHand ? 2246.0f : 2210.0f, _nextTriggerPos, cr->GetPositionZ(), 0.0f);
+ cr->StopMovingOnCurrentPos();
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_checkTarget && !UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_RC_RUNIC_SMASH_TRIGGER:
+ _nextTriggerPos += 16.0f;
+ if (_nextTriggerPos <= -260.0f)
+ {
+ events.RescheduleEvent(EVENT_RC_RUNIC_SMASH_TRIGGER, 500ms);
+ }
+
+ RunRunicSmash(true);
+ break;
+ case EVENT_RC_RUNIC_SMASH:
+ if (urand(0, 1))
+ me->CastSpell(me, SPELL_RUNIC_SMASH_LEFT, false);
+ else
+ me->CastSpell(me, SPELL_RUNIC_SMASH_RIGHT, false);
+
+ _nextTriggerPos = -385.0f;
+ RunRunicSmash(false);
+ events.Repeat(11s);
+ break;
+ case EVENT_RC_RUNIC_BARRIER:
+ me->CastSpell(me, SPELL_RUNIC_BARRIER, false);
+ Talk(SAY_COLOSSUS_RUNIC_BARRIER);
+ events.Repeat(20s);
+ break;
+ case EVENT_RC_SMASH:
+ me->CastSpell(me->GetVictim(), SPELL_SMASH, false);
+ events.Repeat(10s);
+ break;
+ case EVENT_RC_CHARGE:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target, SPELL_CHARGE, false);
+ events.Repeat(15s);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_thorim_ancient_rune_giant : public CreatureScript
+{
+public:
+ boss_thorim_ancient_rune_giant() : CreatureScript("boss_thorim_ancient_rune_giant") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorim_ancient_rune_giantAI : public ScriptedAI
+ {
+ boss_thorim_ancient_rune_giantAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ EventMap events;
+ bool _isInCombat;
+
+ void Reset() override
+ {
+ _isInCombat = false;
+ events.Reset();
+ }
+
+ void JustEngagedWith(Unit*) override
+ {
+ _isInCombat = true;
+ events.CancelEvent(EVENT_ARG_SPAWN);
+ events.ScheduleEvent(EVENT_ARG_RD, 12s);
+ events.ScheduleEvent(EVENT_ARG_STOMP, 8s);
+
+ me->CastSpell(me, SPELL_RUNIC_FORTIFICATION, false);
+ Talk(SAY_GIANT_RUNIC_MIGHT);
+ }
+
+ void JustDied(Unit*) override
+ {
+ if (InstanceScript* pInstance = me->GetInstanceScript())
+ {
+ if (GameObject* go = ObjectAccessor::GetGameObject(*me, pInstance->GetGuidData(DATA_THORIM_SECOND_DOORS)))
+ go->SetGoState(GO_STATE_ACTIVE);
+
+ if (Creature* thorim = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(TYPE_THORIM)))
+ thorim->AI()->DoAction(ACTION_ALLOW_HIT);
+ }
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_IRON_HONOR_DIED)
+ events.RescheduleEvent(EVENT_ARG_SPAWN, 20s);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_isInCombat && !UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_ARG_RD:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target, SPELL_RUNE_DETONATION, false);
+ events.Repeat(12s);
+ break;
+ case EVENT_ARG_STOMP:
+ me->CastSpell(me->GetVictim(), SPELL_STOMP, false);
+ events.Repeat(8s);
+ break;
+ case EVENT_ARG_SPAWN:
+ if (Creature* cr = me->SummonCreature(NPC_IRON_HONOR_GUARD, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000))
+ if (Unit* target = SelectTargetFromPlayerList(150.0f))
+ cr->AI()->AttackStart(target);
+ events.Repeat(10s);
+ break;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class boss_thorim_arena_npcs : public CreatureScript
+{
+public:
+ boss_thorim_arena_npcs() : CreatureScript("boss_thorim_arena_npcs") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_thorim_arena_npcsAI : public ScriptedAI
+ {
+ boss_thorim_arena_npcsAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ EventMap events;
+ bool _isCaster;
+
+ void Reset() override
+ {
+ _isCaster = (me->GetEntry() == NPC_DARK_RUNE_EVOKER);
+ events.Reset();
+ if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER)
+ me->CastSpell(me, SPELL_AURA_OF_CELERITY, true);
+ }
+
+ void JustEngagedWith(Unit*) override
+ {
+ if (me->GetEntry() == NPC_DARK_RUNE_WARBRINGER)
+ {
+ events.ScheduleEvent(EVENT_DR_WARBRINGER_RS, 8s);
+ }
+ else if (me->GetEntry() == NPC_DARK_RUNE_EVOKER)
+ {
+ events.ScheduleEvent(EVENT_DR_EVOKER_RL, 2500ms);
+ events.ScheduleEvent(EVENT_DR_EVOKER_RM, 4s);
+ events.ScheduleEvent(EVENT_DR_EVOKER_RS, 10s);
+ }
+ else if (me->GetEntry() == NPC_DARK_RUNE_CHAMPION)
+ {
+ events.ScheduleEvent(EVENT_DR_CHAMPION_WH, 6s);
+ events.ScheduleEvent(EVENT_DR_CHAMPION_CH, 12s);
+ events.ScheduleEvent(EVENT_DR_CHAMPION_MS, 8s);
+ }
+ else if (me->GetEntry() == NPC_DARK_RUNE_COMMONER)
+ {
+ events.ScheduleEvent(EVENT_DR_COMMONER_LB, 5s);
+ events.ScheduleEvent(EVENT_DR_COMMONER_PM, 6s);
+ }
+ }
+
+ bool CanAIAttack(Unit const* target) const override
+ {
+ return target->GetPositionX() < 2180 && target->GetPositionZ() < 425;
+ }
+
+ bool SelectT()
+ {
+ Player* target = nullptr;
+ Map::PlayerList const& pList = me->GetMap()->GetPlayers();
+ uint8 num = urand(0, pList.getSize() - 1);
+ uint8 count = 0;
+ for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr, ++count)
+ {
+ if (itr->GetSource()->GetPositionX() > 2180 || !itr->GetSource()->IsAlive() || itr->GetSource()->GetPositionZ() > 425)
+ continue;
+
+ if (count <= num || !target)
+ target = itr->GetSource();
+ else
+ break;
+ }
+
+ if (target)
+ {
+ AttackStart(target);
+ me->AddThreat(target, 500.0f);
+ if (me->GetEntry() == NPC_DARK_RUNE_EVOKER && urand(0, 1))
+ me->CastSpell(me, SPELL_RUNIC_SHIELD, false);
+ else if (me->GetEntry() == NPC_DARK_RUNE_CHAMPION && !urand(0, 2))
+ me->CastSpell(target, SPELL_CHARGE, false);
+ return true;
+ }
+ return false;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() && !SelectT())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch (events.ExecuteEvent())
+ {
+ case EVENT_DR_WARBRINGER_RS:
+ me->CastSpell(me->GetVictim(), SPELL_RUNIC_STRIKE, false);
+ events.Repeat(8s);
+ break;
+ case EVENT_DR_EVOKER_RL:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target, SPELL_RUNIC_LIGHTNING, false);
+ events.Repeat(2500ms);
+ break;
+ case EVENT_DR_EVOKER_RM:
+ if (Unit* target = DoSelectLowestHpFriendly(40.0f, 15))
+ me->CastSpell(target, SPELL_RUNIC_MENDING, false);
+ else
+ me->CastSpell(me, SPELL_RUNIC_MENDING, false);
+ events.Repeat(4s);
+ break;
+ case EVENT_DR_EVOKER_RS:
+ me->CastSpell(me, SPELL_RUNIC_SHIELD, false);
+ events.Repeat(10s);
+ break;
+ case EVENT_DR_CHAMPION_CH:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->CastSpell(target, SPELL_CHARGE, false);
+ events.Repeat(12s);
+ break;
+ case EVENT_DR_CHAMPION_WH:
+ if (!me->HasUnitFlag(UNIT_FLAG_DISARMED))
+ me->CastSpell(me, SPELL_WHIRLWIND, false);
+ events.Repeat(6s);
+ break;
+ case EVENT_DR_CHAMPION_MS:
+ me->CastSpell(me->GetVictim(), SPELL_MORTAL_STRIKE, false);
+ events.Repeat(8s);
+ break;
+ case EVENT_DR_COMMONER_LB:
+ me->CastSpell(me->GetVictim(), SPELL_LOW_BLOW, false);
+ events.Repeat(5s);
+ break;
+ case EVENT_DR_COMMONER_PM:
+ me->CastSpell(me->GetVictim(), SPELL_PUMMEL, false);
+ events.Repeat(6s);
+ break;
+ }
+
+ if (!_isCaster || (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA) < 10))
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class go_thorim_lever : public GameObjectScript
+{
+public:
+ go_thorim_lever() : GameObjectScript("go_thorim_lever") { }
+
+ bool OnGossipHello(Player* pPlayer, GameObject* go) override
+ {
+ if (GameObject* g = pPlayer->FindNearestGameObject(GO_ARENA_LEVER_GATE, 50))
+ g->UseDoorOrButton();
+
+ go->UseDoorOrButton();
+ return true;
+ }
+};
+
+class spell_thorim_lightning_pillar_P2 : public SpellScriptLoader
+{
+public:
+ spell_thorim_lightning_pillar_P2() : SpellScriptLoader("spell_thorim_lightning_pillar_P2") { }
+
+ class spell_thorim_lightning_pillar_P2_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_thorim_lightning_pillar_P2_AuraScript);
+
+ void OnPeriodic(AuraEffect const* aurEff)
+ {
+ PreventDefaultAction();
+ if (Unit* caster = GetCaster())
+ GetUnitOwner()->CastSpell(caster, GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell, true);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_thorim_lightning_pillar_P2_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_thorim_lightning_pillar_P2_AuraScript();
+ }
+};
+
+class spell_thorim_trash_impale : public SpellScriptLoader
+{
+public:
+ spell_thorim_trash_impale() : SpellScriptLoader("spell_thorim_trash_impale") { }
+
+ class spell_thorim_trash_impale_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_thorim_trash_impale_AuraScript);
+
+ void OnPeriodic(AuraEffect const* /*aurEff*/)
+ {
+ // deals damage until target is healed above 90%
+ if (GetUnitOwner()->HealthAbovePct(90))
+ SetDuration(0);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_thorim_trash_impale_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_thorim_trash_impale_AuraScript();
+ }
+};
+
+class achievement_thorim_stand_in_the_lightning : public AchievementCriteriaScript
+{
+public:
+ achievement_thorim_stand_in_the_lightning() : AchievementCriteriaScript("achievement_thorim_stand_in_the_lightning") {}
+
+ bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override
+ {
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*player, instance->GetGuidData(TYPE_THORIM)))
+ return cr->AI()->GetData(DATA_HIT_BY_LIGHTNING);
+
+ return false;
+ }
+};
+
+class achievement_thorim_lose_your_illusion : public AchievementCriteriaScript
+{
+public:
+ achievement_thorim_lose_your_illusion() : AchievementCriteriaScript("achievement_thorim_lose_your_illusion") {}
+
+ bool OnCheck(Player* player, Unit*, uint32 /*criteria_id*/) override
+ {
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (Creature* cr = ObjectAccessor::GetCreature(*player, instance->GetGuidData(TYPE_THORIM)))
+ return cr->AI()->GetData(DATA_LOSE_YOUR_ILLUSION);
+
+ return false;
+ }
+};
+
+#endif
\ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp
index 9168fa4b5e5e4d..cadd8da47bffc2 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp
@@ -15,6 +15,7 @@
* with this program. If not, see .
*/
+#include "boss_xt002.h"
#include "AchievementCriteriaScript.h"
#include "CreatureScript.h"
#include "Opcodes.h"
@@ -27,1056 +28,6 @@
#include "Vehicle.h"
#include "ulduar.h"
-enum XT002Spells
-{
- // BASIC
- SPELL_GRAVITY_BOMB_10 = 63024,
- SPELL_GRAVITY_BOMB_25 = 64234,
- SPELL_SEARING_LIGHT_10 = 63018,
- SPELL_SEARING_LIGHT_25 = 65121,
- SPELL_TYMPANIC_TANTARUM = 62776,
- SPELL_XT002_ENRAGE = 26662,
-
- // HELPERS
- SPELL_ARCING_SMASH = 8374,
- SPELL_TRAMPLE = 5568,
- SPELL_UPPERCUT = 10966,
- SPELL_BOOM = 62834,
-
- // HEARTBREAK
- SPELL_HEART_OVERLOAD = 62789,
- SPELL_EXPOSED_HEART = 63849,
- SPELL_ENERGY_ORB = 62790,
- SPELL_ENERGY_ORB_TRIGGER = 62826,
- SPELL_HEARTBREAK_10 = 65737,
- SPELL_HEARTBREAK_25 = 64193,
-
- // VOID ZONE
- SPELL_VOID_ZONE_SUMMON_10 = 64203,
- SPELL_VOID_ZONE_SUMMON_25 = 64235,
- //SPELL_VOID_ZONE_SUMMON = RAID_MODE(SPELL_VOID_ZONE_SUMMON_10, SPELL_VOID_ZONE_SUMMON_25, SPELL_VOID_ZONE_SUMMON_10, SPELL_VOID_ZONE_SUMMON_25),
- SPELL_VOID_ZONE_DAMAGE = 46262,
-
- // SPARK
- SPELL_SPARK_SUMMON = 64210,
- SPELL_SPARK_DAMAGE_10 = 64227,
- SPELL_SPARK_DAMAGE_25 = 64236,
- SPELL_SPARK_MELEE = 64230,
-};
-
-#define SPELL_GRAVITY_BOMB RAID_MODE(SPELL_GRAVITY_BOMB_10, SPELL_GRAVITY_BOMB_25)
-#define SPELL_SEARING_LIGHT RAID_MODE(SPELL_SEARING_LIGHT_10, SPELL_SEARING_LIGHT_25)
-#define SPELL_HEARTBREAK RAID_MODE(SPELL_HEARTBREAK_10, SPELL_HEARTBREAK_25)
-#define SPELL_SPARK_DAMAGE RAID_MODE(SPELL_SPARK_DAMAGE_10, SPELL_SPARK_DAMAGE_25)
-
-enum XT002Events
-{
- EVENT_HEALTH_CHECK = 1,
- EVENT_GRAVITY_BOMB = 2,
- EVENT_SEARING_LIGHT = 3,
- EVENT_ENRAGE = 4,
- EVENT_TYMPANIC_TANTARUM = 5,
- EVENT_RESTORE = 6,
- EVENT_START_SECOND_PHASE = 7,
- EVENT_REMOVE_EMOTE = 8,
- EVENT_CHECK_ROOM = 9,
-};
-
-enum NPCs
-{
- NPC_VOID_ZONE = 34001,
- NPC_LIFE_SPARK = 34004,
- NPC_XT002_HEART = 33329,
- NPC_XS013_SCRAPBOT = 33343,
- NPC_XM024_PUMMELLER = 33344,
- NPC_XE321_BOOMBOT = 33346,
- NPC_PILE_TRIGGER = 33337,
-};
-
-enum Texts
-{
- SAY_AGGRO = 0,
- SAY_HEART_OPENED = 1,
- SAY_HEART_CLOSED = 2,
- SAY_TYMPANIC_TANTRUM = 3,
- SAY_SLAY = 4,
- SAY_BERSERK = 5,
- SAY_DEATH = 6,
- SAY_SUMMON = 7,
- EMOTE_HEART_OPENED = 8,
- EMOTE_HEART_CLOSED = 9,
- EMOTE_TYMPANIC_TANTRUM = 10,
- EMOTE_SCRAPBOT = 11,
-};
-
-enum Misc
-{
- HEART_VEHICLE_SEAT = 0,
-
- ACTION_AWAKEN_HEART = -5,
- ACTION_HIDE_HEART = -4,
- ACTION_HEART_BROKEN = -3,
-
- ACHIEVEMENT_MUST_DECONSTRUCT_FASTER = 21027,
-
- DATA_XT002_NERF_ENGINEERING = 50,
- DATA_XT002_GRAVITY_ACHIEV = 51,
-};
-
-class boss_xt002 : public CreatureScript
-{
-public:
- boss_xt002() : CreatureScript("boss_xt002") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct boss_xt002AI : public ScriptedAI
- {
- boss_xt002AI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
- {
- m_pInstance = pCreature->GetInstanceScript();
- }
-
- InstanceScript* m_pInstance;
- uint8 _healthCheck;
- bool _hardMode;
- bool _nerfAchievement;
- bool _gravityAchievement;
- EventMap events;
- SummonList summons;
-
- void RescheduleEvents()
- {
- events.RescheduleEvent(EVENT_GRAVITY_BOMB, 1s, 1);
- events.RescheduleEvent(EVENT_TYMPANIC_TANTARUM, 1min, 1);
- if (!_hardMode)
- events.RescheduleEvent(EVENT_HEALTH_CHECK, 2s, 1);
- }
-
- void Reset() override
- {
- summons.DespawnAll();
- events.Reset();
-
- me->ResetLootMode();
- me->RemoveAllAuras();
-
- // first heart expose
- _healthCheck = 75;
- _hardMode = false;
- _nerfAchievement = true;
- _gravityAchievement = true;
-
- me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- me->SetControlled(false, UNIT_STATE_STUNNED);
-
- if (m_pInstance)
- {
- m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_MUST_DECONSTRUCT_FASTER);
- m_pInstance->SetData(TYPE_XT002, NOT_STARTED);
- if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS)))
- pGo->SetGoState(GO_STATE_ACTIVE);
- }
- }
-
- void JustSummoned(Creature* cr) override { summons.Summon(cr); }
- void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); }
-
- void AttachHeart()
- {
- if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr)
- heart->SetHealth(heart->GetMaxHealth());
- else if (Creature* accessory = me->SummonCreature(NPC_XT002_HEART, *me, TEMPSUMMON_MANUAL_DESPAWN))
- {
- accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
- if (!me->HandleSpellClick(accessory, 0))
- accessory->DespawnOrUnsummon();
- }
- }
-
- void JustReachedHome() override { me->setActive(false); }
-
- void JustEngagedWith(Unit*) override
- {
- me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
- events.ScheduleEvent(EVENT_ENRAGE, 10min, 0, 0);
- events.ScheduleEvent(EVENT_CHECK_ROOM, 5s, 0, 0);
- RescheduleEvents(); // Other events are scheduled here
-
- me->setActive(true);
- Talk(SAY_AGGRO);
-
- if (m_pInstance)
- {
- m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_MUST_DECONSTRUCT_FASTER);
- m_pInstance->SetData(TYPE_XT002, IN_PROGRESS);
- if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS)))
- pGo->SetGoState(GO_STATE_READY);
- }
-
- me->CallForHelp(175);
- me->SetInCombatWithZone();
- AttachHeart();
- }
-
- void KilledUnit(Unit* victim) override
- {
- if (victim->GetTypeId() == TYPEID_PLAYER && !urand(0, 2))
- {
- Talk(SAY_SLAY);
- }
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- Talk(SAY_DEATH);
-
- if (m_pInstance)
- {
- m_pInstance->SetData(TYPE_XT002, DONE);
- if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS)))
- pGo->SetGoState(GO_STATE_ACTIVE);
- }
-
- // Despawn summons
- summons.DespawnAll();
- }
-
- void DoAction(int32 param) override
- {
- if (param == DATA_XT002_NERF_ENGINEERING)
- {
- _nerfAchievement = false;
- return;
- }
- if (param == DATA_XT002_GRAVITY_ACHIEV)
- {
- _gravityAchievement = false;
- return;
- }
-
- if (!me->IsAlive() || _hardMode)
- return;
-
- // heart destory
- if (param == ACTION_HEART_BROKEN)
- {
- _hardMode = true;
- me->SetLootMode(3); // hard mode + normal loot
- me->SetMaxHealth(me->GetMaxHealth());
- me->SetHealth(me->GetMaxHealth());
- me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge
-
- me->CastSpell(me, SPELL_HEARTBREAK, true);
-
- Talk(EMOTE_HEART_CLOSED);
- events.ScheduleEvent(EVENT_REMOVE_EMOTE, 4s);
- return;
- }
-
- // damage from heart
- if (param > 0)
- {
- // avoid reducing health under 1
- int32 _final = std::min(param, int32(me->GetHealth() - 1));
-
- me->ModifyHealth(-_final);
- me->LowerPlayerDamageReq(_final);
- }
- }
-
- uint32 GetData(uint32 param) const override
- {
- if (param == DATA_XT002_NERF_ENGINEERING)
- return _nerfAchievement;
- else if (param == DATA_XT002_GRAVITY_ACHIEV)
- return _gravityAchievement;
-
- return 0;
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- events.Update(diff);
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- switch(events.ExecuteEvent())
- {
- // Control events
- case EVENT_HEALTH_CHECK:
- if (_hardMode)
- {
- return;
- }
-
- if (me->HealthBelowPct(_healthCheck))
- {
- _healthCheck -= 25;
- me->SetControlled(true, UNIT_STATE_STUNNED);
- me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_SUBMERGED); // submerge with animation
-
- Talk(SAY_HEART_OPENED);
-
- events.CancelEventGroup(1);
- events.ScheduleEvent(EVENT_START_SECOND_PHASE, 5s);
- return;
- }
- events.Repeat(1s);
- break;
- case EVENT_CHECK_ROOM:
- events.Repeat(5s);
- if (me->GetPositionX() < 722 || me->GetPositionX() > 987 || me->GetPositionY() < -139 || me->GetPositionY() > 124)
- EnterEvadeMode();
-
- return;
-
- // Abilities events
- case EVENT_GRAVITY_BOMB:
- me->CastCustomSpell(SPELL_GRAVITY_BOMB, SPELLVALUE_MAX_TARGETS, 1, me, true);
- events.ScheduleEvent(EVENT_SEARING_LIGHT, 10s, 1);
- break;
- case EVENT_SEARING_LIGHT:
- me->CastCustomSpell(SPELL_SEARING_LIGHT, SPELLVALUE_MAX_TARGETS, 1, me, true);
- events.ScheduleEvent(EVENT_GRAVITY_BOMB, 10s, 1);
- break;
- case EVENT_TYMPANIC_TANTARUM:
- Talk(EMOTE_TYMPANIC_TANTRUM);
- Talk(SAY_TYMPANIC_TANTRUM);
- me->CastSpell(me, SPELL_TYMPANIC_TANTARUM, true);
- events.Repeat(1min);
- return;
- case EVENT_ENRAGE:
- Talk(SAY_BERSERK);
- me->CastSpell(me, SPELL_XT002_ENRAGE, true);
- break;
-
- // Animation events
- case EVENT_START_SECOND_PHASE:
- Talk(EMOTE_HEART_OPENED);
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr)
- heart->GetAI()->DoAction(ACTION_AWAKEN_HEART);
-
- events.ScheduleEvent(EVENT_RESTORE, 30s);
- return;
- // Restore from heartbreak
- case EVENT_RESTORE:
- if (_hardMode)
- {
- return;
- }
-
- Talk(SAY_HEART_CLOSED);
-
- me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge
- // Hide heart
- if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr)
- heart->GetAI()->DoAction(ACTION_HIDE_HEART);
-
- events.ScheduleEvent(EVENT_REMOVE_EMOTE, 4s);
- return;
- case EVENT_REMOVE_EMOTE:
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- me->SetControlled(false, UNIT_STATE_STUNNED);
-
- RescheduleEvents();
- return;
- }
-
- // Disabled by stunned state
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class npc_xt002_heart : public CreatureScript
-{
-public:
- npc_xt002_heart() : CreatureScript("npc_xt002_heart") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_xt002_heartAI : public PassiveAI
- {
- npc_xt002_heartAI(Creature* pCreature) : PassiveAI(pCreature), summons(me)
- {
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- }
-
- SummonList summons;
- uint32 _damageDone;
- uint32 _timerSpawn;
-
- uint8 _spawnSelection;
- uint8 _pummelerCount;
-
- void MoveInLineOfSight(Unit*) override { }
- void AttackStart(Unit*) override { }
- void JustSummoned(Creature* cr) override
- {
- summons.Summon(cr);
- if (Unit* owner = me->GetVehicleBase())
- if (owner->GetTypeId() == TYPEID_UNIT)
- owner->ToCreature()->AI()->JustSummoned(cr);
- }
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- _damageDone += damage;
- }
-
- void SummonPiles()
- {
- me->SummonCreature(NPC_PILE_TRIGGER, 893.290f, 66.820f, 409.81f, 4.2f);
- me->SummonCreature(NPC_PILE_TRIGGER, 898.099f, -88.9115f, 409.887f, 2.23402f);
- me->SummonCreature(NPC_PILE_TRIGGER, 793.096f, -95.158f, 409.887f, 0.855211f);
- me->SummonCreature(NPC_PILE_TRIGGER, 794.600f, 59.660f, 409.82f, 5.34f);
- }
-
- void DoAction(int32 param) override
- {
- if (param == ACTION_AWAKEN_HEART)
- {
- _pummelerCount = 0;
- _spawnSelection = 0;
- _damageDone = 0;
- _timerSpawn = 0;
- me->SetHealth(me->GetMaxHealth());
- me->CastSpell(me, SPELL_HEART_OVERLOAD, true);
- me->CastSpell(me, SPELL_EXPOSED_HEART, false); // Channeled
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
-
- if (!summons.HasEntry(NPC_PILE_TRIGGER))
- SummonPiles();
- }
- else if (param == ACTION_HIDE_HEART)
- {
- if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
- if (pXT002->AI())
- {
- pXT002->AI()->DoAction(_damageDone);
- _damageDone = 0;
- }
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
- }
- }
-
- void SendEnergyToCorner()
- {
- Unit* pile = nullptr;
- uint8 num = urand(1, 4);
- for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
- if (Creature* summon = ObjectAccessor::GetCreature(*me, *itr))
- if (summon->GetEntry() == NPC_PILE_TRIGGER)
- {
- pile = summon;
- if ((--num) == 0)
- break;
- }
-
- if (pile)
- me->CastSpell(pile, SPELL_ENERGY_ORB, true);
- }
-
- void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
- {
- // spawn not-so-random robots
- if (spellInfo->Id == SPELL_ENERGY_ORB_TRIGGER && target->GetEntry() == NPC_PILE_TRIGGER)
- switch (_spawnSelection)
- {
- case 0:
- for (uint8 i = 0; i < 5; ++i)
- me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000);
- _spawnSelection++;
- break;
- case 1:
- me->SummonCreature(NPC_XE321_BOOMBOT, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
- _spawnSelection++;
- break;
- case 2:
- for (uint8 i = 0; i < 5; ++i)
- me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000);
- _spawnSelection++;
- break;
- case 3:
- if(_pummelerCount < 2)
- me->SummonCreature(NPC_XM024_PUMMELLER, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
-
- _pummelerCount++;
- _spawnSelection++;
- break;
- case 4:
- for (uint8 i = 0; i < 5; ++i)
- me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000);
- _spawnSelection = 0;
- break;
- }
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- me->SetVisible(false);
- if (me->GetInstanceScript())
- if (Creature* XT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
- if (XT002->AI())
- XT002->AI()->DoAction(ACTION_HEART_BROKEN);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))
- {
- _timerSpawn += diff;
- if (_timerSpawn >= 1900)
- {
- SendEnergyToCorner();
- _timerSpawn -= 1900;
- }
- }
- }
- };
-};
-
-class npc_xt002_scrapbot : public CreatureScript
-{
-public:
- npc_xt002_scrapbot() : CreatureScript("npc_xt002_scrapbot") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_xt002_scrapbotAI : public PassiveAI
- {
- npc_xt002_scrapbotAI(Creature* pCreature) : PassiveAI(pCreature) { }
-
- bool _locked;
- void Reset() override
- {
- me->StopMoving();
- _locked = true;
- me->SetWalk(true);
-
- if (me->GetInstanceScript())
- if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
- {
- if (pXT002->GetPositionZ() > 411.0f) // he is on stairs... idiot cryness protection
- me->GetMotionMaster()->MovePoint(0, 884.028931f, -14.593809f, 409.786987f);
- else
- _locked = false;
- }
- }
-
- void JustDied(Unit* killer) override
- {
- // Nerf Scrapbots achievement
- if (killer && killer->GetEntry() == NPC_XE321_BOOMBOT)
- if (me->GetInstanceScript())
- {
- me->GetInstanceScript()->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, 65037);
- me->GetInstanceScript()->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 65037);
- }
- }
-
- // tc use updateAI, while we have movementinform
- void MovementInform(uint32 type, uint32 /*param*/) override
- {
- if (type == POINT_MOTION_TYPE)
- {
- _locked = false;
- return;
- }
-
- // we reached the target :)
- if (type == FOLLOW_MOTION_TYPE && me->GetInstanceScript())
- if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
- {
- if (pXT002->IsAlive())
- {
- pXT002->AI()->DoAction(DATA_XT002_NERF_ENGINEERING);
- pXT002->ModifyHealth(pXT002->GetMaxHealth() * 0.01f);
- }
-
- if (!urand(0, 2))
- pXT002->AI()->Talk(EMOTE_SCRAPBOT);
-
- me->DespawnOrUnsummon(1);
- }
- }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- if (!_locked)
- {
- if (me->GetInstanceScript())
- if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
- {
- me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f);
- _locked = true;
- }
- }
- }
- };
-};
-
-class npc_xt002_pummeller : public CreatureScript
-{
-public:
- npc_xt002_pummeller() : CreatureScript("npc_xt002_pummeller") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_xt002_pummellerAI : public ScriptedAI
- {
- npc_xt002_pummellerAI(Creature* pCreature) : ScriptedAI(pCreature) { }
-
- int32 _arcingSmashTimer;
- int32 _trampleTimer;
- int32 _uppercutTimer;
-
- void Reset() override
- {
- _arcingSmashTimer = 0;
- _trampleTimer = 0;
- _uppercutTimer = 0;
-
- if (Unit* target = SelectTargetFromPlayerList(200))
- AttackStart(target);
- else
- me->DespawnOrUnsummon(500);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- _arcingSmashTimer += diff;
- _trampleTimer += diff;
- _uppercutTimer += diff;
-
- if (_arcingSmashTimer >= 8000)
- {
- me->CastSpell(me->GetVictim(), SPELL_ARCING_SMASH, false);
- _arcingSmashTimer = 0;
- return;
- }
- if (_trampleTimer >= 11000)
- {
- me->CastSpell(me->GetVictim(), SPELL_TRAMPLE, false);
- _trampleTimer = 0;
- return;
- }
- if (_uppercutTimer >= 14000)
- {
- me->CastSpell(me->GetVictim(), SPELL_UPPERCUT, false);
- _uppercutTimer = 0;
- return;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-};
-
-class BoomEvent : public BasicEvent
-{
-public:
- BoomEvent(Creature* me) : _me(me)
- {
- }
-
- bool Execute(uint64 /*time*/, uint32 /*diff*/) override
- {
- // This hack is here because we suspect our implementation of spell effect execution on targets
- // is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets,
- // then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc.
- // The above situation causes the visual for this spell to be bugged, so we remove the instakill
- // effect and implement a script hack for that.
-
- _me->CastSpell(_me, SPELL_BOOM, false);
- return true;
- }
-
-private:
- Creature* _me;
-};
-
-class npc_xt002_boombot : public CreatureScript
-{
-public:
- npc_xt002_boombot() : CreatureScript("npc_xt002_boombot") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_xt002_boombotAI : public PassiveAI
- {
- npc_xt002_boombotAI(Creature* pCreature) : PassiveAI(pCreature) { }
-
- bool _locked;
- bool _boomed;
- void Reset() override
- {
- me->StopMoving();
- _locked = true;
- _boomed = false;
- me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING);
-
- if (me->GetInstanceScript())
- if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
- {
- if (pXT002->GetPositionZ() > 411.0f) // he is on stairs... idiot cryness protection
- me->GetMotionMaster()->MovePoint(0, 884.028931f, -14.593809f, 409.786987f);
- else
- _locked = false;
- }
- }
-
- void Explode()
- {
- if (_boomed)
- return;
-
- _boomed = true; // Prevent recursive calls
-
- WorldPacket data(SMSG_SPELLINSTAKILLLOG, 8 + 8 + 4);
- data << me->GetGUID();
- data << me->GetGUID();
- data << uint32(SPELL_BOOM);
- me->SendMessageToSet(&data, false);
-
- me->KillSelf();
-
- // Visual only seems to work if the instant kill event is delayed or the spell itself is delayed
- // Casting done from player and caster source has the same targetinfo flags,
- // so that can't be the issue
- // See BoomEvent class
- // Schedule 1s delayed
- me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1 * IN_MILLISECONDS));
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1 * IN_MILLISECONDS));
- }
-
- void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
- {
- if (_boomed)
- damage = 0;
-
- if (me->HealthBelowPctDamaged(50, damage) && !_boomed)
- {
- damage = 0;
- Explode();
- }
- }
-
- // tc they use updateAI, while we have movementinform
- void MovementInform(uint32 type, uint32 /*param*/) override
- {
- if (type == POINT_MOTION_TYPE)
- {
- _locked = false;
- return;
- }
- // we reached the target :)
- //if (type == FOLLOW_MOTION_TYPE)
- // _kill = true;
- }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- if (!_locked)
- {
- if (me->GetInstanceScript())
- if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
- {
- me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f);
- _locked = true;
- }
- }
- }
- };
-};
-
-class npc_xt002_life_spark : public CreatureScript
-{
-public:
- npc_xt002_life_spark() : CreatureScript("npc_xt002_life_spark") { }
-
- CreatureAI* GetAI(Creature* pCreature) const override
- {
- return GetUlduarAI(pCreature);
- }
-
- struct npc_xt002_life_sparkAI : public ScriptedAI
- {
- npc_xt002_life_sparkAI(Creature* pCreature) : ScriptedAI(pCreature)
- {
- me->SetMaxHealth(RAID_MODE(54000, 172000));
- me->SetHealth(me->GetMaxHealth());
- me->CastSpell(me, SPELL_SPARK_DAMAGE, true);
- }
-
- uint32 _attackTimer;
- void Reset() override
- {
- if (Unit* target = SelectTargetFromPlayerList(200))
- AttackStart(target);
- else
- me->DespawnOrUnsummon();
- }
-
- void UpdateAI(uint32 /*diff*/) override
- {
- if (!UpdateVictim())
- return;
-
- me->CastSpell(me->GetVictim(), SPELL_SPARK_MELEE, false);
- DoMeleeAttackIfReady();
- }
- };
-};
-
-// 62775 - Tympanic Tantrum
-class spell_xt002_tympanic_tantrum : public SpellScriptLoader
-{
-public:
- spell_xt002_tympanic_tantrum() : SpellScriptLoader("spell_xt002_tympanic_tantrum") { }
-
- class spell_xt002_tympanic_tantrum_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_xt002_tympanic_tantrum_SpellScript);
-
- void FilterTargets(std::list& targets)
- {
- targets.remove_if(PlayerOrPetCheck());
- }
-
- void RecalculateDamage()
- {
- if (GetHitUnit())
- SetHitDamage(GetHitUnit()->CountPctFromMaxHealth(GetHitDamage()));
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
- OnHit += SpellHitFn(spell_xt002_tympanic_tantrum_SpellScript::RecalculateDamage);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_xt002_tympanic_tantrum_SpellScript();
- }
-};
-
-// 64234, 63024 - Gravity Bomb
-class spell_xt002_gravity_bomb_aura : public SpellScriptLoader
-{
-public:
- spell_xt002_gravity_bomb_aura() : SpellScriptLoader("spell_xt002_gravity_bomb_aura") { }
-
- class spell_xt002_gravity_bomb_aura_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_xt002_gravity_bomb_aura_AuraScript);
-
- void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
- {
- if (Player* player = GetOwner()->ToPlayer())
- if (Unit* xt002 = GetCaster())
- if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode
- if (Creature* cr = xt002->SummonCreature(NPC_VOID_ZONE, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 180000))
- {
- int32 damage = GetSpellInfo()->Id == 63025 ? 5000 : 7500;
- cr->CastCustomSpell(cr, SPELL_VOID_ZONE_DAMAGE, &damage, 0, 0, true);
- }
- }
-
- void OnPeriodic(AuraEffect const* aurEff)
- {
- Unit* xt002 = GetCaster();
- if (!xt002)
- return;
-
- Unit* owner = GetOwner()->ToUnit();
- if (!owner)
- return;
-
- if (aurEff->GetAmount() >= int32(owner->GetHealth()))
- if (xt002->GetAI())
- xt002->GetAI()->DoAction(DATA_XT002_GRAVITY_ACHIEV);
- }
-
- void Register() override
- {
- OnEffectPeriodic += AuraEffectPeriodicFn(spell_xt002_gravity_bomb_aura_AuraScript::OnPeriodic, EFFECT_2, SPELL_AURA_PERIODIC_DAMAGE);
- AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_gravity_bomb_aura_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_xt002_gravity_bomb_aura_AuraScript();
- }
-
- class spell_xt002_gravity_bomb_aura_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_xt002_gravity_bomb_aura_SpellScript);
-
- void SelectTarget(std::list& targets)
- {
- if (Unit* victim = GetCaster()->GetVictim())
- targets.remove_if(Acore::ObjectGUIDCheck(victim->GetGUID(), true));
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_gravity_bomb_aura_SpellScript::SelectTarget, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_xt002_gravity_bomb_aura_SpellScript();
- }
-};
-
-// 64233, 63025 - Gravity Bomb
-class spell_xt002_gravity_bomb_damage : public SpellScriptLoader
-{
-public:
- spell_xt002_gravity_bomb_damage() : SpellScriptLoader("spell_xt002_gravity_bomb_damage") { }
-
- class spell_xt002_gravity_bomb_damage_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_xt002_gravity_bomb_damage_SpellScript);
-
- void HandleScript(SpellEffIndex /*eff*/)
- {
- Unit* caster = GetCaster();
- if (!caster)
- return;
-
- if (GetHitDamage() >= int32(GetHitUnit()->GetHealth()))
- if (caster->GetAI())
- caster->GetAI()->DoAction(DATA_XT002_GRAVITY_ACHIEV);
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_xt002_gravity_bomb_damage_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_xt002_gravity_bomb_damage_SpellScript();
- }
-};
-
-// 63018, 65121 - Searing Light
-class spell_xt002_searing_light_spawn_life_spark : public SpellScriptLoader
-{
-public:
- spell_xt002_searing_light_spawn_life_spark() : SpellScriptLoader("spell_xt002_searing_light_spawn_life_spark") { }
-
- class spell_xt002_searing_light_spawn_life_spark_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_xt002_searing_light_spawn_life_spark_AuraScript);
-
- void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
- {
- if (Player* player = GetOwner()->ToPlayer())
- if (Unit* xt002 = GetCaster())
- if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode
- xt002->SummonCreature(NPC_LIFE_SPARK, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 180000);
- }
-
- void Register() override
- {
- OnEffectRemove += AuraEffectRemoveFn(spell_xt002_searing_light_spawn_life_spark_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const override
- {
- return new spell_xt002_searing_light_spawn_life_spark_AuraScript();
- }
-
- class spell_xt002_searing_light_spawn_life_spark_SpellScript : public SpellScript
- {
- PrepareSpellScript(spell_xt002_searing_light_spawn_life_spark_SpellScript);
-
- void SelectTarget(std::list& targets)
- {
- if (Unit* victim = GetCaster()->GetVictim())
- targets.remove_if(Acore::ObjectGUIDCheck(victim->GetGUID(), true));
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_searing_light_spawn_life_spark_SpellScript::SelectTarget, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_xt002_searing_light_spawn_life_spark_SpellScript();
- }
-};
-
-class achievement_xt002_nerf_engineering : public AchievementCriteriaScript
-{
-public:
- achievement_xt002_nerf_engineering() : AchievementCriteriaScript("achievement_xt002_nerf_engineering") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- if (target)
- if (InstanceScript* instance = target->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_XT002)))
- return cr->AI()->GetData(DATA_XT002_NERF_ENGINEERING);
-
- return false;
- }
-};
-
-class achievement_xt002_nerf_gravity_bombs : public AchievementCriteriaScript
-{
-public:
- achievement_xt002_nerf_gravity_bombs() : AchievementCriteriaScript("achievement_xt002_nerf_gravity_bombs") {}
-
- bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
- {
- if (target)
- if (InstanceScript* instance = target->GetInstanceScript())
- if (Creature* cr = ObjectAccessor::GetCreature(*target, instance->GetGuidData(TYPE_XT002)))
- return cr->AI()->GetData(DATA_XT002_GRAVITY_ACHIEV);
-
- return false;
- }
-};
-
void AddSC_boss_xt002()
{
// Npcs
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.h b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.h
new file mode 100644
index 00000000000000..9b0b9cfeaddd6c
--- /dev/null
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.h
@@ -0,0 +1,1066 @@
+#ifndef BOSS_XT002_H_
+#define BOSS_XT002_H_
+
+#include "AchievementCriteriaScript.h"
+#include "CreatureScript.h"
+#include "Opcodes.h"
+#include "PassiveAI.h"
+#include "Player.h"
+#include "ScriptedCreature.h"
+#include "SpellAuraEffects.h"
+#include "SpellScript.h"
+#include "SpellScriptLoader.h"
+#include "Vehicle.h"
+#include "ulduar.h"
+
+enum XT002Spells
+{
+ // BASIC
+ SPELL_GRAVITY_BOMB_10 = 63024,
+ SPELL_GRAVITY_BOMB_25 = 64234,
+ SPELL_SEARING_LIGHT_10 = 63018,
+ SPELL_SEARING_LIGHT_25 = 65121,
+ SPELL_TYMPANIC_TANTARUM = 62776,
+ SPELL_XT002_ENRAGE = 26662,
+
+ // HELPERS
+ SPELL_ARCING_SMASH = 8374,
+ SPELL_TRAMPLE = 5568,
+ SPELL_UPPERCUT = 10966,
+ SPELL_BOOM = 62834,
+
+ // HEARTBREAK
+ SPELL_HEART_OVERLOAD = 62789,
+ SPELL_EXPOSED_HEART = 63849,
+ SPELL_ENERGY_ORB = 62790,
+ SPELL_ENERGY_ORB_TRIGGER = 62826,
+ SPELL_HEARTBREAK_10 = 65737,
+ SPELL_HEARTBREAK_25 = 64193,
+
+ // VOID ZONE
+ SPELL_VOID_ZONE_SUMMON_10 = 64203,
+ SPELL_VOID_ZONE_SUMMON_25 = 64235,
+ //SPELL_VOID_ZONE_SUMMON = RAID_MODE(SPELL_VOID_ZONE_SUMMON_10, SPELL_VOID_ZONE_SUMMON_25, SPELL_VOID_ZONE_SUMMON_10, SPELL_VOID_ZONE_SUMMON_25),
+ SPELL_VOID_ZONE_DAMAGE = 46262,
+
+ // SPARK
+ SPELL_SPARK_SUMMON = 64210,
+ SPELL_SPARK_DAMAGE_10 = 64227,
+ SPELL_SPARK_DAMAGE_25 = 64236,
+ SPELL_SPARK_MELEE = 64230,
+};
+
+#define SPELL_GRAVITY_BOMB RAID_MODE(SPELL_GRAVITY_BOMB_10, SPELL_GRAVITY_BOMB_25)
+#define SPELL_SEARING_LIGHT RAID_MODE(SPELL_SEARING_LIGHT_10, SPELL_SEARING_LIGHT_25)
+#define SPELL_HEARTBREAK RAID_MODE(SPELL_HEARTBREAK_10, SPELL_HEARTBREAK_25)
+#define SPELL_SPARK_DAMAGE RAID_MODE(SPELL_SPARK_DAMAGE_10, SPELL_SPARK_DAMAGE_25)
+
+enum XT002Events
+{
+ EVENT_HEALTH_CHECK = 1,
+ EVENT_GRAVITY_BOMB = 2,
+ EVENT_SEARING_LIGHT = 3,
+ EVENT_ENRAGE = 4,
+ EVENT_TYMPANIC_TANTARUM = 5,
+ EVENT_RESTORE = 6,
+ EVENT_START_SECOND_PHASE = 7,
+ EVENT_REMOVE_EMOTE = 8,
+ EVENT_CHECK_ROOM = 9,
+};
+
+enum NPCs
+{
+ NPC_VOID_ZONE = 34001,
+ NPC_LIFE_SPARK = 34004,
+ NPC_XT002_HEART = 33329,
+ NPC_XS013_SCRAPBOT = 33343,
+ NPC_XM024_PUMMELLER = 33344,
+ NPC_XE321_BOOMBOT = 33346,
+ NPC_PILE_TRIGGER = 33337,
+};
+
+enum Texts
+{
+ SAY_AGGRO = 0,
+ SAY_HEART_OPENED = 1,
+ SAY_HEART_CLOSED = 2,
+ SAY_TYMPANIC_TANTRUM = 3,
+ SAY_SLAY = 4,
+ SAY_BERSERK = 5,
+ SAY_DEATH = 6,
+ SAY_SUMMON = 7,
+ EMOTE_HEART_OPENED = 8,
+ EMOTE_HEART_CLOSED = 9,
+ EMOTE_TYMPANIC_TANTRUM = 10,
+ EMOTE_SCRAPBOT = 11,
+};
+
+enum Misc
+{
+ HEART_VEHICLE_SEAT = 0,
+
+ ACTION_AWAKEN_HEART = -5,
+ ACTION_HIDE_HEART = -4,
+ ACTION_HEART_BROKEN = -3,
+
+ ACHIEVEMENT_MUST_DECONSTRUCT_FASTER = 21027,
+
+ DATA_XT002_NERF_ENGINEERING = 50,
+ DATA_XT002_GRAVITY_ACHIEV = 51,
+};
+
+class boss_xt002 : public CreatureScript
+{
+public:
+ boss_xt002() : CreatureScript("boss_xt002") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct boss_xt002AI : public ScriptedAI
+ {
+ boss_xt002AI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
+ {
+ m_pInstance = pCreature->GetInstanceScript();
+ }
+
+ InstanceScript* m_pInstance;
+ uint8 _healthCheck;
+ bool _hardMode;
+ bool _nerfAchievement;
+ bool _gravityAchievement;
+ EventMap events;
+ SummonList summons;
+
+ void RescheduleEvents()
+ {
+ events.RescheduleEvent(EVENT_GRAVITY_BOMB, 1s, 1);
+ events.RescheduleEvent(EVENT_TYMPANIC_TANTARUM, 1min, 1);
+ if (!_hardMode)
+ events.RescheduleEvent(EVENT_HEALTH_CHECK, 2s, 1);
+ }
+
+ void Reset() override
+ {
+ summons.DespawnAll();
+ events.Reset();
+
+ me->ResetLootMode();
+ me->RemoveAllAuras();
+
+ // first heart expose
+ _healthCheck = 75;
+ _hardMode = false;
+ _nerfAchievement = true;
+ _gravityAchievement = true;
+
+ me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ me->SetControlled(false, UNIT_STATE_STUNNED);
+
+ if (m_pInstance)
+ {
+ m_pInstance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_MUST_DECONSTRUCT_FASTER);
+ m_pInstance->SetData(TYPE_XT002, NOT_STARTED);
+ if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS)))
+ pGo->SetGoState(GO_STATE_ACTIVE);
+ }
+ }
+
+ void JustSummoned(Creature* cr) override { summons.Summon(cr); }
+ void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); }
+
+ void AttachHeart()
+ {
+ if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr)
+ heart->SetHealth(heart->GetMaxHealth());
+ else if (Creature* accessory = me->SummonCreature(NPC_XT002_HEART, *me, TEMPSUMMON_MANUAL_DESPAWN))
+ {
+ accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
+ if (!me->HandleSpellClick(accessory, 0))
+ accessory->DespawnOrUnsummon();
+ }
+ }
+
+ void JustReachedHome() override { me->setActive(false); }
+
+ void JustEngagedWith(Unit*) override
+ {
+ me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
+ events.ScheduleEvent(EVENT_ENRAGE, 10min, 0, 0);
+ events.ScheduleEvent(EVENT_CHECK_ROOM, 5s, 0, 0);
+ RescheduleEvents(); // Other events are scheduled here
+
+ me->setActive(true);
+ Talk(SAY_AGGRO);
+
+ if (m_pInstance)
+ {
+ m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEVEMENT_MUST_DECONSTRUCT_FASTER);
+ m_pInstance->SetData(TYPE_XT002, IN_PROGRESS);
+ if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS)))
+ pGo->SetGoState(GO_STATE_READY);
+ }
+
+ me->CallForHelp(175);
+ me->SetInCombatWithZone();
+ AttachHeart();
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER && !urand(0, 2))
+ {
+ Talk(SAY_SLAY);
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ Talk(SAY_DEATH);
+
+ if (m_pInstance)
+ {
+ m_pInstance->SetData(TYPE_XT002, DONE);
+ if (GameObject* pGo = ObjectAccessor::GetGameObject(*me, m_pInstance->GetGuidData(GO_XT002_DOORS)))
+ pGo->SetGoState(GO_STATE_ACTIVE);
+ }
+
+ // Despawn summons
+ summons.DespawnAll();
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == DATA_XT002_NERF_ENGINEERING)
+ {
+ _nerfAchievement = false;
+ return;
+ }
+ if (param == DATA_XT002_GRAVITY_ACHIEV)
+ {
+ _gravityAchievement = false;
+ return;
+ }
+
+ if (!me->IsAlive() || _hardMode)
+ return;
+
+ // heart destory
+ if (param == ACTION_HEART_BROKEN)
+ {
+ _hardMode = true;
+ me->SetLootMode(3); // hard mode + normal loot
+ me->SetMaxHealth(me->GetMaxHealth());
+ me->SetHealth(me->GetMaxHealth());
+ me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge
+
+ me->CastSpell(me, SPELL_HEARTBREAK, true);
+
+ Talk(EMOTE_HEART_CLOSED);
+ events.ScheduleEvent(EVENT_REMOVE_EMOTE, 4s);
+ return;
+ }
+
+ // damage from heart
+ if (param > 0)
+ {
+ // avoid reducing health under 1
+ int32 _final = std::min(param, int32(me->GetHealth() - 1));
+
+ me->ModifyHealth(-_final);
+ me->LowerPlayerDamageReq(_final);
+ }
+ }
+
+ uint32 GetData(uint32 param) const override
+ {
+ if (param == DATA_XT002_NERF_ENGINEERING)
+ return _nerfAchievement;
+ else if (param == DATA_XT002_GRAVITY_ACHIEV)
+ return _gravityAchievement;
+
+ return 0;
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ switch(events.ExecuteEvent())
+ {
+ // Control events
+ case EVENT_HEALTH_CHECK:
+ if (_hardMode)
+ {
+ return;
+ }
+
+ if (me->HealthBelowPct(_healthCheck))
+ {
+ _healthCheck -= 25;
+ me->SetControlled(true, UNIT_STATE_STUNNED);
+ me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_SUBMERGED); // submerge with animation
+
+ Talk(SAY_HEART_OPENED);
+
+ events.CancelEventGroup(1);
+ events.ScheduleEvent(EVENT_START_SECOND_PHASE, 5s);
+ return;
+ }
+ events.Repeat(1s);
+ break;
+ case EVENT_CHECK_ROOM:
+ events.Repeat(5s);
+ if (me->GetPositionX() < 722 || me->GetPositionX() > 987 || me->GetPositionY() < -139 || me->GetPositionY() > 124)
+ EnterEvadeMode();
+
+ return;
+
+ // Abilities events
+ case EVENT_GRAVITY_BOMB:
+ me->CastCustomSpell(SPELL_GRAVITY_BOMB, SPELLVALUE_MAX_TARGETS, 1, me, true);
+ events.ScheduleEvent(EVENT_SEARING_LIGHT, 10s, 1);
+ break;
+ case EVENT_SEARING_LIGHT:
+ me->CastCustomSpell(SPELL_SEARING_LIGHT, SPELLVALUE_MAX_TARGETS, 1, me, true);
+ events.ScheduleEvent(EVENT_GRAVITY_BOMB, 10s, 1);
+ break;
+ case EVENT_TYMPANIC_TANTARUM:
+ Talk(EMOTE_TYMPANIC_TANTRUM);
+ Talk(SAY_TYMPANIC_TANTRUM);
+ me->CastSpell(me, SPELL_TYMPANIC_TANTARUM, true);
+ events.Repeat(1min);
+ return;
+ case EVENT_ENRAGE:
+ Talk(SAY_BERSERK);
+ me->CastSpell(me, SPELL_XT002_ENRAGE, true);
+ break;
+
+ // Animation events
+ case EVENT_START_SECOND_PHASE:
+ Talk(EMOTE_HEART_OPENED);
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr)
+ heart->GetAI()->DoAction(ACTION_AWAKEN_HEART);
+
+ events.ScheduleEvent(EVENT_RESTORE, 30s);
+ return;
+ // Restore from heartbreak
+ case EVENT_RESTORE:
+ if (_hardMode)
+ {
+ return;
+ }
+
+ Talk(SAY_HEART_CLOSED);
+
+ me->SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_STAND_STATE, UNIT_STAND_STATE_STAND); // emerge
+ // Hide heart
+ if (Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT) : nullptr)
+ heart->GetAI()->DoAction(ACTION_HIDE_HEART);
+
+ events.ScheduleEvent(EVENT_REMOVE_EMOTE, 4s);
+ return;
+ case EVENT_REMOVE_EMOTE:
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ me->SetControlled(false, UNIT_STATE_STUNNED);
+
+ RescheduleEvents();
+ return;
+ }
+
+ // Disabled by stunned state
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class npc_xt002_heart : public CreatureScript
+{
+public:
+ npc_xt002_heart() : CreatureScript("npc_xt002_heart") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_xt002_heartAI : public PassiveAI
+ {
+ npc_xt002_heartAI(Creature* pCreature) : PassiveAI(pCreature), summons(me)
+ {
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ }
+
+ SummonList summons;
+ uint32 _damageDone;
+ uint32 _timerSpawn;
+
+ uint8 _spawnSelection;
+ uint8 _pummelerCount;
+
+ void MoveInLineOfSight(Unit*) override { }
+ void AttackStart(Unit*) override { }
+ void JustSummoned(Creature* cr) override
+ {
+ summons.Summon(cr);
+ if (Unit* owner = me->GetVehicleBase())
+ if (owner->GetTypeId() == TYPEID_UNIT)
+ owner->ToCreature()->AI()->JustSummoned(cr);
+ }
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ _damageDone += damage;
+ }
+
+ void SummonPiles()
+ {
+ me->SummonCreature(NPC_PILE_TRIGGER, 893.290f, 66.820f, 409.81f, 4.2f);
+ me->SummonCreature(NPC_PILE_TRIGGER, 898.099f, -88.9115f, 409.887f, 2.23402f);
+ me->SummonCreature(NPC_PILE_TRIGGER, 793.096f, -95.158f, 409.887f, 0.855211f);
+ me->SummonCreature(NPC_PILE_TRIGGER, 794.600f, 59.660f, 409.82f, 5.34f);
+ }
+
+ void DoAction(int32 param) override
+ {
+ if (param == ACTION_AWAKEN_HEART)
+ {
+ _pummelerCount = 0;
+ _spawnSelection = 0;
+ _damageDone = 0;
+ _timerSpawn = 0;
+ me->SetHealth(me->GetMaxHealth());
+ me->CastSpell(me, SPELL_HEART_OVERLOAD, true);
+ me->CastSpell(me, SPELL_EXPOSED_HEART, false); // Channeled
+ me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+
+ if (!summons.HasEntry(NPC_PILE_TRIGGER))
+ SummonPiles();
+ }
+ else if (param == ACTION_HIDE_HEART)
+ {
+ if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
+ if (pXT002->AI())
+ {
+ pXT002->AI()->DoAction(_damageDone);
+ _damageDone = 0;
+ }
+ me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ }
+ }
+
+ void SendEnergyToCorner()
+ {
+ Unit* pile = nullptr;
+ uint8 num = urand(1, 4);
+ for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
+ if (Creature* summon = ObjectAccessor::GetCreature(*me, *itr))
+ if (summon->GetEntry() == NPC_PILE_TRIGGER)
+ {
+ pile = summon;
+ if ((--num) == 0)
+ break;
+ }
+
+ if (pile)
+ me->CastSpell(pile, SPELL_ENERGY_ORB, true);
+ }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
+ {
+ // spawn not-so-random robots
+ if (spellInfo->Id == SPELL_ENERGY_ORB_TRIGGER && target->GetEntry() == NPC_PILE_TRIGGER)
+ switch (_spawnSelection)
+ {
+ case 0:
+ for (uint8 i = 0; i < 5; ++i)
+ me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000);
+ _spawnSelection++;
+ break;
+ case 1:
+ me->SummonCreature(NPC_XE321_BOOMBOT, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
+ _spawnSelection++;
+ break;
+ case 2:
+ for (uint8 i = 0; i < 5; ++i)
+ me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000);
+ _spawnSelection++;
+ break;
+ case 3:
+ if(_pummelerCount < 2)
+ me->SummonCreature(NPC_XM024_PUMMELLER, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
+
+ _pummelerCount++;
+ _spawnSelection++;
+ break;
+ case 4:
+ for (uint8 i = 0; i < 5; ++i)
+ me->SummonCreature(NPC_XS013_SCRAPBOT, target->GetPositionX() + irand(-3, 3), target->GetPositionY() + irand(-3, 3), target->GetPositionZ() + 2, 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1000);
+ _spawnSelection = 0;
+ break;
+ }
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ me->SetVisible(false);
+ if (me->GetInstanceScript())
+ if (Creature* XT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
+ if (XT002->AI())
+ XT002->AI()->DoAction(ACTION_HEART_BROKEN);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))
+ {
+ _timerSpawn += diff;
+ if (_timerSpawn >= 1900)
+ {
+ SendEnergyToCorner();
+ _timerSpawn -= 1900;
+ }
+ }
+ }
+ };
+};
+
+class npc_xt002_scrapbot : public CreatureScript
+{
+public:
+ npc_xt002_scrapbot() : CreatureScript("npc_xt002_scrapbot") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_xt002_scrapbotAI : public PassiveAI
+ {
+ npc_xt002_scrapbotAI(Creature* pCreature) : PassiveAI(pCreature) { }
+
+ bool _locked;
+ void Reset() override
+ {
+ me->StopMoving();
+ _locked = true;
+ me->SetWalk(true);
+
+ if (me->GetInstanceScript())
+ if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
+ {
+ if (pXT002->GetPositionZ() > 411.0f) // he is on stairs... idiot cryness protection
+ me->GetMotionMaster()->MovePoint(0, 884.028931f, -14.593809f, 409.786987f);
+ else
+ _locked = false;
+ }
+ }
+
+ void JustDied(Unit* killer) override
+ {
+ // Nerf Scrapbots achievement
+ if (killer && killer->GetEntry() == NPC_XE321_BOOMBOT)
+ if (me->GetInstanceScript())
+ {
+ me->GetInstanceScript()->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, 65037);
+ me->GetInstanceScript()->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 65037);
+ }
+ }
+
+ // tc use updateAI, while we have movementinform
+ void MovementInform(uint32 type, uint32 /*param*/) override
+ {
+ if (type == POINT_MOTION_TYPE)
+ {
+ _locked = false;
+ return;
+ }
+
+ // we reached the target :)
+ if (type == FOLLOW_MOTION_TYPE && me->GetInstanceScript())
+ if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
+ {
+ if (pXT002->IsAlive())
+ {
+ pXT002->AI()->DoAction(DATA_XT002_NERF_ENGINEERING);
+ pXT002->ModifyHealth(pXT002->GetMaxHealth() * 0.01f);
+ }
+
+ if (!urand(0, 2))
+ pXT002->AI()->Talk(EMOTE_SCRAPBOT);
+
+ me->DespawnOrUnsummon(1);
+ }
+ }
+
+ void UpdateAI(uint32 /*diff*/) override
+ {
+ if (!_locked)
+ {
+ if (me->GetInstanceScript())
+ if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
+ {
+ me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f);
+ _locked = true;
+ }
+ }
+ }
+ };
+};
+
+class npc_xt002_pummeller : public CreatureScript
+{
+public:
+ npc_xt002_pummeller() : CreatureScript("npc_xt002_pummeller") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_xt002_pummellerAI : public ScriptedAI
+ {
+ npc_xt002_pummellerAI(Creature* pCreature) : ScriptedAI(pCreature) { }
+
+ int32 _arcingSmashTimer;
+ int32 _trampleTimer;
+ int32 _uppercutTimer;
+
+ void Reset() override
+ {
+ _arcingSmashTimer = 0;
+ _trampleTimer = 0;
+ _uppercutTimer = 0;
+
+ if (Unit* target = SelectTargetFromPlayerList(200))
+ AttackStart(target);
+ else
+ me->DespawnOrUnsummon(500);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ _arcingSmashTimer += diff;
+ _trampleTimer += diff;
+ _uppercutTimer += diff;
+
+ if (_arcingSmashTimer >= 8000)
+ {
+ me->CastSpell(me->GetVictim(), SPELL_ARCING_SMASH, false);
+ _arcingSmashTimer = 0;
+ return;
+ }
+ if (_trampleTimer >= 11000)
+ {
+ me->CastSpell(me->GetVictim(), SPELL_TRAMPLE, false);
+ _trampleTimer = 0;
+ return;
+ }
+ if (_uppercutTimer >= 14000)
+ {
+ me->CastSpell(me->GetVictim(), SPELL_UPPERCUT, false);
+ _uppercutTimer = 0;
+ return;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+class BoomEvent : public BasicEvent
+{
+public:
+ BoomEvent(Creature* me) : _me(me)
+ {
+ }
+
+ bool Execute(uint64 /*time*/, uint32 /*diff*/) override
+ {
+ // This hack is here because we suspect our implementation of spell effect execution on targets
+ // is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets,
+ // then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc.
+ // The above situation causes the visual for this spell to be bugged, so we remove the instakill
+ // effect and implement a script hack for that.
+
+ _me->CastSpell(_me, SPELL_BOOM, false);
+ return true;
+ }
+
+private:
+ Creature* _me;
+};
+
+class npc_xt002_boombot : public CreatureScript
+{
+public:
+ npc_xt002_boombot() : CreatureScript("npc_xt002_boombot") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_xt002_boombotAI : public PassiveAI
+ {
+ npc_xt002_boombotAI(Creature* pCreature) : PassiveAI(pCreature) { }
+
+ bool _locked;
+ bool _boomed;
+ void Reset() override
+ {
+ me->StopMoving();
+ _locked = true;
+ _boomed = false;
+ me->SetUnitMovementFlags(MOVEMENTFLAG_WALKING);
+
+ if (me->GetInstanceScript())
+ if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
+ {
+ if (pXT002->GetPositionZ() > 411.0f) // he is on stairs... idiot cryness protection
+ me->GetMotionMaster()->MovePoint(0, 884.028931f, -14.593809f, 409.786987f);
+ else
+ _locked = false;
+ }
+ }
+
+ void Explode()
+ {
+ if (_boomed)
+ return;
+
+ _boomed = true; // Prevent recursive calls
+
+ WorldPacket data(SMSG_SPELLINSTAKILLLOG, 8 + 8 + 4);
+ data << me->GetGUID();
+ data << me->GetGUID();
+ data << uint32(SPELL_BOOM);
+ me->SendMessageToSet(&data, false);
+
+ me->KillSelf();
+
+ // Visual only seems to work if the instant kill event is delayed or the spell itself is delayed
+ // Casting done from player and caster source has the same targetinfo flags,
+ // so that can't be the issue
+ // See BoomEvent class
+ // Schedule 1s delayed
+ me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1 * IN_MILLISECONDS));
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ me->m_Events.AddEvent(new BoomEvent(me), me->m_Events.CalculateTime(1 * IN_MILLISECONDS));
+ }
+
+ void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
+ {
+ if (_boomed)
+ damage = 0;
+
+ if (me->HealthBelowPctDamaged(50, damage) && !_boomed)
+ {
+ damage = 0;
+ Explode();
+ }
+ }
+
+ // tc they use updateAI, while we have movementinform
+ void MovementInform(uint32 type, uint32 /*param*/) override
+ {
+ if (type == POINT_MOTION_TYPE)
+ {
+ _locked = false;
+ return;
+ }
+ // we reached the target :)
+ //if (type == FOLLOW_MOTION_TYPE)
+ // _kill = true;
+ }
+
+ void UpdateAI(uint32 /*diff*/) override
+ {
+ if (!_locked)
+ {
+ if (me->GetInstanceScript())
+ if (Creature* pXT002 = ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(TYPE_XT002)))
+ {
+ me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f);
+ _locked = true;
+ }
+ }
+ }
+ };
+};
+
+class npc_xt002_life_spark : public CreatureScript
+{
+public:
+ npc_xt002_life_spark() : CreatureScript("npc_xt002_life_spark") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const override
+ {
+ return GetUlduarAI(pCreature);
+ }
+
+ struct npc_xt002_life_sparkAI : public ScriptedAI
+ {
+ npc_xt002_life_sparkAI(Creature* pCreature) : ScriptedAI(pCreature)
+ {
+ me->SetMaxHealth(RAID_MODE(54000, 172000));
+ me->SetHealth(me->GetMaxHealth());
+ me->CastSpell(me, SPELL_SPARK_DAMAGE, true);
+ }
+
+ uint32 _attackTimer;
+ void Reset() override
+ {
+ if (Unit* target = SelectTargetFromPlayerList(200))
+ AttackStart(target);
+ else
+ me->DespawnOrUnsummon();
+ }
+
+ void UpdateAI(uint32 /*diff*/) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ me->CastSpell(me->GetVictim(), SPELL_SPARK_MELEE, false);
+ DoMeleeAttackIfReady();
+ }
+ };
+};
+
+// 62775 - Tympanic Tantrum
+class spell_xt002_tympanic_tantrum : public SpellScriptLoader
+{
+public:
+ spell_xt002_tympanic_tantrum() : SpellScriptLoader("spell_xt002_tympanic_tantrum") { }
+
+ class spell_xt002_tympanic_tantrum_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_xt002_tympanic_tantrum_SpellScript);
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove_if(PlayerOrPetCheck());
+ }
+
+ void RecalculateDamage()
+ {
+ if (GetHitUnit())
+ SetHitDamage(GetHitUnit()->CountPctFromMaxHealth(GetHitDamage()));
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnHit += SpellHitFn(spell_xt002_tympanic_tantrum_SpellScript::RecalculateDamage);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_xt002_tympanic_tantrum_SpellScript();
+ }
+};
+
+// 64234, 63024 - Gravity Bomb
+class spell_xt002_gravity_bomb_aura : public SpellScriptLoader
+{
+public:
+ spell_xt002_gravity_bomb_aura() : SpellScriptLoader("spell_xt002_gravity_bomb_aura") { }
+
+ class spell_xt002_gravity_bomb_aura_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_xt002_gravity_bomb_aura_AuraScript);
+
+ void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
+ {
+ if (Player* player = GetOwner()->ToPlayer())
+ if (Unit* xt002 = GetCaster())
+ if (xt002->HasAura(aurEff->GetAmount())) // Heartbreak aura indicating hard mode
+ if (Creature* cr = xt002->SummonCreature(NPC_VOID_ZONE, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 180000))
+ {
+ int32 damage = GetSpellInfo()->Id == 63025 ? 5000 : 7500;
+ cr->CastCustomSpell(cr, SPELL_VOID_ZONE_DAMAGE, &damage, 0, 0, true);
+ }
+ }
+
+ void OnPeriodic(AuraEffect const* aurEff)
+ {
+ Unit* xt002 = GetCaster();
+ if (!xt002)
+ return;
+
+ Unit* owner = GetOwner()->ToUnit();
+ if (!owner)
+ return;
+
+ if (aurEff->GetAmount() >= int32(owner->GetHealth()))
+ if (xt002->GetAI())
+ xt002->GetAI()->DoAction(DATA_XT002_GRAVITY_ACHIEV);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_xt002_gravity_bomb_aura_AuraScript::OnPeriodic, EFFECT_2, SPELL_AURA_PERIODIC_DAMAGE);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_gravity_bomb_aura_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_xt002_gravity_bomb_aura_AuraScript();
+ }
+
+ class spell_xt002_gravity_bomb_aura_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_xt002_gravity_bomb_aura_SpellScript);
+
+ void SelectTarget(std::list