From 72b10106f6ee70dfaf19f59a5545d0ec88ce9eeb Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Thu, 31 Oct 2019 00:48:56 +0100 Subject: [PATCH] Scripts/BWD: implement normal difficulty mechanics for phase two and scripted intro for phase three and add timers for phase three tail lash and shadowflame breath --- src/server/game/Spells/SpellMgr.cpp | 18 + .../BlackwingDescent/blackwing_descent.h | 3 +- .../BlackwingDescent/boss_nefarians_end.cpp | 472 ++++++++++++++++-- 3 files changed, 441 insertions(+), 52 deletions(-) diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 72a5c358398..41d43680ec5 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -5522,6 +5522,24 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21); // Infinite }); + // Shadowflame Barrage (10 player) + ApplySpellFix({ + 78621, + 94122, + }, [](SpellInfo* spellInfo) + { + spellInfo->MaxAffectedTargets = 4; + }); + + // Shadowflame Barrage (25 player) + ApplySpellFix({ + 94121, + 94123, + }, [](SpellInfo* spellInfo) + { + spellInfo->MaxAffectedTargets = 8; + }); + // ENDOF BLACKWING DESCENT SPELLS // Living Bomb diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/blackwing_descent.h b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/blackwing_descent.h index 96e929e1f21..6ac41e072e3 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/blackwing_descent.h +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/blackwing_descent.h @@ -73,7 +73,7 @@ enum BWDDataTypes DATA_INVISIBLE_STALKER, DATA_BLACKWING_ELEVATOR_ONYXIA, DATA_NEFARIANS_LIGHTNING_MACHINE, - DATA_ONYXIA, + DATA_ONYXIA }; enum BWDCreatureIds @@ -141,6 +141,7 @@ enum BWDCreatureIds NPC_INVISIBLE_STALKER_CATACLYSM_BOSS = 42098, NPC_NEFARIANS_LIGHTNING_MACHINE = 51089, NPC_ONYXIA = 41270, + NPC_CHROMATIC_PROTOTYPE = 41948, /*Events*/ NPC_SPIRIT_OF_MOLTENFIST = 43125, diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_nefarians_end.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_nefarians_end.cpp index ae2e2a9bd35..63bcf8892c9 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_nefarians_end.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_nefarians_end.cpp @@ -44,6 +44,8 @@ enum Spells SPELL_CHILDREN_OF_DEATHWING_NEFARIAN = 80787, SPELL_HAIL_OF_BONES = 78679, SPELL_NEFARIAN_PHASE_2_HEALTH_AURA = 81582, + SPELL_SHADOWFLAME_BARRAGE = 78621, + SPELL_BRUSHFIRE_PRE_START_PERIODIC = 94630, // Onyxia SPELL_PERMANENT_FEIGN_DEATH_1 = 29266, @@ -63,14 +65,24 @@ enum Spells // Nefarian and Onyxia SPELL_TAIL_LASH = 77827, SPELL_SHADOWFLAME_BREATH = 77826, + SPELL_SHADOW_OF_COWARDICE_DAMAGE = 79353, + SPELL_SHADOW_OF_COWARDICE_DUMMY = 80963, // Nefarian's Lightning Machine SPELL_ELECTROCUTE = 81198, + SPELL_ELECTROCUTE_DAMAGE = 81272, // Animated Bone Warrior SPELL_FULL_POWER_NO_REGEN = 78120, SPELL_ANIMATE_BONES = 78122, SPELL_PERMANENT_FEIGN_DEATH_2 = 70628, + SPELL_CLEAR_ALL_DEBUFFS = 34098, + + // Chromatic Prototype + SPELL_JUMP_DOWN_TO_PLATFORM = 79205, + SPELL_READY_UNARMED = 94610, + SPELL_DUMMY_NUKE = 80776, + SPELL_BLAST_NOVA = 80734, // Invisible Stalker (Cataclysm Boss, Ignore Combat, Floating) SPELL_INTRO_1_TRANSFORM_VISUAL = 78205, @@ -88,6 +100,8 @@ enum Texts SAY_ANNOUNCE_AIR_CRACKLES = 0, SAY_HAIL_OF_BONES = 1, SAY_ONYXIA_DIED = 2, + SAY_MOLTEN_LAVA = 3, + SAY_LAND_PHASE_THREE = 4, // Lord Victor Nefarius SAY_INTRO_1 = 0, @@ -105,13 +119,21 @@ enum Events EVENT_MAKE_ATTACKABLE, EVENT_FLY_CYCLIC_PATH, EVENT_PREPARE_LANDING, - EVENT_LAND, + EVENT_LAND_PHASE_ONE, EVENT_LANDED, EVENT_ENGAGE_PLAYERS, EVENT_SAY_ONYXIA_DEAD, EVENT_MOVE_TO_CENTER, EVENT_LIFTOFF_PHASE_TWO, - EVENT_LOWER_PLATFORM, + EVENT_SUMMON_CHROMATIC_PROTOTYPES, + EVENT_LOWER_ELEVATOR, + EVENT_ELEVATOR_LOWERED, + EVENT_SHADOWFLAME_BARRAGE, + EVENT_SAY_PHASE_TWO, + EVENT_ENTER_PHASE_THREE, + EVENT_SAY_PHASE_THREE, + EVENT_LAND_PHASE_THREE, + EVENT_ELECTROCUTE, // Onyxia EVENT_LIGHTNING_DISCHARGE, @@ -125,7 +147,14 @@ enum Events EVENT_TALK_INTRO_2, EVENT_TALK_INTRO_3, EVENT_CAST_TRANSFORM_VISUAL, - EVENT_RAISE_ELEVATOR + EVENT_RAISE_ELEVATOR, + + // Chromatic Prototype + EVENT_JUMP_DOWN_TO_PLATFORM, + EVENT_READY_PROTOTYPE, + EVENT_DUMMY_NUKE, + EVENT_BLAST_NOVA, + EVENT_DISENGAGE_PLAYERS, }; enum Phases @@ -138,15 +167,18 @@ enum Phases enum Actions { // Lord Victor Nefarius - ACTION_START_INTRO = 0, + ACTION_START_INTRO = 1, // Nefarian - ACTION_ONYXIA_ENGAGED = 0, - ACTION_ONYXIA_DIED = 1, + ACTION_ONYXIA_ENGAGED = 1, + ACTION_ONYXIA_DIED = 2, // Onyxia - ACTION_REANIMATED = 0, - ACTION_UPDATE_ELECTRICAL_CHARGE = 1, + ACTION_REANIMATED = 1, + ACTION_UPDATE_ELECTRICAL_CHARGE = 2, + + // Chromatic Prototype + ACTION_DISENGAGE_PLAYERS = 1 }; enum TransportStopFrames @@ -162,17 +194,22 @@ enum SummonGroups enum MovePoints { + // Nefarian + POINT_NONE = 0, POINT_LIFTOFF = 1, POINT_PREPARE_LANDING = 2, POINT_LAND = 3, POINT_ELEVATOR_CENTER = 4, - POINT_LIFTOFF_CENTER = 5, + + // Chromatic Prototype + POINT_JUMP_DOWN = 1 }; enum EncounterFrames { - FRAME_INDEX_ONYXIA = 2, - FRAME_INDEX_NEFARIAN = 3 + FRAME_INDEX_CHROMATIC_PROTOTYPE = 1, + FRAME_INDEX_ONYXIA = 2, + FRAME_INDEX_NEFARIAN = 3 }; struct OnyxiaChainData @@ -194,11 +231,14 @@ enum Misc SOUND_ID_ROAR = 7274 }; -Position const NefarianSummonPosition = { -166.655f, -224.602f, 40.48163f, 0.0f }; -Position const NefarianLiftOffPosition = { -162.076f, -224.604f, 57.9262f }; -Position const NefarianElevatorLandPosition = { -107.2559f, -223.9451f, 17.38522f }; -Position const NefarianElevatorCenterPosition = { -106.2347f, -224.8227f, 6.488089f }; -Position const NefarianElevatorLiftOffPosition = { -107.2065f, -224.6071f, 35.63027f }; +Position const NefarianSummonPosition = { -166.655f, -224.602f, 40.48163f, 0.0f }; +Position const NefarianLiftOffPosition = { -162.076f, -224.604f, 57.9262f }; +Position const NefarianElevatorPrepareLandPositionPhaseOne = { -107.255753f, -223.944778f, 17.38522f }; +Position const NefarianElevatorLandPhaseOnePosition = { -106.899124f, -225.162415f, 6.488089f }; +Position const NefarianElevatorCenterPosition = { -106.209747f, -224.530594f, 6.488089f }; +Position const NefarianElevatorLiftOffPosition = { -107.205688f, -224.597412f, 35.630280f }; +Position const NefarianElevatorPrepareLandPositionPhaseThree = { -107.238045f, -224.599579f, 17.629690f }; +Position const NefarianElevatorLandPhaseThreePosition = { -107.238045f, -224.599579f, 6.488089f }; static constexpr uint32 const CyclicPathPoints = 17; Position const NefarianCyclicPath[CyclicPathPoints] = @@ -222,9 +262,32 @@ Position const NefarianCyclicPath[CyclicPathPoints] = { -174.6406f, -225.2222f, 92.31927f } }; +static constexpr uint8 const MaxChromaticPrototypes = 3; +Position const ChromaticPrototypeSummonPositions[MaxChromaticPrototypes] +{ + { -183.972f, -225.163f, 43.17013f, 0.05235988f }, + { -63.20486f, -135.6719f, 65.17735f, 4.29351f }, + { -62.87326f, -312.467f, 65.01746f, 2.007129f } +}; + +Position const ChromaticPrototypeMovePositions[MaxChromaticPrototypes] +{ + { -164.7852f, -224.4054f, 40.39833f }, + { -73.10334f, -156.7224f, 65.5925f }, + { -72.80968f, -292.0725f, 65.65186f } +}; + +Position const ChromaticPrototypeJumpPositions[MaxChromaticPrototypes] +{ + { 40.50549f, -0.06254366f, 9.92507f }, + { -20.47418f, -34.21686f, 9.925069f }, + { -20.44454f, 34.39596f, 9.925069f } +}; + struct boss_nefarians_end : public BossAI { - boss_nefarians_end(Creature* creature) : BossAI(creature, DATA_NEFARIANS_END), _landed(false) + boss_nefarians_end(Creature* creature) : BossAI(creature, DATA_NEFARIANS_END), + _landed(false), _elevatorLowered(false), _killedChromaticPrototypes(0), _nextElectrocuteHealthPercentage(90) { me->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING); // Remove this little workarround when mmaps for transports have arrived. me->SetReactState(REACT_PASSIVE); @@ -260,7 +323,14 @@ struct boss_nefarians_end : public BossAI instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); if (Transport* transport = GetElevator()) - transport->SetTransportState(GO_STATE_TRANSPORT_STOPPED, TRANSPORT_STOP_FRAME_LOWERED); + transport->SetTransportState(GO_STATE_TRANSPORT_ACTIVE); + + for (ObjectGuid summon : summons) + { + if (Creature* creature = instance->instance->GetCreature(summon)) + if (creature->GetEntry() == NPC_CHROMATIC_PROTOTYPE && creature->IsAlive()) + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, creature); + } summons.DespawnAll(); instance->SetBossState(DATA_NEFARIANS_END, FAIL); @@ -305,7 +375,10 @@ struct boss_nefarians_end : public BossAI } break; case POINT_PREPARE_LANDING: - events.ScheduleEvent(EVENT_LAND, 200ms, 0, PHASE_ONE); + if (events.IsInPhase(PHASE_ONE)) + events.ScheduleEvent(EVENT_LAND_PHASE_ONE, 200ms, 0, PHASE_ONE); + else if (events.IsInPhase(PHASE_THREE)) + events.ScheduleEvent(EVENT_LAND_PHASE_THREE, 200ms, 0, PHASE_THREE); break; case POINT_LAND: events.ScheduleEvent(EVENT_LANDED, 1ms); @@ -313,20 +386,31 @@ struct boss_nefarians_end : public BossAI case POINT_ELEVATOR_CENTER: events.ScheduleEvent(EVENT_LIFTOFF_PHASE_TWO, 1s, 0, PHASE_TWO); break; - case POINT_LIFTOFF_CENTER: - break; default: break; } } + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (damage >= me->GetHealth()) + return; + + if (me->HealthBelowPctDamaged(_nextElectrocuteHealthPercentage, damage)) + { + Talk(SAY_ANNOUNCE_AIR_CRACKLES); + events.ScheduleEvent(EVENT_ELECTROCUTE, 5s); + _nextElectrocuteHealthPercentage -= 10; + } + } + void DoAction(int32 action) override { switch (action) { case ACTION_ONYXIA_ENGAGED: - DoCastSelf(SPELL_ELECTRICAL_CHARGE_NEFARIAN); Talk(SAY_HAIL_OF_BONES); + DoCastSelf(SPELL_ELECTRICAL_CHARGE_NEFARIAN); DoCastSelf(SPELL_HAIL_OF_BONES); events.ScheduleEvent(EVENT_PREPARE_LANDING, 24s, 0, PHASE_ONE); break; @@ -338,6 +422,20 @@ struct boss_nefarians_end : public BossAI } } + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override + { + switch (summon->GetEntry()) + { + case NPC_CHROMATIC_PROTOTYPE: + _killedChromaticPrototypes++; + if (_killedChromaticPrototypes == MaxChromaticPrototypes) + events.ScheduleEvent(EVENT_ENTER_PHASE_THREE, 1ms); + break; + default: + break; + } + } + void UpdateAI(uint32 diff) override { if (!UpdateVictim() && !events.IsInPhase(PHASE_ONE)) @@ -381,43 +479,68 @@ struct boss_nefarians_end : public BossAI me->GetMotionMaster()->MovePoint(POINT_LIFTOFF, NefarianLiftOffPosition, false); break; case EVENT_PREPARE_LANDING: - me->GetMotionMaster()->MovePoint(POINT_PREPARE_LANDING, NefarianElevatorLandPosition, false); + { + Position pos = events.IsInPhase(PHASE_ONE) ? NefarianElevatorPrepareLandPositionPhaseOne : NefarianElevatorPrepareLandPositionPhaseThree; + me->GetMotionMaster()->MovePoint(POINT_PREPARE_LANDING, pos, false); break; - case EVENT_LAND: - if (Transport* transport = GetElevator()) - { - transport->AddPassenger(me); - Position pos = me->GetPosition(); - pos.m_positionZ -= 10.8f; - me->GetMotionMaster()->MoveLand(POINT_LAND, pos); - } + } + case EVENT_LAND_PHASE_ONE: + if (Transport* transport = GetElevator()) + transport->AddPassenger(me); + + me->GetMotionMaster()->MoveLand(POINT_LAND, NefarianElevatorLandPhaseOnePosition); break; case EVENT_LANDED: me->SetDisableGravity(false); me->SendSetPlayHoverAnim(false); + me->SendMovementSetSplineAnim(Movement::AnimType::ToGround); me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); - DoCastSelf(SPELL_SHADOW_OF_COWARDICE); - DoZoneInCombat(); - instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, FRAME_INDEX_NEFARIAN); - events.ScheduleEvent(EVENT_ENGAGE_PLAYERS, 2s, 0, PHASE_ONE); - _landed = true; + + if (events.IsInPhase(PHASE_ONE)) + { + DoCastSelf(SPELL_SHADOW_OF_COWARDICE); + DoZoneInCombat(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, FRAME_INDEX_NEFARIAN); + events.ScheduleEvent(EVENT_ENGAGE_PLAYERS, 2s, 0, PHASE_ONE); + _landed = true; + } + else if (events.IsInPhase(PHASE_THREE)) + events.ScheduleEvent(EVENT_ENGAGE_PLAYERS, 2s, 0, PHASE_THREE); break; case EVENT_ENGAGE_PLAYERS: me->SetReactState(REACT_AGGRESSIVE); - DoCastSelf(SPELL_CHILDREN_OF_DEATHWING_NEFARIAN); - if (Creature* onyxia = instance->GetCreature(DATA_ONYXIA)) - onyxia->CastSpell(onyxia, SPELL_CHILDREN_OF_DEATHWING_ONYXIA, true); - events.ScheduleEvent(EVENT_TAIL_LASH, 18s, 0, PHASE_ONE); - events.ScheduleEvent(EVENT_SHADOWFLAME_BREATH, 9s, 10s, 0, PHASE_ONE); + if (events.IsInPhase(PHASE_ONE)) + { + DoCastSelf(SPELL_CHILDREN_OF_DEATHWING_NEFARIAN); + if (Creature* onyxia = instance->GetCreature(DATA_ONYXIA)) + onyxia->CastSpell(onyxia, SPELL_CHILDREN_OF_DEATHWING_ONYXIA, true); + + events.ScheduleEvent(EVENT_TAIL_LASH, 18s, 0, PHASE_ONE); + events.ScheduleEvent(EVENT_SHADOWFLAME_BREATH, 9s, 10s, 0, PHASE_ONE); + } + else if (events.IsInPhase(PHASE_THREE)) + { + DoCastSelf(SPELL_SHADOW_OF_COWARDICE); + DoCastSelf(SPELL_BRUSHFIRE_PRE_START_PERIODIC); + events.ScheduleEvent(EVENT_SHADOWFLAME_BREATH, 9s, 0, PHASE_THREE); + events.ScheduleEvent(EVENT_TAIL_LASH, 1s, 0, PHASE_THREE); + } break; case EVENT_TAIL_LASH: DoCastSelf(SPELL_TAIL_LASH); - events.Repeat(5s); + if (events.IsInPhase(PHASE_ONE)) + events.Repeat(5s); + else if (events.IsInPhase(PHASE_THREE)) + events.Repeat(15s, 22s); break; case EVENT_SHADOWFLAME_BREATH: DoCastVictim(SPELL_SHADOWFLAME_BREATH); - events.Repeat(9s, 14s); + + if (events.IsInPhase(PHASE_ONE)) + events.Repeat(9s, 14s); + else if (events.IsInPhase(PHASE_THREE)) + events.Repeat(17s, 22s); break; case EVENT_SAY_ONYXIA_DEAD: if (!_landed) // Do not transition to phase two if Nefarian did not land first @@ -427,25 +550,79 @@ struct boss_nefarians_end : public BossAI } me->AttackStop(); me->SetReactState(REACT_PASSIVE); + me->RemoveAurasDueToSpell(SPELL_CHILDREN_OF_DEATHWING_NEFARIAN); + me->RemoveAurasDueToSpell(SPELL_ELECTRICAL_CHARGE_NEFARIAN); + me->RemoveAurasDueToSpell(SPELL_SHADOW_OF_COWARDICE); Talk(SAY_ONYXIA_DIED); events.SetPhase(PHASE_TWO); events.ScheduleEvent(EVENT_MOVE_TO_CENTER, 2s, 0, PHASE_TWO); break; case EVENT_MOVE_TO_CENTER: - // Todo: enable pathfinding when mmaps for transports have arrived - me->GetMotionMaster()->MovePoint(POINT_ELEVATOR_CENTER, NefarianElevatorCenterPosition, false); + me->GetMotionMaster()->MovePoint(POINT_ELEVATOR_CENTER, NefarianElevatorCenterPosition); break; case EVENT_LIFTOFF_PHASE_TWO: DoCastSelf(SPELL_NEFARIAN_PHASE_2_HEALTH_AURA); me->SetDisableGravity(true); me->SendSetPlayHoverAnim(true); - me->GetMotionMaster()->MoveTakeoff(POINT_LIFTOFF_CENTER, NefarianElevatorLiftOffPosition); + me->SendMovementSetSplineAnim(Movement::AnimType::FlyToGround); + me->GetMotionMaster()->MovePoint(POINT_NONE, NefarianElevatorLiftOffPosition); me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); - events.ScheduleEvent(EVENT_LOWER_PLATFORM, 800ms, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_SUMMON_CHROMATIC_PROTOTYPES, 400ms, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_LOWER_ELEVATOR, 800ms, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_SAY_PHASE_TWO, 4s + 800ms, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_ENTER_PHASE_THREE, 2min + 30s, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_SHADOWFLAME_BARRAGE, 2s + 500ms, 0, PHASE_TWO); break; - case EVENT_LOWER_PLATFORM: + case EVENT_SUMMON_CHROMATIC_PROTOTYPES: + for (uint8 i = 0; i < MaxChromaticPrototypes; i++) + { + if (Creature* prototype = DoSummon(NPC_CHROMATIC_PROTOTYPE, ChromaticPrototypeSummonPositions[i], 4000)) + { + Position point = ChromaticPrototypeMovePositions[i]; + prototype->m_Events.AddEventAtOffset([prototype, point]() + { + prototype->GetMotionMaster()->MovePoint(POINT_JUMP_DOWN, point); + }, 800ms); + } + } + break; + case EVENT_LOWER_ELEVATOR: if (Transport* transport = GetElevator()) - transport->SetTransportState(GO_STATE_TRANSPORT_ACTIVE, TRANSPORT_STOP_FRAME_LOWERED); + transport->SetTransportState(GO_STATE_TRANSPORT_ACTIVE); + events.ScheduleEvent(EVENT_ELEVATOR_LOWERED, 8s, 0, PHASE_TWO); + break; + case EVENT_ELEVATOR_LOWERED: + _elevatorLowered = true; + break; + case EVENT_SHADOWFLAME_BARRAGE: + DoCastAOE(SPELL_SHADOWFLAME_BARRAGE); + events.Repeat(2s + 500ms); + break; + case EVENT_SAY_PHASE_TWO: + Talk(SAY_MOLTEN_LAVA); + break; + case EVENT_ENTER_PHASE_THREE: + if (!_elevatorLowered) + { + events.Repeat(1s); + break; + } + EnterPhaseThree(); + break; + case EVENT_SAY_PHASE_THREE: + Talk(SAY_LAND_PHASE_THREE); + break; + case EVENT_LAND_PHASE_THREE: + me->RemoveAurasDueToSpell(SPELL_NEFARIAN_PHASE_2_HEALTH_AURA); + me->SendSetPlayHoverAnim(true); + me->GetMotionMaster()->MoveLand(POINT_LAND, NefarianElevatorLandPhaseThreePosition); + break; + case EVENT_ELECTROCUTE: + if (Creature* machine = instance->GetCreature(DATA_NEFARIANS_LIGHTNING_MACHINE)) + { + machine->CastSpell(machine, SPELL_ELECTROCUTE); + machine->CastSpell(machine, SPELL_ELECTROCUTE_DAMAGE); + } break; default: break; @@ -504,6 +681,25 @@ private: } } + void EnterPhaseThree() + { + if (events.IsInPhase(PHASE_THREE)) + return; + + events.SetPhase(PHASE_THREE); + events.ScheduleEvent(EVENT_SAY_PHASE_THREE, 14s + 700ms); + events.ScheduleEvent(EVENT_LAND_PHASE_THREE, 15s + 500ms, 0, PHASE_THREE); + if (Transport* elevator = GetElevator()) + elevator->SetTransportState(GO_STATE_TRANSPORT_STOPPED, TRANSPORT_STOP_FRAME_RAISED); + + for (ObjectGuid guid : summons) + { + if (Creature* creature = ObjectAccessor::GetCreature(*me, guid)) + if (creature->GetEntry() == NPC_CHROMATIC_PROTOTYPE && creature->IsAlive() && creature->IsAIEnabled) + creature->AI()->DoAction(ACTION_DISENGAGE_PLAYERS); + } + } + Transport* GetElevator() { GameObject* elevator = instance->GetGameObject(DATA_BLACKWING_ELEVATOR_ONYXIA); @@ -514,6 +710,9 @@ private: } bool _landed; + bool _elevatorLowered; + uint8 _killedChromaticPrototypes; + uint8 _nextElectrocuteHealthPercentage; }; struct npc_nefarians_end_onyxia : public ScriptedAI @@ -552,6 +751,8 @@ struct npc_nefarians_end_onyxia : public ScriptedAI _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); if (Creature* nefarian = _instance->GetCreature(DATA_NEFARIANS_END)) nefarian->AI()->DoAction(ACTION_ONYXIA_DIED); + + me->DespawnOrUnsummon(19s); } void DoAction(int32 action) override @@ -735,6 +936,102 @@ struct npc_nefarians_end_animated_bone_warrior : public ScriptedAI } }; +struct npc_nefarians_end_chromatic_prototype : public PassiveAI +{ + npc_nefarians_end_chromatic_prototype(Creature* creature) : PassiveAI(creature), _instance(me->GetInstanceScript()) { } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE) + return; + + switch (id) + { + case POINT_JUMP_DOWN: + _events.ScheduleEvent(EVENT_JUMP_DOWN_TO_PLATFORM, 1s + 200ms); + break; + default: + break; + } + } + + void JustDied(Unit* /*killer*/) override + { + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_DISENGAGE_PLAYERS: + me->InterruptNonMeleeSpells(true); + me->SetHomePosition(me->GetPosition()); + me->DeleteThreatList(); + me->CombatStop(); + _events.Reset(); + _events.ScheduleEvent(EVENT_DISENGAGE_PLAYERS, 3s + 700ms); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_JUMP_DOWN_TO_PLATFORM: + if (GameObject* elevator = _instance->GetGameObject(DATA_BLACKWING_ELEVATOR_ONYXIA)) + { + if (Transport* transport = elevator->ToTransport()) + { + transport->AddPassenger(me); + DoCastAOE(SPELL_JUMP_DOWN_TO_PLATFORM); + } + } + _events.ScheduleEvent(EVENT_READY_PROTOTYPE, 5s); + break; + case EVENT_READY_PROTOTYPE: + DoZoneInCombat(); + _instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, FRAME_INDEX_CHROMATIC_PROTOTYPE); + DoCastSelf(SPELL_READY_UNARMED); + for (uint8 i = 0; i < 3; i++) // no idea what Blizzard was thinking here... + DoCastSelf(SPELL_DUMMY_NUKE); + + _events.ScheduleEvent(EVENT_DUMMY_NUKE, 1s); + _events.ScheduleEvent(EVENT_BLAST_NOVA, 3s + 500ms); + break; + case EVENT_DUMMY_NUKE: + DoCastSelf(SPELL_DUMMY_NUKE); + _events.Repeat(1s); + break; + case EVENT_BLAST_NOVA: + DoCastAOE(SPELL_BLAST_NOVA); + _events.Repeat(13s); + break; + case EVENT_DISENGAGE_PLAYERS: + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + me->DespawnOrUnsummon(5s); + break; + default: + break; + } + } + } + +private: + InstanceScript* _instance; + EventMap _events; +}; + class spell_nefarians_end_electrical_charge : public AuraScript { PrepareAuraScript(spell_nefarians_end_electrical_charge); @@ -917,7 +1214,11 @@ class spell_nefarians_end_animate_bones_dummy : public SpellScript bool Validate(SpellInfo const* /*spellInfo*/) override { - return ValidateSpellInfo({ SPELL_PERMANENT_FEIGN_DEATH_2 }); + return ValidateSpellInfo( + { + SPELL_PERMANENT_FEIGN_DEATH_2, + SPELL_CLEAR_ALL_DEBUFFS + }); } void HandleHit(SpellEffIndex /*effIndex*/) @@ -926,7 +1227,7 @@ class spell_nefarians_end_animate_bones_dummy : public SpellScript if (!target || target->GetPower(POWER_ENERGY) > 1) return; - target->RemoveAllAuras(); + target->CastSpell(target, SPELL_CLEAR_ALL_DEBUFFS, true); target->AttackStop(); target->DeleteThreatList(); target->SetReactState(REACT_PASSIVE); @@ -974,6 +1275,72 @@ class spell_nefarians_end_shadowflame_breath : public SpellScript } }; +class spell_nefarians_end_jump_down_to_platform : public SpellScript +{ + PrepareSpellScript(spell_nefarians_end_jump_down_to_platform); + + void SetDest(SpellDestination& dest) + { + Position positions[MaxChromaticPrototypes]; + + InstanceScript* instance = GetCaster()->GetInstanceScript(); + if (!instance) + return; + + GameObject* elevator = instance->GetGameObject(DATA_BLACKWING_ELEVATOR_ONYXIA); + if (!elevator || !elevator->ToTransport()) + return; + + Transport* transport = elevator->ToTransport(); + + // Transform sniffed transport destinations into map coordinates so we can use them for real time transport position based offsets + for (uint8 i = 0; i < MaxChromaticPrototypes; i++) + { + positions[i] = ChromaticPrototypeJumpPositions[i]; + transport->CalculatePassengerPosition(positions[i].m_positionX, positions[i].m_positionY, positions[i].m_positionZ); + } + + // Pick the closest jump destination + Position pos = positions[0]; + for (uint8 i = 1; i < MaxChromaticPrototypes; i++) + if (GetCaster()->GetExactDist2d(positions[i]) < GetCaster()->GetExactDist2d(pos)) + pos = positions[i]; + + dest.Relocate(pos); + } + + void Register() + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_nefarians_end_jump_down_to_platform::SetDest, EFFECT_0, TARGET_DEST_NEARBY_ENTRY); + } +}; + +class spell_nefarians_end_shadow_of_cowardice : public SpellScript +{ + PrepareSpellScript(spell_nefarians_end_shadow_of_cowardice); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHADOW_OF_COWARDICE_DAMAGE }); + } + + void HandleHit(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + Unit* target = GetHitUnit(); + if (target->GetTransport() && target->GetTransOffsetZ() > 9.5f) + caster->CastSpell(target, SPELL_SHADOW_OF_COWARDICE_DAMAGE, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_nefarians_end_shadow_of_cowardice::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + struct go_nefarians_end_orb_of_culmination : public GameObjectAI { go_nefarians_end_orb_of_culmination(GameObject* go) : GameObjectAI(go), _instance(me->GetInstanceScript()) { } @@ -1003,6 +1370,7 @@ void AddSC_boss_nefarians_end() RegisterBlackwingDescentCreatureAI(npc_nefarians_end_onyxia); RegisterBlackwingDescentCreatureAI(npc_nefarians_end_lord_victor_nefarius); RegisterBlackwingDescentCreatureAI(npc_nefarians_end_animated_bone_warrior); + RegisterBlackwingDescentCreatureAI(npc_nefarians_end_chromatic_prototype); RegisterAuraScript(spell_nefarians_end_electrical_charge); RegisterAuraScript(spell_nefarians_end_lightning_discharge_triggered_periodic_aura); RegisterSpellScript(spell_nefarians_end_lightning_discharge_cone); @@ -1011,6 +1379,8 @@ void AddSC_boss_nefarians_end() RegisterAuraScript(spell_nefarians_end_animate_bones); RegisterSpellScript(spell_nefarians_end_animate_bones_dummy); RegisterSpellScript(spell_nefarians_end_shadowflame_breath); + RegisterSpellScript(spell_nefarians_end_jump_down_to_platform); + RegisterSpellScript(spell_nefarians_end_shadow_of_cowardice); RegisterGameObjectAI(go_nefarians_end_orb_of_culmination); }