diff options
-rw-r--r-- | src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp | 1907 |
1 files changed, 882 insertions, 1025 deletions
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 472b9651d3e..3a7c929eb55 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -246,1141 +246,993 @@ Position const chokePos[6] = Position const finalPos = {-563.7552f, 2211.328f, 538.7848f, 0.0f}; -class boss_deathbringer_saurfang : public CreatureScript +struct boss_deathbringer_saurfang : public BossAI { - public: - boss_deathbringer_saurfang() : CreatureScript("boss_deathbringer_saurfang") { } - - struct boss_deathbringer_saurfangAI : public BossAI + boss_deathbringer_saurfang(Creature* creature) : BossAI(creature, DATA_DEATHBRINGER_SAURFANG), _introDone(false), _frenzied(false), _dead(false) + { + ASSERT(creature->GetVehicleKit()); // we dont actually use it, just check if exists + _fallenChampionCastCount = 0; + } + + void Reset() override + { + if (_dead) + return; + _Reset(); + events.SetPhase(PHASE_COMBAT); + _frenzied = false; + _dead = false; + me->SetPower(POWER_ENERGY, 0); + DoCastSelf(SPELL_ZERO_POWER, true); + DoCastSelf(SPELL_BLOOD_LINK, true); + DoCastSelf(SPELL_BLOOD_POWER, true); + DoCastSelf(SPELL_MARK_OF_THE_FALLEN_CHAMPION_S, true); + DoCastSelf(SPELL_RUNE_OF_BLOOD_S, true); + me->RemoveAurasDueToSpell(SPELL_BERSERK); + me->RemoveAurasDueToSpell(SPELL_FRENZY); + } + + void JustEngagedWith(Unit* who) override + { + if (_dead) + return; + + if (!instance->CheckRequiredBosses(DATA_DEATHBRINGER_SAURFANG, who->ToPlayer())) { - boss_deathbringer_saurfangAI(Creature* creature) : BossAI(creature, DATA_DEATHBRINGER_SAURFANG), _introDone(false), _frenzied(false), _dead(false) - { - ASSERT(creature->GetVehicleKit()); // we dont actually use it, just check if exists - _fallenChampionCastCount = 0; - } - - void Reset() override - { - if (_dead) - return; - _Reset(); - events.SetPhase(PHASE_COMBAT); - _frenzied = false; - _dead = false; - me->SetPower(POWER_ENERGY, 0); - DoCastSelf(SPELL_ZERO_POWER, true); - DoCastSelf(SPELL_BLOOD_LINK, true); - DoCastSelf(SPELL_BLOOD_POWER, true); - DoCastSelf(SPELL_MARK_OF_THE_FALLEN_CHAMPION_S, true); - DoCastSelf(SPELL_RUNE_OF_BLOOD_S, true); - me->RemoveAurasDueToSpell(SPELL_BERSERK); - me->RemoveAurasDueToSpell(SPELL_FRENZY); - } - - void JustEngagedWith(Unit* who) override - { - if (_dead) - return; - - if (!instance->CheckRequiredBosses(DATA_DEATHBRINGER_SAURFANG, who->ToPlayer())) - { - EnterEvadeMode(EVADE_REASON_OTHER); - instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT); - return; - } - - // oh just screw intro, enter combat - no exploits please - me->setActive(true); - DoZoneInCombat(); + EnterEvadeMode(EVADE_REASON_OTHER); + instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT); + return; + } - events.Reset(); - events.SetPhase(PHASE_COMBAT); - me->SetImmuneToPC(false); - if (!_introDone) - { - DoCastSelf(SPELL_GRIP_OF_AGONY); - if (Creature* creature = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SAURFANG_EVENT_NPC))) - creature->AI()->DoAction(ACTION_INTERRUPT_INTRO); - } + // oh just screw intro, enter combat - no exploits please + me->setActive(true); + DoZoneInCombat(); - _introDone = true; + events.Reset(); + events.SetPhase(PHASE_COMBAT); + me->SetImmuneToPC(false); + if (!_introDone) + { + DoCastSelf(SPELL_GRIP_OF_AGONY); + if (Creature* creature = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SAURFANG_EVENT_NPC))) + creature->AI()->DoAction(ACTION_INTERRUPT_INTRO); + } - Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_SUMMON_BLOOD_BEAST, 30s, 0, PHASE_COMBAT); - events.ScheduleEvent(EVENT_BERSERK, IsHeroic() ? 360s : 480s, 0, PHASE_COMBAT); - events.ScheduleEvent(EVENT_BOILING_BLOOD, 15500ms, 0, PHASE_COMBAT); - events.ScheduleEvent(EVENT_BLOOD_NOVA, 17s, 0, PHASE_COMBAT); - events.ScheduleEvent(EVENT_RUNE_OF_BLOOD, 20s, 0, PHASE_COMBAT); + _introDone = true; + + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_SUMMON_BLOOD_BEAST, 30s, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_BERSERK, IsHeroic() ? 360s : 480s, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_BOILING_BLOOD, 15500ms, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_BLOOD_NOVA, 17s, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_RUNE_OF_BLOOD, 20s, 0, PHASE_COMBAT); + + _fallenChampionCastCount = 0; + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MARK_OF_THE_FALLEN_CHAMPION); + instance->SetBossState(DATA_DEATHBRINGER_SAURFANG, IN_PROGRESS); + } + + void JustDied(Unit* /*killer*/) override + { + } + + void AttackStart(Unit* victim) override + { + if (me->IsImmuneToPC()) + return; + + ScriptedAI::AttackStart(victim); + } + + void EnterEvadeMode(EvadeReason why) override + { + ScriptedAI::EnterEvadeMode(why); + if (_introDone) + me->SetImmuneToPC(false); + } + + void JustReachedHome() override + { + if (_dead) + return; + _JustReachedHome(); + Reset(); + instance->SetBossState(DATA_DEATHBRINGER_SAURFANG, FAIL); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MARK_OF_THE_FALLEN_CHAMPION); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_KILL); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + + if (!_frenzied && HealthBelowPct(31)) // AT 30%, not below + { + _frenzied = true; + DoCastSelf(SPELL_FRENZY, true); + Talk(SAY_FRENZY); + } - _fallenChampionCastCount = 0; - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MARK_OF_THE_FALLEN_CHAMPION); - instance->SetBossState(DATA_DEATHBRINGER_SAURFANG, IN_PROGRESS); - } + if (!_dead && me->GetHealth()-damage < FightWonValue) + { + _dead = true; + _JustDied(); + _EnterEvadeMode(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetImmuneToPC(true); + me->RemoveAurasOnEvade(); + DoCastAOE(SPELL_REMOVE_MARKS_OF_THE_FALLEN_CHAMPION); + DoCastSelf(SPELL_ACHIEVEMENT, true); + Talk(SAY_DEATH); + DoCastSelf(SPELL_REPUTATION_BOSS_KILL, true); + DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH); + if (Creature* creature = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SAURFANG_EVENT_NPC))) + creature->AI()->DoAction(ACTION_START_OUTRO); + } + } - void JustDied(Unit* /*killer*/) override + void JustSummoned(Creature* summon) override + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true)) + { + if (target->GetTransport()) { + summon->DespawnOrUnsummon(1ms); + EnterEvadeMode(EVADE_REASON_OTHER); + return; } - void AttackStart(Unit* victim) override - { - if (me->IsImmuneToPC()) - return; + summon->AI()->AttackStart(target); + } - ScriptedAI::AttackStart(victim); - } + summon->CastSpell(summon, SPELL_BLOOD_LINK_BEAST, true); + summon->CastSpell(summon, SPELL_RESISTANT_SKIN, true); + summons.Summon(summon); + DoZoneInCombat(summon); + } - void EnterEvadeMode(EvadeReason why) override - { - ScriptedAI::EnterEvadeMode(why); - if (_introDone) - me->SetImmuneToPC(false); - } + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override + { + summons.Despawn(summon); + } - void JustReachedHome() override - { - if (_dead) - return; - _JustReachedHome(); - Reset(); - instance->SetBossState(DATA_DEATHBRINGER_SAURFANG, FAIL); - instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_MARK_OF_THE_FALLEN_CHAMPION); - } + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE && id != POINT_SAURFANG) + return; - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_KILL); - } + instance->HandleGameObject(instance->GetGuidData(GO_SAURFANG_S_DOOR), false); + } - void DamageTaken(Unit* /*attacker*/, uint32& damage) override - { - if (damage >= me->GetHealth()) - damage = me->GetHealth() - 1; + void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override + { + if (target->GetTransport()) + { + EnterEvadeMode(EVADE_REASON_OTHER); + return; + } - if (!_frenzied && HealthBelowPct(31)) // AT 30%, not below + switch (spellInfo->Id) + { + case SPELL_MARK_OF_THE_FALLEN_CHAMPION: + Talk(SAY_MARK_OF_THE_FALLEN_CHAMPION); + break; + case 72255: // Mark of the Fallen Champion, triggered id + case 72444: + case 72445: + case 72446: + if (me->GetPower(POWER_ENERGY) != me->GetMaxPower(POWER_ENERGY)) { - _frenzied = true; - DoCastSelf(SPELL_FRENZY, true); - Talk(SAY_FRENZY); + CastSpellExtraArgs args(TRIGGERED_FULL_MASK); + args.AddSpellBP0(1); + target->CastSpell(nullptr, SPELL_BLOOD_LINK_DUMMY, args); } + break; + default: + break; + } + } - if (!_dead && me->GetHealth()-damage < FightWonValue) - { - _dead = true; - _JustDied(); - _EnterEvadeMode(); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetImmuneToPC(true); - me->RemoveAurasOnEvade(); - DoCastAOE(SPELL_REMOVE_MARKS_OF_THE_FALLEN_CHAMPION); - DoCastSelf(SPELL_ACHIEVEMENT, true); - Talk(SAY_DEATH); - DoCastSelf(SPELL_REPUTATION_BOSS_KILL, true); - DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH); - if (Creature* creature = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_SAURFANG_EVENT_NPC))) - creature->AI()->DoAction(ACTION_START_OUTRO); - } - } + void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_BLOOD_LINK_POWER) + if (Aura* bloodPower = me->GetAura(SPELL_BLOOD_POWER)) + bloodPower->RecalculateAmountOfEffects(); + } - void JustSummoned(Creature* summon) override - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true)) - { - if (target->GetTransport()) - { - summon->DespawnOrUnsummon(1ms); - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !(events.IsInPhase(PHASE_INTRO_A) || events.IsInPhase(PHASE_INTRO_H))) + return; - summon->AI()->AttackStart(target); - } + events.Update(diff); - summon->CastSpell(summon, SPELL_BLOOD_LINK_BEAST, true); - summon->CastSpell(summon, SPELL_RESISTANT_SKIN, true); - summons.Summon(summon); - DoZoneInCombat(summon); - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override - { - summons.Despawn(summon); + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INTRO_ALLIANCE_2: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetFaction(FACTION_UNDEAD_SCOURGE); + Talk(SAY_INTRO_ALLIANCE_2); + break; + case EVENT_INTRO_ALLIANCE_3: + Talk(SAY_INTRO_ALLIANCE_3); + break; + case EVENT_INTRO_ALLIANCE_6: + Talk(SAY_INTRO_ALLIANCE_6); + Talk(SAY_INTRO_ALLIANCE_7); + DoCastSelf(SPELL_GRIP_OF_AGONY); + break; + case EVENT_INTRO_HORDE_2: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetFaction(FACTION_UNDEAD_SCOURGE); + Talk(SAY_INTRO_HORDE_2); + break; + case EVENT_INTRO_HORDE_4: + Talk(SAY_INTRO_HORDE_4); + break; + case EVENT_INTRO_HORDE_9: + DoCastSelf(SPELL_GRIP_OF_AGONY); + Talk(SAY_INTRO_HORDE_9); + break; + case EVENT_INTRO_FINISH: + events.SetPhase(PHASE_COMBAT); + _introDone = true; + me->SetImmuneToPC(false); + break; + case EVENT_SUMMON_BLOOD_BEAST: + for (uint32 i10 = 0; i10 < 2; ++i10) + DoCastSelf(SPELL_SUMMON_BLOOD_BEAST+i10); + if (Is25ManRaid()) + for (uint32 i25 = 0; i25 < 3; ++i25) + DoCastSelf(SPELL_SUMMON_BLOOD_BEAST_25_MAN+i25); + Talk(SAY_BLOOD_BEASTS); + events.ScheduleEvent(EVENT_SUMMON_BLOOD_BEAST, 40s, 0, PHASE_COMBAT); + if (IsHeroic()) + events.ScheduleEvent(EVENT_SCENT_OF_BLOOD, 10s, 0, PHASE_COMBAT); + break; + case EVENT_BLOOD_NOVA: + DoCastAOE(SPELL_BLOOD_NOVA_TRIGGER); + events.ScheduleEvent(EVENT_BLOOD_NOVA, 20s, 25s, 0, PHASE_COMBAT); + break; + case EVENT_RUNE_OF_BLOOD: + DoCastVictim(SPELL_RUNE_OF_BLOOD); + events.ScheduleEvent(EVENT_RUNE_OF_BLOOD, 20s, 25s, 0, PHASE_COMBAT); + break; + case EVENT_BOILING_BLOOD: + DoCastSelf(SPELL_BOILING_BLOOD); + events.ScheduleEvent(EVENT_BOILING_BLOOD, 15s, 20s, 0, PHASE_COMBAT); + break; + case EVENT_BERSERK: + DoCastSelf(SPELL_BERSERK); + Talk(SAY_BERSERK); + break; + case EVENT_SCENT_OF_BLOOD: + if (!summons.empty()) + { + Talk(EMOTE_SCENT_OF_BLOOD); + DoCastAOE(SPELL_SCENT_OF_BLOOD); + } + break; + default: + break; } - void MovementInform(uint32 type, uint32 id) override - { - if (type != POINT_MOTION_TYPE && id != POINT_SAURFANG) - return; - - instance->HandleGameObject(instance->GetGuidData(GO_SAURFANG_S_DOOR), false); - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + } - void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override - { - if (target->GetTransport()) - { - EnterEvadeMode(EVADE_REASON_OTHER); - return; - } + DoMeleeAttackIfReady(); + } - switch (spellInfo->Id) - { - case SPELL_MARK_OF_THE_FALLEN_CHAMPION: - Talk(SAY_MARK_OF_THE_FALLEN_CHAMPION); - break; - case 72255: // Mark of the Fallen Champion, triggered id - case 72444: - case 72445: - case 72446: - if (me->GetPower(POWER_ENERGY) != me->GetMaxPower(POWER_ENERGY)) - { - CastSpellExtraArgs args(TRIGGERED_FULL_MASK); - args.AddSpellBP0(1); - target->CastSpell(nullptr, SPELL_BLOOD_LINK_DUMMY, args); - } - break; - default: - break; - } - } + uint32 GetData(uint32 type) const override + { + if (type == DATA_MADE_A_MESS) + if (_fallenChampionCastCount < RAID_MODE<uint32>(3, 5, 3, 5)) + return 1; - void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_BLOOD_LINK_POWER) - if (Aura* bloodPower = me->GetAura(SPELL_BLOOD_POWER)) - bloodPower->RecalculateAmountOfEffects(); - } + return 0; + } - void UpdateAI(uint32 diff) override + // intro setup + void DoAction(int32 action) override + { + switch (action) + { + case PHASE_INTRO_A: + case PHASE_INTRO_H: { - if (!UpdateVictim() && !(events.IsInPhase(PHASE_INTRO_A) || events.IsInPhase(PHASE_INTRO_H))) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; + // controls what events will execute + events.SetPhase(uint32(action)); - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_INTRO_ALLIANCE_2: - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(FACTION_UNDEAD_SCOURGE); - Talk(SAY_INTRO_ALLIANCE_2); - break; - case EVENT_INTRO_ALLIANCE_3: - Talk(SAY_INTRO_ALLIANCE_3); - break; - case EVENT_INTRO_ALLIANCE_6: - Talk(SAY_INTRO_ALLIANCE_6); - Talk(SAY_INTRO_ALLIANCE_7); - DoCastSelf(SPELL_GRIP_OF_AGONY); - break; - case EVENT_INTRO_HORDE_2: - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(FACTION_UNDEAD_SCOURGE); - Talk(SAY_INTRO_HORDE_2); - break; - case EVENT_INTRO_HORDE_4: - Talk(SAY_INTRO_HORDE_4); - break; - case EVENT_INTRO_HORDE_9: - DoCastSelf(SPELL_GRIP_OF_AGONY); - Talk(SAY_INTRO_HORDE_9); - break; - case EVENT_INTRO_FINISH: - events.SetPhase(PHASE_COMBAT); - _introDone = true; - me->SetImmuneToPC(false); - break; - case EVENT_SUMMON_BLOOD_BEAST: - for (uint32 i10 = 0; i10 < 2; ++i10) - DoCastSelf(SPELL_SUMMON_BLOOD_BEAST+i10); - if (Is25ManRaid()) - for (uint32 i25 = 0; i25 < 3; ++i25) - DoCastSelf(SPELL_SUMMON_BLOOD_BEAST_25_MAN+i25); - Talk(SAY_BLOOD_BEASTS); - events.ScheduleEvent(EVENT_SUMMON_BLOOD_BEAST, 40s, 0, PHASE_COMBAT); - if (IsHeroic()) - events.ScheduleEvent(EVENT_SCENT_OF_BLOOD, 10s, 0, PHASE_COMBAT); - break; - case EVENT_BLOOD_NOVA: - DoCastAOE(SPELL_BLOOD_NOVA_TRIGGER); - events.ScheduleEvent(EVENT_BLOOD_NOVA, 20s, 25s, 0, PHASE_COMBAT); - break; - case EVENT_RUNE_OF_BLOOD: - DoCastVictim(SPELL_RUNE_OF_BLOOD); - events.ScheduleEvent(EVENT_RUNE_OF_BLOOD, 20s, 25s, 0, PHASE_COMBAT); - break; - case EVENT_BOILING_BLOOD: - DoCastSelf(SPELL_BOILING_BLOOD); - events.ScheduleEvent(EVENT_BOILING_BLOOD, 15s, 20s, 0, PHASE_COMBAT); - break; - case EVENT_BERSERK: - DoCastSelf(SPELL_BERSERK); - Talk(SAY_BERSERK); - break; - case EVENT_SCENT_OF_BLOOD: - if (!summons.empty()) - { - Talk(EMOTE_SCENT_OF_BLOOD); - DoCastAOE(SPELL_SCENT_OF_BLOOD); - } - break; - default: - break; - } + me->SetHomePosition(deathbringerPos.GetPositionX(), deathbringerPos.GetPositionY(), deathbringerPos.GetPositionZ(), me->GetOrientation()); + me->GetMotionMaster()->MovePoint(POINT_SAURFANG, deathbringerPos.GetPositionX(), deathbringerPos.GetPositionY(), deathbringerPos.GetPositionZ()); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - } + events.ScheduleEvent(EVENT_INTRO_ALLIANCE_2, 2500ms, 0, PHASE_INTRO_A); + events.ScheduleEvent(EVENT_INTRO_ALLIANCE_3, 20s, 0, PHASE_INTRO_A); - DoMeleeAttackIfReady(); + events.ScheduleEvent(EVENT_INTRO_HORDE_2, 5s, 0, PHASE_INTRO_H); + break; } - - uint32 GetData(uint32 type) const override + case ACTION_CONTINUE_INTRO: { - if (type == DATA_MADE_A_MESS) - if (_fallenChampionCastCount < RAID_MODE<uint32>(3, 5, 3, 5)) - return 1; + if (_introDone) + return; - return 0; - } + events.ScheduleEvent(EVENT_INTRO_ALLIANCE_6, 7s, 0, PHASE_INTRO_A); + events.ScheduleEvent(EVENT_INTRO_FINISH, 8s, 0, PHASE_INTRO_A); - // intro setup - void DoAction(int32 action) override + events.ScheduleEvent(EVENT_INTRO_HORDE_4, 6500ms, 0, PHASE_INTRO_H); + events.ScheduleEvent(EVENT_INTRO_HORDE_9, 48200ms, 0, PHASE_INTRO_H); + events.ScheduleEvent(EVENT_INTRO_FINISH, 55700ms, 0, PHASE_INTRO_H); + break; + } + case ACTION_MARK_OF_THE_FALLEN_CHAMPION: { - switch (action) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true, true, -SPELL_MARK_OF_THE_FALLEN_CHAMPION)) { - case PHASE_INTRO_A: - case PHASE_INTRO_H: - { - // controls what events will execute - events.SetPhase(uint32(action)); - - me->SetHomePosition(deathbringerPos.GetPositionX(), deathbringerPos.GetPositionY(), deathbringerPos.GetPositionZ(), me->GetOrientation()); - me->GetMotionMaster()->MovePoint(POINT_SAURFANG, deathbringerPos.GetPositionX(), deathbringerPos.GetPositionY(), deathbringerPos.GetPositionZ()); - - events.ScheduleEvent(EVENT_INTRO_ALLIANCE_2, 2500ms, 0, PHASE_INTRO_A); - events.ScheduleEvent(EVENT_INTRO_ALLIANCE_3, 20s, 0, PHASE_INTRO_A); - - events.ScheduleEvent(EVENT_INTRO_HORDE_2, 5s, 0, PHASE_INTRO_H); - break; - } - case ACTION_CONTINUE_INTRO: - { - if (_introDone) - return; - - events.ScheduleEvent(EVENT_INTRO_ALLIANCE_6, 7s, 0, PHASE_INTRO_A); - events.ScheduleEvent(EVENT_INTRO_FINISH, 8s, 0, PHASE_INTRO_A); - - events.ScheduleEvent(EVENT_INTRO_HORDE_4, 6500ms, 0, PHASE_INTRO_H); - events.ScheduleEvent(EVENT_INTRO_HORDE_9, 48200ms, 0, PHASE_INTRO_H); - events.ScheduleEvent(EVENT_INTRO_FINISH, 55700ms, 0, PHASE_INTRO_H); - break; - } - case ACTION_MARK_OF_THE_FALLEN_CHAMPION: - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true, true, -SPELL_MARK_OF_THE_FALLEN_CHAMPION)) - { - ++_fallenChampionCastCount; - DoCast(target, SPELL_MARK_OF_THE_FALLEN_CHAMPION); - me->SetPower(POWER_ENERGY, 0); - if (Aura* bloodPower = me->GetAura(SPELL_BLOOD_POWER)) - bloodPower->RecalculateAmountOfEffects(); - } - break; - } - default: - break; + ++_fallenChampionCastCount; + DoCast(target, SPELL_MARK_OF_THE_FALLEN_CHAMPION); + me->SetPower(POWER_ENERGY, 0); + if (Aura* bloodPower = me->GetAura(SPELL_BLOOD_POWER)) + bloodPower->RecalculateAmountOfEffects(); } + break; } + default: + break; + } + } - bool CanAIAttack(Unit const* target) const override - { - if (target->GetTransport()) - return false; - - return BossAI::CanAIAttack(target); - } + bool CanAIAttack(Unit const* target) const override + { + if (target->GetTransport()) + return false; - static uint32 const FightWonValue; + return BossAI::CanAIAttack(target); + } - private: - uint32 _fallenChampionCastCount; - bool _introDone; - bool _frenzied; // faster than iterating all auras to find Frenzy - bool _dead; - }; + static uint32 const FightWonValue; - CreatureAI* GetAI(Creature* creature) const override - { - return GetIcecrownCitadelAI<boss_deathbringer_saurfangAI>(creature); - } +private: + uint32 _fallenChampionCastCount; + bool _introDone; + bool _frenzied; // faster than iterating all auras to find Frenzy + bool _dead; }; -uint32 const boss_deathbringer_saurfang::boss_deathbringer_saurfangAI::FightWonValue = 100000; +uint32 const boss_deathbringer_saurfang::FightWonValue = 100000; -class npc_high_overlord_saurfang_icc : public CreatureScript +struct npc_high_overlord_saurfang_icc : public ScriptedAI { - public: - npc_high_overlord_saurfang_icc() : CreatureScript("npc_high_overlord_saurfang_icc") { } - - struct npc_high_overlord_saurfangAI : public ScriptedAI + npc_high_overlord_saurfang_icc(Creature* creature) : ScriptedAI(creature) + { + ASSERT(creature->GetVehicleKit()); + _instance = me->GetInstanceScript(); + } + + void Reset() override + { + _events.Reset(); + } + + bool OnGossipSelect(Player* player, uint32 menuId, uint32 /*gossipListId*/) override + { + if (menuId == GOSSIP_MENU_HIGH_OVERLORD_SAURFANG) { - npc_high_overlord_saurfangAI(Creature* creature) : ScriptedAI(creature) - { - ASSERT(creature->GetVehicleKit()); - _instance = me->GetInstanceScript(); - } - - void Reset() override + CloseGossipMenuFor(player); + DoAction(ACTION_START_EVENT); + } + return false; + } + + void GuardBroadcast(std::function<void(Creature*)>&& action) const + { + std::vector<Creature*> guardList; + GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_KOR_KRON_REAVER, 100.0f); + for (Creature* guard : guardList) + action(guard); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_START_EVENT: { - _events.Reset(); - } + // Prevent crashes + if (_events.IsInPhase(PHASE_INTRO_A) || _events.IsInPhase(PHASE_INTRO_H)) + return; - bool OnGossipSelect(Player* player, uint32 menuId, uint32 /*gossipListId*/) override - { - if (menuId == GOSSIP_MENU_HIGH_OVERLORD_SAURFANG) + std::list<Creature*> guardList; + GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_KOR_KRON_REAVER, 20.0f); + guardList.sort(Trinity::ObjectDistanceOrderPred(me)); + uint32 x = 1; + for (auto itr = guardList.begin(); itr != guardList.end(); ++x, ++itr) + (*itr)->AI()->SetData(0, x); + + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + Talk(SAY_INTRO_HORDE_1); + _events.SetPhase(PHASE_INTRO_H); + _events.ScheduleEvent(EVENT_INTRO_HORDE_3, 18500ms, 0, PHASE_INTRO_H); + _instance->HandleGameObject(_instance->GetGuidData(GO_SAURFANG_S_DOOR), true); + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) + deathbringer->AI()->DoAction(PHASE_INTRO_H); + break; + } + case ACTION_START_OUTRO: + { + me->RemoveAurasDueToSpell(SPELL_GRIP_OF_AGONY); + Talk(SAY_OUTRO_HORDE_1); + _events.ScheduleEvent(EVENT_OUTRO_HORDE_2, 10s); // say + _events.ScheduleEvent(EVENT_OUTRO_HORDE_3, 18s); // say + _events.ScheduleEvent(EVENT_OUTRO_HORDE_4, 24s); // cast + _events.ScheduleEvent(EVENT_OUTRO_HORDE_5, 30s); // move + me->SetDisableGravity(false); + me->GetMotionMaster()->MoveFall(); + GuardBroadcast([](Creature* guard) { - CloseGossipMenuFor(player); - DoAction(ACTION_START_EVENT); - } - return false; - } - - void GuardBroadcast(std::function<void(Creature*)>&& action) const - { - std::vector<Creature*> guardList; - GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_KOR_KRON_REAVER, 100.0f); - for (Creature* guard : guardList) - action(guard); + guard->AI()->DoAction(ACTION_DESPAWN); + }); + break; } - - void DoAction(int32 action) override + case ACTION_INTERRUPT_INTRO: { - switch (action) + _events.Reset(); + GuardBroadcast([](Creature* guard) { - case ACTION_START_EVENT: - { - // Prevent crashes - if (_events.IsInPhase(PHASE_INTRO_A) || _events.IsInPhase(PHASE_INTRO_H)) - return; - - std::list<Creature*> guardList; - GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_KOR_KRON_REAVER, 20.0f); - guardList.sort(Trinity::ObjectDistanceOrderPred(me)); - uint32 x = 1; - for (auto itr = guardList.begin(); itr != guardList.end(); ++x, ++itr) - (*itr)->AI()->SetData(0, x); - - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - Talk(SAY_INTRO_HORDE_1); - _events.SetPhase(PHASE_INTRO_H); - _events.ScheduleEvent(EVENT_INTRO_HORDE_3, 18500ms, 0, PHASE_INTRO_H); - _instance->HandleGameObject(_instance->GetGuidData(GO_SAURFANG_S_DOOR), true); - if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) - deathbringer->AI()->DoAction(PHASE_INTRO_H); - break; - } - case ACTION_START_OUTRO: - { - me->RemoveAurasDueToSpell(SPELL_GRIP_OF_AGONY); - Talk(SAY_OUTRO_HORDE_1); - _events.ScheduleEvent(EVENT_OUTRO_HORDE_2, 10s); // say - _events.ScheduleEvent(EVENT_OUTRO_HORDE_3, 18s); // say - _events.ScheduleEvent(EVENT_OUTRO_HORDE_4, 24s); // cast - _events.ScheduleEvent(EVENT_OUTRO_HORDE_5, 30s); // move - me->SetDisableGravity(false); - me->GetMotionMaster()->MoveFall(); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_DESPAWN); - }); - break; - } - case ACTION_INTERRUPT_INTRO: - { - _events.Reset(); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_DESPAWN); - }); - break; - } - default: - break; - } + guard->AI()->DoAction(ACTION_DESPAWN); + }); + break; } + default: + break; + } + } - void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_GRIP_OF_AGONY) - { - me->SetDisableGravity(true); - me->GetMotionMaster()->MovePoint(POINT_CHOKE, chokePos[0]); - } - } + void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_GRIP_OF_AGONY) + { + me->SetDisableGravity(true); + me->GetMotionMaster()->MovePoint(POINT_CHOKE, chokePos[0]); + } + } - void MovementInform(uint32 type, uint32 id) override + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE) + { + switch (id) { - if (type == POINT_MOTION_TYPE) - { - switch (id) + case POINT_FIRST_STEP: + me->SetWalk(false); + Talk(SAY_INTRO_HORDE_3); + _events.ScheduleEvent(EVENT_INTRO_HORDE_5, 15500ms, 0, PHASE_INTRO_H); + _events.ScheduleEvent(EVENT_INTRO_HORDE_6, 29500ms, 0, PHASE_INTRO_H); + _events.ScheduleEvent(EVENT_INTRO_HORDE_7, 43800ms, 0, PHASE_INTRO_H); + _events.ScheduleEvent(EVENT_INTRO_HORDE_8, 47000ms, 0, PHASE_INTRO_H); + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) + deathbringer->AI()->DoAction(ACTION_CONTINUE_INTRO); + break; + case POINT_CORPSE: + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) { - case POINT_FIRST_STEP: - me->SetWalk(false); - Talk(SAY_INTRO_HORDE_3); - _events.ScheduleEvent(EVENT_INTRO_HORDE_5, 15500ms, 0, PHASE_INTRO_H); - _events.ScheduleEvent(EVENT_INTRO_HORDE_6, 29500ms, 0, PHASE_INTRO_H); - _events.ScheduleEvent(EVENT_INTRO_HORDE_7, 43800ms, 0, PHASE_INTRO_H); - _events.ScheduleEvent(EVENT_INTRO_HORDE_8, 47000ms, 0, PHASE_INTRO_H); - if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) - deathbringer->AI()->DoAction(ACTION_CONTINUE_INTRO); - break; - case POINT_CORPSE: - if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) - { - deathbringer->CastSpell(me, SPELL_RIDE_VEHICLE, true); // for the packet logs. - deathbringer->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - deathbringer->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DROWNED); - } - _events.ScheduleEvent(EVENT_OUTRO_HORDE_5, 1s); // move - _events.ScheduleEvent(EVENT_OUTRO_HORDE_6, 4s); // say - break; - case POINT_FINAL: - if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) - deathbringer->DespawnOrUnsummon(); - me->DespawnOrUnsummon(); - break; - default: - break; + deathbringer->CastSpell(me, SPELL_RIDE_VEHICLE, true); // for the packet logs. + deathbringer->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + deathbringer->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DROWNED); } - } - else if (type == WAYPOINT_MOTION_TYPE && id == POINT_EXIT) - { - std::list<Creature*> guards; - GetCreatureListWithEntryInGrid(guards, me, NPC_KOR_KRON_GENERAL, 50.0f); - for (std::list<Creature*>::iterator itr = guards.begin(); itr != guards.end(); ++itr) - (*itr)->DespawnOrUnsummon(); + _events.ScheduleEvent(EVENT_OUTRO_HORDE_5, 1s); // move + _events.ScheduleEvent(EVENT_OUTRO_HORDE_6, 4s); // say + break; + case POINT_FINAL: + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) + deathbringer->DespawnOrUnsummon(); me->DespawnOrUnsummon(); - } - } - - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_INTRO_HORDE_3: - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(POINT_FIRST_STEP, firstStepPos.GetPositionX(), firstStepPos.GetPositionY(), firstStepPos.GetPositionZ()); - break; - case EVENT_INTRO_HORDE_5: - Talk(SAY_INTRO_HORDE_5); - break; - case EVENT_INTRO_HORDE_6: - Talk(SAY_INTRO_HORDE_6); - break; - case EVENT_INTRO_HORDE_7: - Talk(SAY_INTRO_HORDE_7); - break; - case EVENT_INTRO_HORDE_8: - Talk(SAY_INTRO_HORDE_8); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_CHARGE); - }); - me->GetMotionMaster()->MoveCharge(chargePos[0].GetPositionX(), chargePos[0].GetPositionY(), chargePos[0].GetPositionZ(), 8.5f, POINT_CHARGE); - break; - case EVENT_OUTRO_HORDE_2: // say - if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) - me->SetFacingToObject(deathbringer); - Talk(SAY_OUTRO_HORDE_2); - break; - case EVENT_OUTRO_HORDE_3: // say - Talk(SAY_OUTRO_HORDE_3); - break; - case EVENT_OUTRO_HORDE_4: // move - if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) - { - float x, y, z; - deathbringer->GetClosePoint(x, y, z, deathbringer->GetCombatReach()); - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(POINT_CORPSE, x, y, z); - } - break; - case EVENT_OUTRO_HORDE_5: // move - me->GetMotionMaster()->MovePoint(POINT_FINAL, finalPos); - break; - case EVENT_OUTRO_HORDE_6: // say - Talk(SAY_OUTRO_HORDE_4); - break; - } - } + break; + default: + break; } - - private: - EventMap _events; - InstanceScript* _instance; - }; - - CreatureAI* GetAI(Creature* creature) const override + } + else if (type == WAYPOINT_MOTION_TYPE && id == POINT_EXIT) { - return GetIcecrownCitadelAI<npc_high_overlord_saurfangAI>(creature); + std::list<Creature*> guards; + GetCreatureListWithEntryInGrid(guards, me, NPC_KOR_KRON_GENERAL, 50.0f); + for (std::list<Creature*>::iterator itr = guards.begin(); itr != guards.end(); ++itr) + (*itr)->DespawnOrUnsummon(); + me->DespawnOrUnsummon(); } -}; - -class npc_muradin_bronzebeard_icc : public CreatureScript -{ - public: - npc_muradin_bronzebeard_icc() : CreatureScript("npc_muradin_bronzebeard_icc") { } + } - struct npc_muradin_bronzebeard_iccAI : public ScriptedAI + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + while (uint32 eventId = _events.ExecuteEvent()) { - npc_muradin_bronzebeard_iccAI(Creature* creature) : ScriptedAI(creature) - { - _instance = me->GetInstanceScript(); - } - - void Reset() override - { - _events.Reset(); - } - - bool OnGossipSelect(Player* player, uint32 menuId, uint32 /*gossipListId*/) override - { - if (menuId == GOSSIP_MENU_MURADIN_BRONZEBEARD) - { - CloseGossipMenuFor(player); - DoAction(ACTION_START_EVENT); - } - return false; - } - - void GuardBroadcast(std::function<void(Creature*)>&& action) const - { - std::vector<Creature*> guardList; - GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_SKYBREAKER_MARINE, 100.0f); - for (Creature* guard : guardList) - action(guard); - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_START_EVENT: + switch (eventId) + { + case EVENT_INTRO_HORDE_3: + me->SetWalk(true); + me->GetMotionMaster()->MovePoint(POINT_FIRST_STEP, firstStepPos.GetPositionX(), firstStepPos.GetPositionY(), firstStepPos.GetPositionZ()); + break; + case EVENT_INTRO_HORDE_5: + Talk(SAY_INTRO_HORDE_5); + break; + case EVENT_INTRO_HORDE_6: + Talk(SAY_INTRO_HORDE_6); + break; + case EVENT_INTRO_HORDE_7: + Talk(SAY_INTRO_HORDE_7); + break; + case EVENT_INTRO_HORDE_8: + Talk(SAY_INTRO_HORDE_8); + GuardBroadcast([](Creature* guard) { - // Prevent crashes - if (_events.IsInPhase(PHASE_INTRO_A) || _events.IsInPhase(PHASE_INTRO_H)) - return; - - _events.SetPhase(PHASE_INTRO_A); - std::list<Creature*> guardList; - GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_SKYBREAKER_MARINE, 20.0f); - guardList.sort(Trinity::ObjectDistanceOrderPred(me)); - uint32 x = 1; - for (auto itr = guardList.begin(); itr != guardList.end(); ++x, ++itr) - (*itr)->AI()->SetData(0, x); - - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - Talk(SAY_INTRO_ALLIANCE_1); - _events.ScheduleEvent(EVENT_INTRO_ALLIANCE_4, 29500ms, 0, PHASE_INTRO_A); - _instance->HandleGameObject(_instance->GetGuidData(GO_SAURFANG_S_DOOR), true); - if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) - deathbringer->AI()->DoAction(PHASE_INTRO_A); - break; - } - case ACTION_START_OUTRO: - { - me->RemoveAurasDueToSpell(SPELL_GRIP_OF_AGONY); - Talk(SAY_OUTRO_ALLIANCE_1); - me->SetDisableGravity(false); - me->GetMotionMaster()->MoveFall(); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_DESPAWN); - }); - - // temp until outro fully done - to put deathbringer on respawn timer (until next reset) - if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) - deathbringer->DespawnOrUnsummon(5s); - break; - } - case ACTION_INTERRUPT_INTRO: - _events.Reset(); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_DESPAWN); - }); - break; - } - } - - void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_GRIP_OF_AGONY) - { - me->SetDisableGravity(true); - me->GetMotionMaster()->MovePoint(POINT_CHOKE, chokePos[0]); - } - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type == POINT_MOTION_TYPE && id == POINT_FIRST_STEP) - { - me->SetWalk(false); - Talk(SAY_INTRO_ALLIANCE_4); - _events.ScheduleEvent(EVENT_INTRO_ALLIANCE_5, 5s, 0, PHASE_INTRO_A); + guard->AI()->DoAction(ACTION_CHARGE); + }); + me->GetMotionMaster()->MoveCharge(chargePos[0].GetPositionX(), chargePos[0].GetPositionY(), chargePos[0].GetPositionZ(), 8.5f, POINT_CHARGE); + break; + case EVENT_OUTRO_HORDE_2: // say + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) + me->SetFacingToObject(deathbringer); + Talk(SAY_OUTRO_HORDE_2); + break; + case EVENT_OUTRO_HORDE_3: // say + Talk(SAY_OUTRO_HORDE_3); + break; + case EVENT_OUTRO_HORDE_4: // move if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) - deathbringer->AI()->DoAction(ACTION_CONTINUE_INTRO); - } - else if (type == WAYPOINT_MOTION_TYPE && id == POINT_EXIT) - { - std::list<Creature*> guards; - GetCreatureListWithEntryInGrid(guards, me, NPC_ALLIANCE_COMMANDER, 50.0f); - for (std::list<Creature*>::iterator itr = guards.begin(); itr != guards.end(); ++itr) - (*itr)->DespawnOrUnsummon(); - me->DespawnOrUnsummon(); - } - } - - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) { - case EVENT_INTRO_ALLIANCE_4: - me->SetWalk(true); - me->GetMotionMaster()->MovePoint(POINT_FIRST_STEP, firstStepPos.GetPositionX(), firstStepPos.GetPositionY(), firstStepPos.GetPositionZ()); - break; - case EVENT_INTRO_ALLIANCE_5: - Talk(SAY_INTRO_ALLIANCE_5); - GuardBroadcast([](Creature* guard) - { - guard->AI()->DoAction(ACTION_CHARGE); - }); - me->GetMotionMaster()->MoveCharge(chargePos[0].GetPositionX(), chargePos[0].GetPositionY(), chargePos[0].GetPositionZ(), 8.5f, POINT_CHARGE); - break; + float x, y, z; + deathbringer->GetClosePoint(x, y, z, deathbringer->GetCombatReach()); + me->SetWalk(true); + me->GetMotionMaster()->MovePoint(POINT_CORPSE, x, y, z); } - } + break; + case EVENT_OUTRO_HORDE_5: // move + me->GetMotionMaster()->MovePoint(POINT_FINAL, finalPos); + break; + case EVENT_OUTRO_HORDE_6: // say + Talk(SAY_OUTRO_HORDE_4); + break; } - - private: - EventMap _events; - InstanceScript* _instance; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetIcecrownCitadelAI<npc_muradin_bronzebeard_iccAI>(creature); } + } + +private: + EventMap _events; + InstanceScript* _instance; }; -class npc_saurfang_event : public CreatureScript +struct npc_muradin_bronzebeard_icc : public ScriptedAI { - public: - npc_saurfang_event() : CreatureScript("npc_saurfang_event") { } - - struct npc_saurfang_eventAI : public ScriptedAI + npc_muradin_bronzebeard_icc(Creature* creature) : ScriptedAI(creature) + { + _instance = me->GetInstanceScript(); + } + + void Reset() override + { + _events.Reset(); + } + + bool OnGossipSelect(Player* player, uint32 menuId, uint32 /*gossipListId*/) override + { + if (menuId == GOSSIP_MENU_MURADIN_BRONZEBEARD) { - npc_saurfang_eventAI(Creature* creature) : ScriptedAI(creature) - { - _index = 0; - } - - void SetData(uint32 type, uint32 data) override + CloseGossipMenuFor(player); + DoAction(ACTION_START_EVENT); + } + return false; + } + + void GuardBroadcast(std::function<void(Creature*)>&& action) const + { + std::vector<Creature*> guardList; + GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_SKYBREAKER_MARINE, 100.0f); + for (Creature* guard : guardList) + action(guard); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_START_EVENT: { - if (!(!type && data && data < 6)) + // Prevent crashes + if (_events.IsInPhase(PHASE_INTRO_A) || _events.IsInPhase(PHASE_INTRO_H)) return; - _index = data; - } - void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override - { - if (spellInfo->Id == SPELL_GRIP_OF_AGONY) + _events.SetPhase(PHASE_INTRO_A); + std::list<Creature*> guardList; + GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_SKYBREAKER_MARINE, 20.0f); + guardList.sort(Trinity::ObjectDistanceOrderPred(me)); + uint32 x = 1; + for (auto itr = guardList.begin(); itr != guardList.end(); ++x, ++itr) + (*itr)->AI()->SetData(0, x); + + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + Talk(SAY_INTRO_ALLIANCE_1); + _events.ScheduleEvent(EVENT_INTRO_ALLIANCE_4, 29500ms, 0, PHASE_INTRO_A); + _instance->HandleGameObject(_instance->GetGuidData(GO_SAURFANG_S_DOOR), true); + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) + deathbringer->AI()->DoAction(PHASE_INTRO_A); + break; + } + case ACTION_START_OUTRO: + { + me->RemoveAurasDueToSpell(SPELL_GRIP_OF_AGONY); + Talk(SAY_OUTRO_ALLIANCE_1); + me->SetDisableGravity(false); + me->GetMotionMaster()->MoveFall(); + GuardBroadcast([](Creature* guard) { - me->SetDisableGravity(true); - me->GetMotionMaster()->MovePoint(POINT_CHOKE, chokePos[_index]); - } - } + guard->AI()->DoAction(ACTION_DESPAWN); + }); - void DoAction(int32 action) override - { - if (action == ACTION_CHARGE && _index) - me->GetMotionMaster()->MoveCharge(chargePos[_index].GetPositionX(), chargePos[_index].GetPositionY(), chargePos[_index].GetPositionZ(), 13.0f, POINT_CHARGE); - else if (action == ACTION_DESPAWN) - me->DespawnOrUnsummon(); + // temp until outro fully done - to put deathbringer on respawn timer (until next reset) + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) + deathbringer->DespawnOrUnsummon(5s); + break; } + case ACTION_INTERRUPT_INTRO: + _events.Reset(); + GuardBroadcast([](Creature* guard) + { + guard->AI()->DoAction(ACTION_DESPAWN); + }); + break; + } + } - private: - uint32 _index; - }; - - CreatureAI* GetAI(Creature* creature) const override + void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_GRIP_OF_AGONY) { - return GetIcecrownCitadelAI<npc_saurfang_eventAI>(creature); + me->SetDisableGravity(true); + me->GetMotionMaster()->MovePoint(POINT_CHOKE, chokePos[0]); } -}; - -class spell_deathbringer_blood_link : public SpellScriptLoader -{ - public: - spell_deathbringer_blood_link() : SpellScriptLoader("spell_deathbringer_blood_link") { } + } - class spell_deathbringer_blood_link_SpellScript : public SpellScript + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE && id == POINT_FIRST_STEP) { - PrepareSpellScript(spell_deathbringer_blood_link_SpellScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_BLOOD_LINK_POWER, SPELL_BLOOD_POWER }); - } - - void HandleDummy(SpellEffIndex /*effIndex*/) - { - CastSpellExtraArgs args(TRIGGERED_FULL_MASK); - args.AddSpellBP0(GetEffectValue()); - GetHitUnit()->CastSpell(GetHitUnit(), SPELL_BLOOD_LINK_POWER, args); - PreventHitDefaultEffect(EFFECT_0); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_deathbringer_blood_link_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; - - SpellScript* GetSpellScript() const override + me->SetWalk(false); + Talk(SAY_INTRO_ALLIANCE_4); + _events.ScheduleEvent(EVENT_INTRO_ALLIANCE_5, 5s, 0, PHASE_INTRO_A); + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_DEATHBRINGER_SAURFANG))) + deathbringer->AI()->DoAction(ACTION_CONTINUE_INTRO); + } + else if (type == WAYPOINT_MOTION_TYPE && id == POINT_EXIT) { - return new spell_deathbringer_blood_link_SpellScript(); + std::list<Creature*> guards; + GetCreatureListWithEntryInGrid(guards, me, NPC_ALLIANCE_COMMANDER, 50.0f); + for (std::list<Creature*>::iterator itr = guards.begin(); itr != guards.end(); ++itr) + (*itr)->DespawnOrUnsummon(); + me->DespawnOrUnsummon(); } -}; - -class spell_deathbringer_blood_link_aura : public SpellScriptLoader -{ - public: - spell_deathbringer_blood_link_aura() : SpellScriptLoader("spell_deathbringer_blood_link_aura") { } + } - class spell_deathbringer_blood_link_AuraScript : public AuraScript + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + while (uint32 eventId = _events.ExecuteEvent()) { - PrepareAuraScript(spell_deathbringer_blood_link_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MARK_OF_THE_FALLEN_CHAMPION }); - } - - void HandlePeriodicTick(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - if (GetUnitOwner()->GetPowerType() == POWER_ENERGY && GetUnitOwner()->GetPower(POWER_ENERGY) == GetUnitOwner()->GetMaxPower(POWER_ENERGY)) - if (Creature* saurfang = GetUnitOwner()->ToCreature()) - saurfang->AI()->DoAction(ACTION_MARK_OF_THE_FALLEN_CHAMPION); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_deathbringer_blood_link_AuraScript::HandlePeriodicTick, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); + switch (eventId) + { + case EVENT_INTRO_ALLIANCE_4: + me->SetWalk(true); + me->GetMotionMaster()->MovePoint(POINT_FIRST_STEP, firstStepPos.GetPositionX(), firstStepPos.GetPositionY(), firstStepPos.GetPositionZ()); + break; + case EVENT_INTRO_ALLIANCE_5: + Talk(SAY_INTRO_ALLIANCE_5); + GuardBroadcast([](Creature* guard) + { + guard->AI()->DoAction(ACTION_CHARGE); + }); + me->GetMotionMaster()->MoveCharge(chargePos[0].GetPositionX(), chargePos[0].GetPositionY(), chargePos[0].GetPositionZ(), 8.5f, POINT_CHARGE); + break; } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_deathbringer_blood_link_AuraScript(); } + } + +private: + EventMap _events; + InstanceScript* _instance; }; -class spell_deathbringer_blood_power : public SpellScriptLoader +struct npc_saurfang_event : public ScriptedAI { - public: - spell_deathbringer_blood_power() : SpellScriptLoader("spell_deathbringer_blood_power") { } - - class spell_deathbringer_blood_power_SpellScript : public SpellScript - { - PrepareSpellScript(spell_deathbringer_blood_power_SpellScript); - - void ModAuraValue() - { - if (Aura* aura = GetHitAura()) - aura->RecalculateAmountOfEffects(); - } - - void Register() override - { - AfterHit += SpellHitFn(spell_deathbringer_blood_power_SpellScript::ModAuraValue); - } - }; - - class spell_deathbringer_blood_power_AuraScript : public AuraScript - { - PrepareAuraScript(spell_deathbringer_blood_power_AuraScript); - - void RecalculateHook(AuraEffect const* /*aurEffect*/, int32& amount, bool& canBeRecalculated) - { - amount = int32(GetUnitOwner()->GetPower(POWER_ENERGY)); - canBeRecalculated = true; - } - - void Register() override - { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_deathbringer_blood_power_AuraScript::RecalculateHook, EFFECT_0, SPELL_AURA_MOD_SCALE); - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_deathbringer_blood_power_AuraScript::RecalculateHook, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_deathbringer_blood_power_SpellScript(); - } - - AuraScript* GetAuraScript() const override + npc_saurfang_event(Creature* creature) : ScriptedAI(creature) + { + _index = 0; + } + + void SetData(uint32 type, uint32 data) override + { + if (!(!type && data && data < 6)) + return; + _index = data; + } + + void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_GRIP_OF_AGONY) { - return new spell_deathbringer_blood_power_AuraScript(); + me->SetDisableGravity(true); + me->GetMotionMaster()->MovePoint(POINT_CHOKE, chokePos[_index]); } + } + + void DoAction(int32 action) override + { + if (action == ACTION_CHARGE && _index) + me->GetMotionMaster()->MoveCharge(chargePos[_index].GetPositionX(), chargePos[_index].GetPositionY(), chargePos[_index].GetPositionZ(), 13.0f, POINT_CHARGE); + else if (action == ACTION_DESPAWN) + me->DespawnOrUnsummon(); + } + +private: + uint32 _index; }; -class spell_deathbringer_rune_of_blood : public SpellScriptLoader +class spell_deathbringer_blood_link : public SpellScript { - public: - spell_deathbringer_rune_of_blood() : SpellScriptLoader("spell_deathbringer_rune_of_blood") { } - - class spell_deathbringer_rune_of_blood_SpellScript : public SpellScript - { - PrepareSpellScript(spell_deathbringer_rune_of_blood_SpellScript); + PrepareSpellScript(spell_deathbringer_blood_link); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_BLOOD_LINK_POWER, SPELL_BLOOD_POWER }); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + CastSpellExtraArgs args(TRIGGERED_FULL_MASK); + args.AddSpellBP0(GetEffectValue()); + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_BLOOD_LINK_POWER, args); + PreventHitDefaultEffect(EFFECT_0); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_deathbringer_blood_link::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_BLOOD_LINK_DUMMY }); - } +class spell_deathbringer_blood_link_aura : public AuraScript +{ + PrepareAuraScript(spell_deathbringer_blood_link_aura); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_MARK_OF_THE_FALLEN_CHAMPION }); + } + + void HandlePeriodicTick(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + if (GetUnitOwner()->GetPowerType() == POWER_ENERGY && GetUnitOwner()->GetPower(POWER_ENERGY) == GetUnitOwner()->GetMaxPower(POWER_ENERGY)) + if (Creature* saurfang = GetUnitOwner()->ToCreature()) + saurfang->AI()->DoAction(ACTION_MARK_OF_THE_FALLEN_CHAMPION); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_deathbringer_blood_link_aura::HandlePeriodicTick, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); + } +}; - void HandleScript(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); // make this the default handler - GetHitUnit()->CastSpell(nullptr, SPELL_BLOOD_LINK_DUMMY, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(1)); - } +class spell_deathbringer_blood_power : public SpellScript +{ + PrepareSpellScript(spell_deathbringer_blood_power); + + void ModAuraValue() + { + if (Aura* aura = GetHitAura()) + aura->RecalculateAmountOfEffects(); + } + + void Register() override + { + AfterHit += SpellHitFn(spell_deathbringer_blood_power::ModAuraValue); + } +}; - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_deathbringer_rune_of_blood_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; +class spell_deathbringer_blood_power_aura : public AuraScript +{ + PrepareAuraScript(spell_deathbringer_blood_power_aura); + + void RecalculateHook(AuraEffect const* /*aurEffect*/, int32& amount, bool& canBeRecalculated) + { + amount = int32(GetUnitOwner()->GetPower(POWER_ENERGY)); + canBeRecalculated = true; + } + + void Register() override + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_deathbringer_blood_power_aura::RecalculateHook, EFFECT_0, SPELL_AURA_MOD_SCALE); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_deathbringer_blood_power_aura::RecalculateHook, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + } +}; - SpellScript* GetSpellScript() const override - { - return new spell_deathbringer_rune_of_blood_SpellScript(); - } +class spell_deathbringer_rune_of_blood : public SpellScript +{ + PrepareSpellScript(spell_deathbringer_rune_of_blood); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_BLOOD_LINK_DUMMY }); + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); // make this the default handler + GetHitUnit()->CastSpell(nullptr, SPELL_BLOOD_LINK_DUMMY, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(1)); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_deathbringer_rune_of_blood::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } }; // 72176 - Blood Beast's Blood Link -class spell_deathbringer_blood_beast_blood_link : public SpellScriptLoader +class spell_deathbringer_blood_beast_blood_link : public AuraScript { - public: - spell_deathbringer_blood_beast_blood_link() : SpellScriptLoader("spell_deathbringer_blood_beast_blood_link") { } - - class spell_deathbringer_blood_beast_blood_link_AuraScript : public AuraScript - { - PrepareAuraScript(spell_deathbringer_blood_beast_blood_link_AuraScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_BLOOD_LINK_DUMMY }); - } - - void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) - { - PreventDefaultAction(); - eventInfo.GetProcTarget()->CastSpell(nullptr, SPELL_BLOOD_LINK_DUMMY, CastSpellExtraArgs(aurEff).AddSpellBP0(3)); - } - - void Register() override - { - OnEffectProc += AuraEffectProcFn(spell_deathbringer_blood_beast_blood_link_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_deathbringer_blood_beast_blood_link_AuraScript(); - } + PrepareAuraScript(spell_deathbringer_blood_beast_blood_link); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_BLOOD_LINK_DUMMY }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + eventInfo.GetProcTarget()->CastSpell(nullptr, SPELL_BLOOD_LINK_DUMMY, CastSpellExtraArgs(aurEff).AddSpellBP0(3)); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_deathbringer_blood_beast_blood_link::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } }; -class spell_deathbringer_blood_nova : public SpellScriptLoader +class spell_deathbringer_blood_nova : public SpellScript { - public: - spell_deathbringer_blood_nova() : SpellScriptLoader("spell_deathbringer_blood_nova") { } - - class spell_deathbringer_blood_nova_SpellScript : public SpellScript - { - PrepareSpellScript(spell_deathbringer_blood_nova_SpellScript); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_BLOOD_LINK_DUMMY }); - } - - void HandleScript(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); // make this the default handler - GetHitUnit()->CastSpell(nullptr, SPELL_BLOOD_LINK_DUMMY, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(2)); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_deathbringer_blood_nova_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_deathbringer_blood_nova_SpellScript(); - } + PrepareSpellScript(spell_deathbringer_blood_nova); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_BLOOD_LINK_DUMMY }); + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); // make this the default handler + GetHitUnit()->CastSpell(nullptr, SPELL_BLOOD_LINK_DUMMY, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(2)); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_deathbringer_blood_nova::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } }; -class spell_deathbringer_blood_nova_targeting : public SpellScriptLoader +class spell_deathbringer_blood_nova_targeting : public SpellScript { - public: - spell_deathbringer_blood_nova_targeting() : SpellScriptLoader("spell_deathbringer_blood_nova_targeting") { } - - class spell_deathbringer_blood_nova_targeting_SpellScript : public SpellScript - { - PrepareSpellScript(spell_deathbringer_blood_nova_targeting_SpellScript); - - public: - spell_deathbringer_blood_nova_targeting_SpellScript() - { - target = nullptr; - } - - private: - void FilterTargetsInitial(std::list<WorldObject*>& targets) - { - if (targets.empty()) - return; - - // select one random target, preferring ranged targets - uint32 targetsAtRange = 0; - uint32 const minTargets = uint32(GetCaster()->GetMap()->Is25ManRaid() ? 10 : 4); - targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false)); - - // get target count at range - for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr, ++targetsAtRange) - if ((*itr)->GetDistance(GetCaster()) < 12.0f) - break; - - // If not enough ranged targets are present just select anyone - if (targetsAtRange < minTargets) - targetsAtRange = uint32(targets.size()); - - std::list<WorldObject*>::const_iterator itr = targets.begin(); - std::advance(itr, urand(0, targetsAtRange - 1)); - target = *itr; - targets.clear(); - targets.push_back(target); - } - - // use the same target for first and second effect - void FilterTargetsSubsequent(std::list<WorldObject*>& unitList) - { - unitList.clear(); - if (!target) - return; - - unitList.push_back(target); - } - - void HandleForceCast(SpellEffIndex /*effIndex*/) - { - GetCaster()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), TRIGGERED_FULL_MASK); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_deathbringer_blood_nova_targeting_SpellScript::FilterTargetsInitial, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_deathbringer_blood_nova_targeting_SpellScript::FilterTargetsSubsequent, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); - OnEffectHitTarget += SpellEffectFn(spell_deathbringer_blood_nova_targeting_SpellScript::HandleForceCast, EFFECT_0, SPELL_EFFECT_FORCE_CAST); - } - - WorldObject* target; - }; - - SpellScript* GetSpellScript() const override - { - return new spell_deathbringer_blood_nova_targeting_SpellScript(); - } + PrepareSpellScript(spell_deathbringer_blood_nova_targeting); + +public: + spell_deathbringer_blood_nova_targeting() + { + target = nullptr; + } + +private: + void FilterTargetsInitial(std::list<WorldObject*>& targets) + { + if (targets.empty()) + return; + + // select one random target, preferring ranged targets + uint32 targetsAtRange = 0; + uint32 const minTargets = uint32(GetCaster()->GetMap()->Is25ManRaid() ? 10 : 4); + targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), false)); + + // get target count at range + for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr, ++targetsAtRange) + if ((*itr)->GetDistance(GetCaster()) < 12.0f) + break; + + // If not enough ranged targets are present just select anyone + if (targetsAtRange < minTargets) + targetsAtRange = uint32(targets.size()); + + std::list<WorldObject*>::const_iterator itr = targets.begin(); + std::advance(itr, urand(0, targetsAtRange - 1)); + target = *itr; + targets.clear(); + targets.push_back(target); + } + + // use the same target for first and second effect + void FilterTargetsSubsequent(std::list<WorldObject*>& unitList) + { + unitList.clear(); + if (!target) + return; + + unitList.push_back(target); + } + + void HandleForceCast(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), TRIGGERED_FULL_MASK); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_deathbringer_blood_nova_targeting::FilterTargetsInitial, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_deathbringer_blood_nova_targeting::FilterTargetsSubsequent, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_deathbringer_blood_nova_targeting::HandleForceCast, EFFECT_0, SPELL_EFFECT_FORCE_CAST); + } + + WorldObject* target; }; -class spell_deathbringer_boiling_blood : public SpellScriptLoader +class spell_deathbringer_boiling_blood : public SpellScript { - public: - spell_deathbringer_boiling_blood() : SpellScriptLoader("spell_deathbringer_boiling_blood") { } - - class spell_deathbringer_boiling_blood_SpellScript : public SpellScript - { - PrepareSpellScript(spell_deathbringer_boiling_blood_SpellScript); - - bool Load() override - { - return GetCaster()->GetTypeId() == TYPEID_UNIT; - } - - void FilterTargets(std::list<WorldObject*>& targets) - { - targets.remove(GetCaster()->GetVictim()); - if (targets.empty()) - return; - - WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); - targets.clear(); - targets.push_back(target); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_deathbringer_boiling_blood_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_deathbringer_boiling_blood_SpellScript(); - } + PrepareSpellScript(spell_deathbringer_boiling_blood); + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove(GetCaster()->GetVictim()); + if (targets.empty()) + return; + + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + targets.clear(); + targets.push_back(target); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_deathbringer_boiling_blood::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } }; -class spell_deathbringer_remove_marks : public SpellScriptLoader +class spell_deathbringer_remove_marks : public SpellScript { - public: - spell_deathbringer_remove_marks() : SpellScriptLoader("spell_deathbringer_remove_marks") { } - - class spell_deathbringer_remove_marks_SpellScript : public SpellScript - { - PrepareSpellScript(spell_deathbringer_remove_marks_SpellScript); - - void HandleScript(SpellEffIndex effIndex) - { - PreventHitDefaultEffect(effIndex); - GetHitUnit()->RemoveAurasDueToSpell(uint32(GetEffectValue())); - } - - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_deathbringer_remove_marks_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_deathbringer_remove_marks_SpellScript(); - } + PrepareSpellScript(spell_deathbringer_remove_marks); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->RemoveAurasDueToSpell(uint32(GetEffectValue())); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_deathbringer_remove_marks::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } }; class achievement_ive_gone_and_made_a_mess : public AchievementCriteriaScript @@ -1401,18 +1253,23 @@ class achievement_ive_gone_and_made_a_mess : public AchievementCriteriaScript void AddSC_boss_deathbringer_saurfang() { - new boss_deathbringer_saurfang(); - new npc_high_overlord_saurfang_icc(); - new npc_muradin_bronzebeard_icc(); - new npc_saurfang_event(); - new spell_deathbringer_blood_link(); - new spell_deathbringer_blood_link_aura(); - new spell_deathbringer_blood_power(); - new spell_deathbringer_rune_of_blood(); - new spell_deathbringer_blood_beast_blood_link(); - new spell_deathbringer_blood_nova(); - new spell_deathbringer_blood_nova_targeting(); - new spell_deathbringer_boiling_blood(); - new spell_deathbringer_remove_marks(); + // Creatures + RegisterIcecrownCitadelCreatureAI(boss_deathbringer_saurfang); + RegisterIcecrownCitadelCreatureAI(npc_high_overlord_saurfang_icc); + RegisterIcecrownCitadelCreatureAI(npc_muradin_bronzebeard_icc); + RegisterIcecrownCitadelCreatureAI(npc_saurfang_event); + + // Spells + RegisterSpellScript(spell_deathbringer_blood_link); + RegisterSpellScript(spell_deathbringer_blood_link_aura); + RegisterSpellAndAuraScriptPair(spell_deathbringer_blood_power, spell_deathbringer_blood_power_aura); + RegisterSpellScript(spell_deathbringer_rune_of_blood); + RegisterSpellScript(spell_deathbringer_blood_beast_blood_link); + RegisterSpellScript(spell_deathbringer_blood_nova); + RegisterSpellScript(spell_deathbringer_blood_nova_targeting); + RegisterSpellScript(spell_deathbringer_boiling_blood); + RegisterSpellScript(spell_deathbringer_remove_marks); + + // Achievements new achievement_ive_gone_and_made_a_mess(); } |