diff options
author | Keader <keader.android@gmail.com> | 2017-08-07 21:36:19 -0300 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2020-08-22 20:46:26 +0200 |
commit | a1342bc9fcb515b77aee4498d01c52620c53988d (patch) | |
tree | e9194eafbddffbf2d0f80d8e961417419073113d /src | |
parent | 99b8221456a96b29d7c0295a6cede029c4194a6a (diff) |
Core/Scripts: Razorscale Rewrite (#19828)
(cherry picked from commit d825a068300224498a3613299d15a70323af9b73)
Diffstat (limited to 'src')
3 files changed, 1570 insertions, 871 deletions
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index cc0facb9561..5706c8f1b84 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -15,13 +15,13 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/// @todo Harpoon chain from 62505 should not get removed when other chain is applied - #include "ScriptMgr.h" #include "GameObject.h" #include "InstanceScript.h" #include "MotionMaster.h" +#include "MoveSplineInit.h" #include "ObjectAccessor.h" +#include "PassiveAI.h" #include "Player.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" @@ -30,1169 +30,1862 @@ #include "SpellScript.h" #include "TemporarySummon.h" #include "ulduar.h" +#include <G3D/Vector3.h> enum Says { // Expedition Commander - SAY_INTRO = 0, - SAY_GROUND_PHASE = 1, - SAY_AGGRO_2 = 2, + SAY_COMMANDER_AGGRO = 0, + SAY_COMMANDER_GROUND_PHASE = 1, + SAY_COMMANDER_ENGINEERS_DEAD = 2, // Expedition Engineer - SAY_AGGRO_1 = 0, - SAY_AGGRO_3 = 1, - SAY_TURRETS = 2, // unused + SAY_AGGRO = 0, + SAY_START_REPAIR = 1, + SAY_REBUILD_TURRETS = 2, // Razorscale Controller - EMOTE_HARPOON = 0, + EMOTE_HARPOON = 0, // Razorscale - EMOTE_PERMA = 0, - EMOTE_BREATH = 1 + EMOTE_PERMA_GROUND = 0, + EMOTE_BREATH = 1, + EMOTE_BERSERK = 2 }; enum Spells { - SPELL_FLAMEBUFFET = 64016, - SPELL_FIREBALL = 62796, - SPELL_FLAME_GROUND = 64734, - SPELL_WINGBUFFET = 62666, - SPELL_FLAMEBREATH = 63317, - SPELL_FUSEARMOR = 64771, - SPELL_FLAMED = 62696, - SPELL_STUN = 9032, - SPELL_BERSERK = 47008, - // Additonal Spells - // Devouring Flame Spells - SPELL_DEVOURING_FLAME = 63308, - SPELL_DEVOURING_FLAME_DAMAGE = 64704, - SPELL_DEVOURING_FLAME_TRIGGER = 64709, - // HarpoonSpells - SPELL_HARPOON_TRIGGER = 62505, - SPELL_HARPOON_SHOT_1 = 63658, - SPELL_HARPOON_SHOT_2 = 63657, - SPELL_HARPOON_SHOT_3 = 63659, - SPELL_HARPOON_SHOT_4 = 63524, - // MoleMachine Spells - SPELL_SUMMON_MOLE_MACHINE = 62899, - SPELL_SUMMON_IRON_DWARVES = 63116, - SPELL_SUMMON_IRON_DWARVES_2 = 63114, - SPELL_SUMMON_IRON_DWARVE_GUARDIAN = 62926, - SPELL_SUMMON_IRON_DWARVE_WATCHER = 63135, + SPELL_FIREBALL = 63815, + SPELL_DEVOURING_FLAME = 63236, + SPELL_WING_BUFFET = 62666, + SPELL_FIREBOLT = 62669, + SPELL_FLAME_BREATH = 63317, + SPELL_FUSE_ARMOR = 64821, + SPELL_FUSED_ARMOR = 64774, + SPELL_STUN_SELF = 62794, + SPELL_BERSERK = 47008, + + // Razorscale Harpoon Fire State + SPELL_HARPOON_FIRE_STATE = 62696, + + // Harpoon + SPELL_HARPOON_TRIGGER = 62505, + SPELL_HARPOON_SHOT_1 = 63658, + SPELL_HARPOON_SHOT_2 = 63657, + SPELL_HARPOON_SHOT_3 = 63659, + SPELL_HARPOON_SHOT_4 = 63524, + + // Razorscale Spawner + SPELL_SUMMON_MOLE_MACHINE = 62899, + SPELL_SUMMON_IRON_DWARF_GUARDIAN = 62926, + SPELL_TRIGGER_SUMMON_IRON_DWARVES = 63968, + SPELL_TRIGGER_SUMMON_IRON_DWARVES_2 = 63970, + SPELL_TRIGGER_SUMMON_IRON_DWARVES_3 = 63969, + SPELL_TRIGGER_SUMMON_IRON_VRYKUL = 63798, + SPELL_SUMMON_IRON_DWARF_WATCHER = 63135, + + // Dark Rune Watcher + SPELL_CHAIN_LIGHTNING = 64758, + SPELL_LIGHTNING_BOLT = 63809, + + // Dark Rune Guardian + SPELL_STORMSTRIKE = 64757, + + // Dark Rune Sentinel + SPELL_BATTLE_SHOUT = 46763, + SPELL_HEROIC_STRIKE = 45026, + SPELL_WHIRLWIND = 63808, + + // Expedition Defender + SPELL_THREAT = 65146, + + // Expedition Trapper + SPELL_SHACKLE = 62646 }; -enum NPC +enum Actions { - NPC_DARK_RUNE_GUARDIAN = 33388, - NPC_DARK_RUNE_SENTINEL = 33846, - NPC_DARK_RUNE_WATCHER = 33453, - MOLE_MACHINE_TRIGGER = 33245, - NPC_COMMANDER = 33210, - NPC_ENGINEER = 33287, - NPC_DEFENDER = 33816, + ACTION_START_FIGHT = 1, + ACTION_FIX_HARPOONS, + ACTION_GROUND_PHASE, + ACTION_ENGINEER_DEAD, + ACTION_SHACKLE_RAZORSCALE, + ACTION_START_PERMA_GROUND, + ACTION_RETURN_TO_BASE, + ACTION_BUILD_HARPOON_1, + ACTION_BUILD_HARPOON_2, + ACTION_BUILD_HARPOON_3, + ACTION_BUILD_HARPOON_4, + ACTION_DESTROY_HARPOONS, + ACTION_STOP_CONTROLLERS, + ACTION_STOP_CAST }; -enum DarkRuneSpells +enum Events { + EVENT_BERSERK = 1, + EVENT_FIREBALL, + EVENT_DEVOURING_FLAME, + EVENT_SUMMON_MINIONS, + EVENT_SUMMON_MINIONS_2, + EVENT_FLAME_BREATH, + EVENT_FLAME_BREATH_GROUND, + EVENT_WING_BUFFET, + EVENT_RESUME_AIR_PHASE, + EVENT_FIREBOLT, + EVENT_FUSE_ARMOR, + EVENT_RESUME_MOVE_CHASE, + + // Expedition Commander + EVENT_BUILD_HARPOON_1, + EVENT_BUILD_HARPOON_2, + EVENT_BUILD_HARPOON_3, + EVENT_BUILD_HARPOON_4, + EVENT_HANDLE_DESTROY_HARPOON, + + // Dark Rune Sentinel + EVENT_START_COMBAT, + EVENT_HEROIC_STRIKE, + EVENT_BATTLE_SHOUT, + EVENT_WHIRLWIND, + // Dark Rune Watcher - SPELL_CHAIN_LIGHTNING = 64758, - SPELL_LIGHTNING_BOLT = 63809, + EVENT_LIGHTNING_BOLT, + EVENT_CHAIN_LIGHTNING, + // Dark Rune Guardian - SPELL_STORMSTRIKE = 64757, - // Dark Rune Sentinel - SPELL_BATTLE_SHOUT = 46763, - SPELL_HEROIC_STRIKE = 45026, - SPELL_WHIRLWIND = 63807, + EVENT_STORMSTRIKE, }; -enum Actions +enum Misc { - ACTION_EVENT_START = 1, - ACTION_GROUND_PHASE = 2, - ACTION_HARPOON_BUILD = 3, - ACTION_PLACE_BROKEN_HARPOON = 4, - ACTION_COMMANDER_RESET = 7, + DATA_QUICK_SHAVE = 29192921, // 2919, 2921 are achievement IDs + DATA_IRON_DWARF_MEDIUM_RARE = 29232924, + GOSSIP_START_ENCOUNTER = 0, + DATA_EXPEDITION_NUMBER = 1, + RAZORSCALE_EXPEDITION_GROUP = 1, + RAZORSCALE_FIRE_STATE_10_GROUP = 2, + RAZORSCALE_FIRE_STATE_25_GROUP = 3, + ENGINEER_NORTH = 0, + ENGINEER_EAST = 1, + ENGINEER_WEST = 2, + HARPOON_1 = 0, + HARPOON_2 = 1, + HARPOON_3 = 2, + HARPOON_4 = 3, + WORLD_STATE_RAZORSCALE_MUSIC = 4162 }; -enum Phases +enum MovePoints { - PHASE_PERMAGROUND = 1, - PHASE_GROUND = 2, - PHASE_FLIGHT = 3, + POINT_DEFENDER_ATTACK = 1, + POINT_SHACKLE_RAZORSCALE, + POINT_BASE, + POINT_HARPOON_1, + POINT_HARPOON_1_25, + POINT_HARPOON_2, + POINT_HARPOON_2_25, + POINT_HARPOON_3, + POINT_HARPOON_4, + POINT_RAZORSCALE_FLIGHT, + POINT_RAZORSCALE_TAKEOFF, + POINT_RAZORSCALE_FLIGHT_2, + POINT_RAZORSCALE_LAND, + POINT_RAZORSCALE_GROUND, + POINT_START_WAYPOINT, }; -enum Events +enum EngineersSplineMovements { - EVENT_BERSERK = 1, - EVENT_BREATH = 2, - EVENT_BUFFET = 3, - EVENT_FIREBALL = 5, - EVENT_FLIGHT = 6, - EVENT_DEVOURING = 7, - EVENT_FLAME = 8, - EVENT_LAND = 9, - EVENT_GROUND = 10, - EVENT_FUSE = 11, - EVENT_SUMMON = 12, - // Razorscale Controller - EVENT_BUILD_HARPOON_1 = 13, - EVENT_BUILD_HARPOON_2 = 14, - EVENT_BUILD_HARPOON_3 = 15, - EVENT_BUILD_HARPOON_4 = 16, + SPLINE_ENGINEER_NORTH_10_HARPOON_1 = 1, + SPLINE_ENGINEER_NORTH_10_HARPOON_2 = 2, + SPLINE_ENGINEER_NORTH_10_BASE = 3, + SPLINE_ENGINEER_NORTH_25_HARPOON_1 = 4, + SPLINE_ENGINEER_NORTH_25_HARPOON_2 = 5, + SPLINE_ENGINEER_NORTH_25_HARPOON_3 = 6, + SPLINE_ENGINEER_NORTH_25_HARPOON_4 = 7, + SPLINE_ENGINEER_NORTH_25_BASE = 8, + SPLINE_ENGINEER_EAST_10_HARPOON_1 = 9, + SPLINE_ENGINEER_EAST_10_HARPOON_2 = 10, + SPLINE_ENGINEER_EAST_10_BASE = 11, + SPLINE_ENGINEER_EAST_25_HARPOON_1 = 12, + SPLINE_ENGINEER_EAST_25_HARPOON_2 = 13, + SPLINE_ENGINEER_EAST_25_HARPOON_3 = 14, + SPLINE_ENGINEER_EAST_25_HARPOON_4 = 15, + SPLINE_ENGINEER_WEST_10_HARPOON_1 = 16, + SPLINE_ENGINEER_WEST_10_HARPOON_2 = 17, + SPLINE_ENGINEER_WEST_10_BASE = 18, + SPLINE_ENGINEER_WEST_25_HARPOON_1 = 19, + SPLINE_ENGINEER_WEST_25_HARPOON_2 = 20, + SPLINE_ENGINEER_WEST_25_HARPOON_3 = 21, + SPLINE_ENGINEER_WEST_25_HARPOON_4 = 22, + SPLINE_ENGINEER_WEST_25_BASE = 23 +}; + +enum RazorscalePhases +{ + PHASE_NONE = 0, + PHASE_COMBAT, + PHASE_GROUND, + PHASE_AIR, + PHASE_PERMA_GROUND }; -#define GROUND_Z 391.517f -#define GOSSIP_ITEM_1 "Activate Harpoons!" +Position const PosBrokenHarpoon[4] = +{ + { 571.9465f, -136.0118f, 391.5171f, 2.286379f }, // 1 + { 589.9233f, -133.6223f, 391.8968f, 3.298687f }, // 2 + { 559.1199f, -140.5058f, 391.1803f, 4.049168f }, // 0 + { 606.2297f, -136.7212f, 391.1803f, 5.131269f } // 3 +}; -enum Misc +Position const PosHarpoon[4] = { - DATA_QUICK_SHAVE = 29192921, // 2919, 2921 are achievement IDs - DATA_IRON_DWARF_MEDIUM_RARE = 29232924 + { 571.9012f, -136.5541f, 391.5171f, 4.921829f }, // GO_RAZOR_HARPOON_1 + { 589.9233f, -133.6223f, 391.8968f, 4.81711f }, // GO_RAZOR_HARPOON_2 + { 559.1199f, -140.5058f, 391.1803f, 5.061456f }, // GO_RAZOR_HARPOON_3 + { 606.2297f, -136.7212f, 391.1803f, 4.537859f } // GO_RAZOR_HARPOON_4 }; -const Position PosEngRepair[4] = +Position const DefendersPosition[6] = { - { 590.442f, -130.550f, GROUND_Z, 4.789f }, - { 574.850f, -133.687f, GROUND_Z, 4.252f }, - { 606.567f, -143.369f, GROUND_Z, 4.434f }, - { 560.609f, -142.967f, GROUND_Z, 5.074f }, + { 624.3065f, -154.4163f, 391.6442f }, + { 611.6274f, -170.9375f, 391.8087f }, + { 572.1548f, -167.4471f, 391.8087f }, + { 558.4640f, -165.0114f, 391.8087f }, + { 603.3345f, -164.4297f, 391.8087f }, + { 549.1727f, -159.1180f, 391.8087f } }; -const Position PosDefSpawn[4] = +Position const TrapperPosition[3] = { - { 600.75f, -104.850f, GROUND_Z, 0 }, - { 596.38f, -110.262f, GROUND_Z, 0 }, - { 566.47f, -103.633f, GROUND_Z, 0 }, - { 570.41f, -108.791f, GROUND_Z, 0 }, + { 574.9293f, -184.5150f, 391.8921f }, + { 539.7838f, -178.5337f, 391.3053f }, + { 627.1754f, -177.9638f, 391.5553f } }; -const Position PosDefCombat[4] = +uint32 const SummonMinionsSpells[4] = { - { 614.975f, -155.138f, GROUND_Z, 4.154f }, - { 609.814f, -204.968f, GROUND_Z, 5.385f }, - { 563.531f, -201.557f, GROUND_Z, 4.108f }, - { 560.231f, -153.677f, GROUND_Z, 5.403f }, + SPELL_TRIGGER_SUMMON_IRON_DWARVES, + SPELL_TRIGGER_SUMMON_IRON_DWARVES_2, + SPELL_TRIGGER_SUMMON_IRON_DWARVES_3, + SPELL_TRIGGER_SUMMON_IRON_VRYKUL }; -const Position PosHarpoon[4] = +uint32 const pathSize = 11; +G3D::Vector3 const RazorscalePath[pathSize] = { - { 571.901f, -136.554f, GROUND_Z, 0 }, - { 589.450f, -134.888f, GROUND_Z, 0 }, - { 559.119f, -140.505f, GROUND_Z, 0 }, - { 606.229f, -136.721f, GROUND_Z, 0 }, + { 657.0227f, -361.1278f, 519.5406f }, + { 698.9319f, -340.9654f, 520.4857f }, + { 713.8673f, -290.2219f, 518.4573f }, + { 711.1782f, -259.6798f, 524.6802f }, + { 695.5101f, -234.6734f, 529.1528f }, + { 666.9619f, -220.7599f, 531.4860f }, + { 629.2765f, -219.7951f, 528.9301f }, + { 597.4018f, -233.7745f, 526.6508f }, + { 577.5307f, -275.4489f, 528.1241f }, + { 583.1092f, -319.5873f, 527.9302f }, + { 611.5800f, -353.1930f, 526.2653f } }; -const Position RazorFlight = { 588.050f, -251.191f, 470.536f, 1.498f }; -const Position RazorGround = { 586.966f, -175.534f, GROUND_Z, 4.682f }; -const Position PosEngSpawn = { 591.951f, -95.9680f, GROUND_Z, 0.000f }; +Position const RazorFlightPosition = { 585.3610f, -173.5592f, 456.8430f, 1.526665f }; +Position const RazorFlightPositionPhase2 = { 619.1450f, -238.0780f, 475.1800f, 1.423917f }; +Position const RazorscaleLand = { 585.4010f, -173.5430f, 408.5080f, 1.570796f }; +Position const RazorscaleGroundPosition = { 585.4010f, -173.5430f, 391.6421f, 1.570796f }; +Position const RazorscaleFirstPoint = { 657.0227f, -361.1278f, 519.5406f }; -class boss_razorscale_controller : public CreatureScript +class boss_razorscale : public CreatureScript { - public: - boss_razorscale_controller() : CreatureScript("boss_razorscale_controller") { } +public: + boss_razorscale() : CreatureScript("boss_razorscale") { } - struct boss_razorscale_controllerAI : public ScriptedAI + struct boss_razorscaleAI : public BossAI + { + boss_razorscaleAI(Creature* creature) : BossAI(creature, BOSS_RAZORSCALE) { - boss_razorscale_controllerAI(Creature* creature) : ScriptedAI(creature), summons(me) - { - instance = creature->GetInstanceScript(); - me->SetDisplayFromModel(1); - } + Initialize(); + } - InstanceScript* instance; - EventMap events; - SummonList summons; + void Initialize() + { + _engineersCount = 3; + _defendersCount = 0; + _engineersSummonCount = 0; + _harpoonHitCount = 0; + _trappersCount = 0; + _permaGround = false; + _flyCount = 0; + me->SetDisableGravity(true); + me->SetAnimTier(UnitBytes1_Flags(UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER), true); + } - void Reset() override - { - events.Reset(); - summons.DespawnAll(); - me->SetReactState(REACT_PASSIVE); - } + void Reset() override + { + _Reset(); + Initialize(); + events.SetPhase(PHASE_NONE); + me->SummonCreatureGroup(RAZORSCALE_EXPEDITION_GROUP); + me->SummonCreatureGroup(RAZORSCALE_FIRE_STATE_10_GROUP); + if (Is25ManRaid()) + me->SummonCreatureGroup(RAZORSCALE_FIRE_STATE_25_GROUP); + // @Developer remove this comment when someone create a way to change view distance for objects + // me->GetMotionMaster()->MovePoint(POINT_START_WAYPOINT, RazorscaleFirstPoint); + // And apply it on DB: UPDATE `creature` SET `position_x`=699.7847, `position_y`=-424.8246, `position_z`=589.2745, `orientation`=1.972222 WHERE `guid`=137611; -- Razorscale + SetCombatMovement(false); + } - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - switch (spell->Id) - { - case SPELL_FLAMED: - if (GameObject* harpoon = instance->GetGameObject(GO_RAZOR_HARPOON_1)) - harpoon->RemoveFromWorld(); - if (GameObject* harpoon = instance->GetGameObject(GO_RAZOR_HARPOON_2)) - harpoon->RemoveFromWorld(); - if (GameObject* harpoon = instance->GetGameObject(GO_RAZOR_HARPOON_3)) - harpoon->RemoveFromWorld(); - if (GameObject* harpoon = instance->GetGameObject(GO_RAZOR_HARPOON_4)) - harpoon->RemoveFromWorld(); - DoAction(ACTION_HARPOON_BUILD); - DoAction(ACTION_PLACE_BROKEN_HARPOON); - break; - case SPELL_HARPOON_SHOT_1: - case SPELL_HARPOON_SHOT_2: - case SPELL_HARPOON_SHOT_3: - case SPELL_HARPOON_SHOT_4: - DoCast(SPELL_HARPOON_TRIGGER); - break; - } - } + void HandleInitialMovement() + { + Movement::PointsArray path(RazorscalePath, RazorscalePath + pathSize); + Movement::MoveSplineInit init(me); + init.MovebyPath(path, 0); + init.SetCyclic(); + init.SetFly(); + init.Launch(); + } - void JustDied(Unit* /*killer*/) override + bool CanAIAttack(Unit const* target) const override + { + switch (target->GetEntry()) { - events.Reset(); - summons.DespawnAll(); + case NPC_EXPEDITION_DEFENDER: + case NPC_EXPEDITION_TRAPPER: + case NPC_EXPEDITION_COMMANDER: + case NPC_EXPEDITION_ENGINEER: + return false; + default: + return BossAI::CanAIAttack(target); } + } - void DoAction(int32 action) override - { - if (instance->GetBossState(BOSS_RAZORSCALE) != IN_PROGRESS) - return; + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + ScheduleAirPhaseEvents(); + summons.DoAction(ACTION_START_FIGHT, DummyEntryCheckPredicate()); + events.ScheduleEvent(EVENT_BERSERK, Minutes(15)); + HandleMusic(true); + me->SetAnimTier(UnitBytes1_Flags(UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER), true); + } + + void ScheduleAirPhaseEvents() + { + events.ScheduleEvent(EVENT_FIREBALL, Seconds(3), 0, PHASE_AIR); + events.ScheduleEvent(EVENT_DEVOURING_FLAME, Seconds(9), 0, PHASE_AIR); + events.ScheduleEvent(EVENT_SUMMON_MINIONS, Seconds(1), 0, PHASE_AIR); + } + + void ScheduleGroundPhaseEvents() + { + events.ScheduleEvent(EVENT_FIREBOLT, Seconds(3), 0, PHASE_PERMA_GROUND); + events.ScheduleEvent(EVENT_FUSE_ARMOR, Seconds(15), 0, PHASE_PERMA_GROUND); + events.ScheduleEvent(EVENT_FLAME_BREATH_GROUND, Seconds(18), 0, PHASE_PERMA_GROUND); + events.ScheduleEvent(EVENT_DEVOURING_FLAME, Seconds(22), 0, PHASE_PERMA_GROUND); + } - switch (action) + void DoAction(int32 actionId) override + { + switch (actionId) + { + case ACTION_START_FIGHT: + me->SetImmuneToPC(false); + me->SetSpeedRate(MOVE_RUN, 3.0f); + me->StopMoving(); + me->GetMotionMaster()->MovePoint(POINT_RAZORSCALE_FLIGHT, RazorFlightPosition); + break; + case ACTION_GROUND_PHASE: + me->InterruptNonMeleeSpells(false); + events.SetPhase(PHASE_GROUND); + _harpoonHitCount = 0; + me->SetSpeedRate(MOVE_RUN, 3.0f); + me->GetMotionMaster()->MovePoint(POINT_RAZORSCALE_LAND, RazorscaleLand); + break; + case ACTION_START_PERMA_GROUND: { - case ACTION_HARPOON_BUILD: - events.ScheduleEvent(EVENT_BUILD_HARPOON_1, 50000); - if (Is25ManRaid()) - events.ScheduleEvent(EVENT_BUILD_HARPOON_3, 90000); - break; - case ACTION_PLACE_BROKEN_HARPOON: - for (uint8 n = 0; n < RAID_MODE(2, 4); n++) - me->SummonGameObject(GO_RAZOR_BROKEN_HARPOON, PosHarpoon[n].GetPositionX(), PosHarpoon[n].GetPositionY(), PosHarpoon[n].GetPositionZ(), 2.286f, QuaternionData::fromEulerAnglesZYX(2.286f, 0.0f, 0.0f), 180); - break; + me->SetDisableGravity(false); + me->SetAnimTier(UNIT_BYTE1_FLAG_NONE, true); + me->RemoveAurasDueToSpell(SPELL_STUN_SELF); + Talk(EMOTE_PERMA_GROUND); + DoCastSelf(SPELL_WING_BUFFET); + EntryCheckPredicate pred(NPC_EXPEDITION_TRAPPER); + summons.DoAction(ACTION_STOP_CAST, pred); + events.ScheduleEvent(EVENT_RESUME_MOVE_CHASE, Milliseconds(1)); + ScheduleGroundPhaseEvents(); + break; } + default: + break; } + } - void UpdateAI(uint32 Diff) override - { - events.Update(Diff); + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) + return; - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) + switch (pointId) + { + case POINT_START_WAYPOINT: + HandleInitialMovement(); + break; + case POINT_RAZORSCALE_FLIGHT: + me->UpdateSpeed(MOVE_RUN); + me->SetFacingTo(RazorFlightPosition.GetOrientation()); + DoZoneInCombat(); + break; + case POINT_RAZORSCALE_GROUND: + me->SetDisableGravity(false); + me->SetAnimTier(UNIT_BYTE1_FLAG_NONE, true); + if (!_permaGround) { - case EVENT_BUILD_HARPOON_1: - Talk(EMOTE_HARPOON); - if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_1, PosHarpoon[0].GetPositionX(), PosHarpoon[0].GetPositionY(), PosHarpoon[0].GetPositionZ(), 4.790f, QuaternionData::fromEulerAnglesZYX(4.790f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) - { - if (GameObject* brokenHarpoon = harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) //only nearest broken harpoon - brokenHarpoon->RemoveFromWorld(); - events.ScheduleEvent(EVENT_BUILD_HARPOON_2, 20000); - events.CancelEvent(EVENT_BUILD_HARPOON_1); - } - return; - case EVENT_BUILD_HARPOON_2: - Talk(EMOTE_HARPOON); - if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_2, PosHarpoon[1].GetPositionX(), PosHarpoon[1].GetPositionY(), PosHarpoon[1].GetPositionZ(), 4.659f, QuaternionData::fromEulerAnglesZYX(4.659f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) - { - if (GameObject* brokenHarpoon = harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) - brokenHarpoon->RemoveFromWorld(); - events.CancelEvent(EVENT_BUILD_HARPOON_2); - } - return; - case EVENT_BUILD_HARPOON_3: - Talk(EMOTE_HARPOON); - if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_3, PosHarpoon[2].GetPositionX(), PosHarpoon[2].GetPositionY(), PosHarpoon[2].GetPositionZ(), 5.382f, QuaternionData::fromEulerAnglesZYX(5.382f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) - { - if (GameObject* brokenHarpoon = harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) - brokenHarpoon->RemoveFromWorld(); - events.ScheduleEvent(EVENT_BUILD_HARPOON_4, 20000); - events.CancelEvent(EVENT_BUILD_HARPOON_3); - } - return; - case EVENT_BUILD_HARPOON_4: - Talk(EMOTE_HARPOON); - if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_4, PosHarpoon[3].GetPositionX(), PosHarpoon[3].GetPositionY(), PosHarpoon[3].GetPositionZ(), 4.266f, QuaternionData::fromEulerAnglesZYX(4.266f, 0.0f, 0.0f), uint32(me->GetRespawnTime()))) - { - if (GameObject* brokenHarpoon = harpoon->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) - brokenHarpoon->RemoveFromWorld(); - events.CancelEvent(EVENT_BUILD_HARPOON_4); - } - return; + DoCastSelf(SPELL_STUN_SELF, true); + EntryCheckPredicate pred(NPC_EXPEDITION_TRAPPER); + summons.DoAction(ACTION_SHACKLE_RAZORSCALE, pred); + if (Creature* commander = instance->GetCreature(DATA_EXPEDITION_COMMANDER)) + commander->AI()->DoAction(ACTION_GROUND_PHASE); + events.ScheduleEvent(EVENT_FLAME_BREATH, Seconds(30), 0, PHASE_GROUND); } - } + break; + case POINT_RAZORSCALE_TAKEOFF: + me->SetSpeedRate(MOVE_RUN, 3.0f); + me->GetMotionMaster()->MovePoint(POINT_RAZORSCALE_FLIGHT_2, RazorFlightPositionPhase2); + break; + case POINT_RAZORSCALE_FLIGHT_2: + me->SetFacingTo(RazorFlightPositionPhase2.GetOrientation()); + me->SetReactState(REACT_AGGRESSIVE); + ScheduleAirPhaseEvents(); + ++_flyCount; + me->UpdateSpeed(MOVE_RUN); + break; + case POINT_RAZORSCALE_LAND: + me->UpdateSpeed(MOVE_RUN); + me->SetFacingTo(RazorscaleLand.GetOrientation()); + me->GetMotionMaster()->MoveLand(POINT_RAZORSCALE_GROUND, RazorscaleGroundPosition); + break; + default: + break; } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI<boss_razorscale_controllerAI>(creature); } -}; - -class go_razorscale_harpoon : public GameObjectScript -{ - public: - go_razorscale_harpoon() : GameObjectScript("go_razorscale_harpoon") { } - struct go_razorscale_harpoonAI : public GameObjectAI + void JustSummoned(Creature* summon) override { - go_razorscale_harpoonAI(GameObject* go) : GameObjectAI(go), instance(go->GetInstanceScript()) { } + BossAI::JustSummoned(summon); - InstanceScript* instance; - - bool GossipHello(Player* /*player*/) override + switch (summon->GetEntry()) { - if (instance->GetCreature(BOSS_RAZORSCALE)) - me->AddFlag(GO_FLAG_NOT_SELECTABLE); - return false; + case NPC_EXPEDITION_DEFENDER: + summon->AI()->SetData(DATA_EXPEDITION_NUMBER, _defendersCount); + ++_defendersCount; + break; + case NPC_EXPEDITION_ENGINEER: + summon->AI()->SetData(DATA_EXPEDITION_NUMBER, _engineersSummonCount); + ++_engineersSummonCount; + break; + case NPC_EXPEDITION_TRAPPER: + summon->AI()->SetData(DATA_EXPEDITION_NUMBER, _trappersCount); + ++_trappersCount; + break; + default: + break; } - }; - - GameObjectAI* GetAI(GameObject* go) const override - { - return GetUlduarAI<go_razorscale_harpoonAI>(go); } -}; - -class boss_razorscale : public CreatureScript -{ - public: - boss_razorscale() : CreatureScript("boss_razorscale") { } - struct boss_razorscaleAI : public BossAI + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override { - boss_razorscaleAI(Creature* creature) : BossAI(creature, BOSS_RAZORSCALE) + if (summon->GetEntry() == NPC_EXPEDITION_ENGINEER) { - Initialize(); - // Do not let Razorscale be affected by Battle Shout buff - me->ApplySpellImmune(0, IMMUNITY_ID, (SPELL_BATTLE_SHOUT), true); - FlyCount = 0; - EnrageTimer = 0; - Enraged = false; - phase = PHASE_GROUND; + _engineersCount--; + if (_engineersCount == 0) + if (Creature* commander = instance->GetCreature(DATA_EXPEDITION_COMMANDER)) + commander->AI()->DoAction(ACTION_ENGINEER_DEAD); } + } - void Initialize() + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_HARPOON_TRIGGER) { - PermaGround = false; - HarpoonCounter = 0; + _harpoonHitCount++; + if (_harpoonHitCount == RAID_MODE(2, 4)) + DoAction(ACTION_GROUND_PHASE); } + } - Phases phase; + uint32 GetData(uint32 type) const override + { + if (type == DATA_QUICK_SHAVE && _flyCount <= 1) + return 1; + return 0; + } - uint32 EnrageTimer; - uint8 FlyCount; - uint8 HarpoonCounter; - bool PermaGround; - bool Enraged; + void EnterEvadeMode(EvadeReason why) override + { + if (why == EVADE_REASON_BOUNDARY && !events.IsInPhase(PHASE_PERMA_GROUND)) + return; + + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + summons.DespawnAll(); + HandleMusic(false); + _EnterEvadeMode(); + _DespawnAtEvade(); + } - void Reset() override - { - _Reset(); - me->SetCanFly(true); - me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_PASSIVE); - Initialize(); - if (Creature* commander = instance->GetCreature(DATA_EXPEDITION_COMMANDER)) - commander->AI()->DoAction(ACTION_COMMANDER_RESET); - } + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + HandleMusic(false); + } - void EnterCombat(Unit* /*who*/) override - { - _EnterCombat(); - if (Creature* controller = instance->GetCreature(DATA_RAZORSCALE_CONTROL)) - controller->AI()->DoAction(ACTION_HARPOON_BUILD); - me->SetSpeedRate(MOVE_FLIGHT, 3.0f); - me->SetReactState(REACT_PASSIVE); - phase = PHASE_GROUND; - events.SetPhase(PHASE_GROUND); - FlyCount = 0; - EnrageTimer = 600000; - Enraged = false; - events.ScheduleEvent(EVENT_FLIGHT, 0, 0, PHASE_GROUND); - } + void HandleMusic(bool active) + { + uint32 enabled = active ? 1 : 0; + instance->DoUpdateWorldState(WORLD_STATE_RAZORSCALE_MUSIC, enabled); + } - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - if (Creature* controller = instance->GetCreature(DATA_RAZORSCALE_CONTROL)) - controller->AI()->Reset(); - } + void SummonMinions() + { + float x = float(irand(540, 640)); // Safe range is between 500 and 650 + float y = float(irand(-230, -195)); // Safe range is between -235 and -145 + float z = 391.517f; // Ground level + me->SummonCreature(NPC_RAZORSCALE_SPAWNER, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000); + } - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + void DamageTaken(Unit* /*done_by*/, uint32 &damage) override + { + if (!_permaGround && me->HealthBelowPctDamaged(50, damage) && events.IsInPhase(PHASE_GROUND)) { - if (spell->Id == SPELL_HARPOON_TRIGGER) - ++HarpoonCounter; + _permaGround = true; + me->SetReactState(REACT_AGGRESSIVE); + events.SetPhase(PHASE_PERMA_GROUND); + DoAction(ACTION_START_PERMA_GROUND); } + } - void MovementInform(uint32 type, uint32 id) override - { - if (type == EFFECT_MOTION_TYPE && id == 1) - { - phase = PHASE_GROUND; - events.SetPhase(PHASE_GROUND); - events.ScheduleEvent(EVENT_LAND, 0, 0, PHASE_GROUND); - } - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - uint32 GetData(uint32 type) const override - { - if (type == DATA_QUICK_SHAVE) - if (FlyCount <= 2) - return 1; + events.Update(diff); - return 0; - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void UpdateAI(uint32 Diff) override + while (uint32 eventId = events.ExecuteEvent()) { - if (!UpdateVictim()) - return; - - events.Update(Diff); - - if (HealthBelowPct(50) && !PermaGround) - EnterPermaGround(); - - if (EnrageTimer <= Diff && !Enraged) + switch (eventId) { - DoCast(me, SPELL_BERSERK); - Enraged = true; - } - else - EnrageTimer -= Diff; - - if (HarpoonCounter == RAID_MODE(2, 4)) - { - HarpoonCounter = 0; - me->GetMotionMaster()->MoveLand(1, RazorGround); - } - - if (phase == PHASE_GROUND) - { - while (uint32 eventId = events.ExecuteEvent()) + case EVENT_BERSERK: + DoCastSelf(SPELL_BERSERK, true); + Talk(EMOTE_BERSERK, me); + break; + case EVENT_FIREBALL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_FIREBALL); + events.Repeat(Seconds(2), Seconds(3)); + break; + case EVENT_DEVOURING_FLAME: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_DEVOURING_FLAME); + if (_permaGround) + events.Repeat(Seconds(10), Seconds(12)); + else + events.Repeat(Seconds(6), Seconds(12)); + break; + case EVENT_SUMMON_MINIONS: { - switch (eventId) + uint8 random = urand(2, 4); + uint8 time = 5; + for (uint8 n = 0; n < random; ++n) { - case EVENT_FLIGHT: - phase = PHASE_FLIGHT; - events.SetPhase(PHASE_FLIGHT); - me->SetCanFly(true); - me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_PASSIVE); - me->AttackStop(); - me->GetMotionMaster()->MoveTakeoff(0, RazorFlight); - events.ScheduleEvent(EVENT_FIREBALL, 7000, 0, PHASE_FLIGHT); - events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_FLIGHT); - events.ScheduleEvent(EVENT_SUMMON, 5000, 0, PHASE_FLIGHT); - ++FlyCount; - return; - case EVENT_LAND: - me->SetCanFly(false); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->AddUnitFlag(UnitFlags(UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED)); - if (Creature* commander = instance->GetCreature(DATA_EXPEDITION_COMMANDER)) - commander->AI()->DoAction(ACTION_GROUND_PHASE); - events.ScheduleEvent(EVENT_BREATH, 30000, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_BUFFET, 33000, 0, PHASE_GROUND); - events.ScheduleEvent(EVENT_FLIGHT, 35000, 0, PHASE_GROUND); - return; - case EVENT_BREATH: - me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED)); - me->RemoveAllAuras(); - me->SetReactState(REACT_AGGRESSIVE); - Talk(EMOTE_BREATH); - DoCastAOE(SPELL_FLAMEBREATH); - events.CancelEvent(EVENT_BREATH); - return; - case EVENT_BUFFET: - DoCastAOE(SPELL_WINGBUFFET); - if (Creature* controller = instance->GetCreature(DATA_RAZORSCALE_CONTROL)) - controller->CastSpell(controller, SPELL_FLAMED, true); - events.CancelEvent(EVENT_BUFFET); - return; + events.ScheduleEvent(EVENT_SUMMON_MINIONS_2, Seconds(time), 0, PHASE_AIR); + time += 5; } + events.Repeat(Seconds(40)); + break; } - } - if (phase == PHASE_PERMAGROUND) - { - while (uint32 eventId = events.ExecuteEvent()) + case EVENT_SUMMON_MINIONS_2: + SummonMinions(); + break; + case EVENT_FLAME_BREATH: + me->RemoveAurasDueToSpell(SPELL_STUN_SELF); + Talk(EMOTE_BREATH, me); + DoCastVictim(SPELL_FLAME_BREATH); + events.ScheduleEvent(EVENT_WING_BUFFET, Seconds(2), 0, PHASE_GROUND); + break; + case EVENT_FLAME_BREATH_GROUND: + Talk(EMOTE_BREATH, me); + DoCastVictim(SPELL_FLAME_BREATH); + events.Repeat(Seconds(15), Seconds(18)); + break; + case EVENT_WING_BUFFET: { - switch (eventId) - { - case EVENT_FLAME: - DoCastAOE(SPELL_FLAMEBUFFET); - events.ScheduleEvent(EVENT_FLAME, 10000, 0, PHASE_PERMAGROUND); - return; - case EVENT_BREATH: - Talk(EMOTE_BREATH); - DoCastVictim(SPELL_FLAMEBREATH); - events.ScheduleEvent(EVENT_BREATH, 20000, 0, PHASE_PERMAGROUND); - return; - case EVENT_FIREBALL: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) - DoCast(target, SPELL_FIREBALL); - events.ScheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_PERMAGROUND); - return; - case EVENT_DEVOURING: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) - DoCast(target, SPELL_DEVOURING_FLAME); - events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_PERMAGROUND); - return; - case EVENT_BUFFET: - DoCastAOE(SPELL_WINGBUFFET); - events.CancelEvent(EVENT_BUFFET); - return; - case EVENT_FUSE: - DoCastVictim(SPELL_FUSEARMOR); - events.ScheduleEvent(EVENT_FUSE, 10000, 0, PHASE_PERMAGROUND); - return; - } + DoCastSelf(SPELL_WING_BUFFET); + events.ScheduleEvent(EVENT_FIREBOLT, Seconds(2), 0, PHASE_GROUND); + events.ScheduleEvent(EVENT_RESUME_AIR_PHASE, Seconds(4), 0, PHASE_GROUND); + EntryCheckPredicate pred(NPC_EXPEDITION_TRAPPER); + summons.DoAction(ACTION_STOP_CAST, pred); + break; } - - DoMeleeAttackIfReady(); - } - else - { - if (uint32 eventId = events.ExecuteEvent()) + case EVENT_RESUME_AIR_PHASE: { - switch (eventId) - { - case EVENT_FIREBALL: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) - DoCast(target, SPELL_FIREBALL); - events.ScheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_FLIGHT); - return; - case EVENT_DEVOURING: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 200.0f, true)) - me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_DEVOURING_FLAME, true); - events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_FLIGHT); - return; - case EVENT_SUMMON: - SummonMoleMachines(); - events.ScheduleEvent(EVENT_SUMMON, 45000, 0, PHASE_FLIGHT); - return; - } + me->SetDisableGravity(true); + me->SetAnimTier(UnitBytes1_Flags(UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER), true); + events.SetPhase(PHASE_AIR); + me->SetReactState(REACT_PASSIVE); + Position pos = me->GetPosition(); + pos.m_positionZ += 10.0f; + me->GetMotionMaster()->MoveTakeoff(POINT_RAZORSCALE_TAKEOFF, pos); + EntryCheckPredicate pred(NPC_EXPEDITION_ENGINEER); + summons.DoAction(ACTION_FIX_HARPOONS, pred); + break; } - } - } - - void EnterPermaGround() - { - Talk(EMOTE_PERMA); - phase = PHASE_PERMAGROUND; - events.SetPhase(PHASE_PERMAGROUND); - me->SetCanFly(false); - me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED)); - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveAurasDueToSpell(SPELL_HARPOON_TRIGGER); - me->SetSpeedRate(MOVE_FLIGHT, 1.0f); - PermaGround = true; - DoCastAOE(SPELL_FLAMEBREATH); - events.ScheduleEvent(EVENT_FLAME, 15000, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_DEVOURING, 15000, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_BREATH, 20000, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_DEVOURING, 6000, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_BUFFET, 2500, 0, PHASE_PERMAGROUND); - events.RescheduleEvent(EVENT_FUSE, 5000, 0, PHASE_PERMAGROUND); - } - - void SummonMoleMachines() - { - // Adds will come in waves from mole machines. One mole can spawn a Dark Rune Watcher - // with 1-2 Guardians, or a lone Sentinel. Up to 4 mole machines can spawn adds at any given time. - uint8 random = urand(2, 4); - for (uint8 n = 0; n < random; n++) - { - float x = float(irand(540, 640)); // Safe range is between 500 and 650 - float y = float(irand(-230, -195)); // Safe range is between -235 and -145 - float z = GROUND_Z; // Ground level - me->SummonCreature(MOLE_MACHINE_TRIGGER, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 15000); - } - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_EVENT_START: - me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)); - me->SetReactState(REACT_AGGRESSIVE); - DoZoneInCombat(me, 150.0f); + case EVENT_FIREBOLT: + DoCastSelf(SPELL_FIREBOLT); + break; + case EVENT_FUSE_ARMOR: + DoCastVictim(SPELL_FUSE_ARMOR); + events.Repeat(Seconds(10), Seconds(15)); + break; + case EVENT_RESUME_MOVE_CHASE: + SetCombatMovement(true); + if (Unit* victim = me->GetVictim()) + me->GetMotionMaster()->MoveChase(victim); + break; + default: break; } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI<boss_razorscaleAI>(creature); + if (events.IsInPhase(PHASE_PERMA_GROUND)) + DoMeleeAttackIfReady(); } + + private: + uint8 _engineersCount; + uint8 _engineersSummonCount; + uint8 _defendersCount; + uint8 _harpoonHitCount; + uint8 _trappersCount; + bool _permaGround; + uint32 _flyCount; + + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<boss_razorscaleAI>(creature); + } }; class npc_expedition_commander : public CreatureScript { - public: - npc_expedition_commander() : CreatureScript("npc_expedition_commander") { } +public: + npc_expedition_commander() : CreatureScript("npc_expedition_commander") { } - struct npc_expedition_commanderAI : public ScriptedAI + struct npc_expedition_commanderAI : public ScriptedAI + { + npc_expedition_commanderAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), + _is25Man(Is25ManRaid()), _building(false), _destroy(false), _stopControllers(false) { } + + void Reset() override { - npc_expedition_commanderAI(Creature* creature) : ScriptedAI(creature), summons(creature) - { - Initialize(); - instance = me->GetInstanceScript(); - } + _events.Reset(); + _events.SetPhase(PHASE_NONE); + BuildBrokenHarpoons(); + } - void Initialize() + bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override + { + if (gossipListId == GOSSIP_START_ENCOUNTER) { - AttackStartTimer = 0; - Phase = 0; - Greet = false; + CloseGossipMenuFor(player); + _events.SetPhase(PHASE_COMBAT); + me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); + if (Creature* razorscale = _instance->GetCreature(BOSS_RAZORSCALE)) + razorscale->AI()->DoAction(ACTION_START_FIGHT); + return true; } + return false; + } - InstanceScript* instance; - SummonList summons; + void BuildBrokenHarpoons() + { + uint8 harpoonNumber = _is25Man ? 4 : 2; + for (uint8 i = 0; i < harpoonNumber; ++i) + me->SummonGameObject(GO_RAZOR_BROKEN_HARPOON, PosBrokenHarpoon[i], QuaternionData(0.0f, 0.0f, -0.8987932f, 0.4383728f), WEEK); + } - bool Greet; - uint32 AttackStartTimer; - uint8 Phase; - ObjectGuid Engineer[4]; - ObjectGuid Defender[4]; + void DestroyHarpoons() + { + for (ObjectGuid harpoonGuid : _harpoons) + if (GameObject* harpoon = ObjectAccessor::GetGameObject(*me, harpoonGuid)) + harpoon->RemoveFromWorld(); - void Reset() override - { - Initialize(); - summons.DespawnAll(); - } + _harpoons.clear(); + BuildBrokenHarpoons(); + _events.ScheduleEvent(EVENT_HANDLE_DESTROY_HARPOON, Seconds(10)); + } + + void HandleControllersStopCast() + { + std::list<Creature*> Controllers; + me->GetCreatureListWithEntryInGrid(Controllers, NPC_RAZORSCALE_CONTROLLER, 100.0f); - void MoveInLineOfSight(Unit* who) override + for (Creature* controller : Controllers) + controller->InterruptNonMeleeSpells(false); + _stopControllers = false; + } + + void BuildHarpoon(uint8 harpoonNumber) + { + + if (_is25Man) { - if (!Greet && me->IsWithinDistInMap(who, 10.0f) && who->GetTypeId() == TYPEID_PLAYER) + switch (harpoonNumber) { - Talk(SAY_INTRO); - Greet = true; + case HARPOON_1: + if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_3, PosHarpoon[2], QuaternionData(0.0f, 0.0f, -0.573576f, 0.8191524f), WEEK)) + _harpoons.emplace_back(harpoon->GetGUID()); + break; + case HARPOON_2: + if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_1, PosHarpoon[0], QuaternionData(0.0f, 0.0f, -0.6293201f, 0.7771462f), WEEK)) + _harpoons.emplace_back(harpoon->GetGUID()); + break; + case HARPOON_3: + if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_2, PosHarpoon[1], QuaternionData(0.0f, 0.0f, -0.6691303f, 0.743145f), WEEK)) + _harpoons.emplace_back(harpoon->GetGUID()); + break; + case HARPOON_4: + if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_4, PosHarpoon[3], QuaternionData(0.0f, 0.0f, -0.7660437f, 0.6427886f), WEEK)) + _harpoons.emplace_back(harpoon->GetGUID()); + break; + default: + break; } } - - void JustSummoned(Creature* summoned) override - { - summons.Summon(summoned); - } - - void DoAction(int32 action) override + else { - switch (action) + switch (harpoonNumber) { - case ACTION_GROUND_PHASE: - Talk(SAY_GROUND_PHASE); + case HARPOON_1: + if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_1, PosHarpoon[harpoonNumber], QuaternionData(0.0f, 0.0f, -0.6293201f, 0.7771462f), 0)) + _harpoons.emplace_back(harpoon->GetGUID()); break; - case ACTION_COMMANDER_RESET: - summons.DespawnAll(); - me->AddNpcFlag(UNIT_NPC_FLAG_GOSSIP); + case HARPOON_2: + if (GameObject* harpoon = me->SummonGameObject(GO_RAZOR_HARPOON_2, PosHarpoon[harpoonNumber], QuaternionData(0.0f, 0.0f, -0.6691303f, 0.743145f), 0)) + _harpoons.emplace_back(harpoon->GetGUID()); + break; + default: break; } } + } - void UpdateAI(uint32 Diff) override + void DoAction(int32 actionId) override + { + if (_building && actionId != ACTION_ENGINEER_DEAD) + return; + + switch (actionId) { - if (AttackStartTimer <= Diff) - { - switch (Phase) - { - case 1: - instance->SetBossState(BOSS_RAZORSCALE, IN_PROGRESS); - summons.DespawnAll(); - AttackStartTimer = 1000; - Phase = 2; - break; - case 2: - for (uint8 n = 0; n < RAID_MODE(2, 4); n++) - { - if (Creature* summonedEngineer = me->SummonCreature(NPC_ENGINEER, PosEngSpawn, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000)) - { - summonedEngineer->SetWalk(false); - summonedEngineer->SetSpeedRate(MOVE_RUN, 0.5f); - summonedEngineer->SetHomePosition(PosEngRepair[n]); - summonedEngineer->GetMotionMaster()->MoveTargetedHome(); - Engineer[n] = summonedEngineer->GetGUID(); - } - } - if (Creature* firstSummon = ObjectAccessor::GetCreature(*me, Engineer[0])) - firstSummon->AI()->Talk(SAY_AGGRO_3); - Phase = 3; - AttackStartTimer = 14000; - break; - case 3: - for (uint8 n = 0; n < 4; n++) - { - if (Creature* summonedDefender = me->SummonCreature(NPC_DEFENDER, PosDefSpawn[n], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000)) - { - summonedDefender->SetWalk(false); - summonedDefender->SetHomePosition(PosDefCombat[n]); - summonedDefender->GetMotionMaster()->MoveTargetedHome(); - Defender[n] = summonedDefender->GetGUID(); - } - } - Phase = 4; - break; - case 4: - for (uint8 n = 0; n < RAID_MODE(2, 4); n++) - if (Creature* summonedEngineer = ObjectAccessor::GetCreature(*me, Engineer[n])) - summonedEngineer->SetEmoteState(EMOTE_STATE_USE_STANDING); - for (uint8 n = 0; n < 4; ++n) - if (Creature* summonedDefender = ObjectAccessor::GetCreature(*me, Defender[n])) - summonedDefender->SetEmoteState(EMOTE_STATE_READY2H); - Talk(SAY_AGGRO_2); - AttackStartTimer = 16000; - Phase = 5; - break; - case 5: - if (Creature* razorscale = instance->GetCreature(BOSS_RAZORSCALE)) - { - razorscale->AI()->DoAction(ACTION_EVENT_START); - me->SetInCombatWith(razorscale); - } - if (Creature* firstEngineer = ObjectAccessor::GetCreature(*me, Engineer[0])) - firstEngineer->AI()->Talk(SAY_AGGRO_1); - Phase = 6; - break; - } - } - else - AttackStartTimer -= Diff; + case ACTION_START_FIGHT: + Talk(SAY_COMMANDER_AGGRO); + break; + case ACTION_GROUND_PHASE: + Talk(SAY_COMMANDER_GROUND_PHASE); + break; + case ACTION_ENGINEER_DEAD: + Talk(SAY_COMMANDER_ENGINEERS_DEAD); + _events.Reset(); + _building = false; + break; + case ACTION_BUILD_HARPOON_1: + _building = true; + _events.ScheduleEvent(EVENT_BUILD_HARPOON_1, Seconds(18)); + break; + case ACTION_BUILD_HARPOON_2: + _building = true; + _events.ScheduleEvent(EVENT_BUILD_HARPOON_2, Seconds(18)); + break; + case ACTION_BUILD_HARPOON_3: + _building = true; + _events.ScheduleEvent(EVENT_BUILD_HARPOON_3, Seconds(18)); + break; + case ACTION_BUILD_HARPOON_4: + _building = true; + _events.ScheduleEvent(EVENT_BUILD_HARPOON_4, Seconds(18)); + break; + case ACTION_DESTROY_HARPOONS: + if (_destroy) + return; + _destroy = true; + DestroyHarpoons(); + break; + case ACTION_STOP_CONTROLLERS: + if (_stopControllers) + return; + _stopControllers = true; + HandleControllersStopCast(); + break; + default: + break; } + } + + void UpdateAI(uint32 diff) override + { + if (!_events.IsInPhase(PHASE_COMBAT)) + return; + + _events.Update(diff); - bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override + while (uint32 eventId = _events.ExecuteEvent()) { - uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId); - ClearGossipMenuFor(player); - switch (action) + switch (eventId) { - case GOSSIP_ACTION_INFO_DEF: - CloseGossipMenuFor(player); - Phase = 1; + case EVENT_BUILD_HARPOON_1: + BuildHarpoon(HARPOON_1); + _building = false; + break; + case EVENT_BUILD_HARPOON_2: + BuildHarpoon(HARPOON_2); + _building = false; + break; + case EVENT_BUILD_HARPOON_3: + BuildHarpoon(HARPOON_3); + _building = false; + break; + case EVENT_BUILD_HARPOON_4: + BuildHarpoon(HARPOON_4); + _building = false; + break; + case EVENT_HANDLE_DESTROY_HARPOON: + _destroy = false; + break; + default: break; } - return true; } + } - bool GossipHello(Player* player) override - { - if (instance->GetBossState(BOSS_RAZORSCALE) == NOT_STARTED) - { - player->PrepareGossipMenu(me); + private: + InstanceScript* _instance; + GuidVector _harpoons; + bool _is25Man; + bool _building; + bool _destroy; + bool _stopControllers; + EventMap _events; + }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_expedition_commanderAI>(creature); + } +}; - AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - SendGossipMenuFor(player, 13853, me->GetGUID()); - } - else - SendGossipMenuFor(player, 13910, me->GetGUID()); - return true; - } +class npc_expedition_defender : public CreatureScript +{ +public: + npc_expedition_defender() : CreatureScript("npc_expedition_defender") { } - }; + struct npc_expedition_defenderAI : public ScriptedAI + { + npc_expedition_defenderAI(Creature* creature) : ScriptedAI(creature), _myPositionNumber(0), _instance(creature->GetInstanceScript()) + { + me->setRegeneratingHealth(false); + } - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetUlduarAI<npc_expedition_commanderAI>(creature); + DoCastSelf(SPELL_THREAT); } -}; -class npc_mole_machine_trigger : public CreatureScript -{ - public: - npc_mole_machine_trigger() : CreatureScript("npc_mole_machine_trigger") { } + bool CanAIAttack(Unit const* target) const override + { + if (target->GetEntry() == NPC_RAZORSCALE || target->GetEntry() == NPC_RAZORSCALE_SPAWNER) + return false; + + return ScriptedAI::CanAIAttack(target); + } - struct npc_mole_machine_triggerAI : public ScriptedAI + void SetData(uint32 type, uint32 value) override { - npc_mole_machine_triggerAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - SetCombatMovement(false); - me->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED)); - } + if (type == DATA_EXPEDITION_NUMBER) + _myPositionNumber = value; + } - void Initialize() - { - SummonGobTimer = 2000; - SummonNpcTimer = 6000; - DissapearTimer = 10000; - GobSummoned = false; - NpcSummoned = false; - } + void DoAction(int32 actionId) override + { + if (actionId == ACTION_START_FIGHT) + me->GetMotionMaster()->MovePoint(POINT_DEFENDER_ATTACK, DefendersPosition[_myPositionNumber]); + } - uint32 SummonGobTimer; - uint32 SummonNpcTimer; - uint32 DissapearTimer; - bool GobSummoned; - bool NpcSummoned; + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE && pointId != POINT_DEFENDER_ATTACK) + return; - void Reset() override - { - Initialize(); - } + me->SetHomePosition(DefendersPosition[_myPositionNumber]); + me->SetImmuneToNPC(false); + } - void UpdateAI(uint32 Diff) override - { - if (!GobSummoned && SummonGobTimer <= Diff) - { - DoCast(SPELL_SUMMON_MOLE_MACHINE); - GobSummoned = true; - } - else - SummonGobTimer -= Diff; + private: + uint8 _myPositionNumber; + InstanceScript* _instance; + }; - if (!NpcSummoned && SummonNpcTimer <= Diff) - { - switch (urand(0, 1 )) - { - case 0: - DoCast(SPELL_SUMMON_IRON_DWARVES); - break; - case 1: - DoCast(SPELL_SUMMON_IRON_DWARVES_2); - break; - } + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_expedition_defenderAI>(creature); + } +}; - DoCast(SPELL_SUMMON_IRON_DWARVE_GUARDIAN); - DoCast(SPELL_SUMMON_IRON_DWARVE_WATCHER); - NpcSummoned = true; - } - else - SummonNpcTimer -= Diff; +class npc_expedition_trapper : public CreatureScript +{ +public: + npc_expedition_trapper() : CreatureScript("npc_expedition_trapper") { } - if (DissapearTimer <= Diff) - { - if (GameObject* molemachine = me->FindNearestGameObject(GO_MOLE_MACHINE, 1)) - molemachine->Delete(); + struct npc_expedition_trapperAI : public ScriptedAI + { + npc_expedition_trapperAI(Creature* creature) : ScriptedAI(creature), _myPositionNumber(0), _instance(creature->GetInstanceScript()) + { + SetCombatMovement(false); + creature->SetReactState(REACT_PASSIVE); + } - me->DisappearAndDie(); - } - else - DissapearTimer -= Diff; - } + void DoAction(int32 actionId) override + { + if (!me->IsAlive()) + return; - void JustSummoned(Creature* summoned) override + switch (actionId) { - summoned->AI()->DoZoneInCombat(); + case ACTION_SHACKLE_RAZORSCALE: + me->GetMotionMaster()->MovePoint(POINT_SHACKLE_RAZORSCALE, TrapperPosition[_myPositionNumber]); + break; + case ACTION_RETURN_TO_BASE: + me->GetMotionMaster()->MoveTargetedHome(); + break; + case ACTION_START_FIGHT: + me->SetImmuneToNPC(false); + break; + case ACTION_STOP_CAST: + me->InterruptNonMeleeSpells(false); + _scheduler.Schedule(Seconds(2), [this](TaskContext /*context*/) + { + me->GetMotionMaster()->MoveTargetedHome(); + }); + if (Creature* commander = _instance->GetCreature(DATA_EXPEDITION_COMMANDER)) + commander->AI()->DoAction(ACTION_STOP_CONTROLLERS); + break; + default: + break; } - }; + } + + void SetData(uint32 type, uint32 value) override + { + if (type == DATA_EXPEDITION_NUMBER) + _myPositionNumber = value; + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE && pointId != POINT_SHACKLE_RAZORSCALE) + return; - CreatureAI* GetAI(Creature* creature) const override + DoCastSelf(SPELL_SHACKLE); + } + + void UpdateAI(uint32 diff) override { - return GetUlduarAI<npc_mole_machine_triggerAI>(creature); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + _scheduler.Update(diff); } + + private: + uint8 _myPositionNumber; + InstanceScript* _instance; + TaskScheduler _scheduler; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_expedition_trapperAI>(creature); + } }; -class npc_devouring_flame : public CreatureScript +class npc_expedition_engineer : public CreatureScript { - public: - npc_devouring_flame() : CreatureScript("npc_devouring_flame") { } +public: + npc_expedition_engineer() : CreatureScript("npc_expedition_engineer") { } + + struct npc_expedition_engineerAI : public ScriptedAI + { + npc_expedition_engineerAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _myPositionNumber(0), _canUpdateAI(false) { } + + void Reset() override + { + me->SetReactState(REACT_PASSIVE); + _scheduler.CancelAll(); + } - struct npc_devouring_flameAI : public ScriptedAI + void DoAction(int32 actionId) override { - npc_devouring_flameAI(Creature* creature) : ScriptedAI(creature) + if (!me->IsAlive()) + return; + + if (actionId == ACTION_START_FIGHT) { - SetCombatMovement(false); - me->AddUnitFlag(UnitFlags(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED)); + _canUpdateAI = true; + if (_myPositionNumber == ENGINEER_EAST) + Talk(SAY_AGGRO); + _scheduler.Schedule(Seconds(28), [this](TaskContext /*context*/) + { + HandleHarpoonMovement(); + me->SetImmuneToNPC(false); + }); } - - void Reset() override + else if (actionId == ACTION_FIX_HARPOONS) { - DoCast(SPELL_FLAME_GROUND); + if (_myPositionNumber == ENGINEER_EAST) + Talk(SAY_AGGRO); + _scheduler.Schedule(Seconds(28), [this](TaskContext /*context*/) + { + HandleHarpoonMovement(); + }); } - }; + } - CreatureAI* GetAI(Creature* creature) const override + void ChangeOrientation(float orientation) { - return GetUlduarAI<npc_devouring_flameAI>(creature); + _scheduler.Schedule(Milliseconds(1), [this, orientation](TaskContext /*context*/) + { + me->SetFacingTo(orientation); + }); } -}; -class npc_darkrune_watcher : public CreatureScript -{ - public: - npc_darkrune_watcher() : CreatureScript("npc_darkrune_watcher") { } + void HandleHarpoonMovement() + { + switch (_myPositionNumber) + { + case ENGINEER_NORTH: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_1_25, SPLINE_ENGINEER_NORTH_25_HARPOON_1, false); + else + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_1, SPLINE_ENGINEER_NORTH_10_HARPOON_1, false); + break; + case ENGINEER_EAST: + Talk(SAY_START_REPAIR); + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_1_25, SPLINE_ENGINEER_EAST_25_HARPOON_1, false); + else + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_1, SPLINE_ENGINEER_EAST_10_HARPOON_1, false); + break; + case ENGINEER_WEST: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_1_25, SPLINE_ENGINEER_WEST_25_HARPOON_1, false); + else + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_1, SPLINE_ENGINEER_WEST_10_HARPOON_1, false); + break; + default: + break; + } + } - struct npc_darkrune_watcherAI : public ScriptedAI + void HandleSecondHarpoonMovement() { - npc_darkrune_watcherAI(Creature* creature) : ScriptedAI(creature) + switch (_myPositionNumber) { - Initialize(); + case ENGINEER_NORTH: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_2_25, SPLINE_ENGINEER_NORTH_25_HARPOON_2, false); + else + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_2, SPLINE_ENGINEER_NORTH_10_HARPOON_2, false); + break; + case ENGINEER_EAST: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_2_25, SPLINE_ENGINEER_EAST_25_HARPOON_2, false); + else + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_2, SPLINE_ENGINEER_EAST_10_HARPOON_2, false); + break; + case ENGINEER_WEST: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_2_25, SPLINE_ENGINEER_WEST_25_HARPOON_2, false); + else + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_2, SPLINE_ENGINEER_WEST_10_HARPOON_2, false); + break; + default: + break; } + } - void Initialize() + void HandleThirdHarpoonMovement() + { + switch (_myPositionNumber) { - ChainTimer = urand(10000, 15000); - LightTimer = urand(1000, 3000); + case ENGINEER_NORTH: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_3, SPLINE_ENGINEER_NORTH_25_HARPOON_3, false); + else + me->GetMotionMaster()->MoveAlongSplineChain(POINT_BASE, SPLINE_ENGINEER_NORTH_10_BASE, false); + break; + case ENGINEER_EAST: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_3, SPLINE_ENGINEER_EAST_25_HARPOON_3, false); + else + me->GetMotionMaster()->MoveAlongSplineChain(POINT_BASE, SPLINE_ENGINEER_EAST_10_BASE, false); + break; + case ENGINEER_WEST: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_3, SPLINE_ENGINEER_WEST_25_HARPOON_3, false); + else + me->GetMotionMaster()->MoveAlongSplineChain(POINT_BASE, SPLINE_ENGINEER_WEST_10_BASE, false); + break; + default: + break; } + } - uint32 ChainTimer; - uint32 LightTimer; + void HandleFourthHarpoonMovement() + { + switch (_myPositionNumber) + { + case ENGINEER_NORTH: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_4, SPLINE_ENGINEER_NORTH_25_HARPOON_4, false); + break; + case ENGINEER_EAST: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_4, SPLINE_ENGINEER_EAST_25_HARPOON_4, false); + break; + case ENGINEER_WEST: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_HARPOON_4, SPLINE_ENGINEER_WEST_25_HARPOON_4, false); + break; + default: + break; + } + } - void Reset() override + void HandleBaseMovement() + { + switch (_myPositionNumber) { - Initialize(); + case ENGINEER_NORTH: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_BASE, SPLINE_ENGINEER_NORTH_25_BASE, false); + break; + case ENGINEER_EAST: + if (Is25ManRaid()) + me->GetMotionMaster()->MovePoint(POINT_BASE, me->GetHomePosition()); + break; + case ENGINEER_WEST: + if (Is25ManRaid()) + me->GetMotionMaster()->MoveAlongSplineChain(POINT_BASE, SPLINE_ENGINEER_WEST_25_BASE, false); + break; + default: + break; } + } + + void UpdateAI(uint32 diff) override + { + if (!_canUpdateAI) + return; + + _scheduler.Update(diff); + } - void UpdateAI(uint32 Diff) override + void SetData(uint32 type, uint32 value) override + { + if (type == DATA_EXPEDITION_NUMBER) + _myPositionNumber = value; + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE && type != SPLINE_CHAIN_MOTION_TYPE) + return; + + switch (pointId) { - if (!UpdateVictim()) - return; + case POINT_HARPOON_1: + case POINT_HARPOON_1_25: + if (Creature* commander = _instance->GetCreature(DATA_EXPEDITION_COMMANDER)) + commander->AI()->DoAction(ACTION_BUILD_HARPOON_1); + + _scheduler. + Schedule(Seconds(3), [this](TaskContext /*context*/) + { + me->SetEmoteState(EMOTE_STATE_USE_STANDING); + }) + .Schedule(Seconds(18), [this](TaskContext /*context*/) + { + HandleSecondHarpoonMovement(); + }); + break; + case POINT_HARPOON_2: + case POINT_HARPOON_2_25: + if (Creature* commander = _instance->GetCreature(DATA_EXPEDITION_COMMANDER)) + commander->AI()->DoAction(ACTION_BUILD_HARPOON_2); + _scheduler.Schedule(Seconds(18), [this](TaskContext /*context*/) + { + HandleThirdHarpoonMovement(); + }); + break; + case POINT_HARPOON_3: + if (Creature* commander = _instance->GetCreature(DATA_EXPEDITION_COMMANDER)) + commander->AI()->DoAction(ACTION_BUILD_HARPOON_3); + _scheduler.Schedule(Seconds(18), [this](TaskContext /*context*/) + { + HandleFourthHarpoonMovement(); + }); + break; + case POINT_HARPOON_4: + if (Creature* commander = _instance->GetCreature(DATA_EXPEDITION_COMMANDER)) + commander->AI()->DoAction(ACTION_BUILD_HARPOON_4); + _scheduler.Schedule(Seconds(18), [this](TaskContext /*context*/) + { + HandleBaseMovement(); + }); + break; + case POINT_BASE: + ChangeOrientation(4.61684f); + break; + default: + break; + } + } + + private: + InstanceScript* _instance; + TaskScheduler _scheduler; + uint8 _myPositionNumber; + bool _canUpdateAI; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_expedition_engineerAI>(creature); + } +}; + +class npc_razorscale_spawner : public CreatureScript +{ +public: + npc_razorscale_spawner() : CreatureScript("npc_razorscale_spawner") { } + + struct npc_razorscale_spawnerAI : public ScriptedAI + { + npc_razorscale_spawnerAI(Creature* creature) : ScriptedAI(creature) { } - if (ChainTimer <= Diff) + void Reset() override + { + me->setActive(true); + me->SetReactState(REACT_PASSIVE); + _scheduler. + Schedule(Seconds(1), [this](TaskContext /*context*/) { - DoCastVictim(SPELL_CHAIN_LIGHTNING); - ChainTimer = urand(10000, 15000); - } - else - ChainTimer -= Diff; + DoCastSelf(SPELL_SUMMON_MOLE_MACHINE); + }).Schedule(Seconds(6), [this](TaskContext /*context*/) + { + DoCastSelf(SummonMinionsSpells[urand(0, 3)]); + }); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } + + private: + TaskScheduler _scheduler; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_razorscale_spawnerAI>(creature); + } +}; + +class npc_darkrune_watcher : public CreatureScript +{ +public: + npc_darkrune_watcher() : CreatureScript("npc_darkrune_watcher") { } + + struct npc_darkrune_watcherAI : public ScriptedAI + { + npc_darkrune_watcherAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void Reset() override + { + _events.Reset(); + me->SetReactState(REACT_PASSIVE); + _events.ScheduleEvent(EVENT_START_COMBAT, Seconds(2)); + if (Creature* razorscale = _instance->GetCreature(BOSS_RAZORSCALE)) + razorscale->AI()->JustSummoned(me); + } + + void EnterCombat(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_LIGHTNING_BOLT, Seconds(5)); + _events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, Seconds(34)); + } - if (LightTimer <= Diff) + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) { - DoCastVictim(SPELL_LIGHTNING_BOLT); - LightTimer = urand(5000, 7000); + case EVENT_START_COMBAT: + me->SetReactState(REACT_AGGRESSIVE); + me->SetInCombatWithZone(); + break; + case EVENT_LIGHTNING_BOLT: + DoCastVictim(SPELL_LIGHTNING_BOLT); + _events.Repeat(Seconds(3)); + break; + case EVENT_CHAIN_LIGHTNING: + DoCastVictim(SPELL_CHAIN_LIGHTNING); + _events.Repeat(Seconds(9), Seconds(15)); + break; + default: + break; } - else - LightTimer -= Diff; - DoMeleeAttackIfReady(); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI<npc_darkrune_watcherAI>(creature); + DoMeleeAttackIfReady(); } + + private: + InstanceScript* _instance; + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_darkrune_watcherAI>(creature); + } }; class npc_darkrune_guardian : public CreatureScript { - public: - npc_darkrune_guardian() : CreatureScript("npc_darkrune_guardian") { } +public: + npc_darkrune_guardian() : CreatureScript("npc_darkrune_guardian") { } - struct npc_darkrune_guardianAI : public ScriptedAI + struct npc_darkrune_guardianAI : public ScriptedAI + { + npc_darkrune_guardianAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _killedByBreath(false) { } + + void Reset() override { - npc_darkrune_guardianAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - } + _events.Reset(); + me->SetReactState(REACT_PASSIVE); + _events.ScheduleEvent(EVENT_START_COMBAT, Seconds(2)); + if (Creature* razorscale = _instance->GetCreature(BOSS_RAZORSCALE)) + razorscale->AI()->JustSummoned(me); + } - void Initialize() - { - StormTimer = urand(3000, 6000); - killedByBreath = false; - } + void EnterCombat(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_STORMSTRIKE, Seconds(23)); + } - uint32 StormTimer; + uint32 GetData(uint32 type) const override + { + return type == DATA_IRON_DWARF_MEDIUM_RARE ? _killedByBreath : 0; + } - void Reset() override - { - Initialize(); - } + void SetData(uint32 type, uint32 value) override + { + if (type == DATA_IRON_DWARF_MEDIUM_RARE) + _killedByBreath = value != 0; + } - uint32 GetData(uint32 type) const override - { - return type == DATA_IRON_DWARF_MEDIUM_RARE ? killedByBreath : 0; - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void SetData(uint32 type, uint32 value) override - { - if (type == DATA_IRON_DWARF_MEDIUM_RARE) - killedByBreath = value != 0; - } + _events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void UpdateAI(uint32 Diff) override + while (uint32 eventId = _events.ExecuteEvent()) { - if (!UpdateVictim()) - return; - - if (StormTimer <= Diff) + switch (eventId) { - DoCastVictim(SPELL_STORMSTRIKE); - StormTimer = urand(4000, 8000); + case EVENT_START_COMBAT: + me->SetReactState(REACT_AGGRESSIVE); + me->SetInCombatWithZone(); + break; + case EVENT_STORMSTRIKE: + DoCastVictim(SPELL_STORMSTRIKE); + _events.Repeat(Seconds(13), Seconds(25)); + break; + default: + break; } - else - StormTimer -= Diff; - DoMeleeAttackIfReady(); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } - private: - bool killedByBreath; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetUlduarAI<npc_darkrune_guardianAI>(creature); + DoMeleeAttackIfReady(); } + + private: + InstanceScript* _instance; + EventMap _events; + bool _killedByBreath; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_darkrune_guardianAI>(creature); + } }; class npc_darkrune_sentinel : public CreatureScript { - public: - npc_darkrune_sentinel() : CreatureScript("npc_darkrune_sentinel") { } +public: + npc_darkrune_sentinel() : CreatureScript("npc_darkrune_sentinel") { } + + struct npc_darkrune_sentinelAI : public ScriptedAI + { + npc_darkrune_sentinelAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void Reset() override + { + _events.Reset(); + me->SetReactState(REACT_PASSIVE); + _events.ScheduleEvent(EVENT_START_COMBAT, Seconds(2)); + if (Creature* razorscale = _instance->GetCreature(BOSS_RAZORSCALE)) + razorscale->AI()->JustSummoned(me); + } + + void EnterCombat(Unit* /*who*/) override + { + _events.ScheduleEvent(EVENT_HEROIC_STRIKE, Seconds(9)); + _events.ScheduleEvent(EVENT_BATTLE_SHOUT, Seconds(15)); + _events.ScheduleEvent(EVENT_WHIRLWIND, Seconds(17)); + } - struct npc_darkrune_sentinelAI : public ScriptedAI + void UpdateAI(uint32 diff) override { - npc_darkrune_sentinelAI(Creature* creature) : ScriptedAI(creature) + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) { - Initialize(); + switch (eventId) + { + case EVENT_START_COMBAT: + me->SetReactState(REACT_AGGRESSIVE); + me->SetInCombatWithZone(); + break; + case EVENT_HEROIC_STRIKE: + DoCastVictim(SPELL_HEROIC_STRIKE); + _events.Repeat(Seconds(5), Seconds(9)); + break; + case EVENT_BATTLE_SHOUT: + DoCastSelf(SPELL_BATTLE_SHOUT); + _events.Repeat(Seconds(25)); + break; + case EVENT_WHIRLWIND: + DoCastSelf(SPELL_WHIRLWIND); + _events.Repeat(Seconds(10), Seconds(13)); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } - void Initialize() + DoMeleeAttackIfReady(); + } + private: + InstanceScript* _instance; + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_darkrune_sentinelAI>(creature); + } +}; + +class npc_razorscale_harpoon_fire_state : public CreatureScript +{ +public: + npc_razorscale_harpoon_fire_state() : CreatureScript("npc_razorscale_harpoon_fire_state") { } + + struct npc_razorscale_harpoon_fire_stateAI : public ScriptedAI + { + npc_razorscale_harpoon_fire_stateAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()){ } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_FIREBOLT) { - HeroicTimer = urand(4000, 8000); - WhirlTimer = urand(20000, 25000); - ShoutTimer = urand(15000, 30000); + DoCastSelf(SPELL_HARPOON_FIRE_STATE); + if (Creature* commander = _instance->GetCreature(DATA_EXPEDITION_COMMANDER)) + commander->AI()->DoAction(ACTION_DESTROY_HARPOONS); } + } + private: + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_razorscale_harpoon_fire_stateAI>(creature); + } +}; + +class go_razorscale_harpoon : public GameObjectScript +{ +public: + go_razorscale_harpoon() : GameObjectScript("go_razorscale_harpoon") { } + + struct go_razorscale_harpoonAI : public GameObjectAI + { + go_razorscale_harpoonAI(GameObject* go) : GameObjectAI(go) { } + + void Reset() override + { + _scheduler.Schedule(Seconds(1), [this](TaskContext /*context*/) + { + if (Creature* controller = me->FindNearestCreature(NPC_RAZORSCALE_CONTROLLER, 5.0f)) + controller->AI()->Talk(EMOTE_HARPOON); - uint32 HeroicTimer; - uint32 WhirlTimer; - uint32 ShoutTimer; + if (GameObject* brokenHarpoon = me->FindNearestGameObject(GO_RAZOR_BROKEN_HARPOON, 5.0f)) + brokenHarpoon->RemoveFromWorld(); + }); + } - void Reset() override + uint32 SelectRightSpell() + { + switch (me->GetEntry()) { - Initialize(); + case GO_RAZOR_HARPOON_1: + return SPELL_HARPOON_SHOT_1; + case GO_RAZOR_HARPOON_2: + return SPELL_HARPOON_SHOT_2; + case GO_RAZOR_HARPOON_3: + return SPELL_HARPOON_SHOT_3; + case GO_RAZOR_HARPOON_4: + return SPELL_HARPOON_SHOT_4; + default: + return 0; } + } - void UpdateAI(uint32 Diff) override + bool GossipHello(Player* /*player*/) override + { + me->AddFlag(GO_FLAG_NOT_SELECTABLE); + if (Creature* controller = me->FindNearestCreature(NPC_RAZORSCALE_CONTROLLER, 5.0f)) { - if (!UpdateVictim()) - return; + // Prevent 2 players clicking at "same time" + if (controller->HasUnitState(UNIT_STATE_CASTING)) + return true; - if (HeroicTimer <= Diff) - { - DoCastVictim(SPELL_HEROIC_STRIKE); - HeroicTimer = urand(4000, 6000); - } - else - HeroicTimer -= Diff; + uint32 spellId = SelectRightSpell(); + controller->CastSpell((Unit*) nullptr, spellId, true); + } - if (WhirlTimer <= Diff) - { - DoCastVictim(SPELL_WHIRLWIND); - WhirlTimer = urand(20000, 25000); - } - else - WhirlTimer -= Diff; + return true; + } - if (ShoutTimer <= Diff) - { - DoCast(me, SPELL_BATTLE_SHOUT); - ShoutTimer = urand(30000, 40000); - } - else - ShoutTimer -= Diff; + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff); + } - DoMeleeAttackIfReady(); - } - }; + private: + TaskScheduler _scheduler; + }; - CreatureAI* GetAI(Creature* creature) const override + GameObjectAI* GetAI(GameObject* go) const override + { + return GetUlduarAI<go_razorscale_harpoonAI>(go); + } +}; + +class go_razorscale_mole_machine : public GameObjectScript +{ +public: + go_razorscale_mole_machine() : GameObjectScript("go_razorscale_mole_machine") { } + + struct go_razorscale_mole_machineAI : public GameObjectAI + { + go_razorscale_mole_machineAI(GameObject* go) : GameObjectAI(go) { } + + void Reset() override + { + me->AddFlag(GO_FLAG_NOT_SELECTABLE); + _scheduler.Schedule(Seconds(1), [this](TaskContext /*context*/) + { + me->UseDoorOrButton(); + }); + _scheduler.Schedule(Seconds(10), [this](TaskContext /*context*/) + { + me->Delete(); + }); + } + + void UpdateAI(uint32 diff) override { - return GetUlduarAI<npc_darkrune_sentinelAI>(creature); + _scheduler.Update(diff); } + + private: + TaskScheduler _scheduler; + }; + GameObjectAI* GetAI(GameObject* go) const override + { + return GetUlduarAI<go_razorscale_mole_machineAI>(go); + } }; -class spell_razorscale_devouring_flame : public SpellScriptLoader +/* 63317 - Flame Breath + 64021 - Flame Breath +*/ +class spell_razorscale_flame_breath : public SpellScriptLoader { - public: - spell_razorscale_devouring_flame() : SpellScriptLoader("spell_razorscale_devouring_flame") { } +public: + spell_razorscale_flame_breath() : SpellScriptLoader("spell_razorscale_flame_breath") { } - class spell_razorscale_devouring_flame_SpellScript : public SpellScript + class spell_razorscale_flame_breath_SpellScript : public SpellScript + { + PrepareSpellScript(spell_razorscale_flame_breath_SpellScript); + + void CheckDamage() { - PrepareSpellScript(spell_razorscale_devouring_flame_SpellScript); + Creature* target = GetHitCreature(); + if (!target || target->GetEntry() != NPC_DARK_RUNE_GUARDIAN || !target->IsAlive()) + return; + + if (GetHitDamage() >= int32(target->GetHealth())) + target->AI()->SetData(DATA_IRON_DWARF_MEDIUM_RARE, 1); + } - void HandleSummon(SpellEffIndex effIndex) + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if([](WorldObject* obj) { - PreventHitDefaultEffect(effIndex); - Unit* caster = GetCaster(); - uint32 entry = uint32(GetSpellInfo()->GetEffect(effIndex)->MiscValue); - WorldLocation const* summonLocation = GetExplTargetDest(); - if (!caster || !summonLocation) - return; + if (Creature* target = obj->ToCreature()) + if (target->IsTrigger()) + return true; - caster->SummonCreature(entry, summonLocation->GetPositionX(), summonLocation->GetPositionY(), GROUND_Z, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 20000); - } + return false; + }); + } - void Register() override - { - OnEffectHit += SpellEffectFn(spell_razorscale_devouring_flame_SpellScript::HandleSummon, EFFECT_0, SPELL_EFFECT_SUMMON); - } - }; - SpellScript* GetSpellScript() const override + void Register() override { - return new spell_razorscale_devouring_flame_SpellScript(); + OnHit += SpellHitFn(spell_razorscale_flame_breath_SpellScript::CheckDamage); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_razorscale_flame_breath_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_CONE_ENTRY); } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_razorscale_flame_breath_SpellScript(); + } }; -class spell_razorscale_flame_breath : public SpellScriptLoader +/* 63968 - Summon Iron Dwarves + 63970 - Summon Iron Dwarves + 63969 - Summon Iron Dwarves +*/ +class spell_razorscale_summon_iron_dwarves : public SpellScriptLoader { - public: - spell_razorscale_flame_breath() : SpellScriptLoader("spell_razorscale_flame_breath") { } +public: spell_razorscale_summon_iron_dwarves() : SpellScriptLoader("spell_razorscale_summon_iron_dwarves") { } - class spell_razorscale_flame_breath_SpellScript : public SpellScript + class spell_razorscale_summon_iron_dwarves_SpellScript : public SpellScript { - PrepareSpellScript(spell_razorscale_flame_breath_SpellScript); + PrepareSpellScript(spell_razorscale_summon_iron_dwarves_SpellScript); - void CheckDamage() + bool Validate(SpellInfo const* /*spellInfo*/) override { - Creature* target = GetHitCreature(); - if (!target || target->GetEntry() != NPC_DARK_RUNE_GUARDIAN) - return; + return ValidateSpellInfo + ({ + SPELL_SUMMON_IRON_DWARF_GUARDIAN, + SPELL_SUMMON_IRON_DWARF_WATCHER + }); + } - if (GetHitDamage() >= int32(target->GetHealth())) - target->AI()->SetData(DATA_IRON_DWARF_MEDIUM_RARE, 1); + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + switch (GetSpellInfo()->Id) + { + case SPELL_TRIGGER_SUMMON_IRON_DWARVES: + caster->CastSpell(caster, SPELL_SUMMON_IRON_DWARF_GUARDIAN, true); + caster->CastSpell(caster, SPELL_SUMMON_IRON_DWARF_GUARDIAN, true); + caster->CastSpell(caster, SPELL_SUMMON_IRON_DWARF_WATCHER, true); + break; + case SPELL_TRIGGER_SUMMON_IRON_DWARVES_2: + case SPELL_TRIGGER_SUMMON_IRON_DWARVES_3: + caster->CastSpell(caster, SPELL_SUMMON_IRON_DWARF_GUARDIAN, true); + caster->CastSpell(caster, SPELL_SUMMON_IRON_DWARF_WATCHER, true); + caster->CastSpell(caster, SPELL_SUMMON_IRON_DWARF_WATCHER, true); + break; + default: + break; + } } void Register() override { - OnHit += SpellHitFn(spell_razorscale_flame_breath_SpellScript::CheckDamage); + OnEffectHitTarget += SpellEffectFn(spell_razorscale_summon_iron_dwarves_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; SpellScript* GetSpellScript() const override { - return new spell_razorscale_flame_breath_SpellScript(); + return new spell_razorscale_summon_iron_dwarves_SpellScript(); } }; -class achievement_iron_dwarf_medium_rare : public AchievementCriteriaScript +// 64771 - Fuse Armor +class spell_razorscale_fuse_armor : public SpellScriptLoader { - public: - achievement_iron_dwarf_medium_rare() : AchievementCriteriaScript("achievement_iron_dwarf_medium_rare") +public: + spell_razorscale_fuse_armor() : SpellScriptLoader("spell_razorscale_fuse_armor") { } + + class spell_razorscale_fuse_armor_AuraScript : public AuraScript + { + PrepareAuraScript(spell_razorscale_fuse_armor_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo + ({ + SPELL_FUSED_ARMOR + }); + } + + void HandleFused(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { + if (GetStackAmount() == 5) + GetTarget()->CastSpell(GetTarget(), SPELL_FUSED_ARMOR, true); } - bool OnCheck(Player* /*player*/, Unit* target) override + void Register() override { - return target && target->IsAIEnabled && target->GetAI()->GetData(DATA_IRON_DWARF_MEDIUM_RARE); + AfterEffectApply += AuraEffectRemoveFn(spell_razorscale_fuse_armor_AuraScript::HandleFused, EFFECT_1, SPELL_AURA_MOD_MELEE_HASTE, AURA_EFFECT_HANDLE_REAL); } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_razorscale_fuse_armor_AuraScript(); + } }; -class achievement_quick_shave : public AchievementCriteriaScript +class spell_razorscale_firebolt : public SpellScriptLoader { - public: - achievement_quick_shave() : AchievementCriteriaScript("achievement_quick_shave") { } +public: + spell_razorscale_firebolt() : SpellScriptLoader("spell_razorscale_firebolt") { } - bool OnCheck(Player* /*source*/, Unit* target) override + class spell_razorscale_firebolt_SpellScript : public SpellScript + { + PrepareSpellScript(spell_razorscale_firebolt_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) { - if (target) - if (Creature* razorscale = target->ToCreature()) - if (razorscale->AI()->GetData(DATA_QUICK_SHAVE)) - return true; + targets.remove_if([](WorldObject* obj) { return obj->GetEntry() != NPC_RAZORSCALE_HARPOON_FIRE_STATE; }); + } - return false; + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_razorscale_firebolt_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_razorscale_firebolt_SpellScript(); + } +}; + +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) override + { + return target && target->IsAIEnabled && target->GetAI()->GetData(DATA_IRON_DWARF_MEDIUM_RARE); + } +}; + +class achievement_quick_shave : public AchievementCriteriaScript +{ +public: + achievement_quick_shave() : AchievementCriteriaScript("achievement_quick_shave") { } + + bool OnCheck(Player* /*source*/, Unit* target) override + { + if (target) + if (Creature* razorscale = target->ToCreature()) + if (razorscale->AI()->GetData(DATA_QUICK_SHAVE)) + return true; + + return false; + } }; void AddSC_boss_razorscale() { - new boss_razorscale_controller(); - new go_razorscale_harpoon(); new boss_razorscale(); + new npc_expedition_defender(); + new npc_expedition_trapper(); + new npc_expedition_engineer(); new npc_expedition_commander(); - new npc_mole_machine_trigger(); - new npc_devouring_flame(); + new npc_razorscale_spawner(); new npc_darkrune_watcher(); new npc_darkrune_guardian(); new npc_darkrune_sentinel(); - new spell_razorscale_devouring_flame(); + new npc_razorscale_harpoon_fire_state(); + new go_razorscale_harpoon(); + new go_razorscale_mole_machine(); new spell_razorscale_flame_breath(); + new spell_razorscale_summon_iron_dwarves(); + new spell_razorscale_fuse_armor(); + new spell_razorscale_firebolt(); new achievement_iron_dwarf_medium_rare(); new achievement_quick_shave(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index ef69a25f11b..b22b5d242ff 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -498,10 +498,6 @@ class instance_ulduar : public InstanceMapScript if (GetBossState(BOSS_LEVIATHAN) == DONE) gameObject->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); break; - case GO_MOLE_MACHINE: - if (GetBossState(BOSS_RAZORSCALE) == IN_PROGRESS) - gameObject->SetGoState(GO_STATE_ACTIVE); - break; case GO_BRAIN_ROOM_DOOR_1: BrainRoomDoorGUIDs[0] = gameObject->GetGUID(); break; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 885686e6fc6..70e78b7bd1d 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -61,9 +61,7 @@ enum UlduarNPCs NPC_SALVAGED_CHOPPER = 33062, NPC_IGNIS = 33118, NPC_RAZORSCALE = 33186, - NPC_RAZORSCALE_CONTROLLER = 33233, NPC_STEELFORGED_DEFFENDER = 33236, - NPC_EXPEDITION_COMMANDER = 33210, NPC_XT002 = 33293, NPC_XT_TOY_PILE = 33337, NPC_STEELBREAKER = 32867, @@ -84,6 +82,18 @@ enum UlduarNPCs NPC_YOGG_SARON = 33288, NPC_ALGALON = 32871, + // Razorscale + NPC_DARK_RUNE_GUARDIAN = 33388, + NPC_DARK_RUNE_SENTINEL = 33846, + NPC_DARK_RUNE_WATCHER = 33453, + NPC_RAZORSCALE_SPAWNER = 33245, + NPC_EXPEDITION_COMMANDER = 33210, + NPC_EXPEDITION_ENGINEER = 33287, + NPC_EXPEDITION_DEFENDER = 33816, + NPC_EXPEDITION_TRAPPER = 33259, + NPC_RAZORSCALE_CONTROLLER = 33233, + NPC_RAZORSCALE_HARPOON_FIRE_STATE = 33282, + //XT002 NPC_XS013_SCRAPBOT = 33343, |