From 55d4990949fb01d1dcfbd0de47642085cbe3356a Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Tue, 29 Oct 2019 00:17:11 +0100 Subject: [PATCH] Scripts/BWD: finish base work on phase one of Nefarian's End encounter --- src/server/game/Spells/SpellMgr.cpp | 10 + .../BlackwingDescent/boss_nefarians_end.cpp | 470 +++++++++++++++--- 2 files changed, 419 insertions(+), 61 deletions(-) diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index a97be456e47..72a5c358398 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -5511,6 +5511,16 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->Effects[EFFECT_0].MaxRadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_18_YARDS); }); + // Hail of Bones + ApplySpellFix({ + 78684, + 94104, + 94105, + 94106, + }, [](SpellInfo* spellInfo) + { + spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21); // Infinite + }); // ENDOF BLACKWING DESCENT SPELLS 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 37461511099..ae2e2a9bd35 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_nefarians_end.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackwingDescent/boss_nefarians_end.cpp @@ -41,9 +41,12 @@ enum Spells SPELL_INTRO_5A_START_FIGHT_PROC = 78730, SPELL_ELECTRICAL_CHARGE_NEFARIAN = 95793, SPELL_SHADOW_OF_COWARDICE = 79355, + SPELL_CHILDREN_OF_DEATHWING_NEFARIAN = 80787, + SPELL_HAIL_OF_BONES = 78679, + SPELL_NEFARIAN_PHASE_2_HEALTH_AURA = 81582, // Onyxia - SPELL_PERMANENT_FEIGN_DEATH = 29266, + SPELL_PERMANENT_FEIGN_DEATH_1 = 29266, SPELL_ONYXIA_START_FIGHT_1_PERIODIC = 81516, SPELL_ELECTRICAL_CHARGE_ONYXIA = 78949, SPELL_ELECTRICAL_OVERLOAD = 78999, @@ -52,7 +55,10 @@ enum Spells SPELL_LIGHTNING_DISCHARGE_VISUAL_LEFT_2 = 81436, SPELL_LIGHTNING_DISCHARGE_VISUAL_RIGHT_1 = 81437, SPELL_LIGHTNING_DISCHARGE_VISUAL_RIGHT_2 = 81438, - + SPELL_LIGHTNING_DISCHARGE_CONE_BACK = 77833, + SPELL_LIGHTNING_DISCHARGE_CONE_FRONT = 77836, + SPELL_LIGHTNING_DISCHARGE_DAMAGE = 77943, + SPELL_CHILDREN_OF_DEATHWING_ONYXIA = 80785, // Nefarian and Onyxia SPELL_TAIL_LASH = 77827, @@ -61,6 +67,11 @@ enum Spells // Nefarian's Lightning Machine SPELL_ELECTROCUTE = 81198, + // Animated Bone Warrior + SPELL_FULL_POWER_NO_REGEN = 78120, + SPELL_ANIMATE_BONES = 78122, + SPELL_PERMANENT_FEIGN_DEATH_2 = 70628, + // Invisible Stalker (Cataclysm Boss, Ignore Combat, Floating) SPELL_INTRO_1_TRANSFORM_VISUAL = 78205, SPELL_CHAINS_A_STEEL = 81159, @@ -75,6 +86,8 @@ enum Texts { // Nefarian SAY_ANNOUNCE_AIR_CRACKLES = 0, + SAY_HAIL_OF_BONES = 1, + SAY_ONYXIA_DIED = 2, // Lord Victor Nefarius SAY_INTRO_1 = 0, @@ -91,6 +104,14 @@ enum Events EVENT_ANNOUNCE_AIR_CRACKLES, EVENT_MAKE_ATTACKABLE, EVENT_FLY_CYCLIC_PATH, + EVENT_PREPARE_LANDING, + EVENT_LAND, + EVENT_LANDED, + EVENT_ENGAGE_PLAYERS, + EVENT_SAY_ONYXIA_DEAD, + EVENT_MOVE_TO_CENTER, + EVENT_LIFTOFF_PHASE_TWO, + EVENT_LOWER_PLATFORM, // Onyxia EVENT_LIGHTNING_DISCHARGE, @@ -121,6 +142,7 @@ enum Actions // Nefarian ACTION_ONYXIA_ENGAGED = 0, + ACTION_ONYXIA_DIED = 1, // Onyxia ACTION_REANIMATED = 0, @@ -140,7 +162,11 @@ enum SummonGroups enum MovePoints { - POINT_LIFTOFF = 1, + POINT_LIFTOFF = 1, + POINT_PREPARE_LANDING = 2, + POINT_LAND = 3, + POINT_ELEVATOR_CENTER = 4, + POINT_LIFTOFF_CENTER = 5, }; enum EncounterFrames @@ -168,8 +194,11 @@ 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 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 }; static constexpr uint32 const CyclicPathPoints = 17; Position const NefarianCyclicPath[CyclicPathPoints] = @@ -195,11 +224,25 @@ Position const NefarianCyclicPath[CyclicPathPoints] = struct boss_nefarians_end : public BossAI { - boss_nefarians_end(Creature* creature) : BossAI(creature, DATA_NEFARIANS_END) + boss_nefarians_end(Creature* creature) : BossAI(creature, DATA_NEFARIANS_END), _landed(false) { + me->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING); // Remove this little workarround when mmaps for transports have arrived. me->SetReactState(REACT_PASSIVE); } + void JustEngagedWith(Unit* /*who*/) override + { + // Attacking Nefarian while Onyxia is not engaged is not suposed to trigger anything + if (instance->GetBossState(DATA_NEFARIANS_END) != IN_PROGRESS) + { + me->DeleteThreatList(); + me->CombatStop(); + return; + } + + _JustEngagedWith(); + } + void JustAppeared() override { events.SetPhase(PHASE_ONE); @@ -208,22 +251,16 @@ struct boss_nefarians_end : public BossAI me->SendSetPlayHoverAnim(false); DoCastSelf(SPELL_INTRO_2_STALKER_TRANSFORM); DoCastSelf(SPELL_INTRO_3_SHRINK_AURA); - SetupTransportSpawns(); + SetupTransportSpawns(SUMMON_GROUP_ELEVATOR); } void EnterEvadeMode(EvadeReason /*why*/) override { _EnterEvadeMode(); - if (Creature* onyxia = instance->GetCreature(DATA_ONYXIA)) - if (onyxia->IsAlive()) - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, onyxia); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - if (!events.IsInPhase(PHASE_ONE)) - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - - if (GameObject* elevator = instance->GetGameObject(DATA_BLACKWING_ELEVATOR_ONYXIA)) - if (Transport* transport = elevator->ToTransport()) - transport->SetTransportState(GO_STATE_TRANSPORT_STOPPED, TRANSPORT_STOP_FRAME_LOWERED); + if (Transport* transport = GetElevator()) + transport->SetTransportState(GO_STATE_TRANSPORT_STOPPED, TRANSPORT_STOP_FRAME_LOWERED); summons.DespawnAll(); instance->SetBossState(DATA_NEFARIANS_END, FAIL); @@ -232,7 +269,7 @@ struct boss_nefarians_end : public BossAI void MovementInform(uint32 type, uint32 id) override { - if (type != POINT_MOTION_TYPE) + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) return; switch (id) @@ -240,7 +277,7 @@ struct boss_nefarians_end : public BossAI case POINT_LIFTOFF: me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC); DoCastSelf(SPELL_INTRO_5A_START_FIGHT_PROC); - MoveCyclicPath(NefarianCyclicPath, CyclicPathPoints, 14.0f); + me->GetMotionMaster()->MoveCyclicPath(NefarianCyclicPath, CyclicPathPoints, false, true, 14.0f); if (Creature* machine = instance->GetCreature(DATA_NEFARIANS_LIGHTNING_MACHINE)) machine->CastSpell(machine, SPELL_ELECTROCUTE); @@ -267,6 +304,17 @@ struct boss_nefarians_end : public BossAI } } break; + case POINT_PREPARE_LANDING: + events.ScheduleEvent(EVENT_LAND, 200ms, 0, PHASE_ONE); + break; + case POINT_LAND: + events.ScheduleEvent(EVENT_LANDED, 1ms); + break; + case POINT_ELEVATOR_CENTER: + events.ScheduleEvent(EVENT_LIFTOFF_PHASE_TWO, 1s, 0, PHASE_TWO); + break; + case POINT_LIFTOFF_CENTER: + break; default: break; } @@ -278,6 +326,12 @@ struct boss_nefarians_end : public BossAI { case ACTION_ONYXIA_ENGAGED: DoCastSelf(SPELL_ELECTRICAL_CHARGE_NEFARIAN); + Talk(SAY_HAIL_OF_BONES); + DoCastSelf(SPELL_HAIL_OF_BONES); + events.ScheduleEvent(EVENT_PREPARE_LANDING, 24s, 0, PHASE_ONE); + break; + case ACTION_ONYXIA_DIED: + events.ScheduleEvent(EVENT_SAY_ONYXIA_DEAD, 1ms, 0, PHASE_ONE); break; default: break; @@ -291,6 +345,9 @@ struct boss_nefarians_end : public BossAI events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) @@ -323,15 +380,88 @@ struct boss_nefarians_end : public BossAI Talk(SAY_ANNOUNCE_AIR_CRACKLES); me->GetMotionMaster()->MovePoint(POINT_LIFTOFF, NefarianLiftOffPosition, false); break; + case EVENT_PREPARE_LANDING: + me->GetMotionMaster()->MovePoint(POINT_PREPARE_LANDING, NefarianElevatorLandPosition, 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); + } + break; + case EVENT_LANDED: + me->SetDisableGravity(false); + me->SendSetPlayHoverAnim(false); + 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; + 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); + break; + case EVENT_TAIL_LASH: + DoCastSelf(SPELL_TAIL_LASH); + events.Repeat(5s); + break; + case EVENT_SHADOWFLAME_BREATH: + DoCastVictim(SPELL_SHADOWFLAME_BREATH); + events.Repeat(9s, 14s); + break; + case EVENT_SAY_ONYXIA_DEAD: + if (!_landed) // Do not transition to phase two if Nefarian did not land first + { + events.Repeat(1s); + break; + } + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + 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); + 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->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + events.ScheduleEvent(EVENT_LOWER_PLATFORM, 800ms, 0, PHASE_TWO); + break; + case EVENT_LOWER_PLATFORM: + if (Transport* transport = GetElevator()) + transport->SetTransportState(GO_STATE_TRANSPORT_ACTIVE, TRANSPORT_STOP_FRAME_LOWERED); + break; default: break; } } + + DoMeleeAttackIfReady(); } private: - // This is some clusterfuck. Need to remove it once we have a proper generic way - void SetupTransportSpawns() + /* + This is a clusterfuck but required to make spawning on transports work properly. If we don't add creatures to transports before they are + being sent out via update_object the passenger visual will not work so we wont see the passengers move with the transport. This will take care + of it for now. + */ + void SetupTransportSpawns(uint32 summonGroupId) { GameObject* elevator = instance->GetGameObject(DATA_BLACKWING_ELEVATOR_ONYXIA); if (!elevator) @@ -341,7 +471,7 @@ private: if (!transport) return; - std::vector const* data = sObjectMgr->GetSummonGroup(me->GetEntry(), SUMMONER_TYPE_CREATURE, SUMMON_GROUP_ELEVATOR); + std::vector const* data = sObjectMgr->GetSummonGroup(me->GetEntry(), SUMMONER_TYPE_CREATURE, summonGroupId); if (!data) return; @@ -374,24 +504,16 @@ private: } } - void MoveCyclicPath(Position const* pathPoints, size_t pathSize, float velocity) + Transport* GetElevator() { - Movement::MoveSplineInit init(me); - Movement::PointsArray path; - path.reserve(pathSize); - std::transform(pathPoints, pathPoints + pathSize, std::back_inserter(path), [](Position const& point) - { - return G3D::Vector3(point.GetPositionX(), point.GetPositionY(), point.GetPositionZ()); - }); + GameObject* elevator = instance->GetGameObject(DATA_BLACKWING_ELEVATOR_ONYXIA); + if (!elevator || !elevator->ToTransport()) + return nullptr; - init.SetUncompressed(); - init.MovebyPath(path); - init.SetFly(); - init.SetSmooth(); - init.SetCyclic(); - init.SetVelocity(velocity); - init.Launch(); + return elevator->ToTransport(); } + + bool _landed; }; struct npc_nefarians_end_onyxia : public ScriptedAI @@ -420,16 +542,24 @@ struct npc_nefarians_end_onyxia : public ScriptedAI void EnterEvadeMode(EvadeReason /*why*/) override { _EnterEvadeMode(); + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); if (Creature* nefarian = _instance->GetCreature(DATA_NEFARIANS_END)) nefarian->AI()->EnterEvadeMode(); } + void JustDied(Unit* /*killer*/) override + { + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + if (Creature* nefarian = _instance->GetCreature(DATA_NEFARIANS_END)) + nefarian->AI()->DoAction(ACTION_ONYXIA_DIED); + } + void DoAction(int32 action) override { switch (action) { case ACTION_REANIMATED: - me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH); + me->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH_1); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_UNK_29); me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); me->PlayDirectSound(SOUND_ID_ROAR); @@ -454,16 +584,28 @@ struct npc_nefarians_end_onyxia : public ScriptedAI } } + void OnSuccessfulSpellCast(SpellInfo const* spell) override + { + switch (spell->Id) + { + case SPELL_LIGHTNING_DISCHARGE_CONE_FRONT: + DoCastAOE(SPELL_LIGHTNING_DISCHARGE_DAMAGE); + break; + default: + break; + } + } + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; + _events.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) return; - _events.Update(diff); - while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) @@ -555,27 +697,42 @@ private: InstanceScript* _instance; }; -struct go_nefarians_end_orb_of_culmination : public GameObjectAI +struct npc_nefarians_end_animated_bone_warrior : public ScriptedAI { - go_nefarians_end_orb_of_culmination(GameObject* go) : GameObjectAI(go), _instance(me->GetInstanceScript()) { } - - bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override + npc_nefarians_end_animated_bone_warrior(Creature* creature) : ScriptedAI(creature) { - if (Creature* stalker = _instance->GetCreature(DATA_INVISIBLE_STALKER)) - stalker->RemoveAllAuras(); - - if (Creature* nefarius = _instance->GetCreature(DATA_LORD_VICTOR_NEFARIUS_NEFARIANS_END)) - if (nefarius->IsAIEnabled) - nefarius->AI()->DoAction(ACTION_START_INTRO); - - player->PlayerTalkClass->SendCloseGossip(); - me->DespawnOrUnsummon(); - - return false; + me->SetReactState(REACT_PASSIVE); + me->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING); // tempfix until mmaps for transports have arrived } -private: - InstanceScript* _instance; + void IsSummonedBy(Unit* /*summoner*/) override + { + DoCastSelf(SPELL_FULL_POWER_NO_REGEN); + DoCastSelf(SPELL_ANIMATE_BONES); + me->m_Events.AddEventAtOffset([this]() + { + me->SetReactState(REACT_AGGRESSIVE); + if (me->IsAIEnabled) + DoZoneInCombat(); + }, 800ms); + } + + void JustDied(Unit* /*killer*/) override + { + me->DespawnOrUnsummon(4s); + } + + void UpdateAI(uint32 /*diff*/) override + { + // Prevent any victim update while we are in feign death state + if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) + return; + + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } }; class spell_nefarians_end_electrical_charge : public AuraScript @@ -584,9 +741,7 @@ class spell_nefarians_end_electrical_charge : public AuraScript bool Validate(SpellInfo const* /*spellInfo*/) override { - return ValidateSpellInfo( - { - }); + return ValidateSpellInfo({ SPELL_ELECTRICAL_CHARGE_ONYXIA }); } void HandlePeriodic(AuraEffect const* /*aurEff*/) @@ -634,13 +789,17 @@ class spell_nefarians_end_lightning_discharge_triggered_periodic_aura : public A SPELL_LIGHTNING_DISCHARGE_VISUAL_LEFT_1, SPELL_LIGHTNING_DISCHARGE_VISUAL_LEFT_2, SPELL_LIGHTNING_DISCHARGE_VISUAL_RIGHT_1, - SPELL_LIGHTNING_DISCHARGE_VISUAL_RIGHT_2 + SPELL_LIGHTNING_DISCHARGE_VISUAL_RIGHT_2, + SPELL_LIGHTNING_DISCHARGE_CONE_BACK }); } void HandlePeriodic(AuraEffect const* /*aurEff*/) { - Unit* target = GetTarget(); + Creature* target = GetTarget()->ToCreature(); + if (!target) + return; + for (uint8 i = 0; i < 4; i++) { target->CastSpell(target, SPELL_LIGHTNING_DISCHARGE_VISUAL_LEFT_1, true); @@ -648,6 +807,8 @@ class spell_nefarians_end_lightning_discharge_triggered_periodic_aura : public A target->CastSpell(target, SPELL_LIGHTNING_DISCHARGE_VISUAL_RIGHT_1, true); target->CastSpell(target, SPELL_LIGHTNING_DISCHARGE_VISUAL_RIGHT_2, true); } + + target->CastSpell(target, SPELL_LIGHTNING_DISCHARGE_CONE_BACK, true); } void Register() override @@ -656,13 +817,200 @@ class spell_nefarians_end_lightning_discharge_triggered_periodic_aura : public A } }; +class spell_nefarians_end_lightning_discharge_cone : public SpellScript +{ + PrepareSpellScript(spell_nefarians_end_lightning_discharge_cone); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_LIGHTNING_DISCHARGE_DAMAGE }); + } + + void HandleImmunity(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + Unit* target = GetHitUnit(); + if (!caster || !target) + return; + + uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(SPELL_LIGHTNING_DISCHARGE_DAMAGE, caster); + target->ApplySpellImmune(0, IMMUNITY_ID, spellId, true); + + target->m_Events.AddEventAtOffset([spellId, target]() + { + target->ApplySpellImmune(0, IMMUNITY_ID, spellId, false); + }, 500ms); + } + + void Register() override + { + OnEffectLaunchTarget += SpellEffectFn(spell_nefarians_end_lightning_discharge_cone::HandleImmunity, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +class spell_nefarians_end_lightning_discharge_damage : public SpellScript +{ + PrepareSpellScript(spell_nefarians_end_lightning_discharge_damage); + + void FilterTargets(std::list& targets) + { + SpellInfo const* spell = GetSpellInfo(); + Unit* caster = GetCaster(); + + targets.remove_if([spell, caster](WorldObject const* obj)->bool + { + Unit const* target = obj->ToUnit(); + return !target || target->IsImmunedToSpell(spell, caster); + }); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_nefarians_end_lightning_discharge_damage::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } +}; + +class spell_nefarians_end_children_of_deathwing : public AuraScript +{ + PrepareAuraScript(spell_nefarians_end_children_of_deathwing); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_CHILDREN_OF_DEATHWING_NEFARIAN }); + } + + void HandlePeriodic(AuraEffect const* /*aurEff*/) + { + Unit* target = GetTarget(); + uint32 type = GetSpellInfo()->Id == SPELL_CHILDREN_OF_DEATHWING_NEFARIAN ? DATA_ONYXIA : DATA_NEFARIANS_END; + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* sibling = instance->GetCreature(type)) + if (target->GetExactDist2d(sibling) <= 50.f) + target->CastSpell(target, GetSpellInfo()->Effects[EFFECT_0].BasePoints, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_nefarians_end_children_of_deathwing::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } +}; + +class spell_nefarians_end_animate_bones : public AuraScript +{ + PrepareAuraScript(spell_nefarians_end_animate_bones); + + void HandlePeriodicTick(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(GetTarget(), GetSpellInfo()->Effects[EFFECT_1].TriggerSpell, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_POWER_AND_REAGENT_COST)); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_nefarians_end_animate_bones::HandlePeriodicTick, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } +}; + +class spell_nefarians_end_animate_bones_dummy : public SpellScript +{ + PrepareSpellScript(spell_nefarians_end_animate_bones_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PERMANENT_FEIGN_DEATH_2 }); + } + + void HandleHit(SpellEffIndex /*effIndex*/) + { + Creature* target = GetHitCreature(); + if (!target || target->GetPower(POWER_ENERGY) > 1) + return; + + target->RemoveAllAuras(); + target->AttackStop(); + target->DeleteThreatList(); + target->SetReactState(REACT_PASSIVE); + target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + target->CastSpell(target, SPELL_PERMANENT_FEIGN_DEATH_2); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_nefarians_end_animate_bones_dummy::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +class spell_nefarians_end_shadowflame_breath : public SpellScript +{ + PrepareSpellScript(spell_nefarians_end_shadowflame_breath); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_PERMANENT_FEIGN_DEATH_2 }); + } + + void HandleHit(SpellEffIndex effIndex) + { + Creature* target = GetHitCreature(); + if (!target) + return; + + if (target->HasAura(SPELL_PERMANENT_FEIGN_DEATH_2)) + { + target->SetReactState(REACT_AGGRESSIVE); + if (target->IsAIEnabled) + target->AI()->DoZoneInCombat(); + + target->RemoveAurasDueToSpell(SPELL_PERMANENT_FEIGN_DEATH_2); + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + target->CastSpell(target, GetSpellInfo()->Effects[effIndex].BasePoints); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_nefarians_end_shadowflame_breath::HandleHit, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +struct go_nefarians_end_orb_of_culmination : public GameObjectAI +{ + go_nefarians_end_orb_of_culmination(GameObject* go) : GameObjectAI(go), _instance(me->GetInstanceScript()) { } + + bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override + { + if (Creature* stalker = _instance->GetCreature(DATA_INVISIBLE_STALKER)) + stalker->RemoveAllAuras(); + + if (Creature* nefarius = _instance->GetCreature(DATA_LORD_VICTOR_NEFARIUS_NEFARIANS_END)) + if (nefarius->IsAIEnabled) + nefarius->AI()->DoAction(ACTION_START_INTRO); + + player->PlayerTalkClass->SendCloseGossip(); + me->DespawnOrUnsummon(); + + return false; + } + +private: + InstanceScript* _instance; +}; + void AddSC_boss_nefarians_end() { RegisterBlackwingDescentCreatureAI(boss_nefarians_end); RegisterBlackwingDescentCreatureAI(npc_nefarians_end_onyxia); RegisterBlackwingDescentCreatureAI(npc_nefarians_end_lord_victor_nefarius); + RegisterBlackwingDescentCreatureAI(npc_nefarians_end_animated_bone_warrior); RegisterAuraScript(spell_nefarians_end_electrical_charge); RegisterAuraScript(spell_nefarians_end_lightning_discharge_triggered_periodic_aura); + RegisterSpellScript(spell_nefarians_end_lightning_discharge_cone); + RegisterSpellScript(spell_nefarians_end_lightning_discharge_damage); + RegisterAuraScript(spell_nefarians_end_children_of_deathwing); + RegisterAuraScript(spell_nefarians_end_animate_bones); + RegisterSpellScript(spell_nefarians_end_animate_bones_dummy); + RegisterSpellScript(spell_nefarians_end_shadowflame_breath); RegisterGameObjectAI(go_nefarians_end_orb_of_culmination); }