diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp index f2856ab51..65022e721 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp @@ -68,244 +68,222 @@ const Position LarvaPos[2] = { -9701.6005f, 1566.9993f, 24.118f, 0.0f } }; -class boss_ayamiss : public CreatureScript +struct boss_ayamiss : public BossAI { -public: - boss_ayamiss() : CreatureScript("boss_ayamiss") { } + boss_ayamiss(Creature* creature) : BossAI(creature, DATA_AYAMISS) {} - struct boss_ayamissAI : public BossAI + void Reset() override { - boss_ayamissAI(Creature* creature) : BossAI(creature, DATA_AYAMISS) {} - - void Reset() override - { - _Reset(); - _phase = PHASE_AIR; - _enraged = false; - SetCombatMovement(false); - } - - void JustSummoned(Creature* who) override - { - switch (who->GetEntry()) - { - case NPC_SWARMER: - _swarmers.push_back(who->GetGUID()); - break; - case NPC_LARVA: - who->GetMotionMaster()->MovePoint(POINT_PARALYZE, AltarPos); - break; - case NPC_HORNET: - if (Unit* target = SelectTarget(SelectTargetMethod::Random)) - { - who->AI()->AttackStart(target); - } - break; - } - - summons.Summon(who); - } - - void MovementInform(uint32 type, uint32 id) override - { - if (type == POINT_MOTION_TYPE) - { - switch (id) - { - case POINT_AIR: - me->AddUnitState(UNIT_STATE_ROOT); - break; - case POINT_GROUND: - me->GetMotionMaster()->MoveChase(me->GetVictim()); - break; - } - } - } - - void EnterEvadeMode(EvadeReason why) override - { - me->ClearUnitState(UNIT_STATE_ROOT); - BossAI::EnterEvadeMode(why); - } - - void EnterCombat(Unit* attacker) override - { - BossAI::EnterCombat(attacker); - events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(20000, 30000)); - events.ScheduleEvent(EVENT_POISON_STINGER, 5000); - events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000); - events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000); - events.ScheduleEvent(EVENT_PARALYZE, 15000); - me->SetCanFly(true); - me->SetDisableGravity(true); - me->GetMotionMaster()->MovePoint(POINT_AIR, AyamissAirPos); - } - - void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override - { - if (_phase == PHASE_AIR && me->GetHealthPct() < 70.0f) - { - _phase = PHASE_GROUND; - SetCombatMovement(true); - me->ClearUnitState(UNIT_STATE_ROOT); - me->SetCanFly(false); - me->SetDisableGravity(false); - if (Unit* victim = me->GetVictim()) - { - Position victimPos = victim->GetPosition(); - me->GetMotionMaster()->MovePoint(POINT_GROUND, victimPos); - } - events.ScheduleEvent(EVENT_LASH, urand(5000, 8000)); - events.CancelEvent(EVENT_POISON_STINGER); - DoResetThreat(); - } - if (!_enraged && me->GetHealthPct() < 20.0f) - { - DoCastSelf(SPELL_FRENZY); - Talk(EMOTE_FRENZY); - _enraged = true; - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_STINGER_SPRAY: - DoCastSelf(SPELL_STINGER_SPRAY); - events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(15000, 20000)); - break; - case EVENT_POISON_STINGER: - DoCastVictim(SPELL_POISON_STINGER); - events.ScheduleEvent(EVENT_POISON_STINGER, urand(2000, 3000)); - break; - case EVENT_PARALYZE: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true)) - { - DoCast(target, SPELL_PARALYZE); - instance->SetGuidData(DATA_PARALYZED, target->GetGUID()); - uint8 Index = urand(0, 1); - me->SummonCreature(NPC_LARVA, LarvaPos[Index], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); - } - events.ScheduleEvent(EVENT_PARALYZE, 15000); - break; - case EVENT_SWARMER_ATTACK: - for (ObjectGuid const& guid : _swarmers) - { - if (Creature* swarmer = me->GetMap()->GetCreature(guid)) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random)) - { - swarmer->AI()->AttackStart(target); - } - } - } - _swarmers.clear(); - events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000); - break; - case EVENT_SUMMON_SWARMER: - { - Position Pos = me->GetRandomPoint(SwarmerPos, 80.0f); - me->SummonCreature(NPC_SWARMER, Pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); - events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000); - break; - } - case EVENT_LASH: - DoCastVictim(SPELL_LASH); - events.ScheduleEvent(EVENT_LASH, urand(8000, 15000)); - break; - } - } - DoMeleeAttackIfReady(); - } - private: - GuidList _swarmers; - uint8 _phase; - bool _enraged; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetRuinsOfAhnQirajAI(creature); + BossAI::Reset(); + _phase = PHASE_AIR; + _enraged = false; + SetCombatMovement(false); } + + void JustSummoned(Creature* who) override + { + switch (who->GetEntry()) + { + case NPC_SWARMER: + _swarmers.push_back(who->GetGUID()); + break; + case NPC_LARVA: + who->GetMotionMaster()->MovePoint(POINT_PARALYZE, AltarPos); + break; + case NPC_HORNET: + if (Unit* target = SelectTarget(SelectTargetMethod::Random)) + { + who->AI()->AttackStart(target); + } + break; + } + + summons.Summon(who); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE) + { + switch (id) + { + case POINT_AIR: + me->AddUnitState(UNIT_STATE_ROOT); + break; + case POINT_GROUND: + me->GetMotionMaster()->MoveChase(me->GetVictim()); + break; + } + } + } + + void EnterEvadeMode(EvadeReason why) override + { + me->ClearUnitState(UNIT_STATE_ROOT); + BossAI::EnterEvadeMode(why); + } + + void EnterCombat(Unit* attacker) override + { + BossAI::EnterCombat(attacker); + events.ScheduleEvent(EVENT_STINGER_SPRAY, 20s, 30s); + events.ScheduleEvent(EVENT_POISON_STINGER, 5s); + events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5s); + events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60s); + events.ScheduleEvent(EVENT_PARALYZE, 15s); + me->SetCanFly(true); + me->SetDisableGravity(true); + me->GetMotionMaster()->MovePoint(POINT_AIR, AyamissAirPos); + } + + void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override + { + if (_phase == PHASE_AIR && me->GetHealthPct() < 70.0f) + { + _phase = PHASE_GROUND; + SetCombatMovement(true); + me->ClearUnitState(UNIT_STATE_ROOT); + me->SetCanFly(false); + me->SetDisableGravity(false); + if (Unit* victim = me->GetVictim()) + { + Position victimPos = victim->GetPosition(); + me->GetMotionMaster()->MovePoint(POINT_GROUND, victimPos); + } + events.ScheduleEvent(EVENT_LASH, 5s, 8s); + events.CancelEvent(EVENT_POISON_STINGER); + DoResetThreat(); + } + if (!_enraged && me->GetHealthPct() < 20.0f) + { + DoCastSelf(SPELL_FRENZY); + Talk(EMOTE_FRENZY); + _enraged = true; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_STINGER_SPRAY: + DoCastSelf(SPELL_STINGER_SPRAY); + events.ScheduleEvent(EVENT_STINGER_SPRAY, 15s, 20s); + break; + case EVENT_POISON_STINGER: + DoCastVictim(SPELL_POISON_STINGER); + events.ScheduleEvent(EVENT_POISON_STINGER, 2s, 3s); + break; + case EVENT_PARALYZE: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true)) + { + DoCast(target, SPELL_PARALYZE); + instance->SetGuidData(DATA_PARALYZED, target->GetGUID()); + uint8 index = urand(0, 1); + me->SummonCreature(NPC_LARVA, LarvaPos[index], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + } + events.ScheduleEvent(EVENT_PARALYZE, 15s); + break; + case EVENT_SWARMER_ATTACK: + for (ObjectGuid const& guid : _swarmers) + { + if (Creature* swarmer = me->GetMap()->GetCreature(guid)) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random)) + { + swarmer->AI()->AttackStart(target); + } + } + } + _swarmers.clear(); + events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60s); + break; + case EVENT_SUMMON_SWARMER: + { + Position Pos = me->GetRandomPoint(SwarmerPos, 80.0f); + me->SummonCreature(NPC_SWARMER, Pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000); + events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5s); + break; + } + case EVENT_LASH: + DoCastVictim(SPELL_LASH); + events.ScheduleEvent(EVENT_LASH, 8s, 15s); + break; + } + } + DoMeleeAttackIfReady(); + } +private: + GuidList _swarmers; + uint8 _phase; + bool _enraged; }; -class npc_hive_zara_larva : public CreatureScript +struct npc_hive_zara_larva : public ScriptedAI { -public: - npc_hive_zara_larva() : CreatureScript("npc_hive_zara_larva") { } - - struct npc_hive_zara_larvaAI : public ScriptedAI + npc_hive_zara_larva(Creature* creature) : ScriptedAI(creature) { - npc_hive_zara_larvaAI(Creature* creature) : ScriptedAI(creature) - { - _instance = me->GetInstanceScript(); - } + _instance = me->GetInstanceScript(); + } - void MovementInform(uint32 type, uint32 id) override + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE) { - if (type == POINT_MOTION_TYPE) + if (id == POINT_PARALYZE) { - if (id == POINT_PARALYZE) + if (Player* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_PARALYZED))) { - if (Player* target = ObjectAccessor::GetPlayer(*me, _instance->GetGuidData(DATA_PARALYZED))) - { - DoCast(target, SPELL_FEED); - } + DoCast(target, SPELL_FEED); } } } - - void JustSummoned(Creature* summon) override - { - if (Creature* ayamiss = _instance->GetCreature(DATA_AYAMISS)) - { - ayamiss->AI()->JustSummoned(summon); - } - } - - void MoveInLineOfSight(Unit* who) override - - { - if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS) - return; - - ScriptedAI::MoveInLineOfSight(who); - } - - void AttackStart(Unit* victim) override - { - if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS) - return; - - ScriptedAI::AttackStart(victim); - } - - void UpdateAI(uint32 diff) override - { - if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS) - return; - - ScriptedAI::UpdateAI(diff); - } - private: - InstanceScript* _instance; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetRuinsOfAhnQirajAI(creature); } + + void JustSummoned(Creature* summon) override + { + if (Creature* ayamiss = _instance->GetCreature(DATA_AYAMISS)) + { + ayamiss->AI()->JustSummoned(summon); + } + } + + void MoveInLineOfSight(Unit* who) override + + { + if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void AttackStart(Unit* victim) override + { + if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS) + return; + + ScriptedAI::AttackStart(victim); + } + + void UpdateAI(uint32 diff) override + { + if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS) + return; + + ScriptedAI::UpdateAI(diff); + } +private: + InstanceScript* _instance; }; void AddSC_boss_ayamiss() { - new boss_ayamiss(); - new npc_hive_zara_larva(); + RegisterRuinsOfAhnQirajCreatureAI(boss_ayamiss); + RegisterRuinsOfAhnQirajCreatureAI(npc_hive_zara_larva); } diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp index 97a419af7..90744df9a 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp @@ -80,7 +80,7 @@ struct boss_buru : public BossAI void EnterCombat(Unit* who) override { - _EnterCombat(); + BossAI::EnterCombat(who); Talk(EMOTE_TARGET, who); DoCastSelf(SPELL_THORNS); ManipulateEggs(true); diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp index 31ca81096..d5b7269b1 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp @@ -66,9 +66,9 @@ struct boss_moam : public BossAI { BossAI::EnterCombat(who); Talk(EMOTE_AGGRO); - events.ScheduleEvent(EVENT_STONE_PHASE, 90000); - events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 9000); - events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 3000); + events.ScheduleEvent(EVENT_STONE_PHASE, 90s); + events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 9s); + events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 3s); } void JustDied(Unit* /*killer*/) override @@ -113,20 +113,20 @@ struct boss_moam : public BossAI DoCastAOE(SPELL_SUMMON_MANA_FIENDS); DoCastSelf(SPELL_ENERGIZE); events.CancelEvent(EVENT_SPELL_DRAIN_MANA); - events.ScheduleEvent(EVENT_STONE_PHASE_END, 90000); + events.ScheduleEvent(EVENT_STONE_PHASE_END, 90s); break; case EVENT_STONE_PHASE_END: me->RemoveAurasDueToSpell(SPELL_ENERGIZE); - events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, urand(2000, 6000)); - events.ScheduleEvent(EVENT_STONE_PHASE, 90000); + events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 2s, 6s); + events.ScheduleEvent(EVENT_STONE_PHASE, 90s); break; case EVENT_SPELL_DRAIN_MANA: DoCastAOE(SPELL_DRAIN_MANA_SERVERSIDE); - events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, urand(2000, 6000)); + events.ScheduleEvent(EVENT_SPELL_DRAIN_MANA, 2s, 6s); break; case EVENT_SPELL_TRAMPLE: DoCastAOE(SPELL_TRAMPLE); - events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 15000); + events.ScheduleEvent(EVENT_SPELL_TRAMPLE, 15s); break; default: break; diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp index 2c648dfb0..6b543c55b 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp @@ -46,71 +46,60 @@ enum Events EVENT_CHANGE_AGGRO = 3, }; -class boss_rajaxx : public CreatureScript +struct boss_rajaxx : public BossAI { -public: - boss_rajaxx() : CreatureScript("boss_rajaxx") { } + boss_rajaxx(Creature* creature) : BossAI(creature, DATA_RAJAXX) { } - struct boss_rajaxxAI : public BossAI + void Reset() override { - boss_rajaxxAI(Creature* creature) : BossAI(creature, DATA_RAJAXX) { } - - void Reset() override - { - _Reset(); - enraged = false; - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - _JustDied(); - } - - void EnterCombat(Unit* /*victim*/) override - { - _EnterCombat(); - events.ScheduleEvent(EVENT_DISARM, 10000); - events.ScheduleEvent(EVENT_THUNDERCRASH, 12000); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_DISARM: - DoCastVictim(SPELL_DISARM); - events.ScheduleEvent(EVENT_DISARM, 22000); - break; - case EVENT_THUNDERCRASH: - DoCast(me, SPELL_THUNDERCRASH); - events.ScheduleEvent(EVENT_THUNDERCRASH, 21000); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - private: - bool enraged; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetRuinsOfAhnQirajAI(creature); + BossAI::Reset(); + enraged = false; } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); + _JustDied(); + } + + void EnterCombat(Unit* /*victim*/) override + { + _EnterCombat(); + events.ScheduleEvent(EVENT_DISARM, 10s); + events.ScheduleEvent(EVENT_THUNDERCRASH, 12s); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DISARM: + DoCastVictim(SPELL_DISARM); + events.ScheduleEvent(EVENT_DISARM, 22s); + break; + case EVENT_THUNDERCRASH: + DoCastSelf(SPELL_THUNDERCRASH); + events.ScheduleEvent(EVENT_THUNDERCRASH, 21s); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } +private: + bool enraged; }; class spell_rajaxx_thundercrash : public SpellScript @@ -136,6 +125,6 @@ class spell_rajaxx_thundercrash : public SpellScript void AddSC_boss_rajaxx() { - new boss_rajaxx(); + RegisterRuinsOfAhnQirajCreatureAI(boss_rajaxx); RegisterSpellScript(spell_rajaxx_thundercrash); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp index 7eefcd5b9..c57a95144 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp @@ -454,9 +454,9 @@ class spell_vem_vengeance : public SpellScript void AddSC_bug_trio() { - RegisterCreatureAI(boss_kri); - RegisterCreatureAI(boss_vem); - RegisterCreatureAI(boss_yauj); + RegisterTempleOfAhnQirajCreatureAI(boss_kri); + RegisterTempleOfAhnQirajCreatureAI(boss_vem); + RegisterTempleOfAhnQirajCreatureAI(boss_yauj); RegisterSpellScript(spell_vem_knockback); RegisterSpellScript(spell_vem_vengeance); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp index 66211a1b0..778daca97 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp @@ -142,93 +142,85 @@ public: //Kick out position const Position KickPos = { -8545.0f, 1984.0f, -96.0f, 0.0f}; -class boss_eye_of_cthun : public CreatureScript +struct boss_eye_of_cthun : public ScriptedAI { -public: - boss_eye_of_cthun() : CreatureScript("boss_eye_of_cthun") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_eye_of_cthun(Creature* creature) : ScriptedAI(creature), _summons(creature) { - return GetTempleOfAhnQirajAI(creature); + instance = creature->GetInstanceScript(); + + SetCombatMovement(false); } - struct eye_of_cthunAI : public ScriptedAI + void Reset() override { - eye_of_cthunAI(Creature* creature) : ScriptedAI(creature), _summons(creature) + //Dark Beam phase 35 seconds (each tick = 1 second, 35 ticks) + DarkGlareTick = 0; + DarkGlareAngle = 0; + ClockWise = false; + + _eyeTentacleCounter = 0; + + //Reset flags + me->RemoveAurasDueToSpell(SPELL_RED_COLORATION); + me->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + me->SetVisible(true); + + //Reset Phase + instance->SetData(DATA_CTHUN_PHASE, PHASE_NOT_STARTED); + + //to avoid having a following void zone + Creature* pPortal = me->FindNearestCreature(NPC_CTHUN_PORTAL, 10); + if (pPortal) + pPortal->SetReactState(REACT_PASSIVE); + + _summons.DespawnAll(); + _scheduler.CancelAll(); + } + + void EnterCombat(Unit* /*who*/) override + { + DoZoneInCombat(); + ScheduleTasks(); + instance->SetData(DATA_CTHUN_PHASE, PHASE_EYE_GREEN_BEAM); + } + + void MoveInLineOfSight(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER && !me->IsInCombat()) { - instance = creature->GetInstanceScript(); - - SetCombatMovement(false); - } - - void Reset() override - { - //Dark Beam phase 35 seconds (each tick = 1 second, 35 ticks) - DarkGlareTick = 0; - DarkGlareAngle = 0; - ClockWise = false; - - _eyeTentacleCounter = 0; - - //Reset flags - me->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - me->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - me->SetVisible(true); - - //Reset Phase - instance->SetData(DATA_CTHUN_PHASE, PHASE_NOT_STARTED); - - //to avoid having a following void zone - Creature* pPortal = me->FindNearestCreature(NPC_CTHUN_PORTAL, 10); - if (pPortal) - pPortal->SetReactState(REACT_PASSIVE); - - _summons.DespawnAll(); - _scheduler.CancelAll(); - } - - void EnterCombat(Unit* /*who*/) override - { - DoZoneInCombat(); - ScheduleTasks(); - instance->SetData(DATA_CTHUN_PHASE, PHASE_EYE_GREEN_BEAM); - } - - void MoveInLineOfSight(Unit* who) override - { - if (who->GetTypeId() == TYPEID_PLAYER && !me->IsInCombat()) + // Z checks are necessary here because AQ maps do funky stuff. + if (me->IsWithinLOSInMap(who) && me->IsWithinDist2d(who, 50.0f) && who->GetPositionZ() > 100.0f) { - // Z checks are necessary here because AQ maps do funky stuff. - if (me->IsWithinLOSInMap(who) && me->IsWithinDist2d(who, 50.0f) && who->GetPositionZ() > 100.0f) - { - AttackStart(who); - } + AttackStart(who); } } + } - void DoAction(int32 action) override + void DoAction(int32 action) override + { + if (action == ACTION_SPAWN_EYE_TENTACLES) { - if (action == ACTION_SPAWN_EYE_TENTACLES) - { - me->SummonCreatureGroup(_eyeTentacleCounter); - _eyeTentacleCounter++; + me->SummonCreatureGroup(_eyeTentacleCounter); + _eyeTentacleCounter++; - if (_eyeTentacleCounter >= MAX_TENTACLE_GROUPS) - { - _eyeTentacleCounter = 0; - } + if (_eyeTentacleCounter >= MAX_TENTACLE_GROUPS) + { + _eyeTentacleCounter = 0; } } + } - void ScheduleTasks() - { - _scheduler.Schedule(3s, [this](TaskContext task) + void ScheduleTasks() + { + _scheduler. + Schedule(3s, [this](TaskContext task) { DoCastRandomTarget(SPELL_GREEN_BEAM); task.SetGroup(GROUP_BEAM_PHASE); task.Repeat(); - }).Schedule(12s, [this](TaskContext task) + }) + .Schedule(12s, [this](TaskContext task) { if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) { @@ -240,12 +232,14 @@ public: task.SetGroup(GROUP_BEAM_PHASE); task.Repeat(); - }).Schedule(45s, [this](TaskContext task) + }) + .Schedule(45s, [this](TaskContext task) { DoAction(ACTION_SPAWN_EYE_TENTACLES); task.SetGroup(GROUP_BEAM_PHASE); task.Repeat(); - }).Schedule(50s, [this](TaskContext /*task*/) + }) + .Schedule(50s, [this](TaskContext /*task*/) { _scheduler.CancelGroup(GROUP_BEAM_PHASE); @@ -311,340 +305,366 @@ public: }); }); }); - } - - void JustSummoned(Creature* summon) override - { - _summons.Summon(summon); - summon->SetInCombatWithZone(); - } - - void UpdateAI(uint32 diff) override - { - //Check if we have a target - if (!UpdateVictim()) - return; - - switch (instance->GetData(DATA_CTHUN_PHASE)) - { - //Transition phase - case PHASE_CTHUN_TRANSITION: - //Remove any target - me->SetTarget(); - me->SetHealth(0); - me->SetVisible(false); - break; - - //Dead phase - case PHASE_CTHUN_DONE: - if (Creature* pPortal = me->FindNearestCreature(NPC_CTHUN_PORTAL, 10)) - { - pPortal->DespawnOrUnsummon(); - } - - me->DespawnOrUnsummon(); - break; - } - - _scheduler.Update(diff); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - switch (instance->GetData(DATA_CTHUN_PHASE)) - { - case PHASE_EYE_GREEN_BEAM: - case PHASE_EYE_RED_BEAM: - //Only if it will kill - if (damage < me->GetHealth()) - return; - - //Fake death in phase 0 or 1 (green beam or dark glare phase) - me->InterruptNonMeleeSpells(false); - - //Remove Red coloration from c'thun - me->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - - //Reset to normal emote state and prevent select and attack - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - - //Remove Target field - me->SetTarget(); - - //Death animation/respawning; - instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_TRANSITION); - - me->SetHealth(0); - damage = 0; - - me->InterruptNonMeleeSpells(true); - me->RemoveAllAuras(); - _scheduler.CancelAll(); - break; - - case PHASE_CTHUN_DONE: - //Allow death here - return; - - default: - //Prevent death in these phases - damage = 0; - return; - } - } - - private: - InstanceScript* instance; - - //Dark Glare phase - uint32 DarkGlareTick; - float DarkGlareAngle; - bool ClockWise; - - uint32 _eyeTentacleCounter; - TaskScheduler _scheduler; - SummonList _summons; - }; -}; - -class boss_cthun : public CreatureScript -{ -public: - boss_cthun() : CreatureScript("boss_cthun") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetTempleOfAhnQirajAI(creature); } - struct cthunAI : public ScriptedAI + void JustSummoned(Creature* summon) override { - cthunAI(Creature* creature) : ScriptedAI(creature) - { - SetCombatMovement(false); + _summons.Summon(summon); + summon->SetInCombatWithZone(); + } - instance = creature->GetInstanceScript(); + void UpdateAI(uint32 diff) override + { + //Check if we have a target + if (!UpdateVictim()) + return; + + switch (instance->GetData(DATA_CTHUN_PHASE)) + { + //Transition phase + case PHASE_CTHUN_TRANSITION: + //Remove any target + me->SetTarget(); + me->SetHealth(0); + me->SetVisible(false); + break; + + //Dead phase + case PHASE_CTHUN_DONE: + if (Creature* pPortal = me->FindNearestCreature(NPC_CTHUN_PORTAL, 10)) + { + pPortal->DespawnOrUnsummon(); + } + + me->DespawnOrUnsummon(); + break; } - InstanceScript* instance; + _scheduler.Update(diff); + } - //Out of combat whisper timer - uint32 WisperTimer; + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + switch (instance->GetData(DATA_CTHUN_PHASE)) + { + case PHASE_EYE_GREEN_BEAM: + case PHASE_EYE_RED_BEAM: + //Only if it will kill + if (damage < me->GetHealth()) + return; - //Global variables - uint32 PhaseTimer; + //Fake death in phase 0 or 1 (green beam or dark glare phase) + me->InterruptNonMeleeSpells(false); - //------------------- + //Remove Red coloration from c'thun + me->RemoveAurasDueToSpell(SPELL_RED_COLORATION); - //Phase transition - ObjectGuid HoldPlayer; + //Reset to normal emote state and prevent select and attack + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + + //Remove Target field + me->SetTarget(); + + //Death animation/respawning; + instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_TRANSITION); + + me->SetHealth(0); + damage = 0; + + me->InterruptNonMeleeSpells(true); + me->RemoveAllAuras(); + _scheduler.CancelAll(); + break; + + case PHASE_CTHUN_DONE: + //Allow death here + return; + + default: + //Prevent death in these phases + damage = 0; + return; + } + } + +private: + InstanceScript* instance; + + //Dark Glare phase + uint32 DarkGlareTick; + float DarkGlareAngle; + bool ClockWise; + + uint32 _eyeTentacleCounter; + TaskScheduler _scheduler; + SummonList _summons; +}; + +struct boss_cthun : public ScriptedAI +{ + boss_cthun(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + + instance = creature->GetInstanceScript(); + } + + InstanceScript* instance; + + //Out of combat whisper timer + uint32 WisperTimer; + + //Global variables + uint32 PhaseTimer; + + //------------------- + + //Phase transition + ObjectGuid HoldPlayer; + + //Body Phase + uint32 EyeTentacleTimer; + uint8 FleshTentaclesKilled; + uint32 GiantClawTentacleTimer; + uint32 GiantEyeTentacleTimer; + uint32 StomachAcidTimer; + uint32 StomachEnterTimer; + uint32 StomachEnterVisTimer; + ObjectGuid StomachEnterTarget; + + //Stomach map, bool = true then in stomach + std::unordered_map Stomach_Map; + + void Reset() override + { + //One random wisper every 90 - 300 seconds + WisperTimer = 90000; + + //Phase information + PhaseTimer = 10000; //Emerge in 10 seconds + + //No hold player for transition + HoldPlayer.Clear(); //Body Phase - uint32 EyeTentacleTimer; - uint8 FleshTentaclesKilled; - uint32 GiantClawTentacleTimer; - uint32 GiantEyeTentacleTimer; - uint32 StomachAcidTimer; - uint32 StomachEnterTimer; - uint32 StomachEnterVisTimer; - ObjectGuid StomachEnterTarget; + EyeTentacleTimer = 30000; + FleshTentaclesKilled = 0; + GiantClawTentacleTimer = 15000; //15 seconds into body phase (1 min repeat) + GiantEyeTentacleTimer = 45000; //15 seconds into body phase (1 min repeat) + StomachAcidTimer = 4000; //Every 4 seconds + StomachEnterTimer = 10000; //Every 10 seconds + StomachEnterVisTimer = 0; //Always 3.5 seconds after Stomach Enter Timer + StomachEnterTarget.Clear(); //Target to be teleported to stomach - //Stomach map, bool = true then in stomach - std::unordered_map Stomach_Map; + //Clear players in stomach and outside + Stomach_Map.clear(); - void Reset() override + //Reset flags + me->RemoveAurasDueToSpell(SPELL_TRANSFORM); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + me->SetVisible(false); + + instance->SetData(DATA_CTHUN_PHASE, PHASE_NOT_STARTED); + } + + void EnterCombat(Unit* /*who*/) override + { + DoZoneInCombat(); + } + + Unit* SelectRandomNotStomach() + { + if (Stomach_Map.empty()) + return nullptr; + + std::unordered_map::const_iterator i = Stomach_Map.begin(); + + std::list temp; + std::list::const_iterator j; + + //Get all players in map + while (i != Stomach_Map.end()) { - //One random wisper every 90 - 300 seconds - WisperTimer = 90000; + //Check for valid player + Unit* unit = ObjectAccessor::GetUnit(*me, i->first); - //Phase information - PhaseTimer = 10000; //Emerge in 10 seconds + //Only units out of stomach + if (unit && !i->second) + temp.push_back(unit); - //No hold player for transition - HoldPlayer.Clear(); - - //Body Phase - EyeTentacleTimer = 30000; - FleshTentaclesKilled = 0; - GiantClawTentacleTimer = 15000; //15 seconds into body phase (1 min repeat) - GiantEyeTentacleTimer = 45000; //15 seconds into body phase (1 min repeat) - StomachAcidTimer = 4000; //Every 4 seconds - StomachEnterTimer = 10000; //Every 10 seconds - StomachEnterVisTimer = 0; //Always 3.5 seconds after Stomach Enter Timer - StomachEnterTarget.Clear(); //Target to be teleported to stomach - - //Clear players in stomach and outside - Stomach_Map.clear(); - - //Reset flags - me->RemoveAurasDueToSpell(SPELL_TRANSFORM); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - me->SetVisible(false); - - instance->SetData(DATA_CTHUN_PHASE, PHASE_NOT_STARTED); + ++i; } - void EnterCombat(Unit* /*who*/) override + if (temp.empty()) + return nullptr; + + j = temp.begin(); + + //Get random but only if we have more than one unit on threat list + if (temp.size() > 1) + advance(j, rand() % (temp.size() - 1)); + + return (*j); + } + + void UpdateAI(uint32 diff) override + { + //Check if we have a target + if (!UpdateVictim()) { - DoZoneInCombat(); - } - - Unit* SelectRandomNotStomach() - { - if (Stomach_Map.empty()) - return nullptr; - - std::unordered_map::const_iterator i = Stomach_Map.begin(); - - std::list temp; - std::list::const_iterator j; - - //Get all players in map - while (i != Stomach_Map.end()) + //No target so we'll use this section to do our random wispers instance wide + //WisperTimer + if (WisperTimer <= diff) { - //Check for valid player - Unit* unit = ObjectAccessor::GetUnit(*me, i->first); + Map* map = me->GetMap(); + if (!map->IsDungeon()) + return; - //Only units out of stomach - if (unit && !i->second) - temp.push_back(unit); + //Play random sound to the zone + Map::PlayerList const& PlayerList = map->GetPlayers(); - ++i; - } - - if (temp.empty()) - return nullptr; - - j = temp.begin(); - - //Get random but only if we have more than one unit on threat list - if (temp.size() > 1) - advance (j, rand() % (temp.size() - 1)); - - return (*j); - } - - void UpdateAI(uint32 diff) override - { - //Check if we have a target - if (!UpdateVictim()) - { - //No target so we'll use this section to do our random wispers instance wide - //WisperTimer - if (WisperTimer <= diff) + if (!PlayerList.IsEmpty()) { - Map* map = me->GetMap(); - if (!map->IsDungeon()) - return; - - //Play random sound to the zone - Map::PlayerList const& PlayerList = map->GetPlayers(); - - if (!PlayerList.IsEmpty()) + for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) { - for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) - { - if (Player* pPlr = itr->GetSource()) - pPlr->PlayDirectSound(RANDOM_SOUND_WHISPER, pPlr); - } + if (Player* pPlr = itr->GetSource()) + pPlr->PlayDirectSound(RANDOM_SOUND_WHISPER, pPlr); } - - //One random wisper every 90 - 300 seconds - WisperTimer = urand(90000, 300000); } - else WisperTimer -= diff; - return; + //One random wisper every 90 - 300 seconds + WisperTimer = urand(90000, 300000); } + else WisperTimer -= diff; - me->SetTarget(); + return; + } - uint32 currentPhase = instance->GetData(DATA_CTHUN_PHASE); - if (currentPhase == PHASE_CTHUN_STOMACH || currentPhase == PHASE_CTHUN_WEAK) + me->SetTarget(); + + uint32 currentPhase = instance->GetData(DATA_CTHUN_PHASE); + if (currentPhase == PHASE_CTHUN_STOMACH || currentPhase == PHASE_CTHUN_WEAK) + { + // EyeTentacleTimer + if (EyeTentacleTimer <= diff) { - // EyeTentacleTimer - if (EyeTentacleTimer <= diff) + if (Creature* eye = instance->GetCreature(DATA_EYE_OF_CTHUN)) { - if (Creature* eye = instance->GetCreature(DATA_EYE_OF_CTHUN)) - { - eye->AI()->DoAction(ACTION_SPAWN_EYE_TENTACLES); - } - - EyeTentacleTimer = 30000; // every 30sec in phase 2 + eye->AI()->DoAction(ACTION_SPAWN_EYE_TENTACLES); } - else EyeTentacleTimer -= diff; - } - switch (currentPhase) - { + EyeTentacleTimer = 30000; // every 30sec in phase 2 + } + else EyeTentacleTimer -= diff; + } + + switch (currentPhase) + { //Transition phase - case PHASE_CTHUN_TRANSITION: - //PhaseTimer - if (PhaseTimer <= diff) + case PHASE_CTHUN_TRANSITION: + //PhaseTimer + if (PhaseTimer <= diff) + { + //Switch + instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_STOMACH); + + //Switch to c'thun model + me->InterruptNonMeleeSpells(false); + DoCast(me, SPELL_TRANSFORM, false); + me->SetFullHealth(); + + me->SetVisible(true); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + + //Emerging phase + //AttackStart(ObjectAccessor::GetUnit(*me, HoldpPlayer)); + DoZoneInCombat(); + + //Place all units in threat list on outside of stomach + Stomach_Map.clear(); + + for (std::list::const_iterator i = me->GetThreatMgr().getThreatList().begin(); i != me->GetThreatMgr().getThreatList().end(); ++i) + Stomach_Map[(*i)->getUnitGuid()] = false; //Outside stomach + + //Spawn 2 flesh tentacles + FleshTentaclesKilled = 0; + + //Spawn flesh tentacle + for (uint8 i = 0; i < 2; i++) { - //Switch - instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_STOMACH); - - //Switch to c'thun model - me->InterruptNonMeleeSpells(false); - DoCast(me, SPELL_TRANSFORM, false); - me->SetFullHealth(); - - me->SetVisible(true); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - - //Emerging phase - //AttackStart(ObjectAccessor::GetUnit(*me, HoldpPlayer)); - DoZoneInCombat(); - - //Place all units in threat list on outside of stomach - Stomach_Map.clear(); - - for (std::list::const_iterator i = me->GetThreatMgr().getThreatList().begin(); i != me->GetThreatMgr().getThreatList().end(); ++i) - Stomach_Map[(*i)->getUnitGuid()] = false; //Outside stomach - - //Spawn 2 flesh tentacles - FleshTentaclesKilled = 0; - - //Spawn flesh tentacle - for (uint8 i = 0; i < 2; i++) - { - Creature* spawned = me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN); - if (!spawned) - ++FleshTentaclesKilled; - } - - PhaseTimer = 0; + Creature* spawned = me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN); + if (!spawned) + ++FleshTentaclesKilled; } - else PhaseTimer -= diff; - break; + PhaseTimer = 0; + } + else PhaseTimer -= diff; + + break; //Body Phase - case PHASE_CTHUN_STOMACH: - //Remove Target field - me->SetTarget(); + case PHASE_CTHUN_STOMACH: + //Remove Target field + me->SetTarget(); - //Weaken - if (FleshTentaclesKilled > 1) + //Weaken + if (FleshTentaclesKilled > 1) + { + instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_WEAK); + + Talk(EMOTE_WEAKENED); + PhaseTimer = 45000; + + DoCast(me, SPELL_PURPLE_COLORATION, true); + + std::unordered_map::iterator i = Stomach_Map.begin(); + + //Kick all players out of stomach + while (i != Stomach_Map.end()) { - instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_WEAK); + //Check for valid player + Unit* unit = ObjectAccessor::GetUnit(*me, i->first); - Talk(EMOTE_WEAKENED); - PhaseTimer = 45000; - - DoCast(me, SPELL_PURPLE_COLORATION, true); - - std::unordered_map::iterator i = Stomach_Map.begin(); - - //Kick all players out of stomach - while (i != Stomach_Map.end()) + //Only move units in stomach + if (unit && i->second) { - //Check for valid player - Unit* unit = ObjectAccessor::GetUnit(*me, i->first); + //Teleport each player out + DoTeleportPlayer(unit, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10, float(rand() % 6)); - //Only move units in stomach - if (unit && i->second) + //Cast knockback on them + DoCast(unit, SPELL_EXIT_STOMACH_KNOCKBACK, true); + + //Remove the acid debuff + unit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); + + i->second = false; + } + ++i; + } + + return; + } + + //Stomach acid + if (StomachAcidTimer <= diff) + { + //Apply aura to all players in stomach + std::unordered_map::iterator i = Stomach_Map.begin(); + + while (i != Stomach_Map.end()) + { + //Check for valid player + Unit* unit = ObjectAccessor::GetUnit(*me, i->first); + + //Only apply to units in stomach + if (unit && i->second) + { + //Cast digestive acid on them + DoCast(unit, SPELL_DIGESTIVE_ACID, true); + + //Check if player should be kicked from stomach + if (unit->IsWithinDist3d(&KickPos, 15.0f)) { //Teleport each player out DoTeleportPlayer(unit, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10, float(rand() % 6)); @@ -657,388 +677,321 @@ public: i->second = false; } - ++i; } - - return; + ++i; } - //Stomach acid - if (StomachAcidTimer <= diff) + StomachAcidTimer = 4000; + } + else StomachAcidTimer -= diff; + + //Stomach Enter Timer + if (StomachEnterTimer <= diff) + { + if (Unit* target = SelectRandomNotStomach()) { - //Apply aura to all players in stomach - std::unordered_map::iterator i = Stomach_Map.begin(); - - while (i != Stomach_Map.end()) - { - //Check for valid player - Unit* unit = ObjectAccessor::GetUnit(*me, i->first); - - //Only apply to units in stomach - if (unit && i->second) - { - //Cast digestive acid on them - DoCast(unit, SPELL_DIGESTIVE_ACID, true); - - //Check if player should be kicked from stomach - if (unit->IsWithinDist3d(&KickPos, 15.0f)) - { - //Teleport each player out - DoTeleportPlayer(unit, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 10, float(rand() % 6)); - - //Cast knockback on them - DoCast(unit, SPELL_EXIT_STOMACH_KNOCKBACK, true); - - //Remove the acid debuff - unit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); - - i->second = false; - } - } - ++i; - } - - StomachAcidTimer = 4000; + //Set target in stomach + Stomach_Map[target->GetGUID()] = true; + target->InterruptNonMeleeSpells(false); + target->CastSpell(target, SPELL_MOUTH_TENTACLE, true, nullptr, nullptr, me->GetGUID()); + StomachEnterTarget = target->GetGUID(); + StomachEnterVisTimer = 3800; } - else StomachAcidTimer -= diff; - //Stomach Enter Timer - if (StomachEnterTimer <= diff) + StomachEnterTimer = 13800; + } + else StomachEnterTimer -= diff; + + if (StomachEnterVisTimer && StomachEnterTarget) + { + if (StomachEnterVisTimer <= diff) { - if (Unit* target = SelectRandomNotStomach()) + //Check for valid player + Unit* unit = ObjectAccessor::GetUnit(*me, StomachEnterTarget); + + if (unit) { - //Set target in stomach - Stomach_Map[target->GetGUID()] = true; - target->InterruptNonMeleeSpells(false); - target->CastSpell(target, SPELL_MOUTH_TENTACLE, true, nullptr, nullptr, me->GetGUID()); - StomachEnterTarget = target->GetGUID(); - StomachEnterVisTimer = 3800; + DoTeleportPlayer(unit, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O); } - StomachEnterTimer = 13800; + StomachEnterTarget.Clear(); + StomachEnterVisTimer = 0; } - else StomachEnterTimer -= diff; + else StomachEnterVisTimer -= diff; + } - if (StomachEnterVisTimer && StomachEnterTarget) + //GientClawTentacleTimer + if (GiantClawTentacleTimer <= diff) + { + if (Unit* target = SelectRandomNotStomach()) { - if (StomachEnterVisTimer <= diff) - { - //Check for valid player - Unit* unit = ObjectAccessor::GetUnit(*me, StomachEnterTarget); - - if (unit) - { - DoTeleportPlayer(unit, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O); - } - - StomachEnterTarget.Clear(); - StomachEnterVisTimer = 0; - } - else StomachEnterVisTimer -= diff; + //Spawn claw tentacle on the random target + if (Creature* spawned = me->SummonCreature(NPC_GIANT_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500)) + if (spawned->AI()) + spawned->AI()->AttackStart(target); } - //GientClawTentacleTimer - if (GiantClawTentacleTimer <= diff) + //One giant claw tentacle every minute + GiantClawTentacleTimer = 60000; + } + else GiantClawTentacleTimer -= diff; + + //GiantEyeTentacleTimer + if (GiantEyeTentacleTimer <= diff) + { + if (Unit* target = SelectRandomNotStomach()) { - if (Unit* target = SelectRandomNotStomach()) - { - //Spawn claw tentacle on the random target - if (Creature* spawned = me->SummonCreature(NPC_GIANT_CLAW_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500)) - if (spawned->AI()) - spawned->AI()->AttackStart(target); - } - - //One giant claw tentacle every minute - GiantClawTentacleTimer = 60000; + //Spawn claw tentacle on the random target + if (Creature* spawned = me->SummonCreature(NPC_GIANT_EYE_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500)) + if (spawned->AI()) + spawned->AI()->AttackStart(target); } - else GiantClawTentacleTimer -= diff; - //GiantEyeTentacleTimer - if (GiantEyeTentacleTimer <= diff) - { - if (Unit* target = SelectRandomNotStomach()) - { - //Spawn claw tentacle on the random target - if (Creature* spawned = me->SummonCreature(NPC_GIANT_EYE_TENTACLE, *target, TEMPSUMMON_CORPSE_DESPAWN, 500)) - if (spawned->AI()) - spawned->AI()->AttackStart(target); - } + //One giant eye tentacle every minute + GiantEyeTentacleTimer = 60000; + } + else GiantEyeTentacleTimer -= diff; - //One giant eye tentacle every minute - GiantEyeTentacleTimer = 60000; - } - else GiantEyeTentacleTimer -= diff; - - break; + break; //Weakened state - case PHASE_CTHUN_WEAK: - //PhaseTimer - if (PhaseTimer <= diff) + case PHASE_CTHUN_WEAK: + //PhaseTimer + if (PhaseTimer <= diff) + { + //Switch + instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_STOMACH); + + //Remove purple coloration + me->RemoveAurasDueToSpell(SPELL_PURPLE_COLORATION); + + //Spawn 2 flesh tentacles + FleshTentaclesKilled = 0; + + //Spawn flesh tentacle + for (uint8 i = 0; i < 2; i++) { - //Switch - instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_STOMACH); - - //Remove purple coloration - me->RemoveAurasDueToSpell(SPELL_PURPLE_COLORATION); - - //Spawn 2 flesh tentacles - FleshTentaclesKilled = 0; - - //Spawn flesh tentacle - for (uint8 i = 0; i < 2; i++) - { - Creature* spawned = me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN); - if (!spawned) - ++FleshTentaclesKilled; - } - - PhaseTimer = 0; + Creature* spawned = me->SummonCreature(NPC_FLESH_TENTACLE, FleshTentaclePos[i], TEMPSUMMON_CORPSE_DESPAWN); + if (!spawned) + ++FleshTentaclesKilled; } - else PhaseTimer -= diff; - break; - } + PhaseTimer = 0; + } + else PhaseTimer -= diff; + + break; } - - void JustDied(Unit* /*killer*/) override - { - instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_DONE); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - switch (instance->GetData(DATA_CTHUN_PHASE)) - { - case PHASE_CTHUN_STOMACH: - //Not weakened so reduce damage by 99% - damage /= 100; - if (damage == 0) - damage = 1; - - //Prevent death in non-weakened state - if (damage >= me->GetHealth()) - damage = 0; - - return; - - case PHASE_CTHUN_WEAK: - //Weakened - takes normal damage - return; - - default: - damage = 0; - break; - } - } - - void SummonedCreatureDies(Creature* creature, Unit* /*killer*/) override - { - if (creature->GetEntry() == NPC_FLESH_TENTACLE) - { - ++FleshTentaclesKilled; - } - } - }; -}; - -class npc_eye_tentacle : public CreatureScript -{ -public: - npc_eye_tentacle() : CreatureScript("npc_eye_tentacle") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new eye_tentacleAI(creature); } - struct eye_tentacleAI : public ScriptedAI + void JustDied(Unit* /*killer*/) override { - eye_tentacleAI(Creature* creature) : ScriptedAI(creature) - { - if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) - { - portal->SetReactState(REACT_PASSIVE); - _portalGUID = portal->GetGUID(); - } + instance->SetData(DATA_CTHUN_PHASE, PHASE_CTHUN_DONE); + } - SetCombatMovement(false); + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + switch (instance->GetData(DATA_CTHUN_PHASE)) + { + case PHASE_CTHUN_STOMACH: + //Not weakened so reduce damage by 99% + damage /= 100; + if (damage == 0) + damage = 1; + + //Prevent death in non-weakened state + if (damage >= me->GetHealth()) + damage = 0; + + return; + + case PHASE_CTHUN_WEAK: + //Weakened - takes normal damage + return; + + default: + damage = 0; + break; + } + } + + void SummonedCreatureDies(Creature* creature, Unit* /*killer*/) override + { + if (creature->GetEntry() == NPC_FLESH_TENTACLE) + { + ++FleshTentaclesKilled; + } + } +}; + +struct npc_eye_tentacle : public ScriptedAI +{ + npc_eye_tentacle(Creature* creature) : ScriptedAI(creature) + { + if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) + { + portal->SetReactState(REACT_PASSIVE); + _portalGUID = portal->GetGUID(); } - void JustDied(Unit* /*killer*/) override - { - if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID)) - { - Unit::Kill(p, p); - } - } + SetCombatMovement(false); + } - void Reset() override + void JustDied(Unit* /*killer*/) override + { + if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID)) { - _scheduler.Schedule(500ms, [this](TaskContext /*task*/) + Unit::Kill(p, p); + } + } + + void Reset() override + { + _scheduler.Schedule(500ms, [this](TaskContext /*task*/) { DoCastAOE(SPELL_GROUND_RUPTURE); - }).Schedule(5min, [this](TaskContext /*task*/) + }) + .Schedule(5min, [this](TaskContext /*task*/) { me->DespawnOrUnsummon(); - }).Schedule(1s, 5s, [this](TaskContext context) + }) + .Schedule(1s, 5s, [this](TaskContext context) { if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u) { return u && u->GetTypeId() == TYPEID_PLAYER && !u->HasAura(SPELL_DIGESTIVE_ACID) && !u->HasAura(SPELL_MIND_FLAY); })) { - DoCast(target, SPELL_MIND_FLAY); + DoCast(target, SPELL_MIND_FLAY); } context.Repeat(10s, 15s); }); - } - - void EnterCombat(Unit* /*who*/) override - { - DoZoneInCombat(); - } - - void UpdateAI(uint32 diff) override - { - //Check if we have a target - if (!UpdateVictim()) - return; - - _scheduler.Update(diff); - } - - private: - TaskScheduler _scheduler; - ObjectGuid _portalGUID; - }; -}; - -class npc_claw_tentacle : public CreatureScript -{ -public: - npc_claw_tentacle() : CreatureScript("npc_claw_tentacle") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new claw_tentacleAI(creature); } - struct claw_tentacleAI : public ScriptedAI + void EnterCombat(Unit* /*who*/) override { - claw_tentacleAI(Creature* creature) : ScriptedAI(creature) - { - SetCombatMovement(false); + DoZoneInCombat(); + } - if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) - { - portal->SetReactState(REACT_PASSIVE); - _portalGUID = portal->GetGUID(); - } + void UpdateAI(uint32 diff) override + { + //Check if we have a target + if (!UpdateVictim()) + return; + + _scheduler.Update(diff); + } + +private: + TaskScheduler _scheduler; + ObjectGuid _portalGUID; +}; + +struct npc_claw_tentacle : public ScriptedAI +{ + npc_claw_tentacle(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + + if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) + { + portal->SetReactState(REACT_PASSIVE); + _portalGUID = portal->GetGUID(); } + } - void JustDied(Unit* /*killer*/) override + void JustDied(Unit* /*killer*/) override + { + if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID)) { - if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID)) - { - Unit::Kill(p, p); - } + Unit::Kill(p, p); } + } - void Reset() override - { - _scheduler.Schedule(Milliseconds(500), [this](TaskContext /*task*/) + void Reset() override + { + _scheduler.Schedule(Milliseconds(500), [this](TaskContext /*task*/) { DoCastAOE(SPELL_GROUND_RUPTURE); }).Schedule(Minutes(5), [this](TaskContext /*task*/) { me->DespawnOrUnsummon(); }); - } + } - void EnterCombat(Unit* /*who*/) override - { - DoZoneInCombat(); + void EnterCombat(Unit* /*who*/) override + { + DoZoneInCombat(); - _scheduler.Schedule(2s, [this](TaskContext context) + _scheduler.Schedule(2s, [this](TaskContext context) { DoCastVictim(SPELL_HAMSTRING); context.Repeat(5s); }); - } - - void UpdateAI(uint32 diff) override - { - //Check if we have a target - if (!UpdateVictim()) - return; - - _scheduler.Update(diff); - - DoMeleeAttackIfReady(); - } - - private: - TaskScheduler _scheduler; - ObjectGuid _portalGUID; - }; -}; - -class npc_giant_claw_tentacle : public CreatureScript -{ -public: - npc_giant_claw_tentacle() : CreatureScript("npc_giant_claw_tentacle") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new giant_claw_tentacleAI(creature); } - struct giant_claw_tentacleAI : public ScriptedAI + void UpdateAI(uint32 diff) override { - giant_claw_tentacleAI(Creature* creature) : ScriptedAI(creature) - { - SetCombatMovement(false); + //Check if we have a target + if (!UpdateVictim()) + return; - if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) - { - portal->SetReactState(REACT_PASSIVE); - _portalGUID = portal->GetGUID(); - } + _scheduler.Update(diff); + + DoMeleeAttackIfReady(); + } + +private: + TaskScheduler _scheduler; + ObjectGuid _portalGUID; +}; + +struct npc_giant_claw_tentacle : public ScriptedAI +{ + npc_giant_claw_tentacle(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + + if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) + { + portal->SetReactState(REACT_PASSIVE); + _portalGUID = portal->GetGUID(); } + } - void JustDied(Unit* /*killer*/) override + void JustDied(Unit* /*killer*/) override + { + if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID)) { - if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID)) - { - Unit::Kill(p, p); - } + Unit::Kill(p, p); } + } - void Reset() override - { - _scheduler.Schedule(500ms, [this](TaskContext /*task*/) + void Reset() override + { + _scheduler.Schedule(500ms, [this](TaskContext /*task*/) { DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE); }); - } + } - void EnterCombat(Unit* /*who*/) override - { - DoZoneInCombat(); + void EnterCombat(Unit* /*who*/) override + { + DoZoneInCombat(); - _scheduler.Schedule(2s, [this](TaskContext context) + _scheduler.Schedule(2s, [this](TaskContext context) { DoCastVictim(SPELL_HAMSTRING); context.Repeat(10s); - }).Schedule(5s, [this](TaskContext context) { + }).Schedule(5s, [this](TaskContext context) + { DoCastSelf(SPELL_THRASH); context.Repeat(10s); }); - } + } - void ScheduleMeleeCheck() - { - // Check if a target is in melee range - _scheduler.Schedule(10s, [this](TaskContext task) + void ScheduleMeleeCheck() + { + // Check if a target is in melee range + _scheduler.Schedule(10s, [this](TaskContext task) { if (Unit* target = me->GetVictim()) { @@ -1058,108 +1011,98 @@ public: task.Repeat(); }); + } + + void Submerge() + { + if (me->SelectNearestPlayer(5.0f)) + { + return; } - void Submerge() + // Despawn portal + if (Creature* p = ObjectAccessor::GetCreature(*me, _portalGUID)) { - if (me->SelectNearestPlayer(5.0f)) - { - return; - } + p->DespawnOrUnsummon(); + } - // Despawn portal - if (Creature* p = ObjectAccessor::GetCreature(*me, _portalGUID)) - { - p->DespawnOrUnsummon(); - } + DoCastSelf(SPELL_SUBMERGE_VISUAL); + me->SetHealth(me->GetMaxHealth()); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - DoCastSelf(SPELL_SUBMERGE_VISUAL); - me->SetHealth(me->GetMaxHealth()); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); + _scheduler.CancelAll(); - _scheduler.CancelAll(); - - _scheduler.Schedule(5s, [this](TaskContext /*task*/) + _scheduler.Schedule(5s, [this](TaskContext /*task*/) { Emerge(); }); - } - - void Emerge() - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, NotInStomachSelector())) - { - Position pos = target->GetPosition(); - me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), 0); - if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, pos, TEMPSUMMON_CORPSE_DESPAWN)) - { - portal->SetReactState(REACT_PASSIVE); - _portalGUID = portal->GetGUID(); - } - - me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL); - DoCastSelf(SPELL_BIRTH); - DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE, true); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - - ScheduleMeleeCheck(); - } - } - - void UpdateAI(uint32 diff) override - { - //Check if we have a target - if (!UpdateVictim()) - return; - - _scheduler.Update(diff); - - DoMeleeAttackIfReady(); - } - - private: - TaskScheduler _scheduler; - ObjectGuid _portalGUID; - }; -}; - -class npc_giant_eye_tentacle : public CreatureScript -{ -public: - npc_giant_eye_tentacle() : CreatureScript("npc_giant_eye_tentacle") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new giant_eye_tentacleAI(creature); } - struct giant_eye_tentacleAI : public ScriptedAI + void Emerge() { - giant_eye_tentacleAI(Creature* creature) : ScriptedAI(creature) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, NotInStomachSelector())) { - SetCombatMovement(false); - - if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) + Position pos = target->GetPosition(); + me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), 0); + if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, pos, TEMPSUMMON_CORPSE_DESPAWN)) { portal->SetReactState(REACT_PASSIVE); _portalGUID = portal->GetGUID(); } - } - void JustDied(Unit* /*killer*/) override - { - if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID)) - { - Unit::Kill(p, p); - } - } + me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL); + DoCastSelf(SPELL_BIRTH); + DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE, true); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); - void Reset() override + ScheduleMeleeCheck(); + } + } + + void UpdateAI(uint32 diff) override + { + //Check if we have a target + if (!UpdateVictim()) + return; + + _scheduler.Update(diff); + + DoMeleeAttackIfReady(); + } + +private: + TaskScheduler _scheduler; + ObjectGuid _portalGUID; +}; + +struct npc_giant_eye_tentacle : public ScriptedAI +{ + npc_giant_eye_tentacle(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + + if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) { - _scheduler.Schedule(500ms, [this](TaskContext /*task*/) + portal->SetReactState(REACT_PASSIVE); + _portalGUID = portal->GetGUID(); + } + } + + void JustDied(Unit* /*killer*/) override + { + if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID)) + { + Unit::Kill(p, p); + } + } + + void Reset() override + { + _scheduler.Schedule(500ms, [this](TaskContext /*task*/) { DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE); - }).Schedule(1s, 5s, [this](TaskContext context) { + }).Schedule(1s, 5s, [this](TaskContext context) + { if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID)) { DoCast(target, SPELL_GREEN_BEAM); @@ -1167,36 +1110,33 @@ public: context.Repeat(2100ms); }); - } + } - void EnterCombat(Unit* /*who*/) override - { - DoZoneInCombat(); - } + void EnterCombat(Unit* /*who*/) override + { + DoZoneInCombat(); + } - void UpdateAI(uint32 diff) override - { - //Check if we have a target - if (!UpdateVictim()) - return; + void UpdateAI(uint32 diff) override + { + //Check if we have a target + if (!UpdateVictim()) + return; - _scheduler.Update(diff); - } + _scheduler.Update(diff); + } - private: - TaskScheduler _scheduler; - ObjectGuid _portalGUID; - }; +private: + TaskScheduler _scheduler; + ObjectGuid _portalGUID; }; -//GetAIs - void AddSC_boss_cthun() { - new boss_eye_of_cthun(); - new boss_cthun(); - new npc_eye_tentacle(); - new npc_claw_tentacle(); - new npc_giant_claw_tentacle(); - new npc_giant_eye_tentacle(); + RegisterTempleOfAhnQirajCreatureAI(boss_eye_of_cthun); + RegisterTempleOfAhnQirajCreatureAI(boss_cthun); + RegisterTempleOfAhnQirajCreatureAI(npc_eye_tentacle); + RegisterTempleOfAhnQirajCreatureAI(npc_claw_tentacle); + RegisterTempleOfAhnQirajCreatureAI(npc_giant_claw_tentacle); + RegisterTempleOfAhnQirajCreatureAI(npc_giant_eye_tentacle); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp index fdd08243b..c35ddb6ea 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp @@ -42,72 +42,68 @@ enum Spells SPELL_ENRAGE = 28798 }; -class boss_fankriss : public CreatureScript +struct boss_fankriss : public ScriptedAI { -public: - boss_fankriss() : CreatureScript("boss_fankriss") { } + boss_fankriss(Creature* creature) : ScriptedAI(creature) { } - CreatureAI* GetAI(Creature* creature) const override + void SummonSpawn() { - return GetTempleOfAhnQirajAI(creature); - } - - struct boss_fankrissAI : public ScriptedAI - { - boss_fankrissAI(Creature* creature) : ScriptedAI(creature) { } - - void SummonSpawn() + Rand = 10 + (rand() % 10); + switch (rand() % 2) { - Rand = 10 + (rand() % 10); - switch (rand() % 2) - { - case 0: - RandX = 0.0f - Rand; - break; - case 1: - RandX = 0.0f + Rand; - break; - } - - Rand = 10 + (rand() % 10); - switch (rand() % 2) - { - case 0: - RandY = 0.0f - Rand; - break; - case 1: - RandY = 0.0f + Rand; - break; - } - Rand = 0; - DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + case 0: + RandX = 0.0f - Rand; + break; + case 1: + RandX = 0.0f + Rand; + break; } - void EnterCombat(Unit* /*who*/) override + Rand = 10 + (rand() % 10); + switch (rand() % 2) { - _scheduler.CancelAll(); + case 0: + RandY = 0.0f - Rand; + break; + case 1: + RandY = 0.0f + Rand; + break; + } + Rand = 0; + DoSpawnCreature(15630, RandX, RandY, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); + } - _scheduler.Schedule(4s, 8s, [this](TaskContext context) { + void EnterCombat(Unit* /*who*/) override + { + _scheduler.CancelAll(); + + _scheduler + .Schedule(4s, 8s, [this](TaskContext context) + { DoCastVictim(SPELL_MORTAL_WOUND); context.Repeat(); - }).Schedule(15s, 45s, [this](TaskContext context) { + }) + .Schedule(15s, 45s, [this](TaskContext context) + { switch (urand(0, 2)) { - case 0: - SummonSpawn(); - break; - case 1: - SummonSpawn(); - SummonSpawn(); - break; - case 2: - SummonSpawn(); - SummonSpawn(); - SummonSpawn(); - break; + case 0: + SummonSpawn(); + break; + case 1: + SummonSpawn(); + SummonSpawn(); + break; + case 2: + SummonSpawn(); + SummonSpawn(); + SummonSpawn(); + break; } context.Repeat(30s, 60s); - }).Schedule(15s, 45s, [this](TaskContext context) { + }) + .Schedule(15s, 45s, [this](TaskContext context) + { if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) { DoCast(target, SPELL_ROOT); @@ -142,27 +138,26 @@ public: } context.Repeat(45s, 60s); }); - } + } - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) - return; + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; - _scheduler.Update(diff, - std::bind(&ScriptedAI::DoMeleeAttackIfReady, this)); - } + _scheduler.Update(diff, + std::bind(&ScriptedAI::DoMeleeAttackIfReady, this)); + } - private: - TaskScheduler _scheduler; - int Rand; - float RandX; - float RandY; - }; +private: + TaskScheduler _scheduler; + int Rand; + float RandX; + float RandY; }; void AddSC_boss_fankriss() { - new boss_fankriss(); + RegisterTempleOfAhnQirajCreatureAI(boss_fankriss); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp index bdd58744e..5a2d7255b 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp @@ -41,115 +41,104 @@ enum Huhuran SPELL_WYVERN_STING_DAMAGE = 26233 }; -class boss_huhuran : public CreatureScript +struct boss_huhuran : public ScriptedAI { -public: - boss_huhuran() : CreatureScript("boss_huhuran") { } + boss_huhuran(Creature* creature) : ScriptedAI(creature) { } - CreatureAI* GetAI(Creature* creature) const override + uint32 Frenzy_Timer; + uint32 Wyvern_Timer; + uint32 Spit_Timer; + uint32 PoisonBolt_Timer; + uint32 NoxiousPoison_Timer; + uint32 FrenzyBack_Timer; + + bool Frenzy; + bool Berserk; + + void Reset() override { - return GetTempleOfAhnQirajAI(creature); + Frenzy_Timer = urand(25000, 35000); + Wyvern_Timer = urand(18000, 28000); + Spit_Timer = 8000; + PoisonBolt_Timer = 4000; + NoxiousPoison_Timer = urand(10000, 20000); + FrenzyBack_Timer = 15000; + + Frenzy = false; + Berserk = false; } - struct boss_huhuranAI : public ScriptedAI + void UpdateAI(uint32 diff) override { - boss_huhuranAI(Creature* creature) : ScriptedAI(creature) { } + //Return since we have no target + if (!UpdateVictim()) + return; - uint32 Frenzy_Timer; - uint32 Wyvern_Timer; - uint32 Spit_Timer; - uint32 PoisonBolt_Timer; - uint32 NoxiousPoison_Timer; - uint32 FrenzyBack_Timer; - - bool Frenzy; - bool Berserk; - - void Reset() override + //Frenzy_Timer + if (!Frenzy && Frenzy_Timer <= diff) { + DoCast(me, SPELL_FRENZY); + Talk(EMOTE_FRENZY_KILL); + Frenzy = true; + PoisonBolt_Timer = 3000; Frenzy_Timer = urand(25000, 35000); - Wyvern_Timer = urand(18000, 28000); - Spit_Timer = 8000; - PoisonBolt_Timer = 4000; - NoxiousPoison_Timer = urand(10000, 20000); - FrenzyBack_Timer = 15000; - - Frenzy = false; - Berserk = false; } + else Frenzy_Timer -= diff; - void UpdateAI(uint32 diff) override + // Wyvern Timer + if (Wyvern_Timer <= diff) { - //Return since we have no target - if (!UpdateVictim()) - return; - - //Frenzy_Timer - if (!Frenzy && Frenzy_Timer <= diff) - { - DoCast(me, SPELL_FRENZY); - Talk(EMOTE_FRENZY_KILL); - Frenzy = true; - PoisonBolt_Timer = 3000; - Frenzy_Timer = urand(25000, 35000); - } - else Frenzy_Timer -= diff; - - // Wyvern Timer - if (Wyvern_Timer <= diff) - { - DoCastAOE(SPELL_WYVERNSTING); - Wyvern_Timer = urand(15000, 32000); - } - else Wyvern_Timer -= diff; - - //Spit Timer - if (Spit_Timer <= diff) - { - DoCastVictim(SPELL_ACIDSPIT); - Spit_Timer = urand(5000, 10000); - } - else Spit_Timer -= diff; - - //NoxiousPoison_Timer - if (NoxiousPoison_Timer <= diff) - { - DoCastVictim(SPELL_NOXIOUSPOISON); - NoxiousPoison_Timer = urand(12000, 24000); - } - else NoxiousPoison_Timer -= diff; - - //PoisonBolt only if frenzy or berserk - if (Frenzy || Berserk) - { - if (PoisonBolt_Timer <= diff) - { - DoCastVictim(SPELL_POISONBOLT); - PoisonBolt_Timer = 3000; - } - else PoisonBolt_Timer -= diff; - } - - //FrenzyBack_Timer - if (Frenzy && FrenzyBack_Timer <= diff) - { - me->InterruptNonMeleeSpells(false); - Frenzy = false; - FrenzyBack_Timer = 15000; - } - else FrenzyBack_Timer -= diff; - - if (!Berserk && HealthBelowPct(31)) - { - me->InterruptNonMeleeSpells(false); - Talk(EMOTE_BERSERK); - DoCast(me, SPELL_BERSERK); - Berserk = true; - } - - DoMeleeAttackIfReady(); + DoCastAOE(SPELL_WYVERNSTING); + Wyvern_Timer = urand(15000, 32000); } - }; + else Wyvern_Timer -= diff; + + //Spit Timer + if (Spit_Timer <= diff) + { + DoCastVictim(SPELL_ACIDSPIT); + Spit_Timer = urand(5000, 10000); + } + else Spit_Timer -= diff; + + //NoxiousPoison_Timer + if (NoxiousPoison_Timer <= diff) + { + DoCastVictim(SPELL_NOXIOUSPOISON); + NoxiousPoison_Timer = urand(12000, 24000); + } + else NoxiousPoison_Timer -= diff; + + //PoisonBolt only if frenzy or berserk + if (Frenzy || Berserk) + { + if (PoisonBolt_Timer <= diff) + { + DoCastVictim(SPELL_POISONBOLT); + PoisonBolt_Timer = 3000; + } + else PoisonBolt_Timer -= diff; + } + + //FrenzyBack_Timer + if (Frenzy && FrenzyBack_Timer <= diff) + { + me->InterruptNonMeleeSpells(false); + Frenzy = false; + FrenzyBack_Timer = 15000; + } + else FrenzyBack_Timer -= diff; + + if (!Berserk && HealthBelowPct(31)) + { + me->InterruptNonMeleeSpells(false); + Talk(EMOTE_BERSERK); + DoCast(me, SPELL_BERSERK); + Berserk = true; + } + + DoMeleeAttackIfReady(); + } }; // 26180 - Wyvern Sting @@ -173,6 +162,6 @@ class spell_huhuran_wyvern_sting : public AuraScript void AddSC_boss_huhuran() { - new boss_huhuran(); + RegisterTempleOfAhnQirajCreatureAI(boss_huhuran); RegisterSpellScript(spell_huhuran_wyvern_sting); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp index 0969f3e53..59f655c92 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp @@ -36,167 +36,145 @@ enum Spells SPELL_SUMMON_OURO = 26061 }; -class npc_ouro_spawner : public CreatureScript +struct npc_ouro_spawner : public ScriptedAI { -public: - npc_ouro_spawner() : CreatureScript("npc_ouro_spawner") {} - - CreatureAI* GetAI(Creature* creature) const + npc_ouro_spawner(Creature* creature) : ScriptedAI(creature) { - return new npc_ouro_spawnerAI(creature); + Reset(); } - struct npc_ouro_spawnerAI : public ScriptedAI + bool hasSummoned; + + void Reset() override { - npc_ouro_spawnerAI(Creature* creature) : ScriptedAI(creature) + hasSummoned = false; + DoCast(me, SPELL_DIRTMOUND_PASSIVE); + } + + void MoveInLineOfSight(Unit* who) override + { + // Spawn Ouro on LoS check + if (!hasSummoned && who->GetTypeId() == TYPEID_PLAYER && me->IsWithinDistInMap(who, 40.0f)) { - Reset(); + DoCast(me, SPELL_SUMMON_OURO); + hasSummoned = true; } - bool hasSummoned; + ScriptedAI::MoveInLineOfSight(who); + } - void Reset() override + void JustSummoned(Creature* creature) override + { + // Despawn when Ouro is spawned + if (creature->GetEntry() == NPC_OURO) { - hasSummoned = false; - DoCast(me, SPELL_DIRTMOUND_PASSIVE); + creature->SetInCombatWithZone(); + creature->CastSpell(creature, SPELL_BIRTH, false); + me->DespawnOrUnsummon(); } + } - void MoveInLineOfSight(Unit* who) override - { - // Spawn Ouro on LoS check - if (!hasSummoned && who->GetTypeId() == TYPEID_PLAYER && me->IsWithinDistInMap(who, 40.0f)) - { - DoCast(me, SPELL_SUMMON_OURO); - hasSummoned = true; - } - - ScriptedAI::MoveInLineOfSight(who); - } - - void JustSummoned(Creature* creature) override - { - // Despawn when Ouro is spawned - if (creature->GetEntry() == NPC_OURO) - { - creature->SetInCombatWithZone(); - creature->CastSpell(creature, SPELL_BIRTH, false); - me->DespawnOrUnsummon(); - } - } - - }; }; -class boss_ouro : public CreatureScript +struct boss_ouro : public ScriptedAI { -public: - boss_ouro() : CreatureScript("boss_ouro") { } + boss_ouro(Creature* creature) : ScriptedAI(creature) { } - CreatureAI* GetAI(Creature* creature) const override + uint32 Sweep_Timer; + uint32 SandBlast_Timer; + uint32 Submerge_Timer; + uint32 Back_Timer; + uint32 ChangeTarget_Timer; + uint32 Spawn_Timer; + + bool Enrage; + bool Submerged; + + void Reset() override { - return GetTempleOfAhnQirajAI(creature); + Sweep_Timer = urand(5000, 10000); + SandBlast_Timer = urand(20000, 35000); + Submerge_Timer = urand(90000, 150000); + Back_Timer = urand(30000, 45000); + ChangeTarget_Timer = urand(5000, 8000); + Spawn_Timer = urand(10000, 20000); + + Enrage = false; + Submerged = false; } - struct boss_ouroAI : public ScriptedAI + void EnterCombat(Unit* /*who*/) override { - boss_ouroAI(Creature* creature) : ScriptedAI(creature) { } + DoCastVictim(SPELL_BIRTH); + } - uint32 Sweep_Timer; - uint32 SandBlast_Timer; - uint32 Submerge_Timer; - uint32 Back_Timer; - uint32 ChangeTarget_Timer; - uint32 Spawn_Timer; + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; - bool Enrage; - bool Submerged; - - void Reset() override + //Sweep_Timer + if (!Submerged && Sweep_Timer <= diff) { - Sweep_Timer = urand(5000, 10000); + DoCastVictim(SPELL_SWEEP); + Sweep_Timer = urand(15000, 30000); + } + else Sweep_Timer -= diff; + + //SandBlast_Timer + if (!Submerged && SandBlast_Timer <= diff) + { + DoCastVictim(SPELL_SANDBLAST); SandBlast_Timer = urand(20000, 35000); - Submerge_Timer = urand(90000, 150000); + } + else SandBlast_Timer -= diff; + + //Submerge_Timer + if (!Submerged && Submerge_Timer <= diff) + { + //Cast + me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetFaction(FACTION_FRIENDLY); + DoCast(me, SPELL_DIRTMOUND_PASSIVE); + + Submerged = true; Back_Timer = urand(30000, 45000); - ChangeTarget_Timer = urand(5000, 8000); - Spawn_Timer = urand(10000, 20000); + } + else Submerge_Timer -= diff; + + //ChangeTarget_Timer + if (Submerged && ChangeTarget_Timer <= diff) + { + Unit* target = SelectTarget(SelectTargetMethod::Random, 0); + + if (target) + me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), me->GetOrientation()); + + ChangeTarget_Timer = urand(10000, 20000); + } + else ChangeTarget_Timer -= diff; + + //Back_Timer + if (Submerged && Back_Timer <= diff) + { + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetFaction(FACTION_MONSTER); + + DoCastVictim(SPELL_GROUND_RUPTURE); - Enrage = false; Submerged = false; + Submerge_Timer = urand(60000, 120000); } + else Back_Timer -= diff; - void EnterCombat(Unit* /*who*/) override - { - DoCastVictim(SPELL_BIRTH); - } - - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) - return; - - //Sweep_Timer - if (!Submerged && Sweep_Timer <= diff) - { - DoCastVictim(SPELL_SWEEP); - Sweep_Timer = urand(15000, 30000); - } - else Sweep_Timer -= diff; - - //SandBlast_Timer - if (!Submerged && SandBlast_Timer <= diff) - { - DoCastVictim(SPELL_SANDBLAST); - SandBlast_Timer = urand(20000, 35000); - } - else SandBlast_Timer -= diff; - - //Submerge_Timer - if (!Submerged && Submerge_Timer <= diff) - { - //Cast - me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(FACTION_FRIENDLY); - DoCast(me, SPELL_DIRTMOUND_PASSIVE); - - Submerged = true; - Back_Timer = urand(30000, 45000); - } - else Submerge_Timer -= diff; - - //ChangeTarget_Timer - if (Submerged && ChangeTarget_Timer <= diff) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 0); - - if (target) - me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), me->GetOrientation()); - - ChangeTarget_Timer = urand(10000, 20000); - } - else ChangeTarget_Timer -= diff; - - //Back_Timer - if (Submerged && Back_Timer <= diff) - { - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetFaction(FACTION_MONSTER); - - DoCastVictim(SPELL_GROUND_RUPTURE); - - Submerged = false; - Submerge_Timer = urand(60000, 120000); - } - else Back_Timer -= diff; - - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } }; void AddSC_boss_ouro() { - new npc_ouro_spawner(); - new boss_ouro(); + RegisterTempleOfAhnQirajCreatureAI(npc_ouro_spawner); + RegisterTempleOfAhnQirajCreatureAI(boss_ouro); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp index 5944c9e95..4a9fc1ac3 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp @@ -47,183 +47,161 @@ enum Events uint32 const BlinkSpells[3] = { 4801, 8195, 20449 }; -class boss_skeram : public CreatureScript +struct boss_skeram : public BossAI { -public: - boss_skeram() : CreatureScript("boss_skeram") { } + boss_skeram(Creature* creature) : BossAI(creature, DATA_SKERAM) { } - struct boss_skeramAI : public BossAI + void Reset() override { - boss_skeramAI(Creature* creature) : BossAI(creature, DATA_SKERAM) { } + _Reset(); + _flag = 0; + _hpct = 75.0f; + me->SetVisible(true); + } - void Reset() override + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_SLAY); + } + + void EnterEvadeMode(EvadeReason why) override + { + ScriptedAI::EnterEvadeMode(why); + if (me->IsSummon()) + ((TempSummon*)me)->UnSummon(); + } + + void JustSummoned(Creature* creature) override + { + // Shift the boss and images (Get it? *Shift*?) + uint8 rand = 0; + if (_flag != 0) { - _Reset(); - _flag = 0; - _hpct = 75.0f; - me->SetVisible(true); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_SLAY); - } - - void EnterEvadeMode(EvadeReason why) override - { - ScriptedAI::EnterEvadeMode(why); - if (me->IsSummon()) - ((TempSummon*)me)->UnSummon(); - } - - void JustSummoned(Creature* creature) override - { - // Shift the boss and images (Get it? *Shift*?) - uint8 rand = 0; - if (_flag != 0) - { - while (_flag & (1 << rand)) - rand = urand(0, 2); - DoCast(me, BlinkSpells[rand]); - _flag |= (1 << rand); - _flag |= (1 << 7); - } - while (_flag & (1 << rand)) rand = urand(0, 2); - creature->CastSpell(creature, BlinkSpells[rand]); + DoCast(me, BlinkSpells[rand]); _flag |= (1 << rand); - - if (_flag & (1 << 7)) - _flag = 0; - - float ImageHealthPct; - - if (me->GetHealthPct() < 25.0f) - ImageHealthPct = 0.50f; - else if (me->GetHealthPct() < 50.0f) - ImageHealthPct = 0.20f; - else - ImageHealthPct = 0.10f; - - creature->SetMaxHealth(me->GetMaxHealth() * ImageHealthPct); - creature->SetHealth(creature->GetMaxHealth() * (me->GetHealthPct() / 100.0f)); - BossAI::JustSummoned(creature); + _flag |= (1 << 7); } - void JustDied(Unit* /*killer*/) override - { - if (!me->IsSummon()) - { - _JustDied(); - Talk(SAY_DEATH); - } - else - me->RemoveCorpse(); - } + while (_flag & (1 << rand)) + rand = urand(0, 2); + creature->CastSpell(creature, BlinkSpells[rand]); + _flag |= (1 << rand); - void EnterCombat(Unit* /*who*/) override - { - _EnterCombat(); - events.Reset(); + if (_flag & (1 << 7)) + _flag = 0; - events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(6000, 12000)); - events.ScheduleEvent(EVENT_FULLFILMENT, 15000); - events.ScheduleEvent(EVENT_BLINK, urand(30000, 45000)); - events.ScheduleEvent(EVENT_EARTH_SHOCK, 2000); + float ImageHealthPct; - Talk(SAY_AGGRO); - } + if (me->GetHealthPct() < 25.0f) + ImageHealthPct = 0.50f; + else if (me->GetHealthPct() < 50.0f) + ImageHealthPct = 0.20f; + else + ImageHealthPct = 0.10f; - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_ARCANE_EXPLOSION: - DoCastAOE(SPELL_ARCANE_EXPLOSION, true); - events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(8000, 18000)); - break; - case EVENT_FULLFILMENT: - /// @todo For some weird reason boss does not cast this - // Spell actually works, tested in duel - DoCast(SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true), SPELL_TRUE_FULFILLMENT, true); - events.ScheduleEvent(EVENT_FULLFILMENT, urand(20000, 30000)); - break; - case EVENT_BLINK: - DoCast(me, BlinkSpells[urand(0, 2)]); - DoResetThreat(); - me->SetVisible(true); - events.ScheduleEvent(EVENT_BLINK, urand(10000, 30000)); - break; - case EVENT_EARTH_SHOCK: - DoCastVictim(SPELL_EARTH_SHOCK); - events.ScheduleEvent(EVENT_EARTH_SHOCK, 2000); - break; - } - } - - if (!me->IsSummon() && me->GetHealthPct() < _hpct) - { - DoCast(me, SPELL_SUMMON_IMAGES, true); - Talk(SAY_SPLIT); - _hpct -= 25.0f; - me->SetVisible(false); - events.RescheduleEvent(EVENT_BLINK, 2000); - } - - if (me->IsWithinMeleeRange(me->GetVictim())) - { - events.RescheduleEvent(EVENT_EARTH_SHOCK, 2000); - DoMeleeAttackIfReady(); - } - } - - private: - float _hpct; - uint8 _flag; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetTempleOfAhnQirajAI(creature); + creature->SetMaxHealth(me->GetMaxHealth() * ImageHealthPct); + creature->SetHealth(creature->GetMaxHealth() * (me->GetHealthPct() / 100.0f)); + BossAI::JustSummoned(creature); } + + void JustDied(Unit* /*killer*/) override + { + if (!me->IsSummon()) + { + _JustDied(); + Talk(SAY_DEATH); + } + else + me->RemoveCorpse(); + } + + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + events.Reset(); + + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 6s, 12s); + events.ScheduleEvent(EVENT_FULLFILMENT, 15s); + events.ScheduleEvent(EVENT_BLINK, 30s, 45s); + events.ScheduleEvent(EVENT_EARTH_SHOCK, 2s); + + Talk(SAY_AGGRO); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ARCANE_EXPLOSION: + DoCastAOE(SPELL_ARCANE_EXPLOSION, true); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 8s, 18s); + break; + case EVENT_FULLFILMENT: + /// @todo For some weird reason boss does not cast this + // Spell actually works, tested in duel + DoCast(SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true), SPELL_TRUE_FULFILLMENT, true); + events.ScheduleEvent(EVENT_FULLFILMENT, 20s, 30s); + break; + case EVENT_BLINK: + DoCast(me, BlinkSpells[urand(0, 2)]); + DoResetThreat(); + me->SetVisible(true); + events.ScheduleEvent(EVENT_BLINK, 10s, 30s); + break; + case EVENT_EARTH_SHOCK: + DoCastVictim(SPELL_EARTH_SHOCK); + events.ScheduleEvent(EVENT_EARTH_SHOCK, 2s); + break; + } + } + + if (!me->IsSummon() && me->GetHealthPct() < _hpct) + { + DoCast(me, SPELL_SUMMON_IMAGES, true); + Talk(SAY_SPLIT); + _hpct -= 25.0f; + me->SetVisible(false); + events.RescheduleEvent(EVENT_BLINK, 2s); + } + + if (me->IsWithinMeleeRange(me->GetVictim())) + { + events.RescheduleEvent(EVENT_EARTH_SHOCK, 2s); + DoMeleeAttackIfReady(); + } + } + +private: + float _hpct; + uint8 _flag; }; -class spell_skeram_arcane_explosion : public SpellScriptLoader +class spell_skeram_arcane_explosion : public SpellScript { -public: - spell_skeram_arcane_explosion() : SpellScriptLoader("spell_skeram_arcane_explosion") { } + PrepareSpellScript(spell_skeram_arcane_explosion); - class spell_skeram_arcane_explosion_SpellScript : public SpellScript + void FilterTargets(std::list& targets) { - PrepareSpellScript(spell_skeram_arcane_explosion_SpellScript); + targets.remove_if(PlayerOrPetCheck()); + } - void FilterTargets(std::list& targets) - { - targets.remove_if(PlayerOrPetCheck()); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_skeram_arcane_explosion_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override + void Register() override { - return new spell_skeram_arcane_explosion_SpellScript(); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_skeram_arcane_explosion::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); } }; void AddSC_boss_skeram() { - new boss_skeram(); - new spell_skeram_arcane_explosion(); + RegisterTempleOfAhnQirajCreatureAI(boss_skeram); + RegisterSpellScript(spell_skeram_arcane_explosion); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp index 841280dcf..33b32fa44 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp @@ -377,223 +377,203 @@ struct boss_twinemperorsAI : public ScriptedAI } }; -class boss_veknilash : public CreatureScript +struct boss_veknilash : public boss_twinemperorsAI { -public: - boss_veknilash() : CreatureScript("boss_veknilash") { } + boss_veknilash(Creature* creature) : boss_twinemperorsAI(creature) { } - CreatureAI* GetAI(Creature* creature) const override + bool IAmVeklor() override { return false; } + + uint32 UpperCut_Timer; + uint32 UnbalancingStrike_Timer; + uint32 Scarabs_Timer; + int Rand; + int RandX; + int RandY; + + Creature* Summoned; + + void Reset() override { - return GetTempleOfAhnQirajAI(creature); + TwinReset(); + UpperCut_Timer = urand(14000, 29000); + UnbalancingStrike_Timer = urand(8000, 18000); + Scarabs_Timer = urand(7000, 14000); + + //Added. Can be removed if its included in DB. + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); } - struct boss_veknilashAI : public boss_twinemperorsAI + void CastSpellOnBug(Creature* target) override { - bool IAmVeklor() override {return false;} - boss_veknilashAI(Creature* creature) : boss_twinemperorsAI(creature) { } + target->SetFaction(FACTION_MONSTER); + target->AI()->AttackStart(me->GetThreatMgr().getHostileTarget()); + target->AddAura(SPELL_MUTATE_BUG, target); + target->SetFullHealth(); + } - uint32 UpperCut_Timer; - uint32 UnbalancingStrike_Timer; - uint32 Scarabs_Timer; - int Rand; - int RandX; - int RandY; + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; - Creature* Summoned; + if (!TryActivateAfterTTelep(diff)) + return; - void Reset() override + //UnbalancingStrike_Timer + if (UnbalancingStrike_Timer <= diff) { - TwinReset(); - UpperCut_Timer = urand(14000, 29000); - UnbalancingStrike_Timer = urand(8000, 18000); - Scarabs_Timer = urand(7000, 14000); - - //Added. Can be removed if its included in DB. - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true); + DoCastVictim(SPELL_UNBALANCING_STRIKE); + UnbalancingStrike_Timer = 8000 + rand() % 12000; } + else UnbalancingStrike_Timer -= diff; - void CastSpellOnBug(Creature* target) override + if (UpperCut_Timer <= diff) { - target->SetFaction(FACTION_MONSTER); - target->AI()->AttackStart(me->GetThreatMgr().getHostileTarget()); - target->AddAura(SPELL_MUTATE_BUG, target); - target->SetFullHealth(); + Unit* randomMelee = SelectTarget(SelectTargetMethod::Random, 0, NOMINAL_MELEE_RANGE, true); + if (randomMelee) + DoCast(randomMelee, SPELL_UPPERCUT); + UpperCut_Timer = 15000 + rand() % 15000; } + else UpperCut_Timer -= diff; - void UpdateAI(uint32 diff) override + HandleBugs(diff); + + //Heal brother when 60yrds close + TryHealBrother(diff); + + //Teleporting to brother + if (Teleport_Timer <= diff) { - //Return since we have no target - if (!UpdateVictim()) - return; - - if (!TryActivateAfterTTelep(diff)) - return; - - //UnbalancingStrike_Timer - if (UnbalancingStrike_Timer <= diff) - { - DoCastVictim(SPELL_UNBALANCING_STRIKE); - UnbalancingStrike_Timer = 8000 + rand() % 12000; - } - else UnbalancingStrike_Timer -= diff; - - if (UpperCut_Timer <= diff) - { - Unit* randomMelee = SelectTarget(SelectTargetMethod::Random, 0, NOMINAL_MELEE_RANGE, true); - if (randomMelee) - DoCast(randomMelee, SPELL_UPPERCUT); - UpperCut_Timer = 15000 + rand() % 15000; - } - else UpperCut_Timer -= diff; - - HandleBugs(diff); - - //Heal brother when 60yrds close - TryHealBrother(diff); - - //Teleporting to brother - if (Teleport_Timer <= diff) - { - TeleportToMyBrother(); - } - else Teleport_Timer -= diff; - - CheckEnrage(diff); - - DoMeleeAttackIfReady(); + TeleportToMyBrother(); } - }; + else Teleport_Timer -= diff; + + CheckEnrage(diff); + + DoMeleeAttackIfReady(); + } }; -class boss_veklor : public CreatureScript +struct boss_veklor : public boss_twinemperorsAI { -public: - boss_veklor() : CreatureScript("boss_veklor") { } + boss_veklor(Creature* creature) : boss_twinemperorsAI(creature) { } - CreatureAI* GetAI(Creature* creature) const override + bool IAmVeklor() override { return true; } + + uint32 ShadowBolt_Timer; + uint32 Blizzard_Timer; + uint32 ArcaneBurst_Timer; + uint32 Scorpions_Timer; + int Rand; + int RandX; + + Creature* Summoned; + + void Reset() override { - return GetTempleOfAhnQirajAI(creature); + TwinReset(); + ShadowBolt_Timer = 0; + Blizzard_Timer = urand(15000, 20000); + ArcaneBurst_Timer = 1000; + Scorpions_Timer = urand(7000, 14000); + + //Added. Can be removed if its included in DB. + me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); } - struct boss_veklorAI : public boss_twinemperorsAI + void CastSpellOnBug(Creature* target) override { - bool IAmVeklor() override {return true;} - boss_veklorAI(Creature* creature) : boss_twinemperorsAI(creature) { } + target->SetFaction(FACTION_MONSTER); + target->AddAura(SPELL_EXPLODEBUG, target); + target->SetFullHealth(); + } - uint32 ShadowBolt_Timer; - uint32 Blizzard_Timer; - uint32 ArcaneBurst_Timer; - uint32 Scorpions_Timer; - int Rand; - int RandX; + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; - Creature* Summoned; + // reset arcane burst after teleport - we need to do this because + // when VL jumps to VN's location there will be a warrior who will get only 2s to run away + // which is almost impossible + if (AfterTeleport) + ArcaneBurst_Timer = 5000; + if (!TryActivateAfterTTelep(diff)) + return; - void Reset() override + //ShadowBolt_Timer + if (ShadowBolt_Timer <= diff) { - TwinReset(); - ShadowBolt_Timer = 0; - Blizzard_Timer = urand(15000, 20000); - ArcaneBurst_Timer = 1000; - Scorpions_Timer = urand(7000, 14000); - - //Added. Can be removed if its included in DB. - me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); + if (!me->IsWithinDist(me->GetVictim(), 45.0f)) + me->GetMotionMaster()->MoveChase(me->GetVictim(), VEKLOR_DIST, 0); + else + DoCastVictim(SPELL_SHADOWBOLT); + ShadowBolt_Timer = 2000; } + else ShadowBolt_Timer -= diff; - void CastSpellOnBug(Creature* target) override + //Blizzard_Timer + if (Blizzard_Timer <= diff) { - target->SetFaction(FACTION_MONSTER); - target->AddAura(SPELL_EXPLODEBUG, target); - target->SetFullHealth(); + Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45, true); + if (target) + { + DoCast(target, SPELL_BLIZZARD); + } + Blizzard_Timer = 15000 + rand() % 15000; } + else Blizzard_Timer -= diff; - void UpdateAI(uint32 diff) override + if (ArcaneBurst_Timer <= diff) { - //Return since we have no target - if (!UpdateVictim()) - return; - - // reset arcane burst after teleport - we need to do this because - // when VL jumps to VN's location there will be a warrior who will get only 2s to run away - // which is almost impossible - if (AfterTeleport) + Unit* mvic; + if ((mvic = SelectTarget(SelectTargetMethod::MaxDistance, 0, NOMINAL_MELEE_RANGE, true)) != nullptr) + { + DoCast(mvic, SPELL_ARCANEBURST); ArcaneBurst_Timer = 5000; - if (!TryActivateAfterTTelep(diff)) - return; - - //ShadowBolt_Timer - if (ShadowBolt_Timer <= diff) - { - if (!me->IsWithinDist(me->GetVictim(), 45.0f)) - me->GetMotionMaster()->MoveChase(me->GetVictim(), VEKLOR_DIST, 0); - else - DoCastVictim(SPELL_SHADOWBOLT); - ShadowBolt_Timer = 2000; } - else ShadowBolt_Timer -= diff; - - //Blizzard_Timer - if (Blizzard_Timer <= diff) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45, true); - if (target) - { - DoCast(target, SPELL_BLIZZARD); - } - Blizzard_Timer = 15000 + rand() % 15000; - } - else Blizzard_Timer -= diff; - - if (ArcaneBurst_Timer <= diff) - { - Unit* mvic; - if ((mvic = SelectTarget(SelectTargetMethod::MaxDistance, 0, NOMINAL_MELEE_RANGE, true)) != nullptr) - { - DoCast(mvic, SPELL_ARCANEBURST); - ArcaneBurst_Timer = 5000; - } - } - else ArcaneBurst_Timer -= diff; - - HandleBugs(diff); - - //Heal brother when 60yrds close - TryHealBrother(diff); - - //Teleporting to brother - if (Teleport_Timer <= diff) - { - TeleportToMyBrother(); - } - else Teleport_Timer -= diff; - - CheckEnrage(diff); - - //VL doesn't melee - //DoMeleeAttackIfReady(); } + else ArcaneBurst_Timer -= diff; - void AttackStart(Unit* who) override + HandleBugs(diff); + + //Heal brother when 60yrds close + TryHealBrother(diff); + + //Teleporting to brother + if (Teleport_Timer <= diff) { - if (!who) - return; + TeleportToMyBrother(); + } + else Teleport_Timer -= diff; - if (who->isTargetableForAttack()) + CheckEnrage(diff); + + //VL doesn't melee + //DoMeleeAttackIfReady(); + } + + void AttackStart(Unit* who) override + { + if (!who) + return; + + if (who->isTargetableForAttack()) + { + // VL doesn't melee + if (me->Attack(who, false)) { - // VL doesn't melee - if (me->Attack(who, false)) - { - me->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0); - me->AddThreat(who, 0.0f); - } + me->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0); + me->AddThreat(who, 0.0f); } } - }; + } }; void AddSC_boss_twinemperors() { - new boss_veknilash(); - new boss_veklor(); + RegisterTempleOfAhnQirajCreatureAI(boss_veknilash); + RegisterTempleOfAhnQirajCreatureAI(boss_veklor); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp index a993aa06e..e5e0834d1 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp @@ -84,223 +84,201 @@ enum MovePoints Position const ViscidusCoord = { -7992.36f, 908.19f, -52.62f, 1.68f }; /// @todo Visci isn't in room middle float const RoomRadius = 40.0f; /// @todo Not sure if its correct -class boss_viscidus : public CreatureScript +struct boss_viscidus : public BossAI { -public: - boss_viscidus() : CreatureScript("boss_viscidus") { } + boss_viscidus(Creature* creature) : BossAI(creature, DATA_VISCIDUS) { } - struct boss_viscidusAI : public BossAI + void Reset() override { - boss_viscidusAI(Creature* creature) : BossAI(creature, DATA_VISCIDUS) { } + _Reset(); + _hitcounter = 0; + _phase = PHASE_FROST; + } - void Reset() override + void DamageTaken(Unit* attacker, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override + { + if (!attacker || _phase != PHASE_MELEE) + return; + + ++_hitcounter; + + if (attacker->HasUnitState(UNIT_STATE_MELEE_ATTACKING) && _hitcounter >= HITCOUNTER_EXPLODE) { - _Reset(); - _hitcounter = 0; - _phase = PHASE_FROST; + Talk(EMOTE_EXPLODE); + events.Reset(); + _phase = PHASE_GLOB; + DoCast(me, SPELL_VISCIDUS_EXPLODE); + me->SetVisible(false); + me->RemoveAura(SPELL_TOXIN); + me->RemoveAura(SPELL_VISCIDUS_FREEZE); + + uint8 NumGlobes = me->GetHealthPct() / 5.0f; + for (uint8 i = 0; i < NumGlobes; ++i) + { + float Angle = i * 2 * M_PI / NumGlobes; + float X = ViscidusCoord.GetPositionX() + std::cos(Angle) * RoomRadius; + float Y = ViscidusCoord.GetPositionY() + std::sin(Angle) * RoomRadius; + float Z = -35.0f; + + if (TempSummon* Glob = me->SummonCreature(NPC_GLOB_OF_VISCIDUS, X, Y, Z)) + { + Glob->UpdateAllowedPositionZ(X, Y, Z); + Glob->NearTeleportTo(X, Y, Z, 0.0f); + Glob->GetMotionMaster()->MovePoint(ROOM_CENTER, ViscidusCoord); + } + } } + else if (_hitcounter == HITCOUNTER_SHATTER) + Talk(EMOTE_SHATTER); + else if (_hitcounter == HITCOUNTER_CRACK) + Talk(EMOTE_CRACK); + } - void DamageTaken(Unit* attacker, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override + { + if ((spell->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && _phase == PHASE_FROST && me->GetHealthPct() > 5.0f) { - if (!attacker || _phase != PHASE_MELEE) - return; - ++_hitcounter; - if (attacker->HasUnitState(UNIT_STATE_MELEE_ATTACKING) && _hitcounter >= HITCOUNTER_EXPLODE) + if (_hitcounter >= HITCOUNTER_FREEZE) { - Talk(EMOTE_EXPLODE); - events.Reset(); - _phase = PHASE_GLOB; - DoCast(me, SPELL_VISCIDUS_EXPLODE); - me->SetVisible(false); - me->RemoveAura(SPELL_TOXIN); - me->RemoveAura(SPELL_VISCIDUS_FREEZE); - - uint8 NumGlobes = me->GetHealthPct() / 5.0f; - for (uint8 i = 0; i < NumGlobes; ++i) - { - float Angle = i * 2 * M_PI / NumGlobes; - float X = ViscidusCoord.GetPositionX() + std::cos(Angle) * RoomRadius; - float Y = ViscidusCoord.GetPositionY() + std::sin(Angle) * RoomRadius; - float Z = -35.0f; - - if (TempSummon* Glob = me->SummonCreature(NPC_GLOB_OF_VISCIDUS, X, Y, Z)) - { - Glob->UpdateAllowedPositionZ(X, Y, Z); - Glob->NearTeleportTo(X, Y, Z, 0.0f); - Glob->GetMotionMaster()->MovePoint(ROOM_CENTER, ViscidusCoord); - } - } - } - else if (_hitcounter == HITCOUNTER_SHATTER) - Talk(EMOTE_SHATTER); - else if (_hitcounter == HITCOUNTER_CRACK) - Talk(EMOTE_CRACK); - } - - void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override - { - if ((spell->GetSchoolMask() & SPELL_SCHOOL_MASK_FROST) && _phase == PHASE_FROST && me->GetHealthPct() > 5.0f) - { - ++_hitcounter; - - if (_hitcounter >= HITCOUNTER_FREEZE) - { - _hitcounter = 0; - Talk(EMOTE_FROZEN); - _phase = PHASE_MELEE; - DoCast(me, SPELL_VISCIDUS_FREEZE); - me->RemoveAura(SPELL_VISCIDUS_SLOWED_MORE); - events.ScheduleEvent(EVENT_RESET_PHASE, 15000); - } - else if (_hitcounter >= HITCOUNTER_SLOW_MORE) - { - Talk(EMOTE_FREEZE); - me->RemoveAura(SPELL_VISCIDUS_SLOWED); - DoCast(me, SPELL_VISCIDUS_SLOWED_MORE); - } - else if (_hitcounter >= HITCOUNTER_SLOW) - { - Talk(EMOTE_SLOW); - DoCast(me, SPELL_VISCIDUS_SLOWED); - } - } - } - - void EnterCombat(Unit* /*who*/) override - { - _EnterCombat(); - events.Reset(); - InitSpells(); - } - - void InitSpells() - { - DoCast(me, SPELL_TOXIN); - events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, urand(10000, 15000)); - events.ScheduleEvent(EVENT_POISON_SHOCK, urand(7000, 12000)); - } - - void EnterEvadeMode(EvadeReason why) override - { - summons.DespawnAll(); - ScriptedAI::EnterEvadeMode(why); - } - - void JustDied(Unit* /*killer*/) override - { - DoCast(me, SPELL_VISCIDUS_SUICIDE); - summons.DespawnAll(); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - if (_phase == PHASE_GLOB && summons.empty()) - { - DoResetThreat(); - me->NearTeleportTo(ViscidusCoord.GetPositionX(), - ViscidusCoord.GetPositionY(), - ViscidusCoord.GetPositionZ(), - ViscidusCoord.GetOrientation()); - _hitcounter = 0; - _phase = PHASE_FROST; - InitSpells(); - me->SetVisible(true); + Talk(EMOTE_FROZEN); + _phase = PHASE_MELEE; + DoCast(me, SPELL_VISCIDUS_FREEZE); + me->RemoveAura(SPELL_VISCIDUS_SLOWED_MORE); + events.ScheduleEvent(EVENT_RESET_PHASE, 15000); } - - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) + else if (_hitcounter >= HITCOUNTER_SLOW_MORE) { - switch (eventId) - { - case EVENT_POISONBOLT_VOLLEY: - DoCast(me, SPELL_POISONBOLT_VOLLEY); - events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, urand(10000, 15000)); - break; - case EVENT_POISON_SHOCK: - DoCast(me, SPELL_POISON_SHOCK); - events.ScheduleEvent(EVENT_POISON_SHOCK, urand(7000, 12000)); - break; - case EVENT_RESET_PHASE: - _hitcounter = 0; - _phase = PHASE_FROST; - break; - default: - break; - } + Talk(EMOTE_FREEZE); + me->RemoveAura(SPELL_VISCIDUS_SLOWED); + DoCast(me, SPELL_VISCIDUS_SLOWED_MORE); } + else if (_hitcounter >= HITCOUNTER_SLOW) + { + Talk(EMOTE_SLOW); + DoCast(me, SPELL_VISCIDUS_SLOWED); + } + } + } - if (_phase != PHASE_GLOB) - DoMeleeAttackIfReady(); + void EnterCombat(Unit* /*who*/) override + { + _EnterCombat(); + events.Reset(); + InitSpells(); + } + + void InitSpells() + { + DoCast(me, SPELL_TOXIN); + events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, 10s, 15s); + events.ScheduleEvent(EVENT_POISON_SHOCK, 7s, 12s); + } + + void EnterEvadeMode(EvadeReason why) override + { + summons.DespawnAll(); + ScriptedAI::EnterEvadeMode(why); + } + + void JustDied(Unit* /*killer*/) override + { + DoCast(me, SPELL_VISCIDUS_SUICIDE); + summons.DespawnAll(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (_phase == PHASE_GLOB && summons.empty()) + { + DoResetThreat(); + me->NearTeleportTo(ViscidusCoord.GetPositionX(), + ViscidusCoord.GetPositionY(), + ViscidusCoord.GetPositionZ(), + ViscidusCoord.GetOrientation()); + + _hitcounter = 0; + _phase = PHASE_FROST; + InitSpells(); + me->SetVisible(true); } - private: - uint8 _hitcounter; - Phases _phase; - }; + events.Update(diff); - CreatureAI* GetAI(Creature* creature) const override - { - return GetTempleOfAhnQirajAI(creature); + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_POISONBOLT_VOLLEY: + DoCast(me, SPELL_POISONBOLT_VOLLEY); + events.ScheduleEvent(EVENT_POISONBOLT_VOLLEY, 10s, 15s); + break; + case EVENT_POISON_SHOCK: + DoCast(me, SPELL_POISON_SHOCK); + events.ScheduleEvent(EVENT_POISON_SHOCK, 7s, 12s); + break; + case EVENT_RESET_PHASE: + _hitcounter = 0; + _phase = PHASE_FROST; + break; + default: + break; + } + } + + if (_phase != PHASE_GLOB) + DoMeleeAttackIfReady(); } + +private: + uint8 _hitcounter; + Phases _phase; }; -class npc_glob_of_viscidus : public CreatureScript +struct boss_glob_of_viscidus : public ScriptedAI { -public: - npc_glob_of_viscidus() : CreatureScript("boss_glob_of_viscidus") { } + boss_glob_of_viscidus(Creature* creature) : ScriptedAI(creature) { } - struct npc_glob_of_viscidusAI : public ScriptedAI + void JustDied(Unit* /*killer*/) override { - npc_glob_of_viscidusAI(Creature* creature) : ScriptedAI(creature) { } + InstanceScript* instance = me->GetInstanceScript(); - void JustDied(Unit* /*killer*/) override + if (Creature* viscidus = me->GetMap()->GetCreature(instance->GetGuidData(DATA_VISCIDUS))) { - InstanceScript* Instance = me->GetInstanceScript(); + if (BossAI* viscidusAI = dynamic_cast(viscidus->GetAI())) + viscidusAI->SummonedCreatureDespawn(me); - if (Creature* Viscidus = me->GetMap()->GetCreature(Instance->GetGuidData(DATA_VISCIDUS))) + if (viscidus->IsAlive() && viscidus->GetHealthPct() < 5.0f) { - if (BossAI* ViscidusAI = dynamic_cast(Viscidus->GetAI())) - ViscidusAI->SummonedCreatureDespawn(me); - - if (Viscidus->IsAlive() && Viscidus->GetHealthPct() < 5.0f) - { - Viscidus->SetVisible(true); - Unit::Kill(Viscidus->GetVictim(), Viscidus); - } - else - { - Viscidus->SetHealth(Viscidus->GetHealth() - Viscidus->GetMaxHealth() / 20); - Viscidus->CastSpell(Viscidus, SPELL_VISCIDUS_SHRINKS); - } + viscidus->SetVisible(true); + Unit::Kill(viscidus->GetVictim(), viscidus); + } + else + { + viscidus->SetHealth(viscidus->GetHealth() - viscidus->GetMaxHealth() / 20); + viscidus->CastSpell(viscidus, SPELL_VISCIDUS_SHRINKS); } } + } - void MovementInform(uint32 /*type*/, uint32 id) override - { - if (id == ROOM_CENTER) - { - DoCast(me, SPELL_REJOIN_VISCIDUS); - if (TempSummon* summon = me->ToTempSummon()) - summon->UnSummon(); - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void MovementInform(uint32 /*type*/, uint32 id) override { - return GetTempleOfAhnQirajAI(creature); + if (id == ROOM_CENTER) + { + DoCast(me, SPELL_REJOIN_VISCIDUS); + if (TempSummon* summon = me->ToTempSummon()) + summon->UnSummon(); + } } }; void AddSC_boss_viscidus() { - new boss_viscidus(); - new npc_glob_of_viscidus(); + RegisterTempleOfAhnQirajCreatureAI(boss_viscidus); + RegisterTempleOfAhnQirajCreatureAI(boss_glob_of_viscidus); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h index d32f6dbd9..70215f2b1 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h @@ -75,4 +75,6 @@ inline AI* GetTempleOfAhnQirajAI(T* obj) return GetInstanceAI(obj, TempleOfAhnQirajScriptName); } +#define RegisterTempleOfAhnQirajCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetTempleOfAhnQirajAI) + #endif