From 1724088e0665b6105646fc42de2fcf039b27bf50 Mon Sep 17 00:00:00 2001 From: Eddy Vega <61223313+Si1ker@users.noreply.github.com> Date: Sun, 14 May 2023 16:13:42 -0600 Subject: [PATCH] fix(Scripts/HellfireCitadel): Mass struct/model update (#16264) * init * . * check codestyle (ubuntu-20.04) * ubuntu-20.04-clang-with-modules * clang --- .../rev_1684044915713162200.sql | 9 + .../BloodFurnace/blood_furnace.h | 48 +- .../BloodFurnace/boss_broggok.cpp | 15 +- .../BloodFurnace/boss_kelidan_the_breaker.cpp | 517 ++++++++-------- .../BloodFurnace/boss_the_maker.cpp | 152 ++--- .../boss_omor_the_unscarred.cpp | 201 +++--- .../boss_vazruden_the_herald.cpp | 581 ++++++++---------- .../boss_watchkeeper_gargolmar.cpp | 207 +++---- .../HellfireRamparts/hellfire_ramparts.h | 2 + .../ShatteredHalls/boss_nethekurse.cpp | 563 ++++++++--------- .../ShatteredHalls/boss_warbringer_omrogg.cpp | 377 ++++++------ .../boss_warchief_kargath_bladefist.cpp | 265 ++++---- .../ShatteredHalls/shattered_halls.h | 2 + 13 files changed, 1385 insertions(+), 1554 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1684044915713162200.sql diff --git a/data/sql/updates/pending_db_world/rev_1684044915713162200.sql b/data/sql/updates/pending_db_world/rev_1684044915713162200.sql new file mode 100644 index 000000000..38b615465 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1684044915713162200.sql @@ -0,0 +1,9 @@ +-- +DELETE FROM `spelldifficulty_dbc` WHERE `ID` IN (19130,30925,12739,30500,30495); +INSERT INTO `spelldifficulty_dbc` (`ID`, `DifficultySpellID_1`, `DifficultySpellID_2`) VALUES +(19130, 19130, 40392), +(30925, 30925, 40059), +(12739, 12739, 15472), +(30500, 30500, 35954), +(30495, 30495, 35953); + diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/blood_furnace.h b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/blood_furnace.h index 985cb7618..23fc4acce 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/blood_furnace.h +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/blood_furnace.h @@ -29,41 +29,41 @@ constexpr uint32 EncounterCount = 4; enum bloodFurnace { - DATA_THE_MAKER = 0, - DATA_BROGGOK = 1, - DATA_KELIDAN = 2, - MAX_ENCOUNTER = 3, + DATA_THE_MAKER = 0, + DATA_BROGGOK = 1, + DATA_KELIDAN = 2, + MAX_ENCOUNTER = 3, - DATA_DOOR1 = 10, - DATA_DOOR2 = 11, - DATA_DOOR3 = 12, - DATA_BROGGOK_REAR_DOOR = 13, - DATA_BROGGOK_LEVER = 14, - DATA_DOOR6 = 15, + DATA_DOOR1 = 10, + DATA_DOOR2 = 11, + DATA_DOOR3 = 12, + DATA_BROGGOK_REAR_DOOR = 13, + DATA_BROGGOK_LEVER = 14, + DATA_DOOR6 = 15, - DATA_PRISON_CELL1 = 20, - DATA_PRISON_CELL2 = 21, - DATA_PRISON_CELL3 = 22, - DATA_PRISON_CELL4 = 23, + DATA_PRISON_CELL1 = 20, + DATA_PRISON_CELL2 = 21, + DATA_PRISON_CELL3 = 22, + DATA_PRISON_CELL4 = 23, - ACTION_ACTIVATE_BROGGOK = 30, - ACTION_PREPARE_BROGGOK = 31 + ACTION_ACTIVATE_BROGGOK = 30, + ACTION_PREPARE_BROGGOK = 31 }; enum bloodFurnaceNPC { - NPC_THE_MAKER = 17381, - NPC_BROGGOK = 17380, - NPC_KELIDAN = 17377, - NPC_NASCENT_FEL_ORC = 17398, - NPC_CHANNELER = 17653 + NPC_THE_MAKER = 17381, + NPC_BROGGOK = 17380, + NPC_KELIDAN = 17377, + NPC_NASCENT_FEL_ORC = 17398, + NPC_CHANNELER = 17653 }; enum BloodFurnaceGO { - GO_BROGGOK_DOOR_FRONT = 181822, - GO_BROGGOK_DOOR_REAR = 181819, - GO_BROGGOK_LEVER = 181982 + GO_BROGGOK_DOOR_FRONT = 181822, + GO_BROGGOK_DOOR_REAR = 181819, + GO_BROGGOK_LEVER = 181982 }; template diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp index 838216b81..6b2b5b01c 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp @@ -21,14 +21,17 @@ #include "SpellScript.h" #include "blood_furnace.h" -enum eEnums +enum Say { - SAY_AGGRO = 0, + SAY_AGGRO = 0 +}; +enum Spells +{ SPELL_SLIME_SPRAY = 30913, SPELL_POISON_CLOUD = 30916, SPELL_POISON_BOLT = 30917, - SPELL_POISON = 30914, + SPELL_POISON = 30914 }; struct boss_broggok : public BossAI @@ -52,7 +55,6 @@ struct boss_broggok : public BossAI void JustSummoned(Creature* summoned) override { summons.Summon(summoned); - summoned->SetFaction(FACTION_MONSTER_2); summoned->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); summoned->CastSpell(summoned, SPELL_POISON, true, 0, 0, me->GetGUID()); @@ -80,7 +82,6 @@ struct boss_broggok : public BossAI DoCastSelf(SPELL_POISON_CLOUD); context.Repeat(20s); }); - me->SetReactState(REACT_AGGRESSIVE); me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); me->SetImmuneToAll(false); @@ -106,7 +107,6 @@ public: } } } - go->UseDoorOrButton(); return false; } @@ -121,6 +121,7 @@ class spell_broggok_poison_cloud : public AuraScript { if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell)) return false; + return true; } @@ -142,6 +143,6 @@ class spell_broggok_poison_cloud : public AuraScript void AddSC_boss_broggok() { RegisterBloodFurnaceCreatureAI(boss_broggok); - new go_broggok_lever(); RegisterSpellScript(spell_broggok_poison_cloud); + new go_broggok_lever(); } diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp index ce06c53d6..396f24ffd 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp @@ -20,15 +20,18 @@ #include "SpellAuras.h" #include "blood_furnace.h" -enum eKelidan +enum Says { SAY_WAKE = 0, SAY_ADD_AGGRO = 1, SAY_KILL = 2, SAY_NOVA = 3, - SAY_DIE = 4, + SAY_DIE = 4 +}; - // Keldian spells +enum Spells +{ + // Keldian SPELL_CORRUPTION = 30938, SPELL_EVOCATION = 30935, SPELL_FIRE_NOVA = 33132, @@ -36,23 +39,16 @@ enum eKelidan SPELL_BURNING_NOVA = 30940, SPELL_VORTEX = 37370, - // Channelers spells - SPELL_SHADOW_BOLT = 12739, - SPELL_SHADOW_BOLT_H = 15472, - SPELL_MARK_OF_SHADOW = 30937, - SPELL_CHANNELING = 39123, + // Channelers + SPELL_SHADOW_BOLT = 12739, + SPELL_MARK_OF_SHADOW = 30937, + SPELL_CHANNELING = 39123 +}; - // Events - EVENT_SPELL_VOLLEY = 1, - EVENT_SPELL_CORRUPTION = 2, - EVENT_SPELL_BURNING_NOVA = 3, - EVENT_SPELL_FIRE_NOVA = 4, - EVENT_SPELL_SHADOW_BOLT = 5, - EVENT_SPELL_MARK = 6, - - // Actions - ACTION_CHANNELER_ENGAGED = 1, - ACTION_CHANNELER_DIED = 2, +enum Actions +{ + ACTION_CHANNELER_ENGAGED = 1, + ACTION_CHANNELER_DIED = 2 }; const float ShadowmoonChannelers[5][4] = @@ -64,299 +60,276 @@ const float ShadowmoonChannelers[5][4] = {316.0f, -109.0f, -24.6f, 1.257f} }; -class boss_kelidan_the_breaker : public CreatureScript +struct boss_kelidan_the_breaker : public BossAI { -public: - boss_kelidan_the_breaker() : CreatureScript("boss_kelidan_the_breaker") + boss_kelidan_the_breaker(Creature* creature) : BossAI(creature, DATA_KELIDAN) { + scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } - struct boss_kelidan_the_breakerAI : public ScriptedAI + ObjectGuid channelers[5]; + uint32 checkTimer; + bool addYell; + + void Reset() override { - boss_kelidan_the_breakerAI(Creature* creature) : ScriptedAI(creature) + addYell = false; + checkTimer = 5000; + _Reset(); + ApplyImmunities(true); + SummonChannelers(); + me->SetReactState(REACT_PASSIVE); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetImmuneToAll(true); + if (instance) { - instance = creature->GetInstanceScript(); + instance->SetData(DATA_KELIDAN, NOT_STARTED); } + } - InstanceScript* instance; - EventMap events; - ObjectGuid channelers[5]; - uint32 checkTimer; - bool addYell; - - void Reset() override + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_WAKE); + _JustEngagedWith(); + me->InterruptNonMeleeSpells(false); + if (instance) { - addYell = false; - checkTimer = 5000; - - events.Reset(); + instance->SetData(DATA_KELIDAN, IN_PROGRESS); + } + scheduler.Schedule(1s, [this](TaskContext context) + { + DoCastAOE(SPELL_SHADOW_BOLT_VOLLEY); + context.Repeat(8s, 13s); + }).Schedule(5s, [this](TaskContext context) + { + DoCastAOE(SPELL_CORRUPTION); + context.Repeat(30s, 50s); + }).Schedule(15s, [this](TaskContext context) + { + Talk(SAY_NOVA); + ApplyImmunities(false); + me->AddAura(SPELL_BURNING_NOVA, me); ApplyImmunities(true); - SummonChannelers(); - me->SetReactState(REACT_PASSIVE); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetImmuneToAll(true); - if (instance) - instance->SetData(DATA_KELIDAN, NOT_STARTED); - } - - void JustEngagedWith(Unit* /*who*/) override - { - events.ScheduleEvent(EVENT_SPELL_VOLLEY, 1000); - events.ScheduleEvent(EVENT_SPELL_CORRUPTION, 5000); - events.ScheduleEvent(EVENT_SPELL_BURNING_NOVA, 15000); - - me->InterruptNonMeleeSpells(false); - Talk(SAY_WAKE); - - if (instance) - instance->SetData(DATA_KELIDAN, IN_PROGRESS); - } - - void KilledUnit(Unit* /*victim*/) override - { - if (urand(0, 1)) - Talk(SAY_KILL); - } - - void DoAction(int32 param) override - { - if (param == ACTION_CHANNELER_ENGAGED) + if (IsHeroic()) { - if (!addYell) - { - addYell = true; - Talk(SAY_ADD_AGGRO); - - for (uint8 i = 0; i < 5; ++i) - { - Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]); - if (channeler && !channeler->IsInCombat()) - channeler->SetInCombatWithZone(); - } - } + DoCastAOE(SPELL_VORTEX); } - else if (param == ACTION_CHANNELER_DIED) + scheduler.DelayGroup(0, 6s); + scheduler.Schedule(5s, [this](TaskContext /*context*/) { + DoCastSelf(SPELL_FIRE_NOVA, true); + }); + context.Repeat(25s, 32s); + }); + } + + void KilledUnit(Unit* /*victim*/) override + { + if (urand(0, 1)) + { + Talk(SAY_KILL); + } + } + + void DoAction(int32 param) override + { + if (param == ACTION_CHANNELER_ENGAGED) + { + if (!addYell) + { + addYell = true; + Talk(SAY_ADD_AGGRO); for (uint8 i = 0; i < 5; ++i) { Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]); - if (channeler && channeler->IsAlive()) - return; - } - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetImmuneToAll(false); - if (Unit* target = me->SelectNearestPlayer(100.0f)) - AttackStart(target); - } - } - - void CheckChannelers() - { - if (addYell) - { - if (!SelectTargetFromPlayerList(100.0f)) - EnterEvadeMode(); - return; - } - - SummonChannelers(); - for (uint8 i = 0; i < 5; ++i) - { - Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]); - if (channeler && !channeler->HasUnitState(UNIT_STATE_CASTING) && !channeler->IsInCombat()) - { - Creature* target = ObjectAccessor::GetCreature(*me, channelers[(i + 2) % 5]); - if (target) - channeler->CastSpell(target, SPELL_CHANNELING, false); + if (channeler && !channeler->IsInCombat()) + { + channeler->SetInCombatWithZone(); + } } } } - - void SummonChannelers() + else if (param == ACTION_CHANNELER_DIED) { for (uint8 i = 0; i < 5; ++i) { Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]); - if (channeler && channeler->isDead()) - { - channeler->DespawnOrUnsummon(1); - channeler = nullptr; - } - if (!channeler) - channeler = me->SummonCreature(NPC_CHANNELER, ShadowmoonChannelers[i][0], ShadowmoonChannelers[i][1], ShadowmoonChannelers[i][2], ShadowmoonChannelers[i][3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); - - channelers[i] = channeler ? channeler->GetGUID() : ObjectGuid::Empty; + if (channeler && channeler->IsAlive()) + return; } - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DIE); - if (instance) + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetImmuneToAll(false); + if (Unit* target = me->SelectNearestPlayer(100.0f)) { - // Xinef: load grid with start doors - me->GetMap()->LoadGrid(0, -111.0f); - instance->SetData(DATA_KELIDAN, DONE); - instance->HandleGameObject(instance->GetGuidData(DATA_DOOR1), true); - instance->HandleGameObject(instance->GetGuidData(DATA_DOOR6), true); + AttackStart(target); } } + } - void ApplyImmunities(bool apply) - { - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISTRACT, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_KNOCKOUT, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHACKLE, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_TURN, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, apply); - me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - { - checkTimer += diff; - if (checkTimer >= 5000) - { - checkTimer = 0; - CheckChannelers(); - if (!me->HasUnitState(UNIT_STATE_CASTING)) - me->CastSpell(me, SPELL_EVOCATION, false); - } - return; - } - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SPELL_VOLLEY: - me->CastSpell(me, SPELL_SHADOW_BOLT_VOLLEY, false); - events.RepeatEvent(urand(8000, 13000)); - break; - case EVENT_SPELL_CORRUPTION: - me->CastSpell(me, SPELL_CORRUPTION, false); - events.RepeatEvent(urand(30000, 50000)); - break; - case EVENT_SPELL_BURNING_NOVA: - Talk(SAY_NOVA); - - ApplyImmunities(false); - me->AddAura(SPELL_BURNING_NOVA, me); - ApplyImmunities(true); - - if (IsHeroic()) - DoTeleportAll(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); - - events.DelayEvents(6000, 0); - events.RepeatEvent(urand(25000, 32000)); - events.ScheduleEvent(EVENT_SPELL_FIRE_NOVA, 5000); - break; - case EVENT_SPELL_FIRE_NOVA: - me->CastSpell(me, SPELL_FIRE_NOVA, true); - break; - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void CheckChannelers() { - return GetBloodFurnaceAI(creature); + if (addYell) + { + if (!SelectTargetFromPlayerList(100.0f)) + { + EnterEvadeMode(); + } + return; + } + SummonChannelers(); + for (uint8 i = 0; i < 5; ++i) + { + Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]); + if (channeler && !channeler->HasUnitState(UNIT_STATE_CASTING) && !channeler->IsInCombat()) + { + Creature* target = ObjectAccessor::GetCreature(*me, channelers[(i + 2) % 5]); + if (target) + { + channeler->CastSpell(target, SPELL_CHANNELING, false); + } + } + } + } + + void SummonChannelers() + { + for (uint8 i = 0; i < 5; ++i) + { + Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]); + if (channeler && channeler->isDead()) + { + channeler->DespawnOrUnsummon(1); + channeler = nullptr; + } + if (!channeler) + { + channeler = me->SummonCreature(NPC_CHANNELER, ShadowmoonChannelers[i][0], ShadowmoonChannelers[i][1], ShadowmoonChannelers[i][2], ShadowmoonChannelers[i][3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000); + } + channelers[i] = channeler ? channeler->GetGUID() : ObjectGuid::Empty; + } + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DIE); + _JustDied(); + if (instance) + { + me->GetMap()->LoadGrid(0, -111.0f); + instance->SetData(DATA_KELIDAN, DONE); + instance->HandleGameObject(instance->GetGuidData(DATA_DOOR1), true); + instance->HandleGameObject(instance->GetGuidData(DATA_DOOR6), true); + } + } + + void ApplyImmunities(bool apply) + { + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISTRACT, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_KNOCKOUT, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHACKLE, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_TURN, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, apply); + me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + { + checkTimer += diff; + if (checkTimer >= 5000) + { + checkTimer = 0; + CheckChannelers(); + if (!me->HasUnitState(UNIT_STATE_CASTING)) + { + me->CastSpell(me, SPELL_EVOCATION, false); + } + } + return; + } + + scheduler.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + DoMeleeAttackIfReady(); } }; -class npc_shadowmoon_channeler : public CreatureScript +struct npc_shadowmoon_channeler : public ScriptedAI { -public: - npc_shadowmoon_channeler() : CreatureScript("npc_shadowmoon_channeler") {} + npc_shadowmoon_channeler(Creature* creature) : ScriptedAI(creature) {} - struct npc_shadowmoon_channelerAI : public ScriptedAI + Creature* GetKelidan() { - npc_shadowmoon_channelerAI(Creature* creature) : ScriptedAI(creature) {} - - EventMap events; - - void Reset() override + if (InstanceScript* instance = me->GetInstanceScript()) { - events.Reset(); + return instance->GetCreature(DATA_KELIDAN); } - - Creature* GetKelidan() - { - if (InstanceScript* instance = me->GetInstanceScript()) - return instance->GetCreature(DATA_KELIDAN); - - return nullptr; - } - - void JustEngagedWith(Unit* /*who*/) override - { - if (Creature* kelidan = GetKelidan()) - kelidan->AI()->DoAction(ACTION_CHANNELER_ENGAGED); - - me->InterruptNonMeleeSpells(false); - events.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT, urand(1200, 2400)); - events.ScheduleEvent(EVENT_SPELL_MARK, urand(5000, 6500)); - } - - void JustDied(Unit* /*killer*/) override - { - if (Creature* kelidan = GetKelidan()) - kelidan->AI()->DoAction(ACTION_CHANNELER_DIED); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SPELL_SHADOW_BOLT: - me->CastSpell(me->GetVictim(), IsHeroic() ? SPELL_SHADOW_BOLT_H : SPELL_SHADOW_BOLT, false); - events.RepeatEvent(urand(6000, 7200)); - break; - case EVENT_SPELL_MARK: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_MARK_OF_SHADOW, false); - events.RepeatEvent(urand(16000, 17500)); - break; - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetBloodFurnaceAI(creature); + return nullptr; } + + void JustEngagedWith(Unit* /*who*/) override + { + if (Creature* kelidan = GetKelidan()) + { + kelidan->AI()->DoAction(ACTION_CHANNELER_ENGAGED); + } + me->InterruptNonMeleeSpells(false); + _scheduler.Schedule(1200ms, 2400ms, [this](TaskContext context) + { + DoCastVictim(SPELL_SHADOW_BOLT); + context.Repeat(6s, 7200ms); + }).Schedule(5s, 6500ms, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_MARK_OF_SHADOW); + context.Repeat(16s, 17500ms); + }); + } + + void JustDied(Unit* /*killer*/) override + { + if (Creature* kelidan = GetKelidan()) + { + kelidan->AI()->DoAction(ACTION_CHANNELER_DIED); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _scheduler.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + DoMeleeAttackIfReady(); + } + +private: + TaskScheduler _scheduler; }; void AddSC_boss_kelidan_the_breaker() { - new boss_kelidan_the_breaker(); - new npc_shadowmoon_channeler(); + RegisterBloodFurnaceCreatureAI(boss_kelidan_the_breaker); + RegisterBloodFurnaceCreatureAI(npc_shadowmoon_channeler); } diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_the_maker.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_the_maker.cpp index efc7a5316..77bb5ef91 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_the_maker.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_the_maker.cpp @@ -19,111 +19,87 @@ #include "ScriptedCreature.h" #include "blood_furnace.h" -enum eEnums +enum Says { - SAY_AGGRO = 0, - SAY_KILL = 1, - SAY_DIE = 2, - - SPELL_EXPLODING_BREAKER = 30925, - SPELL_DOMINATION = 30923, - - EVENT_SPELL_EXPLODING = 1, - EVENT_SPELL_DOMINATION = 2 + SAY_AGGRO = 0, + SAY_KILL = 1, + SAY_DIE = 2 }; -class boss_the_maker : public CreatureScript +enum Spells { -public: - boss_the_maker() : CreatureScript("boss_the_maker") + SPELL_EXPLODING_BEAKER = 30925, + SPELL_DOMINATION = 30923 +}; + +struct boss_the_maker : public BossAI +{ + boss_the_maker(Creature* creature) : BossAI(creature, DATA_THE_MAKER) { + scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } - struct boss_the_makerAI : public ScriptedAI + void Reset() override { - boss_the_makerAI(Creature* creature) : ScriptedAI(creature) + _Reset(); + if (instance) { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - EventMap events; - - void Reset() override - { - events.Reset(); - if (!instance) - return; - instance->SetData(DATA_THE_MAKER, NOT_STARTED); instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true); } + } - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_SPELL_EXPLODING, 6000); - events.ScheduleEvent(EVENT_SPELL_DOMINATION, 120000); - - if (!instance) - return; - - instance->SetData(DATA_THE_MAKER, IN_PROGRESS); - instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), false); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER && urand(0, 1)) - Talk(SAY_KILL); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DIE); - - if (!instance) - return; - - instance->SetData(DATA_THE_MAKER, DONE); - instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true); - instance->HandleGameObject(instance->GetGuidData(DATA_DOOR3), true); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SPELL_EXPLODING: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_EXPLODING_BREAKER, false); - events.RepeatEvent(urand(7000, 11000)); - break; - case EVENT_SPELL_DOMINATION: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_DOMINATION, false); - events.RepeatEvent(120000); - break; - } - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void JustEngagedWith(Unit* /*who*/) override { - return GetBloodFurnaceAI(creature); + Talk(SAY_AGGRO); + _JustEngagedWith(); + instance->SetData(DATA_THE_MAKER, IN_PROGRESS); + instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), false); + scheduler.Schedule(6s, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_EXPLODING_BEAKER); + context.Repeat(7s, 11s); + }).Schedule(2min, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_DOMINATION); + context.Repeat(2min); + }); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER && urand(0, 1)) + { + Talk(SAY_KILL); + } + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DIE); + _JustDied(); + instance->SetData(DATA_THE_MAKER, DONE); + instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true); + instance->HandleGameObject(instance->GetGuidData(DATA_DOOR3), true); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + scheduler.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + DoMeleeAttackIfReady(); } }; void AddSC_boss_the_maker() { - new boss_the_maker(); + RegisterBloodFurnaceCreatureAI(boss_the_maker); } diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_omor_the_unscarred.cpp b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_omor_the_unscarred.cpp index 01f612a44..4abd908e3 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_omor_the_unscarred.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_omor_the_unscarred.cpp @@ -37,124 +37,111 @@ enum Spells SPELL_DEMONIC_SHIELD = 31901 }; -class boss_omor_the_unscarred : public CreatureScript +struct boss_omor_the_unscarred : public BossAI { -public: - boss_omor_the_unscarred() : CreatureScript("boss_omor_the_unscarred") { } - - struct boss_omor_the_unscarredAI : public BossAI + boss_omor_the_unscarred(Creature* creature) : BossAI(creature, DATA_OMOR_THE_UNSCARRED) { - boss_omor_the_unscarredAI(Creature* creature) : BossAI(creature, DATA_OMOR_THE_UNSCARRED) + SetCombatMovement(false); + scheduler.SetValidator([this] { - SetCombatMovement(false); + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } - scheduler.SetValidator([this] + void Reset() override + { + Talk(SAY_WIPE); + _Reset(); + _targetGUID.Clear(); + ScheduleHealthCheckEvent(21, [&]{ + DoCastSelf(SPELL_DEMONIC_SHIELD); + scheduler.Schedule(15s, [this](TaskContext context) { - return !me->HasUnitState(UNIT_STATE_CASTING); - }); - } - - void Reset() override - { - Talk(SAY_WIPE); - _Reset(); - _targetGUID.Clear(); - - ScheduleHealthCheckEvent(21, [&]{ DoCastSelf(SPELL_DEMONIC_SHIELD); - scheduler.Schedule(15s, [this](TaskContext context) - { - DoCastSelf(SPELL_DEMONIC_SHIELD); - context.Repeat(15s); - }); - }); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - _JustEngagedWith(); - - scheduler.Schedule(6s, [this](TaskContext context) - { - if (roll_chance_i(33)) - { - Talk(SAY_CURSE); - } - DoCastRandomTarget(SPELL_TREACHEROUS_AURA); - context.Repeat(12s, 18s); - }).Schedule(10s, [this](TaskContext /*context*/) - { - DoCastSelf(SPELL_SUMMON_FIENDISH_HOUND); - }).Schedule(25s, [this](TaskContext context) - { - DoCastSelf(SPELL_SUMMON_FIENDISH_HOUND); context.Repeat(15s); }); - } - - void KilledUnit(Unit*) override - { - if(!_hasSpoken) - { - _hasSpoken = true; - Talk(SAY_KILL); - } - scheduler.Schedule(6s, [this](TaskContext /*context*/) - { - _hasSpoken = false; - }); - } - - void JustSummoned(Creature* summon) override - { - Talk(SAY_SUMMON); - summons.Summon(summon); - summon->SetInCombatWithZone(); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DIE); - _JustDied(); - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - if (!me->GetVictim() || !me->isAttackReady()) - return; - - if (me->IsWithinMeleeRange(me->GetVictim())) - { - me->GetMotionMaster()->MoveChase(me->GetVictim()); - DoMeleeAttackIfReady(); - } - else - { - me->GetMotionMaster()->Clear(); - me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false); - me->resetAttackTimer(); - } - } - - private: - ObjectGuid _targetGUID; - bool _hasSpoken; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHellfireRampartsAI(creature); + }); } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + _JustEngagedWith(); + scheduler.Schedule(6s, [this](TaskContext context) + { + if (roll_chance_i(33)) + { + Talk(SAY_CURSE); + } + DoCastRandomTarget(SPELL_TREACHEROUS_AURA); + context.Repeat(12s, 18s); + }).Schedule(10s, [this](TaskContext /*context*/) + { + DoCastSelf(SPELL_SUMMON_FIENDISH_HOUND); + }).Schedule(25s, [this](TaskContext context) + { + DoCastSelf(SPELL_SUMMON_FIENDISH_HOUND); + context.Repeat(15s); + }); + } + + void KilledUnit(Unit*) override + { + if(!_hasSpoken) + { + _hasSpoken = true; + Talk(SAY_KILL); + } + scheduler.Schedule(6s, [this](TaskContext /*context*/) + { + _hasSpoken = false; + }); + } + + void JustSummoned(Creature* summon) override + { + Talk(SAY_SUMMON); + summons.Summon(summon); + summon->SetInCombatWithZone(); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DIE); + _JustDied(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + scheduler.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (!me->GetVictim() || !me->isAttackReady()) + return; + + if (me->IsWithinMeleeRange(me->GetVictim())) + { + me->GetMotionMaster()->MoveChase(me->GetVictim()); + DoMeleeAttackIfReady(); + } + else + { + me->GetMotionMaster()->Clear(); + DoCastVictim(SPELL_SHADOW_BOLT); + me->resetAttackTimer(); + } + } + +private: + ObjectGuid _targetGUID; + bool _hasSpoken; }; void AddSC_boss_omor_the_unscarred() { - new boss_omor_the_unscarred(); + RegisterHellfireRampartsCreatureAI(boss_omor_the_unscarred); } diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp index f11b60189..64a274f6a 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp @@ -21,36 +21,35 @@ enum Says { - SAY_INTRO = 0, - SAY_WIPE = 0, - SAY_AGGRO = 1, - SAY_KILL = 2, - SAY_DIE = 3, - EMOTE_NAZAN = 0 + SAY_INTRO = 0, + SAY_WIPE = 0, + SAY_AGGRO = 1, + SAY_KILL = 2, + SAY_DIE = 3, + EMOTE_NAZAN = 0 }; enum Spells { - SPELL_FIREBALL = 33793, - SPELL_SUMMON_LIQUID_FIRE = 31706, - SPELL_REVENGE = 19130, - SPELL_REVENGE_H = 40392, - SPELL_CALL_NAZAN = 30693, - SPELL_BELLOWING_ROAR = 39427, - SPELL_CONE_OF_FIRE = 30926 + SPELL_FIREBALL = 33793, + SPELL_SUMMON_LIQUID_FIRE = 31706, + SPELL_REVENGE = 19130, + SPELL_CALL_NAZAN = 30693, + SPELL_BELLOWING_ROAR = 39427, + SPELL_CONE_OF_FIRE = 30926 }; enum Misc { - ACTION_FLY_DOWN = 0, - POINT_MIDDLE = 0, - POINT_FLIGHT = 1 + ACTION_FLY_DOWN = 0, + POINT_MIDDLE = 0, + POINT_FLIGHT = 1 }; enum GroupPhase { - GROUP_PHASE_1 = 0, - GROUP_PHASE_2 = 1 + GROUP_PHASE_1 = 0, + GROUP_PHASE_2 = 1 }; const Position NazanPos[3] = @@ -60,354 +59,302 @@ const Position NazanPos[3] = {-1373.84f, 1771.57f, 111.0f, 0.0f} }; -class boss_vazruden_the_herald : public CreatureScript +struct boss_vazruden_the_herald : public BossAI { -public: - boss_vazruden_the_herald() : CreatureScript("boss_vazruden_the_herald") { } + boss_vazruden_the_herald(Creature* creature) : BossAI(creature, DATA_VAZRUDEN) {} - struct boss_vazruden_the_heraldAI : public BossAI + void Reset() override { - boss_vazruden_the_heraldAI(Creature* creature) : BossAI(creature, DATA_VAZRUDEN) - { - } + BossAI::Reset(); + me->SetVisible(true); + me->SetReactState(REACT_PASSIVE); + me->SummonCreature(NPC_HELLFIRE_SENTRY, -1372.56f, 1724.31f, 82.967f, 5.3058f); + me->SummonCreature(NPC_HELLFIRE_SENTRY, -1383.39f, 1711.82f, 82.7961f, 5.67232f); + } - void Reset() override - { - BossAI::Reset(); - me->SetVisible(true); - me->SetReactState(REACT_PASSIVE); - me->SummonCreature(NPC_HELLFIRE_SENTRY, -1372.56f, 1724.31f, 82.967f, 5.3058f); - me->SummonCreature(NPC_HELLFIRE_SENTRY, -1383.39f, 1711.82f, 82.7961f, 5.67232f); - } + void AttackStart(Unit*) override {} - void AttackStart(Unit*) override - { - } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - if (summon->GetEntry() != NPC_HELLFIRE_SENTRY) - summon->SetInCombatWithZone(); - } - - void JustDied(Unit*) override - { - instance->SetBossState(DATA_VAZRUDEN, DONE); - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE) - { - me->SetVisible(false); - me->SummonCreature(NPC_VAZRUDEN, me->GetPositionX(), me->GetPositionY(), 81.2f, 5.46f); - me->SummonCreature(NPC_NAZAN, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 5.46f); - } - } - - void SummonedCreatureDies(Creature* summon, Unit*) override - { - summons.Despawn(summon); - if (summon->GetEntry() == NPC_HELLFIRE_SENTRY && summons.size() == 0) - { - Talk(SAY_INTRO); - me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 85.0f, false); - me->setActive(true); - } - else if (summons.size() == 0) - { - me->KillSelf(); - } - } - - void SummonedCreatureDespawn(Creature* summon) override - { - summons.Despawn(summon); - if (summon->GetEntry() != NPC_HELLFIRE_SENTRY) - BossAI::EnterEvadeMode(); - } - - void SetData(uint32 type, uint32 data) override - { - if (type == 0 && data == 1) - { - summons.DoZoneInCombat(NPC_HELLFIRE_SENTRY); - } - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!me->IsVisible() && summons.size() == 0) - BossAI::EnterEvadeMode(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void JustSummoned(Creature* summon) override { - return GetHellfireRampartsAI(creature); + summons.Summon(summon); + if (summon->GetEntry() != NPC_HELLFIRE_SENTRY) + { + summon->SetInCombatWithZone(); + } + } + + void JustDied(Unit*) override + { + instance->SetBossState(DATA_VAZRUDEN, DONE); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE) + { + me->SetVisible(false); + me->SummonCreature(NPC_VAZRUDEN, me->GetPositionX(), me->GetPositionY(), 81.2f, 5.46f); + me->SummonCreature(NPC_NAZAN, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 5.46f); + } + } + + void SummonedCreatureDies(Creature* summon, Unit*) override + { + summons.Despawn(summon); + if (summon->GetEntry() == NPC_HELLFIRE_SENTRY && summons.size() == 0) + { + Talk(SAY_INTRO); + me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 85.0f, false); + me->setActive(true); + } + else if (summons.size() == 0) + { + me->KillSelf(); + } + } + + void SummonedCreatureDespawn(Creature* summon) override + { + summons.Despawn(summon); + if (summon->GetEntry() != NPC_HELLFIRE_SENTRY) + { + BossAI::EnterEvadeMode(); + } + } + + void SetData(uint32 type, uint32 data) override + { + if (type == 0 && data == 1) + { + summons.DoZoneInCombat(NPC_HELLFIRE_SENTRY); + } + } + + void UpdateAI(uint32 /*diff*/) override + { + if (!me->IsVisible() && summons.size() == 0) + { + BossAI::EnterEvadeMode(); + } } }; -class boss_nazan : public CreatureScript +struct boss_nazan : public BossAI { -public: - boss_nazan() : CreatureScript("boss_nazan") { } - - struct boss_nazanAI : public BossAI + boss_nazan(Creature* creature) : BossAI(creature, DATA_VAZRUDEN) { - boss_nazanAI(Creature* creature) : BossAI(creature, DATA_VAZRUDEN) + scheduler.SetValidator([this] { - scheduler.SetValidator([this] + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + void Reset() override + { + me->SetCanFly(true); + me->SetDisableGravity(true); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + me->DespawnOrUnsummon(1); + } + + void JustEngagedWith(Unit*) override + { + scheduler.CancelGroup(GROUP_PHASE_2); + scheduler.Schedule(5ms, GROUP_PHASE_1, [this](TaskContext context) + { + me->GetMotionMaster()->MovePoint(POINT_FLIGHT, NazanPos[urand(0, 2)], false); + scheduler.DelayAll(7s); + context.Repeat(30s); + }).Schedule(5s, GROUP_PHASE_1, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_FIREBALL); + context.Repeat(4s, 6s); + }); + } + + void AttackStart(Unit* who) override + { + if (me->IsLevitating()) + { + me->Attack(who, true); + } + else + { + ScriptedAI::AttackStart(who); + } + } + + void DoAction(int32 param) override + { + if (param == ACTION_FLY_DOWN) + { + Talk(EMOTE_NAZAN); + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 81.2f, false); + } + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE) + { + me->SetCanFly(false); + me->SetDisableGravity(false); + me->SetReactState(REACT_AGGRESSIVE); + scheduler.CancelGroup(GROUP_PHASE_1); + me->GetMotionMaster()->MoveChase(me->GetVictim()); + scheduler.Schedule(5s, GROUP_PHASE_2, [this](TaskContext context) { - return !me->HasUnitState(UNIT_STATE_CASTING); - }); - } - - void Reset() override - { - me->SetCanFly(true); - me->SetDisableGravity(true); - events.Reset(); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - me->DespawnOrUnsummon(1); - } - - void JustEngagedWith(Unit*) override - { - scheduler.CancelGroup(GROUP_PHASE_2); - scheduler.Schedule(5ms, GROUP_PHASE_1, [this](TaskContext context) - { - me->GetMotionMaster()->MovePoint(POINT_FLIGHT, NazanPos[urand(0, 2)], false); - scheduler.DelayAll(7s); - context.Repeat(30s); - }).Schedule(5s, GROUP_PHASE_1, [this](TaskContext context) + DoCastVictim(SPELL_CONE_OF_FIRE); + context.Repeat(12s); + }).Schedule(6s, GROUP_PHASE_2, [this](TaskContext context) { DoCastRandomTarget(SPELL_FIREBALL); context.Repeat(4s, 6s); }); - } - - void AttackStart(Unit* who) override - { - if (me->IsLevitating()) - me->Attack(who, true); - else - ScriptedAI::AttackStart(who); - } - - void DoAction(int32 param) override - { - if (param == ACTION_FLY_DOWN) + if (IsHeroic()) { - Talk(EMOTE_NAZAN); - events.Reset(); - me->SetReactState(REACT_PASSIVE); - me->InterruptNonMeleeSpells(true); - me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 81.2f, false); - } - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE) - { - me->SetCanFly(false); - me->SetDisableGravity(false); - me->SetReactState(REACT_AGGRESSIVE); - scheduler.CancelGroup(GROUP_PHASE_1); - me->GetMotionMaster()->MoveChase(me->GetVictim()); - - scheduler.Schedule(5s, GROUP_PHASE_2, [this](TaskContext context) + scheduler.Schedule(10s, GROUP_PHASE_2, [this](TaskContext context) { - DoCastVictim(SPELL_CONE_OF_FIRE); - context.Repeat(12s); - }).Schedule(6s, GROUP_PHASE_2, [this](TaskContext context) - { - DoCastRandomTarget(SPELL_FIREBALL); - context.Repeat(4s, 6s); + DoCastSelf(SPELL_BELLOWING_ROAR); + context.Repeat(30s); }); - if (IsHeroic()) - { - scheduler.Schedule(10s, GROUP_PHASE_2, [this](TaskContext context) - { - DoCastSelf(SPELL_BELLOWING_ROAR); - context.Repeat(30s); - }); - } } } - - void UpdateAI(uint32 /*diff*/) override - { - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - if (!me->IsLevitating()) - DoMeleeAttackIfReady(); - } - - private: - EventMap events; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHellfireRampartsAI(creature); } -}; -class boss_vazruden : public CreatureScript -{ -public: - boss_vazruden() : CreatureScript("boss_vazruden") { } - - struct boss_vazrudenAI : public BossAI + void UpdateAI(uint32 /*diff*/) override { - boss_vazrudenAI(Creature* creature) : BossAI(creature, DATA_VAZRUDEN) - { - scheduler.SetValidator([this] - { - return !me->HasUnitState(UNIT_STATE_CASTING); - }); - } + if (!UpdateVictim()) + return; - void Reset() override - { - events.Reset(); - _nazanCalled = false; - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - Talk(SAY_WIPE); - me->DespawnOrUnsummon(1); - } - - void JustEngagedWith(Unit*) override - { - scheduler.Schedule(5s, [this](TaskContext /*context*/) - { - Talk(SAY_AGGRO); - }).Schedule(4s, [this](TaskContext context) - { - DoCastVictim(DUNGEON_MODE(SPELL_REVENGE, SPELL_REVENGE_H)); - context.Repeat(6s); - }); - } - - void KilledUnit(Unit*) override - { - if (!_hasSpoken) - { - _hasSpoken = true; - Talk(SAY_KILL); - } - scheduler.Schedule(6s, [this](TaskContext /*context*/) - { - _hasSpoken = false; - }); - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override - { - if (!_nazanCalled && me->HealthBelowPctDamaged(35, damage)) - { - _nazanCalled = true; - me->CastSpell(me, SPELL_CALL_NAZAN, true); - } - } - - void JustDied(Unit*) override - { - Talk(SAY_DIE); - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!UpdateVictim()) - return; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + if (!me->IsLevitating()) DoMeleeAttackIfReady(); - } - - private: - EventMap events; - bool _hasSpoken; - bool _nazanCalled; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHellfireRampartsAI(creature); } }; -class spell_vazruden_fireball : public SpellScriptLoader +struct boss_vazruden : public BossAI { -public: - spell_vazruden_fireball() : SpellScriptLoader("spell_vazruden_fireball") { } - - class spell_vazruden_fireball_SpellScript : public SpellScript + boss_vazruden(Creature* creature) : BossAI(creature, DATA_VAZRUDEN) { - PrepareSpellScript(spell_vazruden_fireball_SpellScript); - - void HandleScriptEffect(SpellEffIndex /*effIndex*/) + scheduler.SetValidator([this] { - if (Unit* target = GetHitUnit()) - target->CastSpell(target, SPELL_SUMMON_LIQUID_FIRE, true); - } + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_vazruden_fireball_SpellScript::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override + void Reset() override { - return new spell_vazruden_fireball_SpellScript(); + _nazanCalled = false; + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + Talk(SAY_WIPE); + me->DespawnOrUnsummon(1); + } + + void JustEngagedWith(Unit*) override + { + scheduler.Schedule(5s, [this](TaskContext /*context*/) + { + Talk(SAY_AGGRO); + }).Schedule(4s, [this](TaskContext context) + { + DoCastVictim(SPELL_REVENGE); + context.Repeat(6s); + }); + } + + void KilledUnit(Unit*) override + { + if (!_hasSpoken) + { + _hasSpoken = true; + Talk(SAY_KILL); + } + scheduler.Schedule(6s, [this](TaskContext /*context*/) + { + _hasSpoken = false; + }); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override + { + if (!_nazanCalled && me->HealthBelowPctDamaged(35, damage)) + { + _nazanCalled = true; + DoCastSelf(SPELL_CALL_NAZAN, true); + } + } + + void JustDied(Unit*) override + { + Talk(SAY_DIE); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + scheduler.Update(diff); + DoMeleeAttackIfReady(); + } + +private: + bool _hasSpoken; + bool _nazanCalled; +}; + +class spell_vazruden_fireball : public SpellScript +{ + PrepareSpellScript(spell_vazruden_fireball); + + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + { + target->CastSpell(target, SPELL_SUMMON_LIQUID_FIRE, true); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_vazruden_fireball::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); } }; -class spell_vazruden_call_nazan : public SpellScriptLoader +class spell_vazruden_call_nazan : public SpellScript { -public: - spell_vazruden_call_nazan() : SpellScriptLoader("spell_vazruden_call_nazan") { } + PrepareSpellScript(spell_vazruden_call_nazan); - class spell_vazruden_call_nazan_SpellScript : public SpellScript + void HandleScriptEffect(SpellEffIndex /*effIndex*/) { - PrepareSpellScript(spell_vazruden_call_nazan_SpellScript); - - void HandleScriptEffect(SpellEffIndex /*effIndex*/) + if (Unit* target = GetHitUnit()) { - if (Unit* target = GetHitUnit()) - target->GetAI()->DoAction(ACTION_FLY_DOWN); + target->GetAI()->DoAction(ACTION_FLY_DOWN); } + } - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_vazruden_call_nazan_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override + void Register() override { - return new spell_vazruden_call_nazan_SpellScript(); + OnEffectHitTarget += SpellEffectFn(spell_vazruden_call_nazan::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; void AddSC_boss_vazruden_the_herald() { - new boss_vazruden_the_herald(); - new boss_vazruden(); - new boss_nazan(); - new spell_vazruden_fireball(); - new spell_vazruden_call_nazan(); + RegisterHellfireRampartsCreatureAI(boss_vazruden_the_herald); + RegisterHellfireRampartsCreatureAI(boss_vazruden); + RegisterHellfireRampartsCreatureAI(boss_nazan); + RegisterSpellScript(spell_vazruden_fireball); + RegisterSpellScript(spell_vazruden_call_nazan); } diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp index bb3a374d3..4718cc6fb 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp @@ -41,121 +41,110 @@ enum Misc NPC_HELLFIRE_WATCHER = 17309 }; -class boss_watchkeeper_gargolmar : public CreatureScript +struct boss_watchkeeper_gargolmar : public BossAI { -public: - boss_watchkeeper_gargolmar() : CreatureScript("boss_watchkeeper_gargolmar") { } - - struct boss_watchkeeper_gargolmarAI : public BossAI + boss_watchkeeper_gargolmar(Creature* creature) : BossAI(creature, DATA_WATCHKEEPER_GARGOLMAR) { - boss_watchkeeper_gargolmarAI(Creature* creature) : BossAI(creature, DATA_WATCHKEEPER_GARGOLMAR) + _taunted = false; + scheduler.SetValidator([this] { - _taunted = false; - - scheduler.SetValidator([this] - { - return !me->HasUnitState(UNIT_STATE_CASTING); - }); - } - - void Reset() override - { - _Reset(); - - ScheduleHealthCheckEvent(50, [&]{ - Talk(SAY_HEAL); - std::list clist; - me->GetCreaturesWithEntryInRange(clist, 100.0f, NPC_HELLFIRE_WATCHER); - for (std::list::const_iterator itr = clist.begin(); itr != clist.end(); ++itr) - (*itr)->AI()->SetData(NPC_HELLFIRE_WATCHER, 0); - }); - - ScheduleHealthCheckEvent(20, [&]{ - DoCastSelf(SPELL_RETALIATION); - scheduler.Schedule(30s, [this](TaskContext context) - { - DoCastSelf(SPELL_RETALIATION); - context.Repeat(30s); - }); - }); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - _JustEngagedWith(); - - scheduler.Schedule(5s, [this] (TaskContext context) - { - DoCastVictim(SPELL_MORTAL_WOUND); - context.Repeat(8s); - }).Schedule(3s, [this](TaskContext context) - { - Talk(SAY_SURGE); - if(Unit* target = SelectTarget((SelectTargetMethod::MinDistance), 0)) - { - me->CastSpell(target, SPELL_SURGE); - } - context.Repeat(11s); - }); - } - - void MoveInLineOfSight(Unit* who) override - { - if (!_taunted) - { - if (who->GetTypeId() == TYPEID_PLAYER) - { - _taunted = true; - Talk(SAY_TAUNT); - } - } - - BossAI::MoveInLineOfSight(who); - } - - void KilledUnit(Unit*) override - { - if (!_hasSpoken) - { - _hasSpoken = true; - Talk(SAY_KILL); - } - scheduler.Schedule(6s, [this](TaskContext /*context*/) - { - _hasSpoken = false; - }); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DIE); - _JustDied(); - } - - void UpdateAI(uint32 /*diff*/) override - { - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - DoMeleeAttackIfReady(); - } - - private: - bool _taunted; - bool _hasSpoken; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetHellfireRampartsAI(creature); + return !me->HasUnitState(UNIT_STATE_CASTING); + }); } + + void Reset() override + { + _Reset(); + ScheduleHealthCheckEvent(50, [&]{ + Talk(SAY_HEAL); + std::list clist; + me->GetCreaturesWithEntryInRange(clist, 100.0f, NPC_HELLFIRE_WATCHER); + for (std::list::const_iterator itr = clist.begin(); itr != clist.end(); ++itr) + { + (*itr)->AI()->SetData(NPC_HELLFIRE_WATCHER, 0); + } + }); + + ScheduleHealthCheckEvent(20, [&]{ + DoCastSelf(SPELL_RETALIATION); + scheduler.Schedule(30s, [this](TaskContext context) + { + DoCastSelf(SPELL_RETALIATION); + context.Repeat(30s); + }); + }); + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + _JustEngagedWith(); + scheduler.Schedule(5s, [this] (TaskContext context) + { + DoCastVictim(SPELL_MORTAL_WOUND); + context.Repeat(8s); + }).Schedule(3s, [this](TaskContext context) + { + Talk(SAY_SURGE); + if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0)) + { + me->CastSpell(target, SPELL_SURGE); + } + context.Repeat(11s); + }); + } + + void MoveInLineOfSight(Unit* who) override + { + if (!_taunted) + { + if (who->GetTypeId() == TYPEID_PLAYER) + { + _taunted = true; + Talk(SAY_TAUNT); + } + } + BossAI::MoveInLineOfSight(who); + } + + void KilledUnit(Unit*) override + { + if (!_hasSpoken) + { + _hasSpoken = true; + Talk(SAY_KILL); + } + scheduler.Schedule(6s, [this](TaskContext /*context*/) + { + _hasSpoken = false; + }); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DIE); + _JustDied(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + scheduler.Update(diff); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + DoMeleeAttackIfReady(); + } + +private: + bool _taunted; + bool _hasSpoken; + }; void AddSC_boss_watchkeeper_gargolmar() { - new boss_watchkeeper_gargolmar(); + RegisterHellfireRampartsCreatureAI(boss_watchkeeper_gargolmar); } diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/hellfire_ramparts.h b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/hellfire_ramparts.h index 35c71f723..0f6109880 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/hellfire_ramparts.h +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/hellfire_ramparts.h @@ -52,4 +52,6 @@ inline AI* GetHellfireRampartsAI(T* obj) return GetInstanceAI(obj, HellfireRampartsScriptName); } +#define RegisterHellfireRampartsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetHellfireRampartsAI) + #endif diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp index f74bb1aa3..606abfbdb 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp @@ -20,7 +20,7 @@ #include "ScriptedCreature.h" #include "shattered_halls.h" -enum eGrandWarlockNethekurse +enum Says { SAY_INTRO = 0, SAY_INTRO_2 = 1, @@ -30,41 +30,42 @@ enum eGrandWarlockNethekurse SAY_SHADOW_FISSURE = 5, SAY_DEATH_COIL = 6, SAY_SLAY = 7, - SAY_DIE = 8, + SAY_DIE = 8 +}; - SPELL_DEATH_COIL_N = 30500, - SPELL_DEATH_COIL_H = 35954, +enum Spells +{ + SPELL_DEATH_COIL = 30500, SPELL_DARK_SPIN = 30502, SPELL_SHADOW_FISSURE = 30496, - SPELL_SHADOW_CLEAVE_N = 30495, - SPELL_SHADOW_SLAM_H = 35953, + SPELL_SHADOW_CLEAVE = 30495, - // Spells used exclusively in RP SPELL_SHADOW_SEAR = 30735, - SPELL_DEATH_COIL = 30741, - SPELL_SHADOW_FISSURE_RP = 30745, + SPELL_DEATH_COIL_RP = 30741, + SPELL_SHADOW_FISSURE_RP = 30745 +}; +enum Events +{ EVENT_INTRO = 1, EVENT_START_ATTACK = 2, EVENT_STAGE_NONE = 0, EVENT_STAGE_INTRO = 1, EVENT_STAGE_TAUNT = 2, - EVENT_STAGE_MAIN = 3, - - SETDATA_DATA = 1, - SETDATA_PEON_AGGRO = 1, - SETDATA_PEON_DEATH = 2, + EVENT_STAGE_MAIN = 3 }; -enum Creatures +enum Data { - NPC_PEON = 17083 + SETDATA_DATA = 1, + SETDATA_PEON_AGGRO = 1, + SETDATA_PEON_DEATH = 2 }; enum Groups { - GROUP_RP = 0, + GROUP_RP = 0 }; enum Actions @@ -74,336 +75,306 @@ enum Actions ACTION_START_COMBAT = 2, }; -// ######################################################## -// Grand Warlock Nethekurse -// ######################################################## - float NethekurseIntroPath[4][3] = { - {184.78966f, 290.3699f, -8.18139f}, + {184.78966f, 290.3699f, -8.18139f}, {178.51125f, 278.779022f, -8.183065f}, - {171.82281f, 289.97687f, -8.185595f}, - {178.51125f, 287.97794f, -8.183065f} + {171.82281f, 289.97687f, -8.185595f}, + {178.51125f, 287.97794f, -8.183065f} }; -class boss_grand_warlock_nethekurse : public CreatureScript +struct boss_grand_warlock_nethekurse : public BossAI { -public: - boss_grand_warlock_nethekurse() : CreatureScript("boss_grand_warlock_nethekurse") { } - - struct boss_grand_warlock_nethekurseAI : public BossAI + boss_grand_warlock_nethekurse(Creature* creature) : BossAI(creature, DATA_NETHEKURSE) { - boss_grand_warlock_nethekurseAI(Creature* creature) : BossAI(creature, DATA_NETHEKURSE) + scheduler.SetValidator([this] { - scheduler.SetValidator([this] - { - return !me->HasUnitState(UNIT_STATE_CASTING); - }); - } + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } - EventMap events2; - void Reset() override + EventMap events2; + + void Reset() override + { + EventStage = EVENT_STAGE_NONE; + _Reset(); + events2.Reset(); + ScheduleHealthCheckEvent(25, [&] { + DoCastSelf(SPELL_DARK_SPIN); + }); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DIE); + _JustDied(); + } + + void SetData(uint32 data, uint32 value) override + { + if (data != SETDATA_DATA) + return; + + switch (value) { - EventStage = EVENT_STAGE_NONE; - _Reset(); - events2.Reset(); + case SETDATA_PEON_AGGRO: + if (PeonEngagedCount >= 4) + return; - ScheduleHealthCheckEvent(25, [&] { - DoCastSelf(SPELL_DARK_SPIN); - }); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DIE); - _JustDied(); - } - - void SetData(uint32 data, uint32 value) override - { - if (data != SETDATA_DATA) - return; - - switch (value) - { - case SETDATA_PEON_AGGRO: - if (PeonEngagedCount >= 4) - return; - - if (EventStage < EVENT_STAGE_TAUNT) - { - Talk(SAY_PEON_ATTACKED); - } - break; - case SETDATA_PEON_DEATH: - if (PeonKilledCount >= 4) - return; - - if (EventStage < EVENT_STAGE_TAUNT) - { - PeonDieRP(); - } - if (++PeonKilledCount == 4) - DoAction(ACTION_CANCEL_INTRO); - break; - } - } - - void PeonDieRP() - { - me->GetMotionMaster()->Clear(); - me->SetFacingTo(4.572762489318847656f); - scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext /*context*/) - { - me->HandleEmoteCommand(EMOTE_ONESHOT_APPLAUD); - Talk(SAY_PEON_DIES); - }); - } - - void AttackStart(Unit* who) override - { - if (EventStage < EVENT_STAGE_MAIN) - return; - - if (me->Attack(who, true)) - { - DoStartMovement(who); - CombatEventScheduler(); - } - } - - void CombatEventScheduler() - { - scheduler.Schedule(12150ms, 19850ms, [this](TaskContext context) - { - if (me->HealthBelowPct(90)) + if (EventStage < EVENT_STAGE_TAUNT) { - DoCastRandomTarget(DUNGEON_MODE(SPELL_DEATH_COIL_N, SPELL_DEATH_COIL_H), 0, 30.0f, true); + Talk(SAY_PEON_ATTACKED); } - context.Repeat(); - }).Schedule(8100ms, 17300ms, [this](TaskContext context) - { - DoCastRandomTarget(SPELL_SHADOW_FISSURE, 0, 60.0f, true); - context.Repeat(8450ms, 9450ms); - }).Schedule(10950ms, 21850ms, [this](TaskContext context) - { - DoCastVictim(DUNGEON_MODE(SPELL_SHADOW_CLEAVE_N, SPELL_SHADOW_SLAM_H)); - context.Repeat(1200ms, 23900ms); - }); - } + break; + case SETDATA_PEON_DEATH: + if (PeonKilledCount >= 4) + return; - void MoveInLineOfSight(Unit* /*who*/) override - { - if (EventStage == EVENT_STAGE_NONE) - { - if (me->SelectNearestPlayer(30.0f)) + if (EventStage < EVENT_STAGE_TAUNT) + { + PeonDieRP(); + } + if (++PeonKilledCount == 4) { DoAction(ACTION_CANCEL_INTRO); } - } + break; } + } - void IntroRP() + void PeonDieRP() + { + me->GetMotionMaster()->Clear(); + me->SetFacingTo(4.572762489318847656f); + scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext /*context*/) { - scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext context) + me->HandleEmoteCommand(EMOTE_ONESHOT_APPLAUD); + Talk(SAY_PEON_DIES); + }); + } + + void AttackStart(Unit* who) override + { + if (EventStage < EVENT_STAGE_MAIN) + return; + + if (me->Attack(who, true)) + { + DoStartMovement(who); + CombatEventScheduler(); + } + } + + void CombatEventScheduler() + { + scheduler.Schedule(12150ms, 19850ms, [this](TaskContext context) + { + if (me->HealthBelowPct(90)) { - me->GetMotionMaster()->Clear(); - scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext /*context*/) - { - uint32 choicelocation = urand(1, 3); - me->GetMotionMaster()->MoveIdle(); - me->GetMotionMaster()->MovePoint(0, NethekurseIntroPath[choicelocation][0], NethekurseIntroPath[choicelocation][1], NethekurseIntroPath[choicelocation][2]); - scheduler.Schedule(2500ms, GROUP_RP, [this, choicelocation](TaskContext /*context*/) - { - CastRandomPeonSpell(choicelocation); - }); - }); - context.Repeat(16400ms, 28500ms); - }); - } - - void JustEngagedWith(Unit* /*who*/) override + DoCastRandomTarget(SPELL_DEATH_COIL, 0, 30.0f, true); + } + context.Repeat(); + }).Schedule(8100ms, 17300ms, [this](TaskContext context) { - _JustEngagedWith(); - if (EventStage == EVENT_STAGE_NONE) + DoCastRandomTarget(SPELL_SHADOW_FISSURE, 0, 60.0f, true); + context.Repeat(8450ms, 9450ms); + }).Schedule(10950ms, 21850ms, [this](TaskContext context) + { + DoCastVictim(SPELL_SHADOW_CLEAVE); + context.Repeat(1200ms, 23900ms); + }); + } + + void MoveInLineOfSight(Unit* /*who*/) override + { + if (EventStage == EVENT_STAGE_NONE) + { + if (me->SelectNearestPlayer(30.0f)) { DoAction(ACTION_CANCEL_INTRO); - CombatEventScheduler(); } } + } - void CastRandomPeonSpell(uint32 choice) + void IntroRP() + { + scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext context) { - if (choice == 1) + me->GetMotionMaster()->Clear(); + scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext /*context*/) { - Talk(SAY_DEATH_COIL); - me->CastSpell(me, SPELL_DEATH_COIL, false); - } - else if (choice == 2) - { - Talk(SAY_SHADOW_FISSURE); - me->CastSpell(me, SPELL_SHADOW_FISSURE_RP, false); - } - else if (choice == 3) - { - Talk(SAY_SHADOW_SEAR); - me->CastSpell(me, SPELL_SHADOW_SEAR, false); - } + uint32 choicelocation = urand(1, 3); + me->GetMotionMaster()->MoveIdle(); + me->GetMotionMaster()->MovePoint(0, NethekurseIntroPath[choicelocation][0], NethekurseIntroPath[choicelocation][1], NethekurseIntroPath[choicelocation][2]); + scheduler.Schedule(2500ms, GROUP_RP, [this, choicelocation](TaskContext /*context*/) + { + CastRandomPeonSpell(choicelocation); + }); + }); + context.Repeat(16400ms, 28500ms); + }); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + if (EventStage == EVENT_STAGE_NONE) + { + DoAction(ACTION_CANCEL_INTRO); + CombatEventScheduler(); } + } - void KilledUnit(Unit* /*victim*/) override + void CastRandomPeonSpell(uint32 choice) + { + if (choice == 1) { - Talk(SAY_SLAY); + Talk(SAY_DEATH_COIL); + me->CastSpell(me, SPELL_DEATH_COIL_RP, false); } - - void DoAction(int32 action) override + else if (choice == 2) { - if (action == ACTION_CANCEL_INTRO) - { - introDone = true; - scheduler.CancelGroup(GROUP_RP); - events2.ScheduleEvent(EVENT_START_ATTACK, 1000); - instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS); - me->SetInCombatWithZone(); - Talk(SAY_INTRO_2); - me->SetHomePosition(NethekurseIntroPath[3][0], NethekurseIntroPath[3][1], NethekurseIntroPath[3][2], 4.572762489318847656f); - me->RemoveUnitFlag(UNIT_FLAG_NOT_ATTACKABLE_1); - return; - } + Talk(SAY_SHADOW_FISSURE); + me->CastSpell(me, SPELL_SHADOW_FISSURE_RP, false); + } + else if (choice == 3) + { + Talk(SAY_SHADOW_SEAR); + me->CastSpell(me, SPELL_SHADOW_SEAR, false); + } + } - if (action != ACTION_START_INTRO) - { - return; - } + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_SLAY); + } - if (ATreached == true) - { - return; - } - - ATreached = true; - me->SetUnitFlag(UNIT_FLAG_NOT_ATTACKABLE_1); - events2.ScheduleEvent(EVENT_INTRO, 90000); - Talk(SAY_INTRO); - EventStage = EVENT_STAGE_INTRO; + void DoAction(int32 action) override + { + if (action == ACTION_CANCEL_INTRO) + { + introDone = true; + scheduler.CancelGroup(GROUP_RP); + events2.ScheduleEvent(EVENT_START_ATTACK, 1000); instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS); me->SetInCombatWithZone(); - IntroRP(); + Talk(SAY_INTRO_2); + me->SetHomePosition(NethekurseIntroPath[3][0], NethekurseIntroPath[3][1], NethekurseIntroPath[3][2], 4.572762489318847656f); + me->RemoveUnitFlag(UNIT_FLAG_NOT_ATTACKABLE_1); + return; } - void UpdateAI(uint32 diff) override - { - events2.Update(diff); - scheduler.Update(diff); - uint32 eventId = events2.ExecuteEvent(); + if (action != ACTION_START_INTRO) + return; - if (EventStage < EVENT_STAGE_MAIN && instance->GetBossState(DATA_NETHEKURSE) == IN_PROGRESS) + if (ATreached == true) + return; + + ATreached = true; + me->SetUnitFlag(UNIT_FLAG_NOT_ATTACKABLE_1); + events2.ScheduleEvent(EVENT_INTRO, 90000); + Talk(SAY_INTRO); + EventStage = EVENT_STAGE_INTRO; + instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS); + me->SetInCombatWithZone(); + IntroRP(); + } + + void UpdateAI(uint32 diff) override + { + events2.Update(diff); + scheduler.Update(diff); + uint32 eventId = events2.ExecuteEvent(); + if (EventStage < EVENT_STAGE_MAIN && instance->GetBossState(DATA_NETHEKURSE) == IN_PROGRESS) + { + if (eventId == EVENT_INTRO) { - if (eventId == EVENT_INTRO) - { - EventStage = EVENT_STAGE_TAUNT; - } - else if (eventId == EVENT_START_ATTACK) - { - EventStage = EVENT_STAGE_MAIN; - if (Unit* target = me->SelectNearestPlayer(50.0f)) - AttackStart(target); - DoAction(ACTION_CANCEL_INTRO); - return; - } + EventStage = EVENT_STAGE_TAUNT; } - - if (!UpdateVictim()) - return; - - if (EventStage < EVENT_STAGE_MAIN || me->HasUnitState(UNIT_STATE_CASTING)) - return; - - if (!me->HealthBelowPct(25)) - DoMeleeAttackIfReady(); - } - - private: - uint8 PeonEngagedCount = 0; - uint8 PeonKilledCount = 0; - uint8 EventStage; - bool introDone; - bool ATreached = false; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetShatteredHallsAI(creature); - } -}; - -class spell_tsh_shadow_sear : public SpellScriptLoader -{ -public: - spell_tsh_shadow_sear() : SpellScriptLoader("spell_tsh_shadow_sear") { } - - class spell_tsh_shadow_sear_AuraScript : public AuraScript - { - PrepareAuraScript(spell_tsh_shadow_sear_AuraScript); - - void CalculateDamageAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) - { - amount = 0; - } - - void Register() override - { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_tsh_shadow_sear_AuraScript::CalculateDamageAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); - } - }; - - AuraScript* GetAuraScript() const override - { - return new spell_tsh_shadow_sear_AuraScript(); - } -}; - -class spell_tsh_shadow_bolt : public SpellScriptLoader -{ -public: - spell_tsh_shadow_bolt() : SpellScriptLoader("spell_tsh_shadow_bolt") { } - - class spell_tsh_shadow_bolt_SpellScript : public SpellScript - { - PrepareSpellScript(spell_tsh_shadow_bolt_SpellScript); - - void SelectRandomPlayer(WorldObject*& target) - { - if (Creature* caster = GetCaster()->ToCreature()) + else if (eventId == EVENT_START_ATTACK) { - std::list playerList; - Map::PlayerList const& players = caster->GetMap()->GetPlayers(); - for (auto itr = players.begin(); itr != players.end(); ++itr) - if (Player* player = itr->GetSource()->ToPlayer()) - if (player->IsWithinDist(caster, 100.0f) && player->IsAlive()) - playerList.push_back(player); - - if (!playerList.empty()) - target = Acore::Containers::SelectRandomContainerElement(playerList); + EventStage = EVENT_STAGE_MAIN; + if (Unit* target = me->SelectNearestPlayer(50.0f)) + { + AttackStart(target); + } + DoAction(ACTION_CANCEL_INTRO); + return; } } - void Register() override - { - OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_tsh_shadow_bolt_SpellScript::SelectRandomPlayer, EFFECT_0, TARGET_UNIT_TARGET_ENEMY); - } - }; + if (!UpdateVictim()) + return; - SpellScript* GetSpellScript() const override + if (EventStage < EVENT_STAGE_MAIN || me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (!me->HealthBelowPct(25)) + DoMeleeAttackIfReady(); + } + +private: + uint8 PeonEngagedCount = 0; + uint8 PeonKilledCount = 0; + uint8 EventStage; + bool introDone; + bool ATreached = false; +}; + +class spell_tsh_shadow_sear : public AuraScript +{ + PrepareAuraScript(spell_tsh_shadow_sear); + + void CalculateDamageAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) { - return new spell_tsh_shadow_bolt_SpellScript(); + amount = 0; + } + + void Register() override + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_tsh_shadow_sear::CalculateDamageAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); } }; + +class spell_tsh_shadow_bolt : public SpellScript +{ + PrepareSpellScript(spell_tsh_shadow_bolt); + + void SelectRandomPlayer(WorldObject*& target) + { + if (Creature* caster = GetCaster()->ToCreature()) + { + std::list playerList; + Map::PlayerList const& players = caster->GetMap()->GetPlayers(); + for (auto itr = players.begin(); itr != players.end(); ++itr) + { + if (Player* player = itr->GetSource()->ToPlayer()) + { + if (player->IsWithinDist(caster, 100.0f) && player->IsAlive()) + { + playerList.push_back(player); + } + } + } + + if (!playerList.empty()) + { + target = Acore::Containers::SelectRandomContainerElement(playerList); + } + } + } + + void Register() override + { + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_tsh_shadow_bolt::SelectRandomPlayer, EFFECT_0, TARGET_UNIT_TARGET_ENEMY); + } +}; + class at_rp_nethekurse : public AreaTriggerScript { public: - at_rp_nethekurse() : AreaTriggerScript - ("at_rp_nethekurse") { } + at_rp_nethekurse() : AreaTriggerScript("at_rp_nethekurse") { } bool OnTrigger(Player* player, AreaTrigger const* /*at*/) override { @@ -427,8 +398,8 @@ public: void AddSC_boss_grand_warlock_nethekurse() { - new boss_grand_warlock_nethekurse(); - new spell_tsh_shadow_sear(); - new spell_tsh_shadow_bolt(); + RegisterShatteredHallsCreatureAI(boss_grand_warlock_nethekurse); + RegisterSpellScript(spell_tsh_shadow_sear); + RegisterSpellScript(spell_tsh_shadow_bolt); new at_rp_nethekurse(); } diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp index 9f72931a6..eb6ebc266 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp @@ -25,10 +25,13 @@ enum Spells SPELL_FEAR = 30584, SPELL_THUNDERCLAP = 30633, SPELL_BEATDOWN = 30618, - SPELL_BURNING_MAUL_N = 30598, - SPELL_BURNING_MAUL_H = 36056, + SPELL_BURNING_MAUL = 30598 +}; + +enum Equip +{ EQUIP_STANDARD = 1, - EQUIP_BURNING_MAUL = 2, + EQUIP_BURNING_MAUL = 2 }; enum Creatures @@ -50,233 +53,219 @@ enum Events EVENT_AGGRO_YELL_1 = 1, EVENT_AGGRO_YELL_2 = 2, EVENT_AGGRO_YELL_3 = 3, - EVENT_THREAT_YELL_L_1 = 4, EVENT_THREAT_YELL_L_2 = 5, EVENT_THREAT_YELL_L_3 = 6, - EVENT_THREAT_YELL_R_1 = 7, - EVENT_KILL_YELL_LEFT = 8, EVENT_KILL_YELL_RIGHT = 9, - EVENT_DEATH_YELL = 10, + EVENT_DEATH_YELL = 10 }; enum Phase { - GROUP_NON_BURNING_PHASE = 0, - GROUP_BURNING_PHASE = 1, - GROUP_FULL_PHASE = 2 + GROUP_NON_BURNING_PHASE = 0, + GROUP_BURNING_PHASE = 1, + GROUP_FULL_PHASE = 2 }; -// ######################################################## -// Warbringer_Omrogg -// ######################################################## - -class boss_warbringer_omrogg : public CreatureScript +struct boss_warbringer_omrogg : public BossAI { -public: - boss_warbringer_omrogg() : CreatureScript("boss_warbringer_omrogg") { } - - struct boss_warbringer_omroggAI : public BossAI + boss_warbringer_omrogg(Creature* creature) : BossAI(creature, DATA_OMROGG) { - boss_warbringer_omroggAI(Creature* creature) : BossAI(creature, DATA_OMROGG) + scheduler.SetValidator([this] { - scheduler.SetValidator([this] - { - return !me->HasUnitState(UNIT_STATE_CASTING); - }); + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + EventMap events2; + + Creature* GetLeftHead() + { + return summons.GetCreatureWithEntry(NPC_LEFT_HEAD); + } + + Creature* GetRightHead() + { + return summons.GetCreatureWithEntry(NPC_RIGHT_HEAD); + } + + void JustEngagedWith(Unit* /*who*/) override + { + me->SummonCreature(NPC_LEFT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); + me->SummonCreature(NPC_RIGHT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); + + if (Creature* LeftHead = GetLeftHead()) + { + uint8 aggroYell = urand(EVENT_AGGRO_YELL_1, EVENT_AGGRO_YELL_3); + LeftHead->AI()->Talk(aggroYell - 1); + events2.ScheduleEvent(aggroYell, 3000); } - EventMap events2; - - Creature* GetLeftHead() + _JustEngagedWith(); + scheduler.Schedule(500ms, GROUP_FULL_PHASE, [this](TaskContext context) { - return summons.GetCreatureWithEntry(NPC_LEFT_HEAD); - } - - Creature* GetRightHead() - { - return summons.GetCreatureWithEntry(NPC_RIGHT_HEAD); - } - - void JustEngagedWith(Unit* /*who*/) override - { - me->SummonCreature(NPC_LEFT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); - me->SummonCreature(NPC_RIGHT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0); - - if (Creature* LeftHead = GetLeftHead()) + scheduler.Schedule(12100ms, 17300ms, GROUP_NON_BURNING_PHASE, [this](TaskContext context) { - uint8 aggroYell = urand(EVENT_AGGRO_YELL_1, EVENT_AGGRO_YELL_3); - LeftHead->AI()->Talk(aggroYell - 1); - events2.ScheduleEvent(aggroYell, 3000); - } - - _JustEngagedWith(); - scheduler.Schedule(500ms, GROUP_FULL_PHASE, [this](TaskContext context) + DoCastAOE(SPELL_THUNDERCLAP); + context.Repeat(17200ms, 24200ms); + }).Schedule(20s, 30s, GROUP_NON_BURNING_PHASE, [this](TaskContext /*context*/) { - scheduler.Schedule(12100ms, 17300ms, GROUP_NON_BURNING_PHASE, [this](TaskContext context) + DoCastSelf(SPELL_BEATDOWN); + me->SetUnitFlag(UNIT_FLAG_PACIFIED); + me->SetReactState(REACT_PASSIVE); + scheduler.Schedule(200ms, GROUP_NON_BURNING_PHASE, [this](TaskContext /*context*/) { - DoCastAOE(SPELL_THUNDERCLAP); - context.Repeat(17200ms, 24200ms); - }).Schedule(20s, 30s, GROUP_NON_BURNING_PHASE, [this](TaskContext /*context*/) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + { + uint8 threatYell = urand(EVENT_THREAT_YELL_L_1, EVENT_THREAT_YELL_R_1); + if (Creature* head = threatYell == EVENT_THREAT_YELL_R_1 ? GetRightHead() : GetLeftHead()) + { + head->AI()->Talk(threatYell - 1); + } + events.ScheduleEvent(threatYell, 3000); + DoResetThreatList(); + me->AddThreat(target, 2250.0f); + scheduler.Schedule(1200ms, GROUP_BURNING_PHASE, [this](TaskContext /*context*/) + { + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_PACIFIED); + }); + } + }).Schedule(40s, 60s, GROUP_NON_BURNING_PHASE, [this](TaskContext /*context*/) { - DoCastSelf(SPELL_BEATDOWN, false); me->SetUnitFlag(UNIT_FLAG_PACIFIED); me->SetReactState(REACT_PASSIVE); - scheduler.Schedule(200ms, GROUP_NON_BURNING_PHASE, [this](TaskContext /*context*/) + scheduler.Schedule(1200ms, GROUP_NON_BURNING_PHASE, [this](TaskContext /*context*/) { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + DoCastSelf(SPELL_FEAR); + DoCastSelf(SPELL_BURNING_MAUL); + me->LoadEquipment(EQUIP_BURNING_MAUL); + scheduler.CancelGroup(GROUP_NON_BURNING_PHASE); + scheduler.Schedule(200ms, GROUP_BURNING_PHASE, [this](TaskContext /*context*/) { - uint8 threatYell = urand(EVENT_THREAT_YELL_L_1, EVENT_THREAT_YELL_R_1); - if (Creature* head = threatYell == EVENT_THREAT_YELL_R_1 ? GetRightHead() : GetLeftHead()) - head->AI()->Talk(threatYell - 1); - events.ScheduleEvent(threatYell, 3000); - DoResetThreatList(); - me->AddThreat(target, 2250.0f); - scheduler.Schedule(1200ms, GROUP_BURNING_PHASE, [this](TaskContext /*context*/) + me->Yell("%s roars!", LANG_UNIVERSAL); + scheduler.Schedule(2200ms, GROUP_BURNING_PHASE, [this](TaskContext /*context*/) { - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_PACIFIED); - }); - } - }).Schedule(40s, 60s, GROUP_NON_BURNING_PHASE, [this](TaskContext /*context*/) - { - me->SetUnitFlag(UNIT_FLAG_PACIFIED); - me->SetReactState(REACT_PASSIVE); - scheduler.Schedule(1200ms, GROUP_NON_BURNING_PHASE, [this](TaskContext /*context*/) - { - DoCastSelf(SPELL_FEAR, false); - DoCastSelf(DUNGEON_MODE(SPELL_BURNING_MAUL_N, SPELL_BURNING_MAUL_H), false); - me->LoadEquipment(EQUIP_BURNING_MAUL); - scheduler.CancelGroup(GROUP_NON_BURNING_PHASE); - scheduler.Schedule(200ms, GROUP_BURNING_PHASE, [this](TaskContext /*context*/) - { - me->Yell("%s roars!", LANG_UNIVERSAL); - scheduler.Schedule(2200ms, GROUP_BURNING_PHASE, [this](TaskContext /*context*/) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + uint8 threatYell = urand(EVENT_THREAT_YELL_L_1, EVENT_THREAT_YELL_R_1); + if (Creature* head = threatYell == EVENT_THREAT_YELL_R_1 ? GetRightHead() : GetLeftHead()) { - uint8 threatYell = urand(EVENT_THREAT_YELL_L_1, EVENT_THREAT_YELL_R_1); - if (Creature* head = threatYell == EVENT_THREAT_YELL_R_1 ? GetRightHead() : GetLeftHead()) - head->AI()->Talk(threatYell - 1); - events.ScheduleEvent(threatYell, 3000); - - DoResetThreatList(); - me->AddThreat(target, 2250.0f); - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_PACIFIED); + head->AI()->Talk(threatYell - 1); } - }); - }); - scheduler.Schedule(4850ms, 8500ms, GROUP_BURNING_PHASE, [this](TaskContext context) - { - DoCastAOE(SPELL_BLAST_WAVE, false); - context.Repeat(4850ms, 8500ms); - }).Schedule(45s, 60s, GROUP_BURNING_PHASE, [this](TaskContext context) - { - me->LoadEquipment(EQUIP_STANDARD); - context.CancelGroup(GROUP_BURNING_PHASE); - scheduler.RescheduleGroup(GROUP_NON_BURNING_PHASE, 5ms); - context.RescheduleGroup(GROUP_NON_BURNING_PHASE, 5ms); - context.RescheduleGroup(GROUP_FULL_PHASE, 1050ms); + events.ScheduleEvent(threatYell, 3000); + DoResetThreatList(); + me->AddThreat(target, 2250.0f); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_PACIFIED); + } }); }); + scheduler.Schedule(4850ms, 8500ms, GROUP_BURNING_PHASE, [this](TaskContext context) + { + DoCastAOE(SPELL_BLAST_WAVE, false); + context.Repeat(4850ms, 8500ms); + }).Schedule(45s, 60s, GROUP_BURNING_PHASE, [this](TaskContext context) + { + me->LoadEquipment(EQUIP_STANDARD); + context.CancelGroup(GROUP_BURNING_PHASE); + scheduler.RescheduleGroup(GROUP_NON_BURNING_PHASE, 5ms); + context.RescheduleGroup(GROUP_NON_BURNING_PHASE, 5ms); + context.RescheduleGroup(GROUP_FULL_PHASE, 1050ms); + }); }); }); - context.Repeat(130s, 150s); }); - } + context.Repeat(130s, 150s); + }); + } - void JustSummoned(Creature* summoned) override - { - summons.Summon(summoned); - } - - void KilledUnit(Unit* /*victim*/) override - { - Creature* head = nullptr; - uint32 eventId = EVENT_KILL_YELL_LEFT; - if (urand(0, 1)) - { - head = GetLeftHead(); - eventId = EVENT_KILL_YELL_LEFT; - } - else - { - head = GetRightHead(); - eventId = EVENT_KILL_YELL_RIGHT; - } - - if (head) - head->AI()->Talk(eventId - 1); - - events2.ScheduleEvent(eventId, 3000); - } - - void JustDied(Unit* /*killer*/) override - { - Creature* LeftHead = GetLeftHead(); - Creature* RightHead = GetRightHead(); - if (!LeftHead || !RightHead) - return; - - LeftHead->DespawnOrUnsummon(5000); - RightHead->DespawnOrUnsummon(5000); - - LeftHead->AI()->Talk(EVENT_DEATH_YELL - 1); - RightHead->AI()->SetData(SETDATA_DATA, SETDATA_YELL); - - instance->SetBossState(DATA_OMROGG, DONE); - } - - void UpdateAI(uint32 diff) override - { - events2.Update(diff); - scheduler.Update(diff); - switch (uint32 eventId = events2.ExecuteEvent()) - { - case EVENT_AGGRO_YELL_1: - case EVENT_AGGRO_YELL_2: - case EVENT_AGGRO_YELL_3: - case EVENT_KILL_YELL_LEFT: - case EVENT_THREAT_YELL_L_1: - case EVENT_THREAT_YELL_L_2: - case EVENT_THREAT_YELL_L_3: - if (Creature* RightHead = GetRightHead()) - RightHead->AI()->Talk(eventId - 1); - break; - case EVENT_KILL_YELL_RIGHT: - case EVENT_THREAT_YELL_R_1: - if (Creature* LeftHead = GetLeftHead()) - LeftHead->AI()->Talk(eventId - 1); - break; - } - - if (!UpdateVictim()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void JustSummoned(Creature* summoned) override { - return GetShatteredHallsAI(creature); + summons.Summon(summoned); + } + + void KilledUnit(Unit* /*victim*/) override + { + Creature* head = nullptr; + uint32 eventId = EVENT_KILL_YELL_LEFT; + if (urand(0, 1)) + { + head = GetLeftHead(); + eventId = EVENT_KILL_YELL_LEFT; + } + else + { + head = GetRightHead(); + eventId = EVENT_KILL_YELL_RIGHT; + } + + if (head) + { + head->AI()->Talk(eventId - 1); + } + events2.ScheduleEvent(eventId, 3000); + } + + void JustDied(Unit* /*killer*/) override + { + Creature* LeftHead = GetLeftHead(); + Creature* RightHead = GetRightHead(); + if (!LeftHead || !RightHead) + return; + + LeftHead->DespawnOrUnsummon(5000); + RightHead->DespawnOrUnsummon(5000); + LeftHead->AI()->Talk(EVENT_DEATH_YELL - 1); + RightHead->AI()->SetData(SETDATA_DATA, SETDATA_YELL); + instance->SetBossState(DATA_OMROGG, DONE); + } + + void UpdateAI(uint32 diff) override + { + events2.Update(diff); + scheduler.Update(diff); + switch (uint32 eventId = events2.ExecuteEvent()) + { + case EVENT_AGGRO_YELL_1: + case EVENT_AGGRO_YELL_2: + case EVENT_AGGRO_YELL_3: + case EVENT_KILL_YELL_LEFT: + case EVENT_THREAT_YELL_L_1: + case EVENT_THREAT_YELL_L_2: + case EVENT_THREAT_YELL_L_3: + if (Creature* RightHead = GetRightHead()) + { + RightHead->AI()->Talk(eventId - 1); + } + break; + case EVENT_KILL_YELL_RIGHT: + case EVENT_THREAT_YELL_R_1: + if (Creature* LeftHead = GetLeftHead()) + { + LeftHead->AI()->Talk(eventId - 1); + } + break; + } + + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + DoMeleeAttackIfReady(); } }; -class npc_omrogg_heads : public CreatureScript +struct npc_omrogg_heads : public NullCreatureAI { -public: - npc_omrogg_heads() : CreatureScript("npc_omrogg_heads") { } - - struct npc_omrogg_headsAI : public NullCreatureAI - { - npc_omrogg_headsAI(Creature* creature) : NullCreatureAI(creature) { timer = 0; } + npc_omrogg_heads(Creature* creature) : NullCreatureAI(creature) + { + timer = 0; + } void SetData(uint32 data, uint32 value) override { @@ -297,16 +286,10 @@ public: } } uint32 timer; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetShatteredHallsAI(creature); - } }; void AddSC_boss_warbringer_omrogg() { - new boss_warbringer_omrogg(); - new npc_omrogg_heads(); + RegisterShatteredHallsCreatureAI(boss_warbringer_omrogg); + RegisterShatteredHallsCreatureAI(npc_omrogg_heads); } diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp index 1df447a16..5c9a5c09a 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp @@ -21,170 +21,161 @@ enum Says { - SAY_AGGRO = 0, - SAY_SLAY = 1, - SAY_DEATH = 2 + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_DEATH = 2 }; enum Spells { - SPELL_BLADE_DANCE = 30739, - SPELL_CHARGE = 25821, - SPELL_SPRINT = 32720, + SPELL_BLADE_DANCE = 30739, + SPELL_CHARGE = 25821, + SPELL_SPRINT = 32720 }; enum Creatures { - NPC_SHATTERED_ASSASSIN = 17695, - NPC_HEARTHEN_GUARD = 17621, - NPC_SHARPSHOOTER_GUARD = 17622, - NPC_REAVER_GUARD = 17623 + NPC_SHATTERED_ASSASSIN = 17695, + NPC_HEARTHEN_GUARD = 17621, + NPC_SHARPSHOOTER_GUARD = 17622, + NPC_REAVER_GUARD = 17623 +}; + +enum Misc +{ + EVENT_SPELL_CHARGE = 1, + EVENT_MOVE_TO_NEXT_POINT = 2, + EVENT_BLADE_DANCE = 3, + EVENT_FINISH_BLADE_DANCE = 4 }; float AssassEntrance[3] = { 275.136f, -84.29f, 2.3f }; // y -8 float AssassExit[3] = { 184.233f, -84.29f, 2.3f }; // y -8 float AddsEntrance[3] = { 306.036f, -84.29f, 1.93f }; -enum Misc +struct boss_warchief_kargath_bladefist : public BossAI { - EVENT_CHECK_ROOM = 1, - EVENT_SUMMON_ADDS = 2, - EVENT_SUMMON_ASSASSINS = 3, - EVENT_SPELL_CHARGE = 4, - EVENT_MOVE_TO_NEXT_POINT = 5, - EVENT_BLADE_DANCE = 6, - EVENT_FINISH_BLADE_DANCE = 7 -}; - -class boss_warchief_kargath_bladefist : public CreatureScript -{ -public: - boss_warchief_kargath_bladefist() : CreatureScript("boss_warchief_kargath_bladefist") { } - - struct boss_warchief_kargath_bladefistAI : public BossAI + boss_warchief_kargath_bladefist(Creature* creature) : BossAI(creature, DATA_KARGATH) { - boss_warchief_kargath_bladefistAI(Creature* creature) : BossAI(creature, DATA_KARGATH) { } - - void InitializeAI() override + scheduler.SetValidator([this] { - BossAI::InitializeAI(); - if (instance) - if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER))) - executioner->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - } + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } - void JustDied(Unit* /*killer*/) override + void InitializeAI() override + { + BossAI::InitializeAI(); + if (instance) { - Talk(SAY_DEATH); - _JustDied(); - - if (instance) - if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER))) - executioner->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - _JustEngagedWith(); - - events.ScheduleEvent(EVENT_CHECK_ROOM, 5000); - events.ScheduleEvent(EVENT_SUMMON_ADDS, 30000); - events.ScheduleEvent(EVENT_SUMMON_ASSASSINS, 5000); - events.ScheduleEvent(EVENT_BLADE_DANCE, 30000); - events.ScheduleEvent(EVENT_SPELL_CHARGE, 0); - } - - void JustSummoned(Creature* summon) override - { - if (summon->GetEntry() != NPC_SHATTERED_ASSASSIN) - summon->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random, 0)); - - summons.Summon(summon); - } - - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type != POINT_MOTION_TYPE || id != 1) - return; - - me->CastSpell(me, SPELL_BLADE_DANCE, true); - events.ScheduleEvent(EVENT_MOVE_TO_NEXT_POINT, 0); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - switch (events.ExecuteEvent()) + if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER))) { - case EVENT_CHECK_ROOM: - if (me->GetPositionX() > 255 || me->GetPositionX() < 205) - { - EnterEvadeMode(); - return; - } - events.ScheduleEvent(EVENT_CHECK_ROOM, 5000); - break; - case EVENT_SUMMON_ASSASSINS: - me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] + 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] - 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] + 8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] - 8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - break; - case EVENT_SUMMON_ADDS: - for (uint8 i = 0; i < 2; ++i) - me->SummonCreature(NPC_HEARTHEN_GUARD + urand(0, 2), AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); - - events.ScheduleEvent(EVENT_SUMMON_ADDS, 30000); - break; - case EVENT_BLADE_DANCE: - events.DelayEvents(10001); - events.ScheduleEvent(EVENT_BLADE_DANCE, 40000); - events.ScheduleEvent(EVENT_MOVE_TO_NEXT_POINT, 0); - events.ScheduleEvent(EVENT_FINISH_BLADE_DANCE, 10000); - events.SetPhase(1); - me->CastSpell(me, SPELL_SPRINT, true); - break; - case EVENT_MOVE_TO_NEXT_POINT: - { - float x = 210 + frand(0.0f, 35.0f); - float y = -65.0f - frand(0.0f, 35.0f); - me->GetMotionMaster()->MovePoint(1, x, y, me->GetPositionZ()); - break; - } - case EVENT_FINISH_BLADE_DANCE: - events.SetPhase(0); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveChase(me->GetVictim()); - if (IsHeroic()) - events.ScheduleEvent(EVENT_SPELL_CHARGE, 3000); - break; - case EVENT_SPELL_CHARGE: - me->CastSpell(me->GetVictim(), SPELL_CHARGE, false); - break; + executioner->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); } - - if (!events.IsInPhase(1)) - DoMeleeAttackIfReady(); } - }; + } - CreatureAI* GetAI(Creature* creature) const override + void JustDied(Unit* /*killer*/) override { - return GetShatteredHallsAI(creature); + Talk(SAY_DEATH); + _JustDied(); + if (instance) + { + if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER))) + { + executioner->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + } + } + } + + void JustEngagedWith(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + _JustEngagedWith(); + scheduler.Schedule(5s, [this](TaskContext /*context*/) + { + me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] + 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] - 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] + 8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] - 8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + }).Schedule(30s, [this](TaskContext context) + { + for (uint8 i = 0; i < 2; ++i) + { + me->SummonCreature(NPC_HEARTHEN_GUARD + urand(0, 2), AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + } + context.Repeat(30s); + }).Schedule(30s, [this](TaskContext context) + { + scheduler.DelayAll(10001ms); + context.Repeat(40s); + scheduler.Schedule(1ms, [this](TaskContext /*context*/) + { + float x = 210 + frand(0.0f, 35.0f); + float y = -65.0f - frand(0.0f, 35.0f); + me->GetMotionMaster()->MovePoint(1, x, y, me->GetPositionZ()); + }).Schedule(10s, [this](TaskContext /*context*/) + { + //events.SetPhase(0); howToMigrate? + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveChase(me->GetVictim()); + if (IsHeroic()) + { + scheduler.Schedule(3s, [this](TaskContext context) + { + DoCastVictim(SPELL_CHARGE); + context.Repeat(30s); + }); + } + }); + //events.SetPhase(1); howToMigrate? + DoCastSelf(SPELL_SPRINT, true); + }); + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() != NPC_SHATTERED_ASSASSIN) + { + summon->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random, 0)); + } + summons.Summon(summon); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE || id != 1) + return; + + me->CastSpell(me, SPELL_BLADE_DANCE, true); + events.ScheduleEvent(EVENT_MOVE_TO_NEXT_POINT, 0); + } + + void UpdateAI(uint32 diff) override + { + if (me->GetPositionX() > 255 || me->GetPositionX() < 205) + { + EnterEvadeMode(); + return; + } + + if (!UpdateVictim()) + return; + + scheduler.Update(diff); + + if (!events.IsInPhase(1)) // howToMigrate? + DoMeleeAttackIfReady(); } }; void AddSC_boss_warchief_kargath_bladefist() { - new boss_warchief_kargath_bladefist(); + RegisterShatteredHallsCreatureAI(boss_warchief_kargath_bladefist); } diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h index 0e94153ef..249224ae4 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h @@ -73,4 +73,6 @@ inline AI* GetShatteredHallsAI(T* obj) return GetInstanceAI(obj, ShatteredHallsLairScriptName); } +#define RegisterShatteredHallsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetShatteredHallsAI) + #endif