diff options
| author | Keader <keader.android@gmail.com> | 2018-08-26 01:14:18 -0300 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-08-26 01:14:18 -0300 | 
| commit | 81a6e2e5101834b4f8950ea8ecc728f5548ab906 (patch) | |
| tree | e9fb9a959d98aee52f70bea9080f87c42a481cf3 | |
| parent | 4d9c36c8c3bc59afb74ffe336ff121c06812d645 (diff) | |
Scripts/Uduar: XT002 Rework (#21566)
Closes #21489
4 files changed, 779 insertions, 837 deletions
diff --git a/sql/updates/world/3.3.5/2018_08_26_01_world.sql b/sql/updates/world/3.3.5/2018_08_26_01_world.sql new file mode 100644 index 00000000000..09193cc9030 --- /dev/null +++ b/sql/updates/world/3.3.5/2018_08_26_01_world.sql @@ -0,0 +1,45 @@ +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=64799; -- Lightning Tether +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,64799,0,0,31,0,3,33293,0,0,0,0,'','Effect_0 hits XT002'); + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ( +'spell_xt002_exposed_heart', +'spell_xt002_energy_orb'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(63849,'spell_xt002_exposed_heart'), +(62826,'spell_xt002_energy_orb'); + +DELETE FROM `spell_proc` WHERE `SpellId`=63849; -- Disable spell proc to effect_1 +INSERT INTO `spell_proc` (`SpellId`, `SchoolMask`, `SpellFamilyName`, `SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`, `ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`, `AttributesMask`, `ProcsPerMinute`, `Chance`, `Cooldown`, `Charges`) VALUES +(63849,0,0,0,0,0,0,0,0,0,32,0,0,0,0); + +UPDATE `creature` SET `MovementType`=0, `Spawndist`=0 WHERE `id`=33337; -- XT-Toy Pile + +UPDATE `creature_template` SET `speed_walk`=1.2, `speed_run`=0.428571, `ScriptName`='npc_scrapbot' WHERE `entry`=33343; +UPDATE `creature_template` SET `speed_walk`=1.2, `speed_run`=0.428571 WHERE `entry`=33887; -- Scrapbot +UPDATE `creature_template` SET `speed_walk`=1.2, `speed_run`=0.428571, `modelid2`=0, `modelid3`=0 WHERE `entry` IN (33346,33886); -- Boombot +UPDATE `creature_template` SET `BaseAttackTime`=2000 WHERE `entry` IN (33293,33885); -- XT-002 Deconstructor (hi ariel, I stole from you xD) +UPDATE `creature_template` SET `mechanic_immune_mask`=617299839 WHERE `entry` IN (33329,33885); -- Heart mechanical immunities xD + +DELETE FROM `waypoint_scripts` WHERE `id` IN(2,5); +INSERT INTO `waypoint_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`, `guid`) VALUES +(2,0,1,468,1,0,0,0,0,0,1360540), +(2,11,1,0,1,0,0,0,0,0,1360541), +(5,0,1,10,1,0,0,0,0,0,1360542), +(5,30,1,0,1,0,0,0,0,0,1360543); + +DELETE FROM `waypoint_data` WHERE `id`=1360540; +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES +(1360540, 1, 862.5053, 7.207682, 409.8612, 0, 0, 0, 0, 100, 0), +(1360540, 2, 863.4635, 25.65489, 409.8612, 0, 0, 0, 0, 100, 0), +(1360540, 3, 872.6903, 39.44819, 409.8355, 0, 11000, 0, 2, 100, 0), -- emote 468 11s +(1360540, 4, 869.8901, 32.82189, 409.8509, 0, 0, 0, 0, 100, 0), +(1360540, 5, 854.8365, 9.631022, 409.8612, 0, 0, 0, 0, 100, 0), +(1360540, 6, 855.48, -19.90913, 409.8787, 0, 0, 0, 0, 100, 0), +(1360540, 7, 852.1145, -44.87088, 409.8869, 0, 0, 0, 0, 100, 0), +(1360540, 8, 864.5853, -62.56917, 409.6369, 0, 0, 0, 0, 100, 0), +(1360540, 9, 876.4196, -77.23026, 409.9155, 0, 11000, 0, 2, 100, 0), -- emote 468 11s +(1360540, 10, 878.3914, -79.4183, 409.9155, 0, 0, 0, 0, 100, 0), +(1360540, 11, 870.9197, -65.75331, 409.9155, 0, 0, 0, 0, 100, 0), +(1360540, 12, 880.2524, -33.8488, 409.9155, 0, 0, 0, 0, 100, 0), +(1360540, 13, 883.6281, -12.63596, 409.799, 3.159046, 30000, 0, 5, 100, 0); -- emote 10 30s diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp index 8d9f69b9096..8cc94974e14 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -15,12 +15,6 @@   * with this program. If not, see <http://www.gnu.org/licenses/>.   */ -/* -    @todo -        If the boss is to close to a scrap pile -> no summon  -- Needs retail confirmation -        Codestyle -*/ -  #include "ScriptMgr.h"  #include "InstanceScript.h"  #include "MotionMaster.h" @@ -30,6 +24,7 @@  #include "Player.h"  #include "ScriptedCreature.h"  #include "SpellAuraEffects.h" +#include "SpellMgr.h"  #include "SpellScript.h"  #include "ulduar.h"  #include "Vehicle.h" @@ -37,98 +32,78 @@  enum Spells  { -    SPELL_TYMPANIC_TANTRUM                      = 62776, -    SPELL_SEARING_LIGHT                         = 63018, - -    SPELL_SUMMON_LIFE_SPARK                     = 64210, -    SPELL_SUMMON_VOID_ZONE                      = 64203, - -    SPELL_GRAVITY_BOMB                          = 63024, - -    SPELL_HEARTBREAK                            = 65737, - -    // Cast by 33337 at Heartbreak: -    SPELL_RECHARGE_PUMMELER                     = 62831,    // Summons 33344 -    SPELL_RECHARGE_SCRAPBOT                     = 62828,    // Summons 33343 -    SPELL_RECHARGE_BOOMBOT                      = 62835,    // Summons 33346 - -    // Cast by 33329 on 33337 (visual?) -    SPELL_ENERGY_ORB                            = 62790,    // Triggers 62826 - needs spellscript for periodic tick to cast one of the random spells above - -    SPELL_HEART_HEAL_TO_FULL                    = 17683, -    SPELL_HEART_OVERLOAD                        = 62789, - -    SPELL_HEART_LIGHTNING_TETHER                = 64799,    // Cast on self? -    SPELL_ENRAGE                                = 26662, -    SPELL_STAND                                 = 37752, -    SPELL_SUBMERGE                              = 37751, - -    //------------------VOID ZONE-------------------- -    SPELL_VOID_ZONE                             = 64203, -    SPELL_CONSUMPTION                           = 64208, +    SPELL_TYMPANIC_TANTRUM                  = 62776, +    SPELL_SEARING_LIGHT                     = 63018, +    SPELL_SUMMON_LIFE_SPARK                 = 64210, +    SPELL_SUMMON_VOID_ZONE                  = 64203, +    SPELL_GRAVITY_BOMB                      = 63024, +    SPELL_HEARTBREAK                        = 65737, +    SPELL_STAND                             = 37752, +    SPELL_SUBMERGE                          = 37751, +    SPELL_ENRAGE                            = 26662, +    SPELL_COOLDOWN_CREATURE_SPECIAL_2       = 64404, +    SPELL_SCRAP_REPAIR                      = 62832, + +    // XT-Toy Pile +    SPELL_RECHARGE_PUMMELER                 = 62831, +    SPELL_RECHARGE_SCRAPBOT                 = 62828, +    SPELL_RECHARGE_BOOMBOT                  = 62835, + +    // Heart of the Deconstructor +    SPELL_ENERGY_ORB                        = 62790, +    SPELL_RIDE_VEHICLE_EXPOSED              = 63313, +    SPELL_EXPOSED_HEART                     = 63849, +    SPELL_HEART_RIDE_VEHICLE                = 63852, +    SPELL_SCRAPBOT_RIDE_VEHICLE             = 47020, +    SPELL_FULL_HEAL                         = 17683, +    SPELL_HEART_OVERLOAD                    = 62789, +    SPELL_HEART_LIGHTNING_TETHER            = 64799, + +    // Void Zone +    SPELL_CONSUMPTION                       = 64208,      // Life Spark -    SPELL_ARCANE_POWER_STATE                    = 49411, -    SPELL_STATIC_CHARGED                        = 64227, -    SPELL_SHOCK                                 = 64230, - -    //----------------XT-002 HEART------------------- -    SPELL_EXPOSED_HEART                         = 63849, -    SPELL_HEART_RIDE_VEHICLE                    = 63852, -    SPELL_RIDE_VEHICLE_EXPOSED                  = 63313, //Heart Exposed +    SPELL_ARCANE_POWER_STATE                = 49411, +    SPELL_STATIC_CHARGED                    = 64227, +    SPELL_SHOCK                             = 64230, -    //---------------XM-024 PUMMELLER---------------- -    SPELL_ARCING_SMASH                          = 8374, -    SPELL_TRAMPLE                               = 5568, -    SPELL_UPPERCUT                              = 10966, +    // XM-024 Pummeller +    SPELL_ARCING_SMASH                      = 8374, +    SPELL_TRAMPLE                           = 5568, +    SPELL_UPPERCUT                          = 10966, -    // Scrabot: -    SPELL_SCRAPBOT_RIDE_VEHICLE                 = 47020, -    SPELL_SUICIDE                               = 7, - -    //------------------BOOMBOT----------------------- -    SPELL_AURA_BOOMBOT                          = 65032, -    SPELL_BOOM                                  = 62834, +    //Boombot +    SPELL_321_BOOMBOT_AURA                  = 65032, +    SPELL_BOOM                              = 62834,      // Achievement-related spells -    SPELL_ACHIEVEMENT_CREDIT_NERF_SCRAPBOTS     = 65037 +    SPELL_ACHIEVEMENT_CREDIT_NERF_SCRAPBOTS = 65037  };  enum Events  {      EVENT_TYMPANIC_TANTRUM = 1, +    EVENT_PHASE_CHECK,      EVENT_SEARING_LIGHT,      EVENT_GRAVITY_BOMB, -    EVENT_HEART_PHASE, -    EVENT_ENERGY_ORB, +    EVENT_SUBMERGE,      EVENT_DISPOSE_HEART,      EVENT_ENRAGE,      EVENT_ENTER_HARD_MODE, +    EVENT_RESUME_ATTACK  }; -enum Timers +enum XT002Phases  { -    TIMER_TYMPANIC_TANTRUM_MIN                  = 32000, -    TIMER_TYMPANIC_TANTRUM_MAX                  = 36000, -    TIMER_SEARING_LIGHT                         = 20000, -    TIMER_GRAVITY_BOMB                          = 20000, -    TIMER_HEART_PHASE                           = 30000, -    TIMER_ENERGY_ORB_MIN                        = 9000, -    TIMER_ENERGY_ORB_MAX                        = 10000, -    TIMER_ENRAGE                                = 600000, - -    // Pummeller -    // Timers may be off -    TIMER_ARCING_SMASH                          = 27000, -    TIMER_TRAMPLE                               = 22000, -    TIMER_UPPERCUT                              = 17000, - -    TIMER_SPAWN_ADD                             = 12000, +    PHASE_1 = 1, +    PHASE_HEART  };  enum Actions  {      ACTION_ENTER_HARD_MODE, +    ACTION_START_PHASE_HEART, +    ACTION_DISPOSE_HEART  };  enum XT002Data @@ -136,933 +111,851 @@ enum XT002Data      DATA_TRANSFERED_HEALTH,      DATA_HARD_MODE,      DATA_HEALTH_RECOVERED, -    DATA_GRAVITY_BOMB_CASUALTY, +    DATA_GRAVITY_BOMB_CASUALTY  };  enum Yells  { -    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 +    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 AchievementCredits +enum Misc  { -    ACHIEV_MUST_DECONSTRUCT_FASTER              = 21027, +    ACHIEV_MUST_DECONSTRUCT_FASTER = 21027, +    HEART_VEHICLE_SEAT_EXPOSED     = 1, +    GROUP_SEARING_GRAVITY          = 1  }; -enum VehicleSeats +struct boss_xt002 : public BossAI  { -    HEART_VEHICLE_SEAT_NORMAL   = 0, -    HEART_VEHICLE_SEAT_EXPOSED  = 1, -}; +    boss_xt002(Creature* creature) : BossAI(creature, BOSS_XT002) +    { +        Initialize(); +    } -/*------------------------------------------------------- - * - *        XT-002 DECONSTRUCTOR - * - *///---------------------------------------------------- -class boss_xt002 : public CreatureScript -{ -    public: -        boss_xt002() : CreatureScript("boss_xt002") { } +    void Initialize() +    { +        _healthRecovered = false; +        _gravityBombCasualty = false; +        _hardMode = false; +        _exposeHeartPercent = 75; +    } -        struct boss_xt002_AI : public BossAI +    void ChangeNextExpose() +    { +        switch (_exposeHeartPercent)          { -            boss_xt002_AI(Creature* creature) : BossAI(creature, BOSS_XT002) -            { -                Initialize(); -                _transferHealth = 0; -            } - -            void Initialize() -            { -                _healthRecovered = false; -                _gravityBombCasualty = false; -                _hardMode = false; - -                _phase = 1; -                _heartExposed = 0; -            } - -            void Reset() override -            { -                _Reset(); - -                me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                me->SetReactState(REACT_AGGRESSIVE); -                DoCastSelf(SPELL_STAND); - -                Initialize(); +            case 75: +                _exposeHeartPercent = 50; +                break; +            case 50: +                _exposeHeartPercent = 25; +                break; +            default: +                _exposeHeartPercent = 0; +                break; +        } +    } -                instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); -            } +    void Reset() override +    { +        _Reset(); +        events.SetPhase(PHASE_1); +        me->SetReactState(REACT_DEFENSIVE); +        Initialize(); +        instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); +    } -            void EnterEvadeMode(EvadeReason /*why*/) override -            { -                summons.DespawnAll(); -                _DespawnAtEvade(); -            } +    void EnterEvadeMode(EvadeReason /*why*/) override +    { +        summons.DespawnAll(); +        _DespawnAtEvade(); +    } -            void JustEngagedWith(Unit* /*who*/) override -            { -                Talk(SAY_AGGRO); -                _JustEngagedWith(); +    void JustEngagedWith(Unit* /*who*/) override +    { +        Talk(SAY_AGGRO); +        _JustEngagedWith(); +        events.ScheduleEvent(EVENT_SEARING_LIGHT, Is25ManRaid() ? 9s : 11s, GROUP_SEARING_GRAVITY, PHASE_1); +        events.ScheduleEvent(EVENT_GRAVITY_BOMB, Is25ManRaid() ? 18s : 21s, GROUP_SEARING_GRAVITY, PHASE_1); +        events.ScheduleEvent(EVENT_ENRAGE, 10min); +        events.ScheduleEvent(EVENT_TYMPANIC_TANTRUM, 60s, 0, PHASE_1); +        events.ScheduleEvent(EVENT_PHASE_CHECK, 1s, 0, PHASE_1); +        instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); +    } -                events.ScheduleEvent(EVENT_ENRAGE, TIMER_ENRAGE); -                events.ScheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); -                events.ScheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT); -                //Tantrum is cast a bit slower the first time. -                events.ScheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX) * 2); +    void DoAction(int32 action) override +    { +        if (action == ACTION_ENTER_HARD_MODE) +            events.ScheduleEvent(EVENT_ENTER_HARD_MODE, 1); +    } -                instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); -            } +    void KilledUnit(Unit* who) override +    { +        if (who->GetTypeId() == TYPEID_PLAYER) +            Talk(SAY_SLAY); +    } -            void DoAction(int32 action) override -            { -                switch (action) -                { -                    case ACTION_ENTER_HARD_MODE: -                        events.ScheduleEvent(EVENT_ENTER_HARD_MODE, 1); -                        break; -                } -            } +    void JustDied(Unit* /*killer*/) override +    { +        Talk(SAY_DEATH); +        _JustDied(); +        me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +    } -            void KilledUnit(Unit* who) override -            { -                if (who->GetTypeId() == TYPEID_PLAYER) -                    Talk(SAY_SLAY); -            } +    void ExposeHeart() +    { +        events.SetPhase(PHASE_HEART); +        me->SetReactState(REACT_PASSIVE); +        me->AttackStop(); +        Talk(SAY_HEART_OPENED); +        events.CancelEvent(EVENT_TYMPANIC_TANTRUM); +        events.ScheduleEvent(EVENT_SUBMERGE, 6s, 0, PHASE_HEART); +        ChangeNextExpose(); +    } -            void JustDied(Unit* /*killer*/) override -            { -                Talk(SAY_DEATH); -                _JustDied(); -                me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -            } +    void DisposeHeart(bool isHardMode = false) +    { +        Talk(SAY_HEART_CLOSED); -            void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) override -            { -                if (!_hardMode && _phase == 1 && !HealthAbovePct(100 - 25 * (_heartExposed+1))) -                    ExposeHeart(); -            } +        if (isHardMode) +        { +            me->SetReactState(REACT_AGGRESSIVE); +            RescheduleEvents(); +        } +        else +        { +            Talk(EMOTE_HEART_CLOSED); +            events.ScheduleEvent(EVENT_RESUME_ATTACK, 1s, 0, PHASE_HEART); +        } -            void UpdateAI(uint32 diff) override -            { -                if (!UpdateVictim()) -                    return; +        DoCastSelf(SPELL_STAND); +        DoCastSelf(SPELL_COOLDOWN_CREATURE_SPECIAL_2); +        me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +        if (Creature* heart = instance->GetCreature(DATA_XT002_HEART)) +        { +            if (heart->IsAlive()) +                heart->AI()->DoAction(ACTION_DISPOSE_HEART); +            else +                heart->DespawnOrUnsummon(); +        } -                events.Update(diff); +    } -                if (me->HasUnitState(UNIT_STATE_CASTING)) -                    return; +    void RescheduleEvents() +    { +        events.SetPhase(PHASE_1); +        events.ScheduleEvent(EVENT_SEARING_LIGHT, 25s, GROUP_SEARING_GRAVITY, PHASE_1); +        events.ScheduleEvent(EVENT_GRAVITY_BOMB, Is25ManRaid() ? 33s : 15s, GROUP_SEARING_GRAVITY, PHASE_1); +        events.ScheduleEvent(EVENT_TYMPANIC_TANTRUM, 25s, 0, PHASE_1); +        if (!_hardMode) +            events.ScheduleEvent(EVENT_PHASE_CHECK, 1s, 0, PHASE_1); +    } -                while (uint32 eventId = events.ExecuteEvent()) -                { -                    switch (eventId) -                    { -                        case EVENT_SEARING_LIGHT: -                            if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) -                                DoCast(target, SPELL_SEARING_LIGHT); - -                            events.ScheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT); -                            break; -                        case EVENT_GRAVITY_BOMB: -                            if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) -                                DoCast(target, SPELL_GRAVITY_BOMB); - -                            events.ScheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); -                            break; -                        case EVENT_TYMPANIC_TANTRUM: -                            Talk(SAY_TYMPANIC_TANTRUM); -                            Talk(EMOTE_TYMPANIC_TANTRUM); -                            DoCast(SPELL_TYMPANIC_TANTRUM); -                            events.ScheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX)); -                            break; -                        case EVENT_DISPOSE_HEART: -                            SetPhaseOne(); -                            break; -                        case EVENT_ENRAGE: -                            Talk(SAY_BERSERK); -                            DoCastSelf(SPELL_ENRAGE); -                            break; -                        case EVENT_ENTER_HARD_MODE: -                            me->SetFullHealth(); -                            DoCastSelf(SPELL_HEARTBREAK, true); -                            me->AddLootMode(LOOT_MODE_HARD_MODE_1); -                            _hardMode = true; -                            SetPhaseOne(); -                            break; -                    } +    void PassengerBoarded(Unit* who, int8 seatId, bool apply) override +    { +        if (!apply) +            return; -                    if (me->HasUnitState(UNIT_STATE_CASTING)) -                        return; -                } +        if (who->GetEntry() == NPC_XS013_SCRAPBOT) +        { +            Talk(EMOTE_SCRAPBOT); +            _healthRecovered = true; +        } +        else if (seatId == HEART_VEHICLE_SEAT_EXPOSED) +            who->CastSpell(who, SPELL_EXPOSED_HEART);   // Channeled +    } -                if (_phase == 1) -                    DoMeleeAttackIfReady(); -            } +    uint32 GetData(uint32 type) const override +    { +        switch (type) +        { +            case DATA_HARD_MODE: +                return _hardMode ? 1 : 0; +            case DATA_HEALTH_RECOVERED: +                return _healthRecovered ? 1 : 0; +            case DATA_GRAVITY_BOMB_CASUALTY: +                return _gravityBombCasualty ? 1 : 0; +            default: +                return 0; +        } +    } -            void PassengerBoarded(Unit* who, int8 seatId, bool apply) override -            { -                if (apply && who->GetEntry() == NPC_XS013_SCRAPBOT) +    void SetData(uint32 type, uint32 data) override +    { +        switch (type) +        { +            case DATA_TRANSFERED_HEALTH: +                if (!_hardMode)                  { -                    // Need this so we can properly determine when to expose heart again in damagetaken hook -                    if (me->GetHealthPct() > (25 * (4 - _heartExposed))) -                        ++_heartExposed; +                    uint32 transferHealth = data; +                    if (transferHealth >= me->GetHealth()) +                        transferHealth = me->GetHealth() - 1; -                    Talk(EMOTE_SCRAPBOT); -                    _healthRecovered = true; +                    me->ModifyHealth(-static_cast<int32>(transferHealth)); +                    me->LowerPlayerDamageReq(transferHealth);                  } +                break; +            case DATA_GRAVITY_BOMB_CASUALTY: +                _gravityBombCasualty = (data > 0) ? true : false; +                break; +            default: +                break; +        } +    } -                if (apply && seatId == HEART_VEHICLE_SEAT_EXPOSED) -                    who->CastSpell(who, SPELL_EXPOSED_HEART);   // Channeled -            } +    void UpdateAI(uint32 diff) override +    { +        if (!UpdateVictim()) +            return; -            uint32 GetData(uint32 type) const override -            { -                switch (type) -                { -                    case DATA_HARD_MODE: -                        return _hardMode ? 1 : 0; -                    case DATA_HEALTH_RECOVERED: -                        return _healthRecovered ? 1 : 0; -                    case DATA_GRAVITY_BOMB_CASUALTY: -                        return _gravityBombCasualty ? 1 : 0; -                } +        events.Update(diff); -                return 0; -            } +        if (me->HasUnitState(UNIT_STATE_CASTING)) +            return; -            void SetData(uint32 type, uint32 data) override -            { -                switch (type) -                { -                    case DATA_TRANSFERED_HEALTH: -                        _transferHealth = data; -                        break; -                    case DATA_GRAVITY_BOMB_CASUALTY: -                        _gravityBombCasualty = (data > 0) ? true : false; -                        break; -                } -            } - -            void ExposeHeart() +        while (uint32 eventId = events.ExecuteEvent()) +        { +            switch (eventId)              { -                Talk(SAY_HEART_OPENED); -                Talk(EMOTE_HEART_OPENED); - -                DoCastSelf(SPELL_SUBMERGE);  // Will make creature untargetable -                me->AttackStop(); -                me->SetReactState(REACT_PASSIVE); - -                Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT_NORMAL) : nullptr; -                if (heart) -                { -                    heart->CastSpell(heart, SPELL_HEART_OVERLOAD); -                    heart->CastSpell(me, SPELL_HEART_LIGHTNING_TETHER); -                    heart->CastSpell(heart, SPELL_HEART_HEAL_TO_FULL, true); -                    heart->CastSpell(me, SPELL_RIDE_VEHICLE_EXPOSED, true); -                    heart->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                    heart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29); -               } - -                events.CancelEvent(EVENT_SEARING_LIGHT); -                events.CancelEvent(EVENT_GRAVITY_BOMB); -                events.CancelEvent(EVENT_TYMPANIC_TANTRUM); - -                // Start "end of phase 2 timer" -                events.ScheduleEvent(EVENT_DISPOSE_HEART, TIMER_HEART_PHASE); - -                // Phase 2 has officially started -                _phase = 2; -                _heartExposed++; +                case EVENT_SEARING_LIGHT: +                    DoCastSelf(SPELL_SEARING_LIGHT); +                    events.Repeat(Is25ManRaid() ? 16s : 20s); +                    break; +                case EVENT_GRAVITY_BOMB: +                    DoCastSelf(SPELL_GRAVITY_BOMB); +                    events.Repeat(Is25ManRaid() ? 16s : 20s); +                    break; +                case EVENT_TYMPANIC_TANTRUM: +                    Talk(SAY_TYMPANIC_TANTRUM); +                    Talk(EMOTE_TYMPANIC_TANTRUM); +                    events.DelayEvents(10s, GROUP_SEARING_GRAVITY); +                    DoCastSelf(SPELL_TYMPANIC_TANTRUM); +                    events.Repeat(60s); +                    break; +                case EVENT_PHASE_CHECK: +                    if (me->HealthBelowPct(_exposeHeartPercent)) +                        ExposeHeart(); +                    events.Repeat(1s); +                    break; +                case EVENT_SUBMERGE: +                    DoCastSelf(SPELL_SUBMERGE); +                    Talk(EMOTE_HEART_OPENED); +                    if (Creature* heart = instance->GetCreature(DATA_XT002_HEART)) +                        heart->AI()->DoAction(ACTION_START_PHASE_HEART); +                    events.ScheduleEvent(EVENT_DISPOSE_HEART, 30s, PHASE_HEART); +                    break; +                case EVENT_DISPOSE_HEART: +                    DisposeHeart(); +                    break; +                case EVENT_ENRAGE: +                    Talk(SAY_BERSERK); +                    DoCastSelf(SPELL_ENRAGE); +                    break; +                case EVENT_ENTER_HARD_MODE: +                    me->SetFullHealth(); +                    DoCastSelf(SPELL_HEARTBREAK, true); +                    me->AddLootMode(LOOT_MODE_HARD_MODE_1); +                    _hardMode = true; +                    DisposeHeart(_hardMode); +                    break; +                case EVENT_RESUME_ATTACK: +                    me->SetReactState(REACT_AGGRESSIVE); +                    RescheduleEvents(); +                    break; +                default: +                    break;              } -            void SetPhaseOne() -            { -                Talk(SAY_HEART_CLOSED); -                Talk(EMOTE_HEART_CLOSED); - -                me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                me->SetReactState(REACT_AGGRESSIVE); -                DoCastSelf(SPELL_STAND); - -                _phase = 1; - -                events.RescheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT / 2); -                events.RescheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); -                events.RescheduleEvent(EVENT_TYMPANIC_TANTRUM, urand(TIMER_TYMPANIC_TANTRUM_MIN, TIMER_TYMPANIC_TANTRUM_MAX)); - -                Unit* heart = me->GetVehicleKit() ? me->GetVehicleKit()->GetPassenger(HEART_VEHICLE_SEAT_EXPOSED) : nullptr; -                if (!heart) -                    return; - -                heart->CastSpell(me, SPELL_HEART_RIDE_VEHICLE, true); -                heart->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                heart->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29); -                heart->RemoveAurasDueToSpell(SPELL_EXPOSED_HEART); - -                if (!_hardMode) -                { -                    if (!_transferHealth) -                        _transferHealth = (heart->GetMaxHealth() - heart->GetHealth()); +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; +        } -                    if (_transferHealth >= me->GetHealth()) -                        _transferHealth = me->GetHealth() - 1; +        if (events.IsInPhase(PHASE_1)) +            DoMeleeAttackIfReady(); +    } -                    me->ModifyHealth(-((int32)_transferHealth)); -                    me->LowerPlayerDamageReq(_transferHealth); -                } -            } +private: +    bool _healthRecovered;       // Did a scrapbot recover XT-002's health during the encounter? +    bool _hardMode;              // Are we in hard mode? Or: was the heart killed during phase 2? +    bool _gravityBombCasualty;   // Did someone die because of Gravity Bomb damage? +    uint8 _exposeHeartPercent; +}; -            private: -                // Achievement related -                bool _healthRecovered;       // Did a scrapbot recover XT-002's health during the encounter? -                bool _hardMode;              // Are we in hard mode? Or: was the heart killed during phase 2? -                bool _gravityBombCasualty;   // Did someone die because of Gravity Bomb damage? +struct npc_xt002_heart : public NullCreatureAI +{ +    npc_xt002_heart(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()) { } -                uint8 _phase; -                uint8 _heartExposed; -                uint32 _transferHealth; -        }; +    void DoAction(int32 action) override +    { +        Creature* xt002 = _instance->GetCreature(BOSS_XT002); +        if (!xt002) +            return; -        CreatureAI* GetAI(Creature* creature) const override +        if (action == ACTION_START_PHASE_HEART)          { -            return GetUlduarAI<boss_xt002_AI>(creature); +            DoCastSelf(SPELL_FULL_HEAL); +            DoCast(xt002, SPELL_RIDE_VEHICLE_EXPOSED, true); +            DoCastSelf(SPELL_HEART_OVERLOAD); +            me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);          } - -}; - -/*------------------------------------------------------- - * - *        XT-002 HEART - * - *///---------------------------------------------------- - -class npc_xt002_heart : public CreatureScript -{ -    public: -        npc_xt002_heart() : CreatureScript("npc_xt002_heart") { } - -        struct npc_xt002_heartAI : public NullCreatureAI +        else if (action == ACTION_DISPOSE_HEART)          { -            npc_xt002_heartAI(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()) { } - -            void JustDied(Unit* /*killer*/) override -            { -                if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) -                { -                    xt002->AI()->SetData(DATA_TRANSFERED_HEALTH, me->GetHealth()); -                    xt002->AI()->DoAction(ACTION_ENTER_HARD_MODE); -                } -            } +            DoCast(xt002, SPELL_HEART_RIDE_VEHICLE, true); +            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +            me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29); +        } +    } -        private: -            InstanceScript* _instance; -        }; +    void JustDied(Unit* /*killer*/) override +    { +        if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) +            xt002->AI()->DoAction(ACTION_ENTER_HARD_MODE); +    } -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetUlduarAI<npc_xt002_heartAI>(creature); -        } +private: +    InstanceScript * _instance;  }; -/*------------------------------------------------------- - * - *        XS-013 SCRAPBOT - * - *///---------------------------------------------------- -class npc_scrapbot : public CreatureScript +struct npc_scrapbot : public ScriptedAI  { -    public: -        npc_scrapbot() : CreatureScript("npc_scrapbot") { } +    npc_scrapbot(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } -        struct npc_scrapbotAI : public ScriptedAI +    void Reset() override +    { +        me->SetReactState(REACT_PASSIVE); +        _scheduler.CancelAll(); + +        if (_instance->GetBossState(BOSS_XT002) != IN_PROGRESS)          { -            npc_scrapbotAI(Creature* creature) : ScriptedAI(creature) -            { -                Initialize(); -                _instance = me->GetInstanceScript(); -            } +            me->DespawnOrUnsummon(); +            return; +        } -            void Initialize() -            { -                _rangeCheckTimer = 500; -            } +        if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) +            xt002->AI()->JustSummoned(me); -            void Reset() override +        _scheduler. +            Schedule(2s, [this](TaskContext /*StartMove*/)              { -                me->SetReactState(REACT_PASSIVE); - -                Initialize(); -                  if (Creature* xt002 = _instance->GetCreature(BOSS_XT002))                      me->GetMotionMaster()->MoveFollow(xt002, 0.0f, 0.0f); -            } - -            void UpdateAI(uint32 diff) override +            }) +            .Schedule(1s, [this](TaskContext checkXt002)              { -                if (_rangeCheckTimer <= diff) +                if (Creature* xt002 = _instance->GetCreature(BOSS_XT002))                  { -                    if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) +                    if (me->IsWithinMeleeRange(xt002))                      { -                        if (me->IsWithinMeleeRange(xt002)) +                        DoCast(xt002, SPELL_SCRAPBOT_RIDE_VEHICLE); +                        _scheduler.Schedule(1s, [this](TaskContext /*ScrapRepair*/)                          { -                            DoCast(xt002, SPELL_SCRAPBOT_RIDE_VEHICLE); -                            // Unapply vehicle aura again -                            xt002->RemoveAurasDueToSpell(SPELL_SCRAPBOT_RIDE_VEHICLE); -                            me->DespawnOrUnsummon(); -                        } +                            if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) +                                xt002->CastSpell(me, SPELL_SCRAP_REPAIR, true); +                            me->DespawnOrUnsummon(1s); +                        });                      } +                    else +                        checkXt002.Repeat();                  }                  else -                    _rangeCheckTimer -= diff; -            } +                    me->DespawnOrUnsummon(); +            }); +    } -            private: -                InstanceScript* _instance; -                uint32 _rangeCheckTimer; -        }; +    void UpdateAI(uint32 diff) override +    { +        _scheduler.Update(diff); +    } -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetUlduarAI<npc_scrapbotAI>(creature); -        } +private: +    InstanceScript* _instance; +    TaskScheduler _scheduler;  }; -/*------------------------------------------------------- - * - *        XM-024 PUMMELLER - * - *///---------------------------------------------------- -class npc_pummeller : public CreatureScript +struct npc_pummeller : public ScriptedAI  { -    public: -        npc_pummeller() : CreatureScript("npc_pummeller") { } +    npc_pummeller(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } -        struct npc_pummellerAI : public ScriptedAI -        { -            npc_pummellerAI(Creature* creature) : ScriptedAI(creature) -            { -                Initialize(); -                _instance = creature->GetInstanceScript(); -            } +    void Reset() override +    { +        me->SetReactState(REACT_PASSIVE); +        _scheduler.CancelAll(); -            void Initialize() -            { -                _arcingSmashTimer = TIMER_ARCING_SMASH; -                _trampleTimer = TIMER_TRAMPLE; -                _uppercutTimer = TIMER_UPPERCUT; -            } +        if (_instance->GetBossState(BOSS_XT002) != IN_PROGRESS) +        { +            me->DespawnOrUnsummon(); +            return; +        } -            void Reset() override -            { -                Initialize(); -                if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) -                { -                    Position pos = xt002->GetPosition(); -                    me->GetMotionMaster()->MovePoint(0, pos); -                } -            } +        if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) +            xt002->AI()->JustSummoned(me); -            void UpdateAI(uint32 diff) override +        _scheduler. +            Schedule(1s, [this](TaskContext /*StartMove*/)              { -                if (!UpdateVictim()) -                    return; - -                if (me->IsWithinMeleeRange(me->GetVictim())) -                { -                    if (_arcingSmashTimer <= diff) -                    { -                        DoCastVictim(SPELL_ARCING_SMASH); -                        _arcingSmashTimer = TIMER_ARCING_SMASH; -                    } -                    else -                        _arcingSmashTimer -= diff; - -                    if (_trampleTimer <= diff) -                    { -                        DoCastVictim(SPELL_TRAMPLE); -                        _trampleTimer = TIMER_TRAMPLE; -                    } -                    else -                        _trampleTimer -= diff; - -                    if (_uppercutTimer <= diff) -                    { -                        DoCastVictim(SPELL_UPPERCUT); -                        _uppercutTimer = TIMER_UPPERCUT; -                    } -                    else -                        _uppercutTimer -= diff; -                } +                me->SetReactState(REACT_AGGRESSIVE); +                DoZoneInCombat(); +            }) +            .Schedule(17s, [this](TaskContext trample) +            { +                DoCastSelf(SPELL_TRAMPLE); +                trample.Repeat(11s); +            }) +            .Schedule(19s, [this](TaskContext arcingSmash) +            { +                DoCastSelf(SPELL_ARCING_SMASH); +                arcingSmash.Repeat(8s); +            }) +            .Schedule(19s, [this](TaskContext upperCut) +            { +                DoCastVictim(SPELL_UPPERCUT); +                upperCut.Repeat(14s); +            }); -                DoMeleeAttackIfReady(); -            } +    } -            private: -                InstanceScript* _instance; -                uint32 _arcingSmashTimer; -                uint32 _trampleTimer; -                uint32 _uppercutTimer; -        }; +    void UpdateAI(uint32 diff) override +    { +        if (!UpdateVictim()) +            return; -        CreatureAI* GetAI(Creature* creature) const override +        _scheduler.Update(diff, [this]          { -            return GetUlduarAI<npc_pummellerAI>(creature); -        } +            DoMeleeAttackIfReady(); +        }); +    } + +private: +    InstanceScript* _instance; +    TaskScheduler _scheduler;  }; -/*------------------------------------------------------- - * - *        XE-321 BOOMBOT - * - *///---------------------------------------------------- -class npc_boombot : public CreatureScript +struct npc_boombot : public ScriptedAI  { -    public: -        npc_boombot() : CreatureScript("npc_boombot") { } - -        struct npc_boombotAI : public ScriptedAI -        { -            npc_boombotAI(Creature* creature) : ScriptedAI(creature) -            { -                Initialize(); -                _instance = creature->GetInstanceScript(); -            } +    npc_boombot(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _boomed(false) { } -            void Initialize() -            { -                _boomed = false; -            } +    void Reset() override +    { +        DoCastSelf(SPELL_321_BOOMBOT_AURA); +        me->SetReactState(REACT_PASSIVE); +        _scheduler.CancelAll(); -            void Reset() override -            { -                Initialize(); +        if (_instance->GetBossState(BOSS_XT002) != IN_PROGRESS) +        { +            me->DespawnOrUnsummon(); +            return; +        } -                DoCast(SPELL_AURA_BOOMBOT); // For achievement +        // HACK/workaround: +        // these values aren't confirmed - lack of data - and the values in DB are incorrect +        // these values are needed for correct damage of Boom spell +        me->SetFloatValue(UNIT_FIELD_MINDAMAGE, 15000.0f); +        me->SetFloatValue(UNIT_FIELD_MAXDAMAGE, 18000.0f); -                // HACK/workaround: -                // these values aren't confirmed - lack of data - and the values in DB are incorrect -                // these values are needed for correct damage of Boom spell -                me->SetFloatValue(UNIT_FIELD_MINDAMAGE, 15000.0f); -                me->SetFloatValue(UNIT_FIELD_MAXDAMAGE, 18000.0f); +        if (Creature* xt002 = _instance->GetCreature(BOSS_XT002)) +            xt002->AI()->JustSummoned(me); -                /// @todo proper waypoints? +        _scheduler. +            Schedule(4s, [this](TaskContext /*StartMove*/) +            {                  if (Creature* xt002 = _instance->GetCreature(BOSS_XT002))                      me->GetMotionMaster()->MoveFollow(xt002, 0.0f, 0.0f); -            } -            void DamageTaken(Unit* /*who*/, uint32& damage) override +            }) +            .Schedule(1s, [this](TaskContext checkXt002)              { -                if (damage >= (me->GetHealth() - me->GetMaxHealth() * 0.5f) && !_boomed) +                if (Creature* xt002 = _instance->GetCreature(BOSS_XT002))                  { -                    _boomed = true; // Prevent recursive calls - -                    WorldPacket data(SMSG_SPELLINSTAKILLLOG, 8+8+4); -                    data << uint64(me->GetGUID()); -                    data << uint64(me->GetGUID()); -                    data << uint32(SPELL_BOOM); -                    me->SendMessageToSet(&data, false); - -                    me->KillSelf(); - -                    damage = 0; - -                    DoCastAOE(SPELL_BOOM); +                    if (me->IsWithinMeleeRange(xt002)) +                        DoCastAOE(SPELL_BOOM); +                    else +                        checkXt002.Repeat();                  } -            } - -            void UpdateAI(uint32 /*diff*/) override -            { -                if (!UpdateVictim()) -                    return; - -                // No melee attack -            } - -           private: -                InstanceScript* _instance; -                bool _boomed; -        }; +                else +                    me->DespawnOrUnsummon(); +            }); +    } -        CreatureAI* GetAI(Creature* creature) const override +    void DamageTaken(Unit* /*who*/, uint32& damage) override +    { +        if (damage >= (me->GetHealth() - me->GetMaxHealth() * 0.5f) && !_boomed)          { -            return GetUlduarAI<npc_boombotAI>(creature); +            _boomed = true; // Prevent recursive call +            damage = 0; +            DoCastAOE(SPELL_BOOM);          } +    } + +    void UpdateAI(uint32 diff) override +    { +        _scheduler.Update(diff); +    } + +private: +    InstanceScript* _instance; +    bool _boomed; +    TaskScheduler _scheduler;  }; -class npc_life_spark : public CreatureScript +struct npc_life_spark : public ScriptedAI  { -    public: -        npc_life_spark() : CreatureScript("npc_life_spark") { } +    npc_life_spark(Creature* creature) : ScriptedAI(creature) { } -        CreatureAI* GetAI(Creature* creature) const override -        { -            return GetUlduarAI<npc_life_sparkAI>(creature); -        } +    void Reset() override +    { +        DoCastSelf(SPELL_ARCANE_POWER_STATE); +        _scheduler.CancelAll(); +    } -        struct npc_life_sparkAI : public ScriptedAI +    void JustEngagedWith(Unit* /*who*/) override +    { +        DoCastSelf(SPELL_STATIC_CHARGED); +        _scheduler.Schedule(12s, [this](TaskContext spellShock)          { -            npc_life_sparkAI(Creature* creature) : ScriptedAI(creature){ } - -            void Reset() override -            { -                DoCastSelf(SPELL_ARCANE_POWER_STATE); -                _scheduler.CancelAll(); -            } - -            void JustEngagedWith(Unit* /*who*/) override -            { -                DoCastSelf(SPELL_STATIC_CHARGED); -                _scheduler.Schedule(Seconds(12), [this](TaskContext spellShock) -                { -                    DoCastVictim(SPELL_SHOCK); -                    spellShock.Repeat(); -                }); -            } +            DoCastVictim(SPELL_SHOCK); +            spellShock.Repeat(); +        }); +    } -            void UpdateAI(uint32 diff) override -            { -                if (!UpdateVictim()) -                    return; +    void UpdateAI(uint32 diff) override +    { +        if (!UpdateVictim()) +            return; -                if (me->HasUnitState(UNIT_STATE_CASTING)) -                    return; +        if (me->HasUnitState(UNIT_STATE_CASTING)) +            return; -                _scheduler.Update(diff, [this] -                { -                    DoMeleeAttackIfReady(); -                }); -            } +        _scheduler.Update(diff, [this] +        { +            DoMeleeAttackIfReady(); +        }); +    } -            private: -                TaskScheduler _scheduler; -        }; +private: +    TaskScheduler _scheduler;  }; -class npc_xt_void_zone : public CreatureScript +struct npc_xt_void_zone : public PassiveAI  { -public: -    npc_xt_void_zone() : CreatureScript("npc_xt_void_zone") { } +    npc_xt_void_zone(Creature* creature) : PassiveAI(creature) { } -    struct npc_xt_void_zoneAI : public PassiveAI +    void Reset() override      { -        npc_xt_void_zoneAI(Creature* creature) : PassiveAI(creature) { } +        int32 bp = 0; +        if (SpellInfo const* createdBySpell = sSpellMgr->GetSpellInfo(me->GetUInt32Value(UNIT_CREATED_BY_SPELL))) +            bp = createdBySpell->Effects[EFFECT_1].CalcValue(); -        void Reset() override +        _scheduler.Schedule(1s, [this, bp](TaskContext consumption)          { -            _scheduler.Schedule(Seconds(1), [this](TaskContext consumption) -            { -                DoCastSelf(SPELL_CONSUMPTION); -                consumption.Repeat(); -            }); -        } - -        void UpdateAI(uint32 diff) override -        { -            _scheduler.Update(diff); -        } - -    private: -        TaskScheduler _scheduler; -    }; +            CastSpellExtraArgs args(false); +            if (bp) +                args.AddSpellBP0(bp); +            DoCastSelf(SPELL_CONSUMPTION, args); +            consumption.Repeat(); +        }); +    } -    CreatureAI* GetAI(Creature* creature) const override +    void UpdateAI(uint32 diff) override      { -        return GetUlduarAI<npc_xt_void_zoneAI>(creature); +        _scheduler.Update(diff);      } +private: +    TaskScheduler _scheduler;  }; -class spell_xt002_searing_light_spawn_life_spark : public SpellScriptLoader +/* 63018 - Searing Light +   65121 - Searing Light */ +class spell_xt002_searing_light_spawn_life_spark : public AuraScript  { -    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); +    PrepareAuraScript(spell_xt002_searing_light_spawn_life_spark); -            bool Validate(SpellInfo const* /*spell*/) override -            { -                return ValidateSpellInfo({ SPELL_SUMMON_LIFE_SPARK }); -            } - -            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->CastSpell(player, SPELL_SUMMON_LIFE_SPARK, true); -            } +    bool Validate(SpellInfo const* /*spell*/) override +    { +        return ValidateSpellInfo({ SPELL_SUMMON_LIFE_SPARK }); +    } -            void Register() override -            { -                AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_searing_light_spawn_life_spark_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); -            } -        }; +    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->CastSpell(player, SPELL_SUMMON_LIFE_SPARK, true); +    } -        AuraScript* GetAuraScript() const override -        { -            return new spell_xt002_searing_light_spawn_life_spark_AuraScript(); -        } +    void Register() override +    { +        AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_searing_light_spawn_life_spark::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); +    }  }; -class spell_xt002_gravity_bomb_aura : public SpellScriptLoader +/* 63024 - Gravity Bomb +   64234 - Gravity Bomb */ +class spell_xt002_gravity_bomb_aura : public AuraScript  { -    public: -        spell_xt002_gravity_bomb_aura() : SpellScriptLoader("spell_xt002_gravity_bomb_aura") { } +    PrepareAuraScript(spell_xt002_gravity_bomb_aura); -        class spell_xt002_gravity_bomb_aura_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_xt002_gravity_bomb_aura_AuraScript); +    bool Validate(SpellInfo const* /*spell*/) override +    { +        return ValidateSpellInfo({ SPELL_SUMMON_VOID_ZONE }); +    } -            bool Validate(SpellInfo const* /*spell*/) override -            { -                return ValidateSpellInfo({ SPELL_SUMMON_VOID_ZONE }); -            } +    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->CastSpell(player, SPELL_SUMMON_VOID_ZONE, true); +    } -            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->CastSpell(player, SPELL_SUMMON_VOID_ZONE, true); -            } +    void OnPeriodic(AuraEffect const* aurEff) +    { +        Unit* xt002 = GetCaster(); +        Unit* owner = GetTarget(); +        if (!xt002 || !xt002->IsAIEnabled) +            return; -            void OnPeriodic(AuraEffect const* aurEff) -            { -                Unit* xt002 = GetCaster(); -                if (!xt002) -                    return; +        if (aurEff->GetAmount() >= int32(owner->GetHealth())) +            xt002->GetAI()->SetData(DATA_GRAVITY_BOMB_CASUALTY, 1); +    } -                Unit* owner = GetOwner()->ToUnit(); -                if (!owner) -                    return; +    void Register() override +    { +        OnEffectPeriodic += AuraEffectPeriodicFn(spell_xt002_gravity_bomb_aura::OnPeriodic, EFFECT_2, SPELL_AURA_PERIODIC_DAMAGE); +        AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_gravity_bomb_aura::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); +    } +}; -                if (aurEff->GetAmount() >= int32(owner->GetHealth())) -                    if (xt002->GetAI()) -                        xt002->GetAI()->SetData(DATA_GRAVITY_BOMB_CASUALTY, 1); -            } +/*  63025 - Gravity Bomb +    64233 - Gravity Bomb */ +class spell_xt002_gravity_bomb_damage : public SpellScript +{ +    PrepareSpellScript(spell_xt002_gravity_bomb_damage); -            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); -            } -        }; +    void HandleScript(SpellEffIndex /*eff*/) +    { +        Unit* caster = GetCaster(); +        if (GetHitDamage() >= int32(GetHitUnit()->GetHealth())) +            if (caster->IsAIEnabled) +                caster->GetAI()->SetData(DATA_GRAVITY_BOMB_CASUALTY, 1); +    } -        AuraScript* GetAuraScript() const override -        { -            return new spell_xt002_gravity_bomb_aura_AuraScript(); -        } +    void Register() override +    { +        OnEffectHitTarget += SpellEffectFn(spell_xt002_gravity_bomb_damage::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); +    }  }; -class spell_xt002_gravity_bomb_damage : public SpellScriptLoader +// 62791 - XT-002 Heart Overload Trigger Spell (SERVERSIDE) +class spell_xt002_heart_overload_periodic : public SpellScript  { -    public: -        spell_xt002_gravity_bomb_damage() : SpellScriptLoader("spell_xt002_gravity_bomb_damage") { } +    PrepareSpellScript(spell_xt002_heart_overload_periodic); -        class spell_xt002_gravity_bomb_damage_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_xt002_gravity_bomb_damage_SpellScript); +    bool Validate(SpellInfo const* /*spell*/) override +    { +        return ValidateSpellInfo +        ({ +            SPELL_ENERGY_ORB, +            SPELL_HEART_LIGHTNING_TETHER +         }); +    } -            void HandleScript(SpellEffIndex /*eff*/) -            { -                Unit* caster = GetCaster(); -                if (!caster) -                    return; +    Creature* GetRandomToyPile() +    { +        std::list<Creature*> possibleCreatures; +        Unit* caster = GetCaster(); +        caster->GetCreatureListWithEntryInGrid(possibleCreatures, NPC_XT_TOY_PILE); +        possibleCreatures.remove_if([caster](Creature* creature) +        { +            return caster->GetDistance2d(creature) < 60.0f; +        }); -                if (GetHitDamage() >= int32(GetHitUnit()->GetHealth())) -                    if (caster->GetAI()) -                        caster->GetAI()->SetData(DATA_GRAVITY_BOMB_CASUALTY, 1); -            } +        if (possibleCreatures.empty()) +            return nullptr; -            void Register() override -            { -                OnEffectHitTarget += SpellEffectFn(spell_xt002_gravity_bomb_damage_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); -            } -        }; +        return Trinity::Containers::SelectRandomContainerElement(possibleCreatures); +    } -        SpellScript* GetSpellScript() const override +    void HandleScript(SpellEffIndex /*effIndex*/) +    { +        Unit* caster = GetCaster(); +        if (Creature* toyPile = GetRandomToyPile())          { -            return new spell_xt002_gravity_bomb_damage_SpellScript(); +            caster->CastSpell(toyPile, SPELL_ENERGY_ORB, true); +            caster->CastSpell(nullptr, SPELL_HEART_LIGHTNING_TETHER, true);          } +    } + +    void Register() override +    { +        OnEffectHit += SpellEffectFn(spell_xt002_heart_overload_periodic::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); +    }  }; -class spell_xt002_heart_overload_periodic : public SpellScriptLoader +// 62826 Energy Orb +class spell_xt002_energy_orb : public SpellScript  { -    public: -        spell_xt002_heart_overload_periodic() : SpellScriptLoader("spell_xt002_heart_overload_periodic") { } +    PrepareSpellScript(spell_xt002_energy_orb); -        class spell_xt002_heart_overload_periodic_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_xt002_heart_overload_periodic_SpellScript); +    bool Validate(SpellInfo const* /*spell*/) override +    { +        return ValidateSpellInfo +        ({ +            SPELL_RECHARGE_BOOMBOT, +            SPELL_RECHARGE_PUMMELER, +            SPELL_RECHARGE_SCRAPBOT +        }); +    } -            bool Validate(SpellInfo const* /*spell*/) override -            { -                return ValidateSpellInfo({ SPELL_ENERGY_ORB, SPELL_RECHARGE_BOOMBOT, SPELL_RECHARGE_PUMMELER, SPELL_RECHARGE_SCRAPBOT }); -            } +    void HandleSummons(SpellEffIndex /*effIndex*/) +    { +        Unit* target = GetHitUnit(); +        if (target->GetEntry() != NPC_XT_TOY_PILE) +            return; -            void HandleScript(SpellEffIndex /*effIndex*/) -            { -                if (Unit* caster = GetCaster()) -                { -                    if (InstanceScript* instance = caster->GetInstanceScript()) -                    { -                        if (Unit* toyPile = ObjectAccessor::GetUnit(*caster, instance->GetGuidData(DATA_TOY_PILE_0 + urand(0, 3)))) -                        { -                            caster->CastSpell(toyPile, SPELL_ENERGY_ORB, true); - -                            // This should probably be incorporated in a dummy effect handler, but I've had trouble getting the correct target -                            // Weighed randomization (approximation) -                            uint32 const spells[] = { SPELL_RECHARGE_SCRAPBOT, SPELL_RECHARGE_SCRAPBOT, SPELL_RECHARGE_SCRAPBOT, -                                SPELL_RECHARGE_PUMMELER, SPELL_RECHARGE_BOOMBOT }; - -                            for (uint8 i = 0; i < 5; ++i) -                            { -                                uint8 a = urand(0, 4); -                                uint32 spellId = spells[a]; -                                toyPile->CastSpell(toyPile, spellId, instance->GetGuidData(BOSS_XT002)); -                            } -                        } -                    } +        target->CastSpell(target, SPELL_RECHARGE_BOOMBOT, true); -                    if (Creature* base = caster->GetVehicleCreatureBase()) -                        base->AI()->Talk(SAY_SUMMON); -                } -            } +        if (roll_chance_i(30)) +            target->CastSpell(target, SPELL_RECHARGE_PUMMELER, true); -            void Register() override -            { -                OnEffectHit += SpellEffectFn(spell_xt002_heart_overload_periodic_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); -            } -        }; +        for (uint8 i = 0; i < urand(5, 7); ++i) +            target->CastSpell(target, SPELL_RECHARGE_SCRAPBOT, true); -        SpellScript* GetSpellScript() const override -        { -            return new spell_xt002_heart_overload_periodic_SpellScript(); -        } +        if (Creature* base = GetCaster()->GetVehicleCreatureBase()) +            base->AI()->Talk(SAY_SUMMON); +    } + +    void Register() override +    { +        OnEffectHitTarget += SpellEffectFn(spell_xt002_energy_orb::HandleSummons, EFFECT_2, SPELL_EFFECT_DUMMY); +    }  }; -class spell_xt002_tympanic_tantrum : public SpellScriptLoader +// 62775 - Tympanic Tantrum +class spell_xt002_tympanic_tantrum : public SpellScript  { -    public: -        spell_xt002_tympanic_tantrum() : SpellScriptLoader("spell_xt002_tympanic_tantrum") { } +    PrepareSpellScript(spell_xt002_tympanic_tantrum); -        class spell_xt002_tympanic_tantrum_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_xt002_tympanic_tantrum_SpellScript); +    void FilterTargets(std::list<WorldObject*>& targets) +    { +        targets.remove_if(PlayerOrPetCheck()); +    } -            void FilterTargets(std::list<WorldObject*>& targets) -            { -                targets.remove_if(PlayerOrPetCheck()); -            } +    void RecalculateDamage() +    { +        SetHitDamage(GetHitUnit()->CountPctFromMaxHealth(GetHitDamage())); +    } -            void RecalculateDamage() -            { -                SetHitDamage(GetHitUnit()->CountPctFromMaxHealth(GetHitDamage())); -            } +    void Register() override +    { +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_tympanic_tantrum::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); +        OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_tympanic_tantrum::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); +        OnHit += SpellHitFn(spell_xt002_tympanic_tantrum::RecalculateDamage); +    } +}; -            void Register() override -            { -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); -                OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_xt002_tympanic_tantrum_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); -                OnHit += SpellHitFn(spell_xt002_tympanic_tantrum_SpellScript::RecalculateDamage); -            } -        }; +// 37751 - Submerged +class spell_xt002_submerged : public SpellScript +{ +    PrepareSpellScript(spell_xt002_submerged); -        SpellScript* GetSpellScript() const override -        { -            return new spell_xt002_tympanic_tantrum_SpellScript(); -        } +    void HandleScript(SpellEffIndex /*eff*/) +    { +        Creature* target = GetHitCreature(); +        if (!target) +            return; + +        target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +        target->SetStandState(UNIT_STAND_STATE_SUBMERGED); +    } + +    void Register() override +    { +        OnEffectHitTarget += SpellEffectFn(spell_xt002_submerged::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); +    }  }; -class spell_xt002_submerged : public SpellScriptLoader +// 65032 - 321-Boombot Aura +class spell_xt002_321_boombot_aura : public AuraScript  { -    public: -        spell_xt002_submerged() : SpellScriptLoader("spell_xt002_submerged") { } - -        class spell_xt002_submerged_SpellScript : public SpellScript -        { -            PrepareSpellScript(spell_xt002_submerged_SpellScript); +    PrepareAuraScript(spell_xt002_321_boombot_aura); -            void HandleScript(SpellEffIndex /*eff*/) -            { -                Creature* target = GetHitCreature(); -                if (!target) -                    return; +    bool Validate(SpellInfo const* /*spellInfo*/) override +    { +        return ValidateSpellInfo({ SPELL_ACHIEVEMENT_CREDIT_NERF_SCRAPBOTS }); +    } -                target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                target->SetStandState(UNIT_STAND_STATE_SUBMERGED); -            } +    bool CheckProc(ProcEventInfo& eventInfo) +    { +        if (eventInfo.GetActionTarget()->GetEntry() != NPC_XS013_SCRAPBOT) +            return false; +        return true; +    } -            void Register() override -            { -                OnEffectHitTarget += SpellEffectFn(spell_xt002_submerged_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); -            } -        }; +    void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) +    { +        if (InstanceScript* instance = eventInfo.GetActor()->GetInstanceScript()) +            instance->DoCastSpellOnPlayers(SPELL_ACHIEVEMENT_CREDIT_NERF_SCRAPBOTS); +    } -        SpellScript* GetSpellScript() const override -        { -            return new spell_xt002_submerged_SpellScript(); -        } +    void Register() override +    { +        DoCheckProc += AuraCheckProcFn(spell_xt002_321_boombot_aura::CheckProc); +        OnEffectProc += AuraEffectProcFn(spell_xt002_321_boombot_aura::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); +    }  }; -class spell_xt002_321_boombot_aura : public SpellScriptLoader +// 63849 - Exposed Heart +class spell_xt002_exposed_heart : public AuraScript  { -    public: -        spell_xt002_321_boombot_aura() : SpellScriptLoader("spell_xt002_321_boombot_aura") { } +    PrepareAuraScript(spell_xt002_exposed_heart); -        class spell_xt002_321_boombot_aura_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_xt002_321_boombot_aura_AuraScript); - -            bool Validate(SpellInfo const* /*spellInfo*/) override -            { -                return ValidateSpellInfo({ SPELL_ACHIEVEMENT_CREDIT_NERF_SCRAPBOTS }); -            } +    bool Load() override +    { +        _damageAmount = 0; +        return true; +    } -            bool CheckProc(ProcEventInfo& eventInfo) -            { -                if (eventInfo.GetActionTarget()->GetEntry() != NPC_XS013_SCRAPBOT) -                    return false; -                return true; -            } +    void OnProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) +    { +        PreventDefaultAction(); +        DamageInfo* damageInfo = eventInfo.GetDamageInfo(); +        if (!damageInfo || !damageInfo->GetDamage()) +            return; -            void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) -            { -                InstanceScript* instance = eventInfo.GetActor()->GetInstanceScript(); -                if (!instance) -                    return; +        _damageAmount += damageInfo->GetDamage(); +    } -                instance->DoCastSpellOnPlayers(SPELL_ACHIEVEMENT_CREDIT_NERF_SCRAPBOTS); -            } +    void HandleLifeTransfer(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +    { +        if (InstanceScript* instance = GetTarget()->GetInstanceScript()) +            if (Creature* xt002 = instance->GetCreature(BOSS_XT002)) +                xt002->AI()->SetData(DATA_TRANSFERED_HEALTH, _damageAmount); +    } -            void Register() override -            { -                DoCheckProc += AuraCheckProcFn(spell_xt002_321_boombot_aura_AuraScript::CheckProc); -                OnEffectProc += AuraEffectProcFn(spell_xt002_321_boombot_aura_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); -            } -        }; +    void Register() override +    { +        OnEffectProc += AuraEffectProcFn(spell_xt002_exposed_heart::OnProc, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); +        AfterEffectRemove += AuraEffectRemoveFn(spell_xt002_exposed_heart::HandleLifeTransfer, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); +    } -        AuraScript* GetAuraScript() const override -        { -            return new spell_xt002_321_boombot_aura_AuraScript(); -        } +private: +    uint32 _damageAmount;  };  class achievement_nerf_engineering : public AchievementCriteriaScript @@ -1109,22 +1002,23 @@ class achievement_nerf_gravity_bombs : public AchievementCriteriaScript  void AddSC_boss_xt002()  { -    new npc_xt002_heart(); -    new npc_scrapbot(); -    new npc_pummeller(); -    new npc_boombot(); - -    new npc_life_spark(); -    new npc_xt_void_zone(); -    new boss_xt002(); - -    new spell_xt002_searing_light_spawn_life_spark(); -    new spell_xt002_gravity_bomb_aura(); -    new spell_xt002_gravity_bomb_damage(); -    new spell_xt002_heart_overload_periodic(); -    new spell_xt002_tympanic_tantrum(); -    new spell_xt002_submerged(); -    new spell_xt002_321_boombot_aura(); +    RegisterUlduarCreatureAI(boss_xt002); +    RegisterUlduarCreatureAI(npc_xt002_heart); +    RegisterUlduarCreatureAI(npc_scrapbot); +    RegisterUlduarCreatureAI(npc_pummeller); +    RegisterUlduarCreatureAI(npc_boombot); +    RegisterUlduarCreatureAI(npc_life_spark); +    RegisterUlduarCreatureAI(npc_xt_void_zone); + +    RegisterAuraScript(spell_xt002_searing_light_spawn_life_spark); +    RegisterAuraScript(spell_xt002_gravity_bomb_aura); +    RegisterSpellScript(spell_xt002_gravity_bomb_damage); +    RegisterSpellScript(spell_xt002_heart_overload_periodic); +    RegisterSpellScript(spell_xt002_energy_orb); +    RegisterSpellScript(spell_xt002_tympanic_tantrum); +    RegisterSpellScript(spell_xt002_submerged); +    RegisterAuraScript(spell_xt002_321_boombot_aura); +    RegisterAuraScript(spell_xt002_exposed_heart);      new achievement_nerf_engineering();      new achievement_heartbreaker(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 9e4ef839c6e..5c2301c0210 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -114,6 +114,7 @@ ObjectData const creatureData[] =      { NPC_LORE_KEEPER_OF_NORGANNON, DATA_LORE_KEEPER_OF_NORGANNON },      { NPC_HIGH_EXPLORER_DELLORAH,   DATA_DELLORAH                 },      { NPC_BRONZEBEARD_RADIO,        DATA_BRONZEBEARD_RADIO        }, +    { NPC_HEART_OF_DECONSTRUCTOR,   DATA_XT002_HEART              },      { 0,                            0,                            }  }; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 80fcfe04b46..3283588a43a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -94,6 +94,7 @@ enum UlduarNPCs      //XT002      NPC_XS013_SCRAPBOT                      = 33343, +    NPC_HEART_OF_DECONSTRUCTOR              = 33329,      // Flame Leviathan      NPC_ULDUAR_COLOSSUS                     = 33237, @@ -407,6 +408,7 @@ enum UlduarData      DATA_TOY_PILE_1,      DATA_TOY_PILE_2,      DATA_TOY_PILE_3, +    DATA_XT002_HEART,      // Assembly of Iron      DATA_STEELBREAKER,  | 
