diff options
8 files changed, 2190 insertions, 2510 deletions
diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp index f7d921875f9..72623c68ace 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp @@ -98,618 +98,562 @@ enum FathomlordKarathress #define MAX_ADVISORS 3 //Fathom-Lord Karathress AI -class boss_fathomlord_karathress : public CreatureScript +struct boss_fathomlord_karathress : public BossAI { -public: - boss_fathomlord_karathress() : CreatureScript("boss_fathomlord_karathress") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_fathomlord_karathress(Creature* creature) : BossAI(creature, BOSS_FATHOM_LORD_KARATHRESS) { - return GetSerpentshrineCavernAI<boss_fathomlord_karathressAI>(creature); + Initialize(); } - struct boss_fathomlord_karathressAI : public ScriptedAI + void Initialize() { - boss_fathomlord_karathressAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - } - - void Initialize() - { - CataclysmicBolt_Timer = 10000; - Enrage_Timer = 600000; //10 minutes - SearNova_Timer = 20000 + rand32() % 40000; // 20 - 60 seconds - - BlessingOfTides = false; - } - - InstanceScript* instance; + CataclysmicBolt_Timer = 10000; + Enrage_Timer = 600000; //10 minutes + SearNova_Timer = 20000 + rand32() % 40000; // 20 - 60 seconds - uint32 CataclysmicBolt_Timer; - uint32 Enrage_Timer; - uint32 SearNova_Timer; + BlessingOfTides = false; + } - bool BlessingOfTides; + uint32 CataclysmicBolt_Timer; + uint32 Enrage_Timer; + uint32 SearNova_Timer; - ObjectGuid Advisors[MAX_ADVISORS]; + bool BlessingOfTides; - void Reset() override - { - Initialize(); + ObjectGuid Advisors[MAX_ADVISORS]; - ObjectGuid RAdvisors[MAX_ADVISORS]; - RAdvisors[0] = instance->GetGuidData(DATA_SHARKKIS); - RAdvisors[1] = instance->GetGuidData(DATA_TIDALVESS); - RAdvisors[2] = instance->GetGuidData(DATA_CARIBDIS); - // Respawn of the 3 Advisors - for (uint8 i = 0; i < MAX_ADVISORS; ++i) + void Reset() override + { + Initialize(); + + ObjectGuid RAdvisors[MAX_ADVISORS]; + RAdvisors[0] = instance->GetGuidData(DATA_SHARKKIS); + RAdvisors[1] = instance->GetGuidData(DATA_TIDALVESS); + RAdvisors[2] = instance->GetGuidData(DATA_CARIBDIS); + // Respawn of the 3 Advisors + for (uint8 i = 0; i < MAX_ADVISORS; ++i) + if (!RAdvisors[i].IsEmpty()) { - if (!RAdvisors[i].IsEmpty()) + Creature* advisor = ObjectAccessor::GetCreature(*me, RAdvisors[i]); + if (advisor && !advisor->IsAlive()) { - Creature* advisor = ObjectAccessor::GetCreature(*me, RAdvisors[i]); - if (advisor && !advisor->IsAlive()) - { - advisor->Respawn(); - advisor->AI()->EnterEvadeMode(); - advisor->GetMotionMaster()->MoveTargetedHome(); - } + advisor->Respawn(); + advisor->AI()->EnterEvadeMode(); + advisor->GetMotionMaster()->MoveTargetedHome(); } } - instance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); - } + _Reset(); + } - void EventSharkkisDeath() - { - Talk(SAY_GAIN_ABILITY1); - DoCast(me, SPELL_POWER_OF_SHARKKIS); - } + void EventSharkkisDeath() + { + Talk(SAY_GAIN_ABILITY1); + DoCast(me, SPELL_POWER_OF_SHARKKIS); + } - void EventTidalvessDeath() - { - Talk(SAY_GAIN_ABILITY2); - DoCast(me, SPELL_POWER_OF_TIDALVESS); - } + void EventTidalvessDeath() + { + Talk(SAY_GAIN_ABILITY2); + DoCast(me, SPELL_POWER_OF_TIDALVESS); + } - void EventCaribdisDeath() - { - Talk(SAY_GAIN_ABILITY3); - DoCast(me, SPELL_POWER_OF_CARIBDIS); - } + void EventCaribdisDeath() + { + Talk(SAY_GAIN_ABILITY3); + DoCast(me, SPELL_POWER_OF_CARIBDIS); + } - void GetAdvisors() - { - Advisors[0] = instance->GetGuidData(DATA_SHARKKIS); - Advisors[1] = instance->GetGuidData(DATA_TIDALVESS); - Advisors[2] = instance->GetGuidData(DATA_CARIBDIS); - } + void GetAdvisors() + { + Advisors[0] = instance->GetGuidData(DATA_SHARKKIS); + Advisors[1] = instance->GetGuidData(DATA_TIDALVESS); + Advisors[2] = instance->GetGuidData(DATA_CARIBDIS); + } - void StartEvent(Unit* who) - { - GetAdvisors(); + void StartEvent(Unit* who) + { + GetAdvisors(); - Talk(SAY_AGGRO); - DoZoneInCombat(); + Talk(SAY_AGGRO); - instance->SetGuidData(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); - instance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); - } + instance->SetGuidData(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); + } - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_SLAY); - } + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_SLAY); + } - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); - instance->SetData(DATA_FATHOMLORDKARATHRESSEVENT, DONE); + instance->SetData(DATA_FATHOMLORDKARATHRESSEVENT, DONE); - //support for quest 10944 - me->SummonCreature(SEER_OLUM, OLUM_X, OLUM_Y, OLUM_Z, OLUM_O, TEMPSUMMON_TIMED_DESPAWN, 1h); - } + //support for quest 10944 + me->SummonCreature(SEER_OLUM, OLUM_X, OLUM_Y, OLUM_Z, OLUM_O, TEMPSUMMON_TIMED_DESPAWN, 1h); + } - void JustEngagedWith(Unit* who) override - { - StartEvent(who); - } + void JustEngagedWith(Unit* who) override + { + _JustEngagedWith(who); + StartEvent(who); + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + //Only if not incombat check if the event is started + if (!me->IsInCombat() && instance->GetBossState(BOSS_FATHOM_LORD_KARATHRESS) == IN_PROGRESS) { - //Only if not incombat check if the event is started - if (!me->IsInCombat() && instance->GetData(DATA_KARATHRESSEVENT)) + if (Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_KARATHRESSEVENT_STARTER))) { - if (Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_KARATHRESSEVENT_STARTER))) - { - AttackStart(target); - GetAdvisors(); - } + AttackStart(target); + GetAdvisors(); } + } - //Return since we have no target - if (!UpdateVictim()) - return; + //Return since we have no target + if (!UpdateVictim()) + return; - //someone evaded! - if (!instance->GetData(DATA_KARATHRESSEVENT)) - { - EnterEvadeMode(); - return; - } + //someone evaded! + if (instance->GetBossState(BOSS_FATHOM_LORD_KARATHRESS) == NOT_STARTED) + { + EnterEvadeMode(); + return; + } - //CataclysmicBolt_Timer - if (CataclysmicBolt_Timer <= diff) - { - //select a random unit other than the main tank - Unit* target = SelectTarget(SelectTargetMethod::Random, 1); + //CataclysmicBolt_Timer + if (CataclysmicBolt_Timer <= diff) + { + //select a random unit other than the main tank + Unit* target = SelectTarget(SelectTargetMethod::Random, 1); - //if there aren't other units, cast on the tank - if (!target) - target = me->GetVictim(); + //if there aren't other units, cast on the tank + if (!target) + target = me->GetVictim(); - if (target) - DoCast(target, SPELL_CATACLYSMIC_BOLT); - CataclysmicBolt_Timer = 10000; - } else CataclysmicBolt_Timer -= diff; + if (target) + DoCast(target, SPELL_CATACLYSMIC_BOLT); + CataclysmicBolt_Timer = 10000; + } else CataclysmicBolt_Timer -= diff; - //SearNova_Timer - if (SearNova_Timer <= diff) - { - DoCastVictim(SPELL_SEAR_NOVA); - SearNova_Timer = 20000 + rand32() % 40000; - } else SearNova_Timer -= diff; + //SearNova_Timer + if (SearNova_Timer <= diff) + { + DoCastVictim(SPELL_SEAR_NOVA); + SearNova_Timer = 20000 + rand32() % 40000; + } else SearNova_Timer -= diff; - //Enrage_Timer - if (Enrage_Timer <= diff) - { - DoCast(me, SPELL_ENRAGE); - Enrage_Timer = 90000; - } else Enrage_Timer -= diff; + //Enrage_Timer + if (Enrage_Timer <= diff) + { + DoCast(me, SPELL_ENRAGE); + Enrage_Timer = 90000; + } else Enrage_Timer -= diff; - //Blessing of Tides Trigger - if (!HealthAbovePct(75) && !BlessingOfTides) - { - BlessingOfTides = true; - bool continueTriggering = false; - for (uint8 i = 0; i < MAX_ADVISORS; ++i) + //Blessing of Tides Trigger + if (!HealthAbovePct(75) && !BlessingOfTides) + { + BlessingOfTides = true; + bool continueTriggering = false; + for (uint8 i = 0; i < MAX_ADVISORS; ++i) + if (!Advisors[i].IsEmpty()) { - if (!Advisors[i].IsEmpty()) + Creature* advisor = ObjectAccessor::GetCreature(*me, Advisors[i]); + if (advisor && advisor->IsAlive()) { - Creature* advisor = ObjectAccessor::GetCreature(*me, Advisors[i]); - if (advisor && advisor->IsAlive()) - { - continueTriggering = true; - break; - } + continueTriggering = true; + break; } } - - if (continueTriggering) - { - DoCast(me, SPELL_BLESSING_OF_THE_TIDES); - Talk(SAY_GAIN_BLESSING); - } + if (continueTriggering) + { + DoCast(me, SPELL_BLESSING_OF_THE_TIDES); + Talk(SAY_GAIN_BLESSING); } - - DoMeleeAttackIfReady(); } - }; + DoMeleeAttackIfReady(); + } }; //Fathom-Guard Sharkkis AI -class boss_fathomguard_sharkkis : public CreatureScript +struct boss_fathomguard_sharkkis : public ScriptedAI { -public: - boss_fathomguard_sharkkis() : CreatureScript("boss_fathomguard_sharkkis") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_fathomguard_sharkkis(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<boss_fathomguard_sharkkisAI>(creature); + Initialize(); + instance = creature->GetInstanceScript(); } - struct boss_fathomguard_sharkkisAI : public ScriptedAI + void Initialize() { - boss_fathomguard_sharkkisAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - } + LeechingThrow_Timer = 20000; + TheBeastWithin_Timer = 30000; + Multishot_Timer = 15000; + Pet_Timer = 10000; - void Initialize() - { - LeechingThrow_Timer = 20000; - TheBeastWithin_Timer = 30000; - Multishot_Timer = 15000; - Pet_Timer = 10000; + pet = false; + } - pet = false; - } + InstanceScript* instance; - InstanceScript* instance; + uint32 LeechingThrow_Timer; + uint32 TheBeastWithin_Timer; + uint32 Multishot_Timer; + uint32 Pet_Timer; - uint32 LeechingThrow_Timer; - uint32 TheBeastWithin_Timer; - uint32 Multishot_Timer; - uint32 Pet_Timer; + bool pet; - bool pet; + ObjectGuid SummonedPet; - ObjectGuid SummonedPet; + void Reset() override + { + Initialize(); - void Reset() override - { - Initialize(); + Creature* Pet = ObjectAccessor::GetCreature(*me, SummonedPet); + if (Pet && Pet->IsAlive()) + Pet->KillSelf(); - Creature* Pet = ObjectAccessor::GetCreature(*me, SummonedPet); - if (Pet && Pet->IsAlive()) - Pet->KillSelf(); + SummonedPet.Clear(); - SummonedPet.Clear(); + instance->SetBossState(BOSS_FATHOM_LORD_KARATHRESS, NOT_STARTED); + } - instance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); - } + void JustDied(Unit* /*killer*/) override + { + if (Creature* Karathress = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KARATHRESS))) + ENSURE_AI(boss_fathomlord_karathress, Karathress->AI())->EventSharkkisDeath(); + } + + void JustEngagedWith(Unit* who) override + { + instance->SetGuidData(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); + instance->SetBossState(BOSS_FATHOM_LORD_KARATHRESS, IN_PROGRESS); + } - void JustDied(Unit* /*killer*/) override + void UpdateAI(uint32 diff) override + { + //Only if not incombat check if the event is started + if (!me->IsInCombat() && instance->GetBossState(BOSS_FATHOM_LORD_KARATHRESS) == IN_PROGRESS) { - if (Creature* Karathress = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KARATHRESS))) - ENSURE_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventSharkkisDeath(); + if (Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_KARATHRESSEVENT_STARTER))) + AttackStart(target); } - void JustEngagedWith(Unit* who) override + //Return since we have no target + if (!UpdateVictim()) + return; + + //someone evaded! + if (instance->GetBossState(BOSS_FATHOM_LORD_KARATHRESS) == NOT_STARTED) { - instance->SetGuidData(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); - instance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); + EnterEvadeMode(); + return; } - void UpdateAI(uint32 diff) override + //LeechingThrow_Timer + if (LeechingThrow_Timer <= diff) { - //Only if not incombat check if the event is started - if (!me->IsInCombat() && instance->GetData(DATA_KARATHRESSEVENT)) - { - if (Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_KARATHRESSEVENT_STARTER))) - AttackStart(target); - } + DoCastVictim(SPELL_LEECHING_THROW); + LeechingThrow_Timer = 20000; + } else LeechingThrow_Timer -= diff; - //Return since we have no target - if (!UpdateVictim()) - return; + //Multishot_Timer + if (Multishot_Timer <= diff) + { + DoCastVictim(SPELL_MULTISHOT); + Multishot_Timer = 20000; + } else Multishot_Timer -= diff; - //someone evaded! - if (!instance->GetData(DATA_KARATHRESSEVENT)) - { - EnterEvadeMode(); - return; - } + //TheBeastWithin_Timer + if (TheBeastWithin_Timer <= diff) + { + DoCast(me, SPELL_THE_BEAST_WITHIN); - //LeechingThrow_Timer - if (LeechingThrow_Timer <= diff) - { - DoCastVictim(SPELL_LEECHING_THROW); - LeechingThrow_Timer = 20000; - } else LeechingThrow_Timer -= diff; + Creature* Pet = ObjectAccessor::GetCreature(*me, SummonedPet); + if (Pet && Pet->IsAlive()) + Pet->CastSpell(Pet, SPELL_PET_ENRAGE, true); - //Multishot_Timer - if (Multishot_Timer <= diff) - { - DoCastVictim(SPELL_MULTISHOT); - Multishot_Timer = 20000; - } else Multishot_Timer -= diff; + TheBeastWithin_Timer = 30000; + } else TheBeastWithin_Timer -= diff; - //TheBeastWithin_Timer - if (TheBeastWithin_Timer <= diff) + //Pet_Timer + if (Pet_Timer < diff && pet == false) + { + pet = true; + //uint32 spell_id; + uint32 pet_id; + if (!urand(0, 1)) { - DoCast(me, SPELL_THE_BEAST_WITHIN); - - Creature* Pet = ObjectAccessor::GetCreature(*me, SummonedPet); - if (Pet && Pet->IsAlive()) - Pet->CastSpell(Pet, SPELL_PET_ENRAGE, true); - - TheBeastWithin_Timer = 30000; - } else TheBeastWithin_Timer -= diff; - - //Pet_Timer - if (Pet_Timer < diff && pet == false) + //spell_id = SPELL_SUMMON_FATHOM_LURKER; + pet_id = CREATURE_FATHOM_LURKER; + } + else { - pet = true; - //uint32 spell_id; - uint32 pet_id; - if (!urand(0, 1)) - { - //spell_id = SPELL_SUMMON_FATHOM_LURKER; - pet_id = CREATURE_FATHOM_LURKER; - } - else - { - //spell_id = SPELL_SUMMON_FATHOM_SPOREBAT; - pet_id = CREATURE_FATHOM_SPOREBAT; - } - //DoCast(me, spell_id, true); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + //spell_id = SPELL_SUMMON_FATHOM_SPOREBAT; + pet_id = CREATURE_FATHOM_SPOREBAT; + } + //DoCast(me, spell_id, true); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + { + if (Creature* Pet = DoSpawnCreature(pet_id, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15s)) { - if (Creature* Pet = DoSpawnCreature(pet_id, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15s)) - { - Pet->AI()->AttackStart(target); - SummonedPet = Pet->GetGUID(); - } + Pet->AI()->AttackStart(target); + SummonedPet = Pet->GetGUID(); } - } else Pet_Timer -= diff; - - DoMeleeAttackIfReady(); - } - }; + } + } else Pet_Timer -= diff; + DoMeleeAttackIfReady(); + } }; //Fathom-Guard Tidalvess AI -class boss_fathomguard_tidalvess : public CreatureScript +struct boss_fathomguard_tidalvess : public ScriptedAI { -public: - boss_fathomguard_tidalvess() : CreatureScript("boss_fathomguard_tidalvess") { } + boss_fathomguard_tidalvess(Creature* creature) : ScriptedAI(creature) + { + Initialize(); + instance = creature->GetInstanceScript(); + } - CreatureAI* GetAI(Creature* creature) const override + void Initialize() { - return GetSerpentshrineCavernAI<boss_fathomguard_tidalvessAI>(creature); + FrostShock_Timer = 25000; + Spitfire_Timer = 60000; + PoisonCleansing_Timer = 30000; + Earthbind_Timer = 45000; } - struct boss_fathomguard_tidalvessAI : public ScriptedAI + InstanceScript* instance; + + uint32 FrostShock_Timer; + uint32 Spitfire_Timer; + uint32 PoisonCleansing_Timer; + uint32 Earthbind_Timer; + + void Reset() override { - boss_fathomguard_tidalvessAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - } + Initialize(); - void Initialize() - { - FrostShock_Timer = 25000; - Spitfire_Timer = 60000; - PoisonCleansing_Timer = 30000; - Earthbind_Timer = 45000; - } + instance->SetBossState(BOSS_FATHOM_LORD_KARATHRESS, NOT_STARTED); + } - InstanceScript* instance; + void JustDied(Unit* /*killer*/) override + { + if (Creature* Karathress = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KARATHRESS))) + ENSURE_AI(boss_fathomlord_karathress, Karathress->AI())->EventTidalvessDeath(); + } - uint32 FrostShock_Timer; - uint32 Spitfire_Timer; - uint32 PoisonCleansing_Timer; - uint32 Earthbind_Timer; + void JustEngagedWith(Unit* who) override + { + instance->SetGuidData(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); + instance->SetBossState(BOSS_FATHOM_LORD_KARATHRESS, IN_PROGRESS); + DoCast(me, SPELL_WINDFURY_WEAPON); + } - void Reset() override + void UpdateAI(uint32 diff) override + { + //Only if not incombat check if the event is started + if (!me->IsInCombat() && instance->GetBossState(BOSS_FATHOM_LORD_KARATHRESS) == IN_PROGRESS) { - Initialize(); - - instance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); + if (Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_KARATHRESSEVENT_STARTER))) + AttackStart(target); } - void JustDied(Unit* /*killer*/) override + //Return since we have no target + if (!UpdateVictim()) + return; + + //someone evaded! + if (instance->GetBossState(BOSS_FATHOM_LORD_KARATHRESS) == NOT_STARTED) { - if (Creature* Karathress = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KARATHRESS))) - ENSURE_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventTidalvessDeath(); + EnterEvadeMode(); + return; } - void JustEngagedWith(Unit* who) override + if (!me->HasAura(SPELL_WINDFURY_WEAPON)) { - instance->SetGuidData(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); - instance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); DoCast(me, SPELL_WINDFURY_WEAPON); } - void UpdateAI(uint32 diff) override + //FrostShock_Timer + if (FrostShock_Timer <= diff) { - //Only if not incombat check if the event is started - if (!me->IsInCombat() && instance->GetData(DATA_KARATHRESSEVENT)) - { - if (Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_KARATHRESSEVENT_STARTER))) - AttackStart(target); - } - - //Return since we have no target - if (!UpdateVictim()) - return; - - //someone evaded! - if (!instance->GetData(DATA_KARATHRESSEVENT)) - { - EnterEvadeMode(); - return; - } - - if (!me->HasAura(SPELL_WINDFURY_WEAPON)) - { - DoCast(me, SPELL_WINDFURY_WEAPON); - } - - //FrostShock_Timer - if (FrostShock_Timer <= diff) - { - DoCastVictim(SPELL_FROST_SHOCK); - FrostShock_Timer = 25000 + rand32() % 5000; - } else FrostShock_Timer -= diff; - - //Spitfire_Timer - if (Spitfire_Timer <= diff) - { - DoCast(me, SPELL_SPITFIRE_TOTEM); - if (Unit* SpitfireTotem = me->FindNearestCreature(CREATURE_SPITFIRE_TOTEM, 100.0f)) - SpitfireTotem->ToCreature()->AI()->AttackStart(me->GetVictim()); + DoCastVictim(SPELL_FROST_SHOCK); + FrostShock_Timer = 25000 + rand32() % 5000; + } else FrostShock_Timer -= diff; - Spitfire_Timer = 60000; - } - else - Spitfire_Timer -= diff; + //Spitfire_Timer + if (Spitfire_Timer <= diff) + { + DoCast(me, SPELL_SPITFIRE_TOTEM); + if (Unit* SpitfireTotem = me->FindNearestCreature(CREATURE_SPITFIRE_TOTEM, 100.0f)) + SpitfireTotem->ToCreature()->AI()->AttackStart(me->GetVictim()); - //PoisonCleansing_Timer - if (PoisonCleansing_Timer <= diff) - { - DoCast(me, SPELL_POISON_CLEANSING_TOTEM); - PoisonCleansing_Timer = 30000; - } - else - PoisonCleansing_Timer -= diff; + Spitfire_Timer = 60000; + } + else + Spitfire_Timer -= diff; - //Earthbind_Timer - if (Earthbind_Timer <= diff) - { - DoCast(me, SPELL_EARTHBIND_TOTEM); - Earthbind_Timer = 45000; - } - else - Earthbind_Timer -= diff; + //PoisonCleansing_Timer + if (PoisonCleansing_Timer <= diff) + { + DoCast(me, SPELL_POISON_CLEANSING_TOTEM); + PoisonCleansing_Timer = 30000; + } + else + PoisonCleansing_Timer -= diff; - DoMeleeAttackIfReady(); + //Earthbind_Timer + if (Earthbind_Timer <= diff) + { + DoCast(me, SPELL_EARTHBIND_TOTEM); + Earthbind_Timer = 45000; } - }; + else + Earthbind_Timer -= diff; + DoMeleeAttackIfReady(); + } }; //Fathom-Guard Caribdis AI -class boss_fathomguard_caribdis : public CreatureScript +struct boss_fathomguard_caribdis : public ScriptedAI { -public: - boss_fathomguard_caribdis() : CreatureScript("boss_fathomguard_caribdis") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_fathomguard_caribdis(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<boss_fathomguard_caribdisAI>(creature); + Initialize(); + instance = creature->GetInstanceScript(); } - struct boss_fathomguard_caribdisAI : public ScriptedAI + void Initialize() { - boss_fathomguard_caribdisAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - } + WaterBoltVolley_Timer = 35000; + TidalSurge_Timer = 15000 + rand32() % 5000; + Heal_Timer = 55000; + Cyclone_Timer = 30000 + rand32() % 10000; + } - void Initialize() - { - WaterBoltVolley_Timer = 35000; - TidalSurge_Timer = 15000 + rand32() % 5000; - Heal_Timer = 55000; - Cyclone_Timer = 30000 + rand32() % 10000; - } + InstanceScript* instance; - InstanceScript* instance; + uint32 WaterBoltVolley_Timer; + uint32 TidalSurge_Timer; + uint32 Heal_Timer; + uint32 Cyclone_Timer; - uint32 WaterBoltVolley_Timer; - uint32 TidalSurge_Timer; - uint32 Heal_Timer; - uint32 Cyclone_Timer; + void Reset() override + { + Initialize(); - void Reset() override - { - Initialize(); + instance->SetBossState(BOSS_FATHOM_LORD_KARATHRESS, NOT_STARTED); + } - instance->SetData(DATA_KARATHRESSEVENT, NOT_STARTED); - } + void JustDied(Unit* /*killer*/) override + { + if (Creature* Karathress = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KARATHRESS))) + ENSURE_AI(boss_fathomlord_karathress, Karathress->AI())->EventCaribdisDeath(); + } + + void JustEngagedWith(Unit* who) override + { + instance->SetGuidData(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); + instance->SetBossState(BOSS_FATHOM_LORD_KARATHRESS, IN_PROGRESS); + } - void JustDied(Unit* /*killer*/) override + void UpdateAI(uint32 diff) override + { + //Only if not incombat check if the event is started + if (!me->IsInCombat() && instance->GetBossState(BOSS_FATHOM_LORD_KARATHRESS) == IN_PROGRESS) { - if (Creature* Karathress = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_KARATHRESS))) - ENSURE_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventCaribdisDeath(); + if (Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_KARATHRESSEVENT_STARTER))) + AttackStart(target); } - void JustEngagedWith(Unit* who) override + //Return since we have no target + if (!UpdateVictim()) + return; + + //someone evaded! + if (instance->GetBossState(BOSS_FATHOM_LORD_KARATHRESS) == NOT_STARTED) { - instance->SetGuidData(DATA_KARATHRESSEVENT_STARTER, who->GetGUID()); - instance->SetData(DATA_KARATHRESSEVENT, IN_PROGRESS); + EnterEvadeMode(); + return; } - void UpdateAI(uint32 diff) override + //WaterBoltVolley_Timer + if (WaterBoltVolley_Timer <= diff) { - //Only if not incombat check if the event is started - if (!me->IsInCombat() && instance->GetData(DATA_KARATHRESSEVENT)) - { - if (Unit* target = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_KARATHRESSEVENT_STARTER))) - AttackStart(target); - } - - //Return since we have no target - if (!UpdateVictim()) - return; + DoCastVictim(SPELL_WATER_BOLT_VOLLEY); + WaterBoltVolley_Timer = 30000; + } else WaterBoltVolley_Timer -= diff; - //someone evaded! - if (!instance->GetData(DATA_KARATHRESSEVENT)) - { - EnterEvadeMode(); - return; - } - - //WaterBoltVolley_Timer - if (WaterBoltVolley_Timer <= diff) - { - DoCastVictim(SPELL_WATER_BOLT_VOLLEY); - WaterBoltVolley_Timer = 30000; - } else WaterBoltVolley_Timer -= diff; + //TidalSurge_Timer + if (TidalSurge_Timer <= diff) + { + DoCastSelf(SPELL_TIDAL_SURGE); + TidalSurge_Timer = 15000 + rand32() % 5000; + } else TidalSurge_Timer -= diff; - //TidalSurge_Timer - if (TidalSurge_Timer <= diff) - { - DoCastSelf(SPELL_TIDAL_SURGE); - TidalSurge_Timer = 15000 + rand32() % 5000; - } else TidalSurge_Timer -= diff; + //Cyclone_Timer + if (Cyclone_Timer <= diff) + { + //DoCast(me, SPELL_SUMMON_CYCLONE); // Doesn't work + Cyclone_Timer = 30000 + rand32() % 10000; - //Cyclone_Timer - if (Cyclone_Timer <= diff) + if (Creature* Cyclone = me->SummonCreature(CREATURE_CYCLONE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), float(rand32() % 5), TEMPSUMMON_TIMED_DESPAWN, 15s)) { - //DoCast(me, SPELL_SUMMON_CYCLONE); // Doesn't work - Cyclone_Timer = 30000 + rand32() % 10000; - - if (Creature* Cyclone = me->SummonCreature(CREATURE_CYCLONE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), float(rand32() % 5), TEMPSUMMON_TIMED_DESPAWN, 15s)) - { - Cyclone->SetObjectScale(3.0f); - Cyclone->SetFaction(me->GetFaction()); - Cyclone->CastSpell(Cyclone, SPELL_CYCLONE_CYCLONE, true); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - Cyclone->AI()->AttackStart(target); - } + Cyclone->SetObjectScale(3.0f); + Cyclone->SetFaction(me->GetFaction()); + Cyclone->CastSpell(Cyclone, SPELL_CYCLONE_CYCLONE, true); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + Cyclone->AI()->AttackStart(target); } - else - Cyclone_Timer -= diff; - - //Heal_Timer - if (Heal_Timer <= diff) - { - // It can be cast on any of the mobs - Unit* unit = nullptr; + } + else + Cyclone_Timer -= diff; - while (unit == nullptr || !unit->IsAlive()) - unit = selectAdvisorUnit(); + //Heal_Timer + if (Heal_Timer <= diff) + { + // It can be cast on any of the mobs + Unit* unit = nullptr; - DoCast(unit, SPELL_HEAL); - Heal_Timer = 60000; - } - else - Heal_Timer -= diff; + while (unit == nullptr || !unit->IsAlive()) + unit = selectAdvisorUnit(); - DoMeleeAttackIfReady(); + DoCast(unit, SPELL_HEAL); + Heal_Timer = 60000; } + else + Heal_Timer -= diff; - Unit* selectAdvisorUnit() + DoMeleeAttackIfReady(); + } + + Unit* selectAdvisorUnit() + { + Unit* unit = nullptr; + switch (rand32() % 4) { - Unit* unit = nullptr; - switch (rand32() % 4) - { - case 0: - unit = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_KARATHRESS)); - break; - case 1: - unit = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_SHARKKIS)); - break; - case 2: - unit = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_TIDALVESS)); - break; - case 3: - unit = me; - break; - } - return unit; + case 0: + unit = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_KARATHRESS)); + break; + case 1: + unit = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_SHARKKIS)); + break; + case 2: + unit = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_TIDALVESS)); + break; + case 3: + unit = me; + break; } - }; + return unit; + } }; // 38358 - Tidal Surge @@ -735,9 +679,9 @@ class spell_fathomlord_karathress_tidal_surge : public SpellScript void AddSC_boss_fathomlord_karathress() { - new boss_fathomlord_karathress(); - new boss_fathomguard_sharkkis(); - new boss_fathomguard_tidalvess(); - new boss_fathomguard_caribdis(); + RegisterSerpentshrineCavernCreatureAI(boss_fathomlord_karathress); + RegisterSerpentshrineCavernCreatureAI(boss_fathomguard_sharkkis); + RegisterSerpentshrineCavernCreatureAI(boss_fathomguard_tidalvess); + RegisterSerpentshrineCavernCreatureAI(boss_fathomguard_caribdis); RegisterSpellScript(spell_fathomlord_karathress_tidal_surge); } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp index 19fb7ef0cdd..f22d7fe791a 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp @@ -80,329 +80,304 @@ enum HydrossTheUnstable #define SPAWN_X_DIFF4 12.577011f #define SPAWN_Y_DIFF4 4.72702f -class boss_hydross_the_unstable : public CreatureScript +struct boss_hydross_the_unstable : public BossAI { -public: - boss_hydross_the_unstable() : CreatureScript("boss_hydross_the_unstable") { } + boss_hydross_the_unstable(Creature* creature) : BossAI(creature, BOSS_HYDROSS_THE_UNSTABLE) + { + Initialize(); + } + + void Initialize() + { + beams[0].Clear(); + beams[1].Clear(); + PosCheck_Timer = 2500; + MarkOfHydross_Timer = 15000; + MarkOfCorruption_Timer = 15000; + WaterTomb_Timer = 7000; + VileSludge_Timer = 7000; + MarkOfHydross_Count = 0; + MarkOfCorruption_Count = 0; + EnrageTimer = 600000; + + CorruptedForm = false; + beam = false; + } - CreatureAI* GetAI(Creature* creature) const override + ObjectGuid beams[2]; + uint32 PosCheck_Timer; + uint32 MarkOfHydross_Timer; + uint32 MarkOfCorruption_Timer; + uint32 WaterTomb_Timer; + uint32 VileSludge_Timer; + uint32 MarkOfHydross_Count; + uint32 MarkOfCorruption_Count; + uint32 EnrageTimer; + bool CorruptedForm; + bool beam; + + void Reset() override { - return GetSerpentshrineCavernAI<boss_hydross_the_unstableAI>(creature); + DeSummonBeams(); + Initialize(); + + me->SetMeleeDamageSchool(SPELL_SCHOOL_FROST); + me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); + me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); + + me->SetDisplayId(MODEL_CLEAN); + + _Reset(); } - struct boss_hydross_the_unstableAI : public ScriptedAI + void SummonBeams() { - boss_hydross_the_unstableAI(Creature* creature) : ScriptedAI(creature), Summons(me) + Creature* beamer = me->SummonCreature(ENTRY_BEAM_DUMMY, -258.333f, -356.34f, 22.0499f, 5.90835f, TEMPSUMMON_CORPSE_DESPAWN); + if (beamer) { - Initialize(); - instance = creature->GetInstanceScript(); + beamer->CastSpell(me, SPELL_BLUE_BEAM, true); + beamer->SetDisplayId(11686); //invisible + beams[0] = beamer->GetGUID(); } - - void Initialize() + beamer = me->SummonCreature(ENTRY_BEAM_DUMMY, -219.918f, -371.308f, 22.0042f, 2.73072f, TEMPSUMMON_CORPSE_DESPAWN); + if (beamer) { - beams[0].Clear(); - beams[1].Clear(); - PosCheck_Timer = 2500; - MarkOfHydross_Timer = 15000; - MarkOfCorruption_Timer = 15000; - WaterTomb_Timer = 7000; - VileSludge_Timer = 7000; - MarkOfHydross_Count = 0; - MarkOfCorruption_Count = 0; - EnrageTimer = 600000; - - CorruptedForm = false; - beam = false; + beamer->CastSpell(me, SPELL_BLUE_BEAM, true); + beamer->SetDisplayId(11686); //invisible + beams[1] = beamer->GetGUID(); } + } - InstanceScript* instance; - - ObjectGuid beams[2]; - uint32 PosCheck_Timer; - uint32 MarkOfHydross_Timer; - uint32 MarkOfCorruption_Timer; - uint32 WaterTomb_Timer; - uint32 VileSludge_Timer; - uint32 MarkOfHydross_Count; - uint32 MarkOfCorruption_Count; - uint32 EnrageTimer; - bool CorruptedForm; - bool beam; - SummonList Summons; - - void Reset() override + void DeSummonBeams() + { + for (uint8 i = 0; i < 2; ++i) { - DeSummonBeams(); - Initialize(); + if (Creature* mob = ObjectAccessor::GetCreature(*me, beams[i])) + mob->DespawnOrUnsummon(); + } + } - me->SetMeleeDamageSchool(SPELL_SCHOOL_FROST); - me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); - me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); + void JustEngagedWith(Unit* who) override + { + Talk(SAY_AGGRO); - me->SetDisplayId(MODEL_CLEAN); + _JustEngagedWith(who); + } - instance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, NOT_STARTED); - Summons.DespawnAll(); - } + void KilledUnit(Unit* /*victim*/) override + { + Talk(CorruptedForm ? SAY_CORRUPT_SLAY : SAY_CLEAN_SLAY); + } - void SummonBeams() - { - Creature* beamer = me->SummonCreature(ENTRY_BEAM_DUMMY, -258.333f, -356.34f, 22.0499f, 5.90835f, TEMPSUMMON_CORPSE_DESPAWN); - if (beamer) - { - beamer->CastSpell(me, SPELL_BLUE_BEAM, true); - beamer->SetDisplayId(11686); //invisible - beams[0] = beamer->GetGUID(); - } - beamer = me->SummonCreature(ENTRY_BEAM_DUMMY, -219.918f, -371.308f, 22.0042f, 2.73072f, TEMPSUMMON_CORPSE_DESPAWN); - if (beamer) - { - beamer->CastSpell(me, SPELL_BLUE_BEAM, true); - beamer->SetDisplayId(11686); //invisible - beams[1] = beamer->GetGUID(); - } - } - void DeSummonBeams() - { - for (uint8 i = 0; i < 2; ++i) - { - if (Creature* mob = ObjectAccessor::GetCreature(*me, beams[i])) - { - mob->DespawnOrUnsummon(); - } - } - } - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_AGGRO); + void JustSummoned(Creature* summoned) override + { + if (summoned->GetEntry() == ENTRY_PURE_SPAWN) + summoned->CastSpell(summoned, SPELL_ELEMENTAL_SPAWNIN, true); - instance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, IN_PROGRESS); - } + if (summoned->GetEntry() == ENTRY_TAINTED_SPAWN) + summoned->CastSpell(summoned, SPELL_ELEMENTAL_SPAWNIN, true); - void KilledUnit(Unit* /*victim*/) override - { - Talk(CorruptedForm ? SAY_CORRUPT_SLAY : SAY_CLEAN_SLAY); - } + BossAI::JustSummoned(summoned); + } - void JustSummoned(Creature* summoned) override - { - if (summoned->GetEntry() == ENTRY_PURE_SPAWN) - { - summoned->CastSpell(summoned, SPELL_ELEMENTAL_SPAWNIN, true); - Summons.Summon(summoned); - } - if (summoned->GetEntry() == ENTRY_TAINTED_SPAWN) - { - summoned->CastSpell(summoned, SPELL_ELEMENTAL_SPAWNIN, true); - Summons.Summon(summoned); - } - } + void JustDied(Unit* /*killer*/) override + { + Talk(CorruptedForm ? SAY_CORRUPT_DEATH : SAY_CLEAN_DEATH); - void SummonedCreatureDespawn(Creature* summon) override - { - Summons.Despawn(summon); - } + _JustDied(); + } - void JustDied(Unit* /*killer*/) override + void UpdateAI(uint32 diff) override + { + if (!beam) { - Talk(CorruptedForm ? SAY_CORRUPT_DEATH : SAY_CLEAN_DEATH); - - instance->SetData(DATA_HYDROSSTHEUNSTABLEEVENT, DONE); - Summons.DespawnAll(); + SummonBeams(); + beam = true; } + //Return since we have no target + if (!UpdateVictim()) + return; - void UpdateAI(uint32 diff) override + // corrupted form + if (CorruptedForm) { - if (!beam) - { - SummonBeams(); - beam = true; - } - //Return since we have no target - if (!UpdateVictim()) - return; - - // corrupted form - if (CorruptedForm) + //MarkOfCorruption_Timer + if (MarkOfCorruption_Timer <= diff) { - //MarkOfCorruption_Timer - if (MarkOfCorruption_Timer <= diff) + if (MarkOfCorruption_Count <= 5) { - if (MarkOfCorruption_Count <= 5) - { - uint32 mark_spell = 0; + uint32 mark_spell = 0; - switch (MarkOfCorruption_Count) - { - case 0: - mark_spell = SPELL_MARK_OF_CORRUPTION1; - break; + switch (MarkOfCorruption_Count) + { + case 0: + mark_spell = SPELL_MARK_OF_CORRUPTION1; + break; - case 1: - mark_spell = SPELL_MARK_OF_CORRUPTION2; - break; + case 1: + mark_spell = SPELL_MARK_OF_CORRUPTION2; + break; - case 2: - mark_spell = SPELL_MARK_OF_CORRUPTION3; - break; + case 2: + mark_spell = SPELL_MARK_OF_CORRUPTION3; + break; - case 3: - mark_spell = SPELL_MARK_OF_CORRUPTION4; - break; + case 3: + mark_spell = SPELL_MARK_OF_CORRUPTION4; + break; - case 4: - mark_spell = SPELL_MARK_OF_CORRUPTION5; - break; + case 4: + mark_spell = SPELL_MARK_OF_CORRUPTION5; + break; - case 5: - mark_spell = SPELL_MARK_OF_CORRUPTION6; - break; - } + case 5: + mark_spell = SPELL_MARK_OF_CORRUPTION6; + break; + } - DoCastVictim(mark_spell); + DoCastVictim(mark_spell); - if (MarkOfCorruption_Count < 5) - ++MarkOfCorruption_Count; - } + if (MarkOfCorruption_Count < 5) + ++MarkOfCorruption_Count; + } - MarkOfCorruption_Timer = 15000; - } else MarkOfCorruption_Timer -= diff; + MarkOfCorruption_Timer = 15000; + } else MarkOfCorruption_Timer -= diff; - //VileSludge_Timer - if (VileSludge_Timer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - DoCast(target, SPELL_VILE_SLUDGE); + //VileSludge_Timer + if (VileSludge_Timer <= diff) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + DoCast(target, SPELL_VILE_SLUDGE); - VileSludge_Timer = 15000; - } else VileSludge_Timer -= diff; + VileSludge_Timer = 15000; + } else VileSludge_Timer -= diff; - //PosCheck_Timer - if (PosCheck_Timer <= diff) + //PosCheck_Timer + if (PosCheck_Timer <= diff) + { + if (me->IsWithinDist2d(HYDROSS_X, HYDROSS_Y, SWITCH_RADIUS)) { - if (me->IsWithinDist2d(HYDROSS_X, HYDROSS_Y, SWITCH_RADIUS)) - { - // switch to clean form - me->SetDisplayId(MODEL_CLEAN); - CorruptedForm = false; - MarkOfHydross_Count = 0; - - Talk(SAY_SWITCH_TO_CLEAN); - ResetThreatList(); - SummonBeams(); - - // spawn 4 adds - DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); - DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); - DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); - DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); - - me->SetMeleeDamageSchool(SPELL_SCHOOL_FROST); - me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); - me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); - } + // switch to clean form + me->SetDisplayId(MODEL_CLEAN); + CorruptedForm = false; + MarkOfHydross_Count = 0; + + Talk(SAY_SWITCH_TO_CLEAN); + ResetThreatList(); + SummonBeams(); + + // spawn 4 adds + DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); + DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); + DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); + DoSpawnCreature(ENTRY_PURE_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); + + me->SetMeleeDamageSchool(SPELL_SCHOOL_FROST); + me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); + me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false); + } - PosCheck_Timer = 2500; - } else PosCheck_Timer -=diff; - } - // clean form - else + PosCheck_Timer = 2500; + } else PosCheck_Timer -=diff; + } + // clean form + else + { + //MarkOfHydross_Timer + if (MarkOfHydross_Timer <= diff) { - //MarkOfHydross_Timer - if (MarkOfHydross_Timer <= diff) + if (MarkOfHydross_Count <= 5) { - if (MarkOfHydross_Count <= 5) - { - uint32 mark_spell = 0; - - switch (MarkOfHydross_Count) - { - case 0: - mark_spell = SPELL_MARK_OF_HYDROSS1; - break; - - case 1: - mark_spell = SPELL_MARK_OF_HYDROSS2; - break; + uint32 mark_spell = 0; - case 2: - mark_spell = SPELL_MARK_OF_HYDROSS3; - break; + switch (MarkOfHydross_Count) + { + case 0: + mark_spell = SPELL_MARK_OF_HYDROSS1; + break; - case 3: - mark_spell = SPELL_MARK_OF_HYDROSS4; - break; + case 1: + mark_spell = SPELL_MARK_OF_HYDROSS2; + break; - case 4: - mark_spell = SPELL_MARK_OF_HYDROSS5; - break; + case 2: + mark_spell = SPELL_MARK_OF_HYDROSS3; + break; - case 5: - mark_spell = SPELL_MARK_OF_HYDROSS6; - break; - } + case 3: + mark_spell = SPELL_MARK_OF_HYDROSS4; + break; - DoCastVictim(mark_spell); + case 4: + mark_spell = SPELL_MARK_OF_HYDROSS5; + break; - if (MarkOfHydross_Count < 5) - ++MarkOfHydross_Count; + case 5: + mark_spell = SPELL_MARK_OF_HYDROSS6; + break; } - MarkOfHydross_Timer = 15000; - } else MarkOfHydross_Timer -= diff; + DoCastVictim(mark_spell); - //WaterTomb_Timer - if (WaterTomb_Timer <= diff) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true); - if (target) - DoCast(target, SPELL_WATER_TOMB); + if (MarkOfHydross_Count < 5) + ++MarkOfHydross_Count; + } - WaterTomb_Timer = 7000; - } else WaterTomb_Timer -= diff; + MarkOfHydross_Timer = 15000; + } else MarkOfHydross_Timer -= diff; - //PosCheck_Timer - if (PosCheck_Timer <= diff) - { - if (!me->IsWithinDist2d(HYDROSS_X, HYDROSS_Y, SWITCH_RADIUS)) - { - // switch to corrupted form - me->SetDisplayId(MODEL_CORRUPT); - MarkOfCorruption_Count = 0; - CorruptedForm = true; - - Talk(SAY_SWITCH_TO_CORRUPT); - ResetThreatList(); - DeSummonBeams(); - - // spawn 4 adds - DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); - DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); - DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); - DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); - - me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE); - me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); - me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); - } + //WaterTomb_Timer + if (WaterTomb_Timer <= diff) + { + Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true); + if (target) + DoCast(target, SPELL_WATER_TOMB); - PosCheck_Timer = 2500; - } else PosCheck_Timer -=diff; - } + WaterTomb_Timer = 7000; + } else WaterTomb_Timer -= diff; - //EnrageTimer - if (EnrageTimer <= diff) + //PosCheck_Timer + if (PosCheck_Timer <= diff) { - DoCast(me, SPELL_ENRAGE); - EnrageTimer = 60000; - } else EnrageTimer -= diff; + if (!me->IsWithinDist2d(HYDROSS_X, HYDROSS_Y, SWITCH_RADIUS)) + { + // switch to corrupted form + me->SetDisplayId(MODEL_CORRUPT); + MarkOfCorruption_Count = 0; + CorruptedForm = true; + + Talk(SAY_SWITCH_TO_CORRUPT); + ResetThreatList(); + DeSummonBeams(); + + // spawn 4 adds + DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF1, SPAWN_Y_DIFF1, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); + DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF2, SPAWN_Y_DIFF2, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); + DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF3, SPAWN_Y_DIFF3, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); + DoSpawnCreature(ENTRY_TAINTED_SPAWN, SPAWN_X_DIFF4, SPAWN_Y_DIFF4, 3, 0, TEMPSUMMON_CORPSE_DESPAWN, 0s); + + me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE); + me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); + me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false); + } - DoMeleeAttackIfReady(); + PosCheck_Timer = 2500; + } else PosCheck_Timer -=diff; } - }; + + //EnrageTimer + if (EnrageTimer <= diff) + { + DoCast(me, SPELL_ENRAGE); + EnrageTimer = 60000; + } else EnrageTimer -= diff; + + DoMeleeAttackIfReady(); + } }; void AddSC_boss_hydross_the_unstable() { - new boss_hydross_the_unstable(); + RegisterSerpentshrineCavernCreatureAI(boss_hydross_the_unstable); } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp index cccd2184da3..6cec120340f 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp @@ -131,745 +131,684 @@ float ShieldGeneratorChannelPos[4][4] = {49.3126f, -943.398f, 42.5501f, 2.40174f} }; -class boss_lady_vashj : public CreatureScript +struct boss_lady_vashj : public BossAI { -public: - boss_lady_vashj() : CreatureScript("boss_lady_vashj") { } + boss_lady_vashj(Creature* creature) : BossAI(creature, BOSS_LADY_VASHJ) + { + Initialize(); + instance = creature->GetInstanceScript(); + Intro = false; + JustCreated = true; + CanAttack = false; + creature->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); // set it only once on Creature create (no need do intro if wiped) + } - CreatureAI* GetAI(Creature* creature) const override + void Initialize() { - return GetSerpentshrineCavernAI<boss_lady_vashjAI>(creature); + AggroTimer = 19000; + ShockBlastTimer = 1 + rand32() % 60000; + EntangleTimer = 30000; + StaticChargeTimer = 10000 + rand32() % 15000; + ForkedLightningTimer = 2000; + CheckTimer = 15000; + EnchantedElementalTimer = 5000; + TaintedElementalTimer = 50000; + CoilfangEliteTimer = 45000 + rand32() % 5000; + CoilfangStriderTimer = 60000 + rand32() % 10000; + SummonSporebatTimer = 10000; + SummonSporebatStaticTimer = 30000; + EnchantedElementalPos = 0; + Phase = 0; + + Entangle = false; } - struct boss_lady_vashjAI : public ScriptedAI + InstanceScript* instance; + + ObjectGuid ShieldGeneratorChannel[4]; + + uint32 AggroTimer; + uint32 ShockBlastTimer; + uint32 EntangleTimer; + uint32 StaticChargeTimer; + uint32 ForkedLightningTimer; + uint32 CheckTimer; + uint32 EnchantedElementalTimer; + uint32 TaintedElementalTimer; + uint32 CoilfangEliteTimer; + uint32 CoilfangStriderTimer; + uint32 SummonSporebatTimer; + uint32 SummonSporebatStaticTimer; + uint8 EnchantedElementalPos; + uint8 Phase; + + bool Entangle; + bool Intro; + bool CanAttack; + bool JustCreated; + + void Reset() override { - boss_lady_vashjAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - Intro = false; - JustCreated = true; - CanAttack = false; - creature->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); // set it only once on Creature create (no need do intro if wiped) - } + Initialize(); - void Initialize() + if (JustCreated) { - AggroTimer = 19000; - ShockBlastTimer = 1 + rand32() % 60000; - EntangleTimer = 30000; - StaticChargeTimer = 10000 + rand32() % 15000; - ForkedLightningTimer = 2000; - CheckTimer = 15000; - EnchantedElementalTimer = 5000; - TaintedElementalTimer = 50000; - CoilfangEliteTimer = 45000 + rand32() % 5000; - CoilfangStriderTimer = 60000 + rand32() % 10000; - SummonSporebatTimer = 10000; - SummonSporebatStaticTimer = 30000; - EnchantedElementalPos = 0; - Phase = 0; - - Entangle = false; - } + CanAttack = false; + JustCreated = false; + } else CanAttack = true; - InstanceScript* instance; - - ObjectGuid ShieldGeneratorChannel[4]; - - uint32 AggroTimer; - uint32 ShockBlastTimer; - uint32 EntangleTimer; - uint32 StaticChargeTimer; - uint32 ForkedLightningTimer; - uint32 CheckTimer; - uint32 EnchantedElementalTimer; - uint32 TaintedElementalTimer; - uint32 CoilfangEliteTimer; - uint32 CoilfangStriderTimer; - uint32 SummonSporebatTimer; - uint32 SummonSporebatStaticTimer; - uint8 EnchantedElementalPos; - uint8 Phase; - - bool Entangle; - bool Intro; - bool CanAttack; - bool JustCreated; - - void Reset() override + for (uint8 i = 0; i < 4; ++i) { - Initialize(); - - if (JustCreated) - { - CanAttack = false; - JustCreated = false; - } else CanAttack = true; - - for (uint8 i = 0; i < 4; ++i) + if (!ShieldGeneratorChannel[i].IsEmpty()) { - if (!ShieldGeneratorChannel[i].IsEmpty()) + if (Unit* remo = ObjectAccessor::GetUnit(*me, ShieldGeneratorChannel[i])) { - if (Unit* remo = ObjectAccessor::GetUnit(*me, ShieldGeneratorChannel[i])) - { - remo->setDeathState(JUST_DIED); - ShieldGeneratorChannel[i].Clear(); - } + remo->setDeathState(JUST_DIED); + ShieldGeneratorChannel[i].Clear(); } } + } - instance->SetData(DATA_LADYVASHJEVENT, NOT_STARTED); + _Reset(); - me->SetCorpseDelay(1000*60*60); - } + me->SetCorpseDelay(1000*60*60); + } - // Called when a tainted elemental dies - void EventTaintedElementalDeath() - { - // the next will spawn 50 seconds after the previous one's death - if (TaintedElementalTimer > 50000) - TaintedElementalTimer = 50000; - } - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_SLAY); - } + // Called when a tainted elemental dies + void EventTaintedElementalDeath() + { + // the next will spawn 50 seconds after the previous one's death + if (TaintedElementalTimer > 50000) + TaintedElementalTimer = 50000; + } + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_SLAY); + } - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); - instance->SetData(DATA_LADYVASHJEVENT, DONE); - } + _JustDied(); + } - void StartEvent() - { - Talk(SAY_AGGRO); + void StartEvent(Unit* who) + { + Talk(SAY_AGGRO); - Phase = 1; + Phase = 1; - instance->SetData(DATA_LADYVASHJEVENT, IN_PROGRESS); - } + _JustEngagedWith(who); + } - void JustEngagedWith(Unit* who) override - { - // remove old tainted cores to prevent cheating in phase 2 - Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) - if (Player* player = itr->GetSource()) - player->DestroyItemCount(31088, 1, true); - StartEvent(); // this is JustEngagedWith(), so were are 100% in combat, start the event - - if (Phase != 2) - AttackStart(who); - } + void JustEngagedWith(Unit* who) override + { + // remove old tainted cores to prevent cheating in phase 2 + Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) + if (Player* player = itr->GetSource()) + player->DestroyItemCount(31088, 1, true); + StartEvent(who); // this is JustEngagedWith(), so were are 100% in combat, start the event - void MoveInLineOfSight(Unit* who) override + if (Phase != 2) + AttackStart(who); + } + + void MoveInLineOfSight(Unit* who) override + { + if (!Intro) { - if (!Intro) - { - Intro = true; - Talk(SAY_INTRO); - } - if (!CanAttack) - return; - if (!who || me->GetVictim()) - return; + Intro = true; + Talk(SAY_INTRO); + } + if (!CanAttack) + return; + if (!who || me->GetVictim()) + return; - if (me->CanCreatureAttack(who)) + if (me->CanCreatureAttack(who)) + { + float attackRadius = me->GetAttackDistance(who); + if (me->IsWithinDistInMap(who, attackRadius) && me->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && me->IsWithinLOSInMap(who)) { - float attackRadius = me->GetAttackDistance(who); - if (me->IsWithinDistInMap(who, attackRadius) && me->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && me->IsWithinLOSInMap(who)) - { - if (!me->IsInCombat()) // AttackStart() sets UNIT_FLAG_IN_COMBAT, so this msut be before attacking - StartEvent(); + if (!me->IsInCombat()) // AttackStart() sets UNIT_FLAG_IN_COMBAT, so this msut be before attacking + StartEvent(who); - if (Phase != 2) - AttackStart(who); - } + if (Phase != 2) + AttackStart(who); } } + } - void CastShootOrMultishot() + void CastShootOrMultishot() + { + switch (urand(0, 1)) { - switch (urand(0, 1)) - { - case 0: - // Shoot - // Used in Phases 1 and 3 after Entangle or while having nobody in melee range. A shot that hits her target for 4097-5543 Physical damage. - DoCastVictim(SPELL_SHOOT); - break; - case 1: - // Multishot - // Used in Phases 1 and 3 after Entangle or while having nobody in melee range. A shot that hits 1 person and 4 people around him for 6475-7525 physical damage. - DoCastVictim(SPELL_MULTI_SHOT); - break; - } - if (rand32() % 3) - { - Talk(SAY_BOWSHOT); - } + case 0: + // Shoot + // Used in Phases 1 and 3 after Entangle or while having nobody in melee range. A shot that hits her target for 4097-5543 Physical damage. + DoCastVictim(SPELL_SHOOT); + break; + case 1: + // Multishot + // Used in Phases 1 and 3 after Entangle or while having nobody in melee range. A shot that hits 1 person and 4 people around him for 6475-7525 physical damage. + DoCastVictim(SPELL_MULTI_SHOT); + break; + } + if (rand32() % 3) + { + Talk(SAY_BOWSHOT); } + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + if (!CanAttack && Intro) { - if (!CanAttack && Intro) + if (AggroTimer <= diff) { - if (AggroTimer <= diff) - { - CanAttack = true; - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - AggroTimer=19000; - } - else - { - AggroTimer -= diff; - return; - } + CanAttack = true; + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + AggroTimer=19000; } - // to prevent abuses during phase 2 - if (Phase == 2 && !me->GetVictim() && me->IsInCombat()) + else { - EnterEvadeMode(); + AggroTimer -= diff; return; } - // Return since we have no target - if (!UpdateVictim()) - return; + } + // to prevent abuses during phase 2 + if (Phase == 2 && !me->GetVictim() && me->IsInCombat()) + { + EnterEvadeMode(); + return; + } + // Return since we have no target + if (!UpdateVictim()) + return; - if (Phase == 1 || Phase == 3) + if (Phase == 1 || Phase == 3) + { + // ShockBlastTimer + if (ShockBlastTimer <= diff) { - // ShockBlastTimer - if (ShockBlastTimer <= diff) - { - // Shock Burst - // Randomly used in Phases 1 and 3 on Vashj's target, it's a Shock spell doing 8325-9675 nature damage and stunning the target for 5 seconds, during which she will not attack her target but switch to the next person on the aggro list. - DoCastVictim(SPELL_SHOCK_BLAST); + // Shock Burst + // Randomly used in Phases 1 and 3 on Vashj's target, it's a Shock spell doing 8325-9675 nature damage and stunning the target for 5 seconds, during which she will not attack her target but switch to the next person on the aggro list. + DoCastVictim(SPELL_SHOCK_BLAST); - ShockBlastTimer = 1000 + rand32() % 14000; // random cooldown - } else ShockBlastTimer -= diff; + ShockBlastTimer = 1000 + rand32() % 14000; // random cooldown + } else ShockBlastTimer -= diff; - // StaticChargeTimer - if (StaticChargeTimer <= diff) - { - // Static Charge - // Used on random people (only 1 person at any given time) in Phases 1 and 3, it's a debuff doing 2775 to 3225 Nature damage to the target and everybody in about 5 yards around it, every 1 seconds for 30 seconds. It can be removed by Cloak of Shadows, Iceblock, Divine Shield, etc, but not by Cleanse or Dispel Magic. - Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 200, true); - if (target && !target->HasAura(SPELL_STATIC_CHARGE_TRIGGER)) - DoCast(target, SPELL_STATIC_CHARGE_TRIGGER); // cast Static Charge every 2 seconds for 20 seconds + // StaticChargeTimer + if (StaticChargeTimer <= diff) + { + // Static Charge + // Used on random people (only 1 person at any given time) in Phases 1 and 3, it's a debuff doing 2775 to 3225 Nature damage to the target and everybody in about 5 yards around it, every 1 seconds for 30 seconds. It can be removed by Cloak of Shadows, Iceblock, Divine Shield, etc, but not by Cleanse or Dispel Magic. + Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 200, true); + if (target && !target->HasAura(SPELL_STATIC_CHARGE_TRIGGER)) + DoCast(target, SPELL_STATIC_CHARGE_TRIGGER); // cast Static Charge every 2 seconds for 20 seconds - StaticChargeTimer = 10000 + rand32() % 20000; - } else StaticChargeTimer -= diff; + StaticChargeTimer = 10000 + rand32() % 20000; + } else StaticChargeTimer -= diff; - // EntangleTimer - if (EntangleTimer <= diff) + // EntangleTimer + if (EntangleTimer <= diff) + { + if (!Entangle) { - if (!Entangle) - { - // Entangle - // Used in Phases 1 and 3, it casts Entangling Roots on everybody in a 15 yard radius of Vashj, immobilzing them for 10 seconds and dealing 500 damage every 2 seconds. It's not a magic effect so it cannot be dispelled, but is removed by various buffs such as Cloak of Shadows or Blessing of Freedom. - DoCastVictim(SPELL_ENTANGLE); - Entangle = true; - EntangleTimer = 10000; - } - else - { - CastShootOrMultishot(); - Entangle = false; - EntangleTimer = 20000 + rand32() % 5000; - } - } else EntangleTimer -= diff; + // Entangle + // Used in Phases 1 and 3, it casts Entangling Roots on everybody in a 15 yard radius of Vashj, immobilzing them for 10 seconds and dealing 500 damage every 2 seconds. It's not a magic effect so it cannot be dispelled, but is removed by various buffs such as Cloak of Shadows or Blessing of Freedom. + DoCastVictim(SPELL_ENTANGLE); + Entangle = true; + EntangleTimer = 10000; + } + else + { + CastShootOrMultishot(); + Entangle = false; + EntangleTimer = 20000 + rand32() % 5000; + } + } else EntangleTimer -= diff; - // Phase 1 - if (Phase == 1) + // Phase 1 + if (Phase == 1) + { + // Start phase 2 + if (HealthBelowPct(70)) { - // Start phase 2 - if (HealthBelowPct(70)) - { - // Phase 2 begins when Vashj hits 70%. She will run to the middle of her platform and surround herself in a shield making her invulerable. - Phase = 2; + // Phase 2 begins when Vashj hits 70%. She will run to the middle of her platform and surround herself in a shield making her invulerable. + Phase = 2; - me->GetMotionMaster()->Clear(); - DoTeleportTo(MIDDLE_X, MIDDLE_Y, MIDDLE_Z); + me->GetMotionMaster()->Clear(); + DoTeleportTo(MIDDLE_X, MIDDLE_Y, MIDDLE_Z); - for (uint8 i = 0; i < 4; ++i) - if (Creature* creature = me->SummonCreature(SHIED_GENERATOR_CHANNEL, ShieldGeneratorChannelPos[i][0], ShieldGeneratorChannelPos[i][1], ShieldGeneratorChannelPos[i][2], ShieldGeneratorChannelPos[i][3], TEMPSUMMON_CORPSE_DESPAWN)) - ShieldGeneratorChannel[i] = creature->GetGUID(); + for (uint8 i = 0; i < 4; ++i) + if (Creature* creature = me->SummonCreature(SHIED_GENERATOR_CHANNEL, ShieldGeneratorChannelPos[i][0], ShieldGeneratorChannelPos[i][1], ShieldGeneratorChannelPos[i][2], ShieldGeneratorChannelPos[i][3], TEMPSUMMON_CORPSE_DESPAWN)) + ShieldGeneratorChannel[i] = creature->GetGUID(); - Talk(SAY_PHASE2); - } + Talk(SAY_PHASE2); } - // Phase 3 - else + } + // Phase 3 + else + { + // SummonSporebatTimer + if (SummonSporebatTimer <= diff) { - // SummonSporebatTimer - if (SummonSporebatTimer <= diff) - { - if (Creature* sporebat = me->SummonCreature(TOXIC_SPOREBAT, SPOREBAT_X, SPOREBAT_Y, SPOREBAT_Z, SPOREBAT_O, TEMPSUMMON_CORPSE_DESPAWN)) - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - sporebat->AI()->AttackStart(target); + if (Creature* sporebat = me->SummonCreature(TOXIC_SPOREBAT, SPOREBAT_X, SPOREBAT_Y, SPOREBAT_Z, SPOREBAT_O, TEMPSUMMON_CORPSE_DESPAWN)) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + sporebat->AI()->AttackStart(target); - // summon sporebats faster and faster - if (SummonSporebatStaticTimer > 1000) - SummonSporebatStaticTimer -= 1000; + // summon sporebats faster and faster + if (SummonSporebatStaticTimer > 1000) + SummonSporebatStaticTimer -= 1000; - SummonSporebatTimer = SummonSporebatStaticTimer; + SummonSporebatTimer = SummonSporebatStaticTimer; - if (SummonSporebatTimer < 5000) - SummonSporebatTimer = 5000; + if (SummonSporebatTimer < 5000) + SummonSporebatTimer = 5000; - } else SummonSporebatTimer -= diff; - } + } else SummonSporebatTimer -= diff; + } - // Melee attack - DoMeleeAttackIfReady(); + // Melee attack + DoMeleeAttackIfReady(); - // CheckTimer - used to check if somebody is in melee range - if (CheckTimer <= diff) + // CheckTimer - used to check if somebody is in melee range + if (CheckTimer <= diff) + { + bool inMeleeRange = false; + for (auto* ref : me->GetThreatManager().GetUnsortedThreatList()) { - bool inMeleeRange = false; - for (auto* ref : me->GetThreatManager().GetUnsortedThreatList()) + Unit* target = ref->GetVictim(); + if (target->IsWithinMeleeRange(me)) // if in melee range { - Unit* target = ref->GetVictim(); - if (target->IsWithinMeleeRange(me)) // if in melee range - { - inMeleeRange = true; - break; - } + inMeleeRange = true; + break; } + } - // if nobody is in melee range - if (!inMeleeRange) - CastShootOrMultishot(); + // if nobody is in melee range + if (!inMeleeRange) + CastShootOrMultishot(); - CheckTimer = 5000; - } else CheckTimer -= diff; - } - // Phase 2 - else + CheckTimer = 5000; + } else CheckTimer -= diff; + } + // Phase 2 + else + { + // ForkedLightningTimer + if (ForkedLightningTimer <= diff) { - // ForkedLightningTimer - if (ForkedLightningTimer <= diff) - { - // Forked Lightning - // Used constantly in Phase 2, it shoots out completely randomly targeted bolts of lightning which hit everybody in a roughtly 60 degree cone in front of Vashj for 2313-2687 nature damage. - Unit* target = SelectTarget(SelectTargetMethod::Random, 0); + // Forked Lightning + // Used constantly in Phase 2, it shoots out completely randomly targeted bolts of lightning which hit everybody in a roughtly 60 degree cone in front of Vashj for 2313-2687 nature damage. + Unit* target = SelectTarget(SelectTargetMethod::Random, 0); - if (!target) - target = me->GetVictim(); + if (!target) + target = me->GetVictim(); - DoCast(target, SPELL_FORKED_LIGHTNING); + DoCast(target, SPELL_FORKED_LIGHTNING); - ForkedLightningTimer = 2000 + rand32() % 6000; - } else ForkedLightningTimer -= diff; + ForkedLightningTimer = 2000 + rand32() % 6000; + } else ForkedLightningTimer -= diff; - // EnchantedElementalTimer - if (EnchantedElementalTimer <= diff) - { - me->SummonCreature(ENCHANTED_ELEMENTAL, ElementPos[EnchantedElementalPos][0], ElementPos[EnchantedElementalPos][1], ElementPos[EnchantedElementalPos][2], ElementPos[EnchantedElementalPos][3], TEMPSUMMON_CORPSE_DESPAWN); + // EnchantedElementalTimer + if (EnchantedElementalTimer <= diff) + { + me->SummonCreature(ENCHANTED_ELEMENTAL, ElementPos[EnchantedElementalPos][0], ElementPos[EnchantedElementalPos][1], ElementPos[EnchantedElementalPos][2], ElementPos[EnchantedElementalPos][3], TEMPSUMMON_CORPSE_DESPAWN); - if (EnchantedElementalPos == 7) - EnchantedElementalPos = 0; - else - ++EnchantedElementalPos; + if (EnchantedElementalPos == 7) + EnchantedElementalPos = 0; + else + ++EnchantedElementalPos; - EnchantedElementalTimer = 10000 + rand32() % 5000; - } else EnchantedElementalTimer -= diff; + EnchantedElementalTimer = 10000 + rand32() % 5000; + } else EnchantedElementalTimer -= diff; - // TaintedElementalTimer - if (TaintedElementalTimer <= diff) - { - uint32 pos = rand32() % 8; - me->SummonCreature(TAINTED_ELEMENTAL, ElementPos[pos][0], ElementPos[pos][1], ElementPos[pos][2], ElementPos[pos][3], TEMPSUMMON_DEAD_DESPAWN); + // TaintedElementalTimer + if (TaintedElementalTimer <= diff) + { + uint32 pos = rand32() % 8; + me->SummonCreature(TAINTED_ELEMENTAL, ElementPos[pos][0], ElementPos[pos][1], ElementPos[pos][2], ElementPos[pos][3], TEMPSUMMON_DEAD_DESPAWN); - TaintedElementalTimer = 120000; - } else TaintedElementalTimer -= diff; + TaintedElementalTimer = 120000; + } else TaintedElementalTimer -= diff; - // CoilfangEliteTimer - if (CoilfangEliteTimer <= diff) + // CoilfangEliteTimer + if (CoilfangEliteTimer <= diff) + { + uint32 pos = rand32() % 3; + Creature* coilfangElite = me->SummonCreature(COILFANG_ELITE, CoilfangElitePos[pos][0], CoilfangElitePos[pos][1], CoilfangElitePos[pos][2], CoilfangElitePos[pos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s); + if (coilfangElite) { - uint32 pos = rand32() % 3; - Creature* coilfangElite = me->SummonCreature(COILFANG_ELITE, CoilfangElitePos[pos][0], CoilfangElitePos[pos][1], CoilfangElitePos[pos][2], CoilfangElitePos[pos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s); - if (coilfangElite) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - coilfangElite->AI()->AttackStart(target); - else if (me->GetVictim()) - coilfangElite->AI()->AttackStart(me->GetVictim()); - } - CoilfangEliteTimer = 45000 + rand32() % 5000; - } else CoilfangEliteTimer -= diff; + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + coilfangElite->AI()->AttackStart(target); + else if (me->GetVictim()) + coilfangElite->AI()->AttackStart(me->GetVictim()); + } + CoilfangEliteTimer = 45000 + rand32() % 5000; + } else CoilfangEliteTimer -= diff; - // CoilfangStriderTimer - if (CoilfangStriderTimer <= diff) + // CoilfangStriderTimer + if (CoilfangStriderTimer <= diff) + { + uint32 pos = rand32() % 3; + if (Creature* CoilfangStrider = me->SummonCreature(COILFANG_STRIDER, CoilfangStriderPos[pos][0], CoilfangStriderPos[pos][1], CoilfangStriderPos[pos][2], CoilfangStriderPos[pos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s)) { - uint32 pos = rand32() % 3; - if (Creature* CoilfangStrider = me->SummonCreature(COILFANG_STRIDER, CoilfangStriderPos[pos][0], CoilfangStriderPos[pos][1], CoilfangStriderPos[pos][2], CoilfangStriderPos[pos][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s)) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - CoilfangStrider->AI()->AttackStart(target); - else if (me->GetVictim()) - CoilfangStrider->AI()->AttackStart(me->GetVictim()); - } - CoilfangStriderTimer = 60000 + rand32() % 10000; - } else CoilfangStriderTimer -= diff; + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + CoilfangStrider->AI()->AttackStart(target); + else if (me->GetVictim()) + CoilfangStrider->AI()->AttackStart(me->GetVictim()); + } + CoilfangStriderTimer = 60000 + rand32() % 10000; + } else CoilfangStriderTimer -= diff; - // CheckTimer - if (CheckTimer <= diff) + // CheckTimer + if (CheckTimer <= diff) + { + // Start Phase 3 + if (instance->GetData(DATA_CANSTARTPHASE3)) { - // Start Phase 3 - if (instance->GetData(DATA_CANSTARTPHASE3)) - { - // set life 50% - me->SetHealth(me->CountPctFromMaxHealth(50)); + // set life 50% + me->SetHealth(me->CountPctFromMaxHealth(50)); - me->RemoveAurasDueToSpell(SPELL_MAGIC_BARRIER); + me->RemoveAurasDueToSpell(SPELL_MAGIC_BARRIER); - Talk(SAY_PHASE3); + Talk(SAY_PHASE3); - Phase = 3; + Phase = 3; - // return to the tank - me->GetMotionMaster()->MoveChase(me->GetVictim()); - } - CheckTimer = 1000; - } else CheckTimer -= diff; - } + // return to the tank + me->GetMotionMaster()->MoveChase(me->GetVictim()); + } + CheckTimer = 1000; + } else CheckTimer -= diff; } - }; - + } }; // Enchanted Elemental // If one of them reaches Vashj he will increase her damage done by 5%. -class npc_enchanted_elemental : public CreatureScript +struct npc_enchanted_elemental : public ScriptedAI { -public: - npc_enchanted_elemental() : CreatureScript("npc_enchanted_elemental") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_enchanted_elemental(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<npc_enchanted_elementalAI>(creature); + Initialize(); + instance = creature->GetInstanceScript(); } - struct npc_enchanted_elementalAI : public ScriptedAI + void Initialize() { - npc_enchanted_elementalAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - } + Move = 0; + Phase = 1; - void Initialize() - { - Move = 0; - Phase = 1; + X = ElementWPPos[0][0]; + Y = ElementWPPos[0][1]; + Z = ElementWPPos[0][2]; + } - X = ElementWPPos[0][0]; - Y = ElementWPPos[0][1]; - Z = ElementWPPos[0][2]; - } + InstanceScript* instance; + uint32 Move; + uint32 Phase; + float X, Y, Z; - InstanceScript* instance; - uint32 Move; - uint32 Phase; - float X, Y, Z; + ObjectGuid VashjGUID; - ObjectGuid VashjGUID; + void Reset() override + { + me->SetSpeedRate(MOVE_WALK, 0.6f); // walk + me->SetSpeedRate(MOVE_RUN, 0.6f); // run + Initialize(); - void Reset() override + //search for nearest waypoint (up on stairs) + for (uint32 i = 1; i < 8; ++i) { - me->SetSpeedRate(MOVE_WALK, 0.6f); // walk - me->SetSpeedRate(MOVE_RUN, 0.6f); // run - Initialize(); - - //search for nearest waypoint (up on stairs) - for (uint32 i = 1; i < 8; ++i) + if (me->GetDistance(ElementWPPos[i][0], ElementWPPos[i][1], ElementWPPos[i][2]) < me->GetDistance(X, Y, Z)) { - if (me->GetDistance(ElementWPPos[i][0], ElementWPPos[i][1], ElementWPPos[i][2]) < me->GetDistance(X, Y, Z)) - { - X = ElementWPPos[i][0]; - Y = ElementWPPos[i][1]; - Z = ElementWPPos[i][2]; - } + X = ElementWPPos[i][0]; + Y = ElementWPPos[i][1]; + Z = ElementWPPos[i][2]; } - - VashjGUID = instance->GetGuidData(DATA_LADYVASHJ); } - void JustEngagedWith(Unit* /*who*/) override { } + VashjGUID = instance->GetGuidData(DATA_LADYVASHJ); + } - void MoveInLineOfSight(Unit* /*who*/) override { } + void JustEngagedWith(Unit* /*who*/) override { } - void UpdateAI(uint32 diff) override - { - if (!VashjGUID) - return; + void MoveInLineOfSight(Unit* /*who*/) override { } - if (Move <= diff) - { - me->SetWalk(true); - if (Phase == 1) - me->GetMotionMaster()->MovePoint(0, X, Y, Z); - if (Phase == 1 && me->IsWithinDist3d(X, Y, Z, 0.1f)) - Phase = 2; - if (Phase == 2) - { - me->GetMotionMaster()->MovePoint(0, MIDDLE_X, MIDDLE_Y, MIDDLE_Z); - Phase = 3; - } - if (Phase == 3) - { - me->GetMotionMaster()->MovePoint(0, MIDDLE_X, MIDDLE_Y, MIDDLE_Z); - if (me->IsWithinDist3d(MIDDLE_X, MIDDLE_Y, MIDDLE_Z, 3)) - DoCast(me, SPELL_SURGE); - } - if (Creature* vashj = ObjectAccessor::GetCreature(*me, VashjGUID)) - if (!vashj->IsInCombat() || ENSURE_AI(boss_lady_vashj::boss_lady_vashjAI, vashj->AI())->Phase != 2 || vashj->isDead()) - me->KillSelf(); - Move = 1000; - } else Move -= diff; - } - }; + void UpdateAI(uint32 diff) override + { + if (!VashjGUID) + return; + if (Move <= diff) + { + me->SetWalk(true); + if (Phase == 1) + me->GetMotionMaster()->MovePoint(0, X, Y, Z); + if (Phase == 1 && me->IsWithinDist3d(X, Y, Z, 0.1f)) + Phase = 2; + if (Phase == 2) + { + me->GetMotionMaster()->MovePoint(0, MIDDLE_X, MIDDLE_Y, MIDDLE_Z); + Phase = 3; + } + if (Phase == 3) + { + me->GetMotionMaster()->MovePoint(0, MIDDLE_X, MIDDLE_Y, MIDDLE_Z); + if (me->IsWithinDist3d(MIDDLE_X, MIDDLE_Y, MIDDLE_Z, 3)) + DoCast(me, SPELL_SURGE); + } + if (Creature* vashj = ObjectAccessor::GetCreature(*me, VashjGUID)) + if (!vashj->IsInCombat() || ENSURE_AI(boss_lady_vashj, vashj->AI())->Phase != 2 || vashj->isDead()) + me->KillSelf(); + Move = 1000; + } else Move -= diff; + } }; // Tainted Elemental // This mob has 7, 900 life, doesn't move, and shoots Poison Bolts at one person anywhere in the area, doing 3, 000 nature damage and placing a posion doing 2, 000 damage every 2 seconds. He will switch targets often, or sometimes just hang on a single player, but there is nothing you can do about it except heal the damage and kill the Tainted Elemental -class npc_tainted_elemental : public CreatureScript +struct npc_tainted_elemental : public ScriptedAI { -public: - npc_tainted_elemental() : CreatureScript("npc_tainted_elemental") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_tainted_elemental(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<npc_tainted_elementalAI>(creature); + Initialize(); + instance = creature->GetInstanceScript(); } - struct npc_tainted_elementalAI : public ScriptedAI + void Initialize() { - npc_tainted_elementalAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - } - - void Initialize() - { - PoisonBoltTimer = 5000 + rand32() % 5000; - DespawnTimer = 30000; - } + PoisonBoltTimer = 5000 + rand32() % 5000; + DespawnTimer = 30000; + } - InstanceScript* instance; + InstanceScript* instance; - uint32 PoisonBoltTimer; - uint32 DespawnTimer; + uint32 PoisonBoltTimer; + uint32 DespawnTimer; - void Reset() override - { - Initialize(); - } + void Reset() override + { + Initialize(); + } - void JustDied(Unit* /*killer*/) override - { - if (Creature* vashj = ObjectAccessor::GetCreature((*me), instance->GetGuidData(DATA_LADYVASHJ))) - ENSURE_AI(boss_lady_vashj::boss_lady_vashjAI, vashj->AI())->EventTaintedElementalDeath(); - } + void JustDied(Unit* /*killer*/) override + { + if (Creature* vashj = ObjectAccessor::GetCreature((*me), instance->GetGuidData(DATA_LADYVASHJ))) + ENSURE_AI(boss_lady_vashj, vashj->AI())->EventTaintedElementalDeath(); + } - void JustEngagedWith(Unit* who) override - { - AddThreat(who, 0.1f); - } + void JustEngagedWith(Unit* who) override + { + AddThreat(who, 0.1f); + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + // PoisonBoltTimer + if (PoisonBoltTimer <= diff) { - // PoisonBoltTimer - if (PoisonBoltTimer <= diff) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 0); - - if (target && target->IsWithinDistInMap(me, 30)) - DoCast(target, SPELL_POISON_BOLT); + Unit* target = SelectTarget(SelectTargetMethod::Random, 0); - PoisonBoltTimer = 5000 + rand32() % 5000; - } else PoisonBoltTimer -= diff; + if (target && target->IsWithinDistInMap(me, 30)) + DoCast(target, SPELL_POISON_BOLT); - // DespawnTimer - if (DespawnTimer <= diff) - { - // call Unsummon() - me->setDeathState(DEAD); + PoisonBoltTimer = 5000 + rand32() % 5000; + } else PoisonBoltTimer -= diff; - // to prevent crashes - DespawnTimer = 1000; - } else DespawnTimer -= diff; - } - }; + // DespawnTimer + if (DespawnTimer <= diff) + { + // call Unsummon() + me->setDeathState(DEAD); + // to prevent crashes + DespawnTimer = 1000; + } else DespawnTimer -= diff; + } }; //Toxic Sporebat //Toxic Spores: Used in Phase 3 by the Spore Bats, it creates a contaminated green patch of ground, dealing about 2775-3225 nature damage every second to anyone who stands in it. -class npc_toxic_sporebat : public CreatureScript +struct npc_toxic_sporebat : public ScriptedAI { -public: - npc_toxic_sporebat() : CreatureScript("npc_toxic_sporebat") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_toxic_sporebat(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<npc_toxic_sporebatAI>(creature); + Initialize(); + instance = creature->GetInstanceScript(); + EnterEvadeMode(); } - struct npc_toxic_sporebatAI : public ScriptedAI + void Initialize() { - npc_toxic_sporebatAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - EnterEvadeMode(); - } + MovementTimer = 0; + ToxicSporeTimer = 5000; + BoltTimer = 5500; + CheckTimer = 1000; + } - void Initialize() - { - MovementTimer = 0; - ToxicSporeTimer = 5000; - BoltTimer = 5500; - CheckTimer = 1000; - } + InstanceScript* instance; - InstanceScript* instance; + uint32 MovementTimer; + uint32 ToxicSporeTimer; + uint32 BoltTimer; + uint32 CheckTimer; - uint32 MovementTimer; - uint32 ToxicSporeTimer; - uint32 BoltTimer; - uint32 CheckTimer; + void Reset() override + { + me->SetDisableGravity(true); + me->SetFaction(FACTION_MONSTER); + Initialize(); + } - void Reset() override - { - me->SetDisableGravity(true); - me->SetFaction(FACTION_MONSTER); - Initialize(); - } + void MoveInLineOfSight(Unit* /*who*/) override + { + } - void MoveInLineOfSight(Unit* /*who*/) override + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE) + return; - { - } + if (id == 1) + MovementTimer = 0; + } - void MovementInform(uint32 type, uint32 id) override + void UpdateAI(uint32 diff) override + { + // Random movement + if (MovementTimer <= diff) { - if (type != POINT_MOTION_TYPE) - return; - - if (id == 1) - MovementTimer = 0; - } + uint32 rndpos = rand32() % 8; + me->GetMotionMaster()->MovePoint(1, SporebatWPPos[rndpos][0], SporebatWPPos[rndpos][1], SporebatWPPos[rndpos][2]); + MovementTimer = 6000; + } else MovementTimer -= diff; - void UpdateAI(uint32 diff) override + // toxic spores + if (BoltTimer <= diff) { - // Random movement - if (MovementTimer <= diff) - { - uint32 rndpos = rand32() % 8; - me->GetMotionMaster()->MovePoint(1, SporebatWPPos[rndpos][0], SporebatWPPos[rndpos][1], SporebatWPPos[rndpos][2]); - MovementTimer = 6000; - } else MovementTimer -= diff; - - // toxic spores - if (BoltTimer <= diff) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + if (Creature* trig = me->SummonCreature(TOXIC_SPORES_TRIGGER, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 30s)) { - if (Creature* trig = me->SummonCreature(TOXIC_SPORES_TRIGGER, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 30s)) - { - trig->SetFaction(FACTION_MONSTER); - trig->CastSpell(trig, SPELL_TOXIC_SPORES, true); - } + trig->SetFaction(FACTION_MONSTER); + trig->CastSpell(trig, SPELL_TOXIC_SPORES, true); } - BoltTimer = 10000 + rand32() % 5000; } - else BoltTimer -= diff; + BoltTimer = 10000 + rand32() % 5000; + } + else BoltTimer -= diff; - // CheckTimer - if (CheckTimer <= diff) + // CheckTimer + if (CheckTimer <= diff) + { + // check if vashj is death + Unit* Vashj = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_LADYVASHJ)); + if (!Vashj || !Vashj->IsAlive() || ENSURE_AI(boss_lady_vashj, Vashj->ToCreature()->AI())->Phase != 3) { - // check if vashj is death - Unit* Vashj = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_LADYVASHJ)); - if (!Vashj || !Vashj->IsAlive() || ENSURE_AI(boss_lady_vashj::boss_lady_vashjAI, Vashj->ToCreature()->AI())->Phase != 3) - { - // remove - me->SetFaction(FACTION_FRIENDLY); - me->DespawnOrUnsummon(); - return; - } - - CheckTimer = 1000; + // remove + me->SetFaction(FACTION_FRIENDLY); + me->DespawnOrUnsummon(); + return; } - else - CheckTimer -= diff; - } - }; + CheckTimer = 1000; + } + else + CheckTimer -= diff; + } }; -class npc_shield_generator_channel : public CreatureScript +struct npc_shield_generator_channel : public ScriptedAI { -public: - npc_shield_generator_channel() : CreatureScript("npc_shield_generator_channel") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_shield_generator_channel(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<npc_shield_generator_channelAI>(creature); + Initialize(); + instance = creature->GetInstanceScript(); } - struct npc_shield_generator_channelAI : public ScriptedAI + void Initialize() { - npc_shield_generator_channelAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - } - - void Initialize() - { - CheckTimer = 0; - Cast = false; - } + CheckTimer = 0; + Cast = false; + } - InstanceScript* instance; - uint32 CheckTimer; - bool Cast; + InstanceScript* instance; + uint32 CheckTimer; + bool Cast; - void Reset() override - { - Initialize(); - me->SetDisplayId(11686); // invisible - } + void Reset() override + { + Initialize(); + me->SetDisplayId(11686); // invisible + } - void MoveInLineOfSight(Unit* /*who*/) override { } + void MoveInLineOfSight(Unit* /*who*/) override { } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + if (CheckTimer <= diff) { - if (CheckTimer <= diff) - { - Unit* vashj = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_LADYVASHJ)); + Unit* vashj = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_LADYVASHJ)); - if (vashj && vashj->IsAlive()) + if (vashj && vashj->IsAlive()) + { + // start visual channel + if (!Cast || !vashj->HasAura(SPELL_MAGIC_BARRIER)) { - // start visual channel - if (!Cast || !vashj->HasAura(SPELL_MAGIC_BARRIER)) - { - DoCast(vashj, SPELL_MAGIC_BARRIER, true); - Cast = true; - } + DoCast(vashj, SPELL_MAGIC_BARRIER, true); + Cast = true; } - CheckTimer = 1000; - } else CheckTimer -= diff; - } - }; - + } + CheckTimer = 1000; + } else CheckTimer -= diff; + } }; class item_tainted_core : public ItemScript @@ -884,7 +823,7 @@ public: return true; Creature* vashj = ObjectAccessor::GetCreature((*player), instance->GetGuidData(DATA_LADYVASHJ)); - if (vashj && (ENSURE_AI(boss_lady_vashj::boss_lady_vashjAI, vashj->AI())->Phase == 2)) + if (vashj && (ENSURE_AI(boss_lady_vashj, vashj->AI())->Phase == 2)) { if (GameObject* gObj = targets.GetGOTarget()) { @@ -916,7 +855,7 @@ public: return true; // get and remove channel - if (Unit* channel = ObjectAccessor::GetCreature(*vashj, ENSURE_AI(boss_lady_vashj::boss_lady_vashjAI, vashj->AI())->ShieldGeneratorChannel[channelIdentifier])) + if (Unit* channel = ObjectAccessor::GetCreature(*vashj, ENSURE_AI(boss_lady_vashj, vashj->AI())->ShieldGeneratorChannel[channelIdentifier])) channel->setDeathState(JUST_DIED); // call Unsummon() instance->SetData(identifier, 1); @@ -941,10 +880,10 @@ public: void AddSC_boss_lady_vashj() { - new boss_lady_vashj(); - new npc_enchanted_elemental(); - new npc_tainted_elemental(); - new npc_toxic_sporebat(); - new npc_shield_generator_channel(); + RegisterSerpentshrineCavernCreatureAI(boss_lady_vashj); + RegisterSerpentshrineCavernCreatureAI(npc_enchanted_elemental); + RegisterSerpentshrineCavernCreatureAI(npc_tainted_elemental); + RegisterSerpentshrineCavernCreatureAI(npc_toxic_sporebat); + RegisterSerpentshrineCavernCreatureAI(npc_shield_generator_channel); new item_tainted_core(); } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp index 7293fc9f6ee..10bdf3bc631 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp @@ -73,746 +73,698 @@ enum LeotherasTheBlind SAY_DEATH = 7 }; -class npc_inner_demon : public CreatureScript +struct npc_inner_demon : public ScriptedAI { -public: - npc_inner_demon() : CreatureScript("npc_inner_demon") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_inner_demon(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<npc_inner_demonAI>(creature); + Initialize(); } - struct npc_inner_demonAI : public ScriptedAI + void Initialize() { - npc_inner_demonAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - } + ShadowBolt_Timer = 10000; + Link_Timer = 1000; + } - void Initialize() - { - ShadowBolt_Timer = 10000; - Link_Timer = 1000; - } + uint32 ShadowBolt_Timer; - uint32 ShadowBolt_Timer; + uint32 Link_Timer; + ObjectGuid victimGUID; - uint32 Link_Timer; - ObjectGuid victimGUID; + void Reset() override + { + Initialize(); + } - void Reset() override - { - Initialize(); - } + void SetGUID(ObjectGuid const& guid, int32 id) override + { + if (id == INNER_DEMON_VICTIM) + victimGUID = guid; + } - void SetGUID(ObjectGuid const& guid, int32 id) override - { - if (id == INNER_DEMON_VICTIM) - victimGUID = guid; - } + ObjectGuid GetGUID(int32 id/* = 0 */) const override + { + if (id == INNER_DEMON_VICTIM) + return victimGUID; + return ObjectGuid::Empty; + } - ObjectGuid GetGUID(int32 id/* = 0 */) const override - { - if (id == INNER_DEMON_VICTIM) - return victimGUID; - return ObjectGuid::Empty; - } + void JustDied(Unit* /*killer*/) override + { + Unit* unit = ObjectAccessor::GetUnit(*me, victimGUID); + if (unit && unit->HasAura(SPELL_INSIDIOUS_WHISPER)) + unit->RemoveAurasDueToSpell(SPELL_INSIDIOUS_WHISPER); + } - void JustDied(Unit* /*killer*/) override + void DamageTaken(Unit* done_by, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override + { + if (!done_by || (done_by->GetGUID() != victimGUID && done_by->GetGUID() != me->GetGUID())) { - Unit* unit = ObjectAccessor::GetUnit(*me, victimGUID); - if (unit && unit->HasAura(SPELL_INSIDIOUS_WHISPER)) - unit->RemoveAurasDueToSpell(SPELL_INSIDIOUS_WHISPER); + damage = 0; + ModifyThreatByPercent(done_by, -100); } + } - void DamageTaken(Unit* done_by, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override - { - if (!done_by || (done_by->GetGUID() != victimGUID && done_by->GetGUID() != me->GetGUID())) - { - damage = 0; - ModifyThreatByPercent(done_by, -100); - } - } + void JustEngagedWith(Unit* /*who*/) override + { + if (!victimGUID) + return; + } - void JustEngagedWith(Unit* /*who*/) override - { - if (!victimGUID) - return; - } + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim() || !me->GetVictim()) + return; - void UpdateAI(uint32 diff) override + if (me->EnsureVictim()->GetGUID() != victimGUID) { - //Return since we have no target - if (!UpdateVictim() || !me->GetVictim()) - return; - - if (me->EnsureVictim()->GetGUID() != victimGUID) + ModifyThreatByPercent(me->GetVictim(), -100); + Unit* owner = ObjectAccessor::GetUnit(*me, victimGUID); + if (owner && owner->IsAlive()) { - ModifyThreatByPercent(me->GetVictim(), -100); - Unit* owner = ObjectAccessor::GetUnit(*me, victimGUID); - if (owner && owner->IsAlive()) - { - AddThreat(owner, 999999); - AttackStart(owner); - } else if (owner && owner->isDead()) - { - me->KillSelf(); - return; - } + AddThreat(owner, 999999); + AttackStart(owner); + } else if (owner && owner->isDead()) + { + me->KillSelf(); + return; } + } - if (Link_Timer <= diff) - { - DoCastVictim(SPELL_SOUL_LINK, true); - Link_Timer = 1000; - } else Link_Timer -= diff; + if (Link_Timer <= diff) + { + DoCastVictim(SPELL_SOUL_LINK, true); + Link_Timer = 1000; + } else Link_Timer -= diff; - if (!me->HasAura(AURA_DEMONIC_ALIGNMENT)) - DoCast(me, AURA_DEMONIC_ALIGNMENT, true); + if (!me->HasAura(AURA_DEMONIC_ALIGNMENT)) + DoCast(me, AURA_DEMONIC_ALIGNMENT, true); - if (ShadowBolt_Timer <= diff) - { - DoCastVictim(SPELL_SHADOWBOLT, false); - ShadowBolt_Timer = 10000; - } else ShadowBolt_Timer -= diff; + if (ShadowBolt_Timer <= diff) + { + DoCastVictim(SPELL_SHADOWBOLT, false); + ShadowBolt_Timer = 10000; + } else ShadowBolt_Timer -= diff; - DoMeleeAttackIfReady(); - } - }; + DoMeleeAttackIfReady(); + } }; //Original Leotheras the Blind AI -class boss_leotheras_the_blind : public CreatureScript +struct boss_leotheras_the_blind : public BossAI { -public: - boss_leotheras_the_blind() : CreatureScript("boss_leotheras_the_blind") { } + boss_leotheras_the_blind(Creature* creature) : BossAI(creature, BOSS_LEOTHERAS_THE_BLIND) + { + Initialize(); + creature->GetPosition(x, y, z); + } - CreatureAI* GetAI(Creature* creature) const override + void Initialize() { - return GetSerpentshrineCavernAI<boss_leotheras_the_blindAI>(creature); + BanishTimer = 1000; + Whirlwind_Timer = 15000; + ChaosBlast_Timer = 1000; + SwitchToDemon_Timer = 45000; + SwitchToHuman_Timer = 60000; + Berserk_Timer = 600000; + InnerDemons_Timer = 30000; + + DealDamage = true; + DemonForm = false; + IsFinalForm = false; + NeedThreatReset = false; + EnrageUsed = false; + for (ObjectGuid& guid : InnderDemon) + guid.Clear(); + InnerDemon_Count = 0; } - struct boss_leotheras_the_blindAI : public ScriptedAI + uint32 Whirlwind_Timer; + uint32 ChaosBlast_Timer; + uint32 SwitchToDemon_Timer; + uint32 SwitchToHuman_Timer; + uint32 Berserk_Timer; + uint32 InnerDemons_Timer; + uint32 BanishTimer; + + bool DealDamage; + bool NeedThreatReset; + bool DemonForm; + bool IsFinalForm; + bool EnrageUsed; + float x, y, z; + + ObjectGuid InnderDemon[5]; + uint32 InnerDemon_Count; + ObjectGuid Demon; + ObjectGuid SpellBinderGUID[3]; + + void Reset() override { - boss_leotheras_the_blindAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - creature->GetPosition(x, y, z); - instance = creature->GetInstanceScript(); - } + CheckChannelers(); + Initialize(); + me->SetCanDualWield(true); + me->SetSpeedRate(MOVE_RUN, 2.0f); + me->SetDisplayId(MODEL_NIGHTELF); + me->SetVirtualItem(0, 0); + me->SetVirtualItem(1, 0); + DoCast(me, SPELL_DUAL_WIELD, true); + me->SetCorpseDelay(1000*60*60); + _Reset(); + } - void Initialize() + void CheckChannelers(/*bool DoEvade = true*/) + { + for (uint8 i = 0; i < 3; ++i) { - BanishTimer = 1000; - Whirlwind_Timer = 15000; - ChaosBlast_Timer = 1000; - SwitchToDemon_Timer = 45000; - SwitchToHuman_Timer = 60000; - Berserk_Timer = 600000; - InnerDemons_Timer = 30000; - - DealDamage = true; - DemonForm = false; - IsFinalForm = false; - NeedThreatReset = false; - EnrageUsed = false; - for (ObjectGuid& guid : InnderDemon) - guid.Clear(); - InnerDemon_Count = 0; - } + if (Creature* add = ObjectAccessor::GetCreature(*me, SpellBinderGUID[i])) + add->DisappearAndDie(); - InstanceScript* instance; - - uint32 Whirlwind_Timer; - uint32 ChaosBlast_Timer; - uint32 SwitchToDemon_Timer; - uint32 SwitchToHuman_Timer; - uint32 Berserk_Timer; - uint32 InnerDemons_Timer; - uint32 BanishTimer; - - bool DealDamage; - bool NeedThreatReset; - bool DemonForm; - bool IsFinalForm; - bool EnrageUsed; - float x, y, z; - - ObjectGuid InnderDemon[5]; - uint32 InnerDemon_Count; - ObjectGuid Demon; - ObjectGuid SpellBinderGUID[3]; - - void Reset() override - { - CheckChannelers(); - Initialize(); - me->SetCanDualWield(true); - me->SetSpeedRate(MOVE_RUN, 2.0f); - me->SetDisplayId(MODEL_NIGHTELF); - me->SetVirtualItem(0, 0); - me->SetVirtualItem(1, 0); - DoCast(me, SPELL_DUAL_WIELD, true); - me->SetCorpseDelay(1000*60*60); - instance->SetData(DATA_LEOTHERASTHEBLINDEVENT, NOT_STARTED); + float nx = x; + float ny = y; + float o = 2.4f; + if (i == 0) {nx += 10; ny -= 5; o=2.5f;} + if (i == 1) {nx -= 8; ny -= 7; o=0.9f;} + if (i == 2) {nx -= 3; ny += 9; o=5.0f;} + Creature* binder = me->SummonCreature(NPC_SPELLBINDER, nx, ny, z, o, TEMPSUMMON_DEAD_DESPAWN); + if (binder) + SpellBinderGUID[i] = binder->GetGUID(); } + } + void MoveInLineOfSight(Unit* who) override - void CheckChannelers(/*bool DoEvade = true*/) - { - for (uint8 i = 0; i < 3; ++i) - { - if (Creature* add = ObjectAccessor::GetCreature(*me, SpellBinderGUID[i])) - add->DisappearAndDie(); - - float nx = x; - float ny = y; - float o = 2.4f; - if (i == 0) {nx += 10; ny -= 5; o=2.5f;} - if (i == 1) {nx -= 8; ny -= 7; o=0.9f;} - if (i == 2) {nx -= 3; ny += 9; o=5.0f;} - Creature* binder = me->SummonCreature(NPC_SPELLBINDER, nx, ny, z, o, TEMPSUMMON_DEAD_DESPAWN); - if (binder) - SpellBinderGUID[i] = binder->GetGUID(); - } - } - void MoveInLineOfSight(Unit* who) override + { + if (me->HasAura(AURA_BANISH)) + return; + if (!me->GetVictim() && me->CanCreatureAttack(who)) { - if (me->HasAura(AURA_BANISH)) + if (me->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) return; - if (!me->GetVictim() && me->CanCreatureAttack(who)) + float attackRadius = me->GetAttackDistance(who); + if (me->IsWithinDistInMap(who, attackRadius)) { - if (me->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE) - return; - - float attackRadius = me->GetAttackDistance(who); - if (me->IsWithinDistInMap(who, attackRadius)) + // Check first that object is in an angle in front of this one before LoS check + if (me->HasInArc(float(M_PI) / 2.0f, who) && me->IsWithinLOSInMap(who)) { - // Check first that object is in an angle in front of this one before LoS check - if (me->HasInArc(float(M_PI) / 2.0f, who) && me->IsWithinLOSInMap(who)) - { - AttackStart(who); - } + AttackStart(who); } } } + } - void StartEvent() + void StartEvent() + { + Talk(SAY_AGGRO); + instance->SetBossState(BOSS_LEOTHERAS_THE_BLIND, IN_PROGRESS); + } + + void CheckBanish() + { + uint8 AliveChannelers = 0; + for (uint8 i = 0; i < 3; ++i) { - Talk(SAY_AGGRO); - instance->SetData(DATA_LEOTHERASTHEBLINDEVENT, IN_PROGRESS); + Unit* add = ObjectAccessor::GetUnit(*me, SpellBinderGUID[i]); + if (add && add->IsAlive()) + ++AliveChannelers; } - void CheckBanish() + // channelers == 0 remove banish aura + if (AliveChannelers == 0 && me->HasAura(AURA_BANISH)) { - uint8 AliveChannelers = 0; - for (uint8 i = 0; i < 3; ++i) - { - Unit* add = ObjectAccessor::GetUnit(*me, SpellBinderGUID[i]); - if (add && add->IsAlive()) - ++AliveChannelers; - } + // removing banish aura + me->RemoveAurasDueToSpell(AURA_BANISH); - // channelers == 0 remove banish aura - if (AliveChannelers == 0 && me->HasAura(AURA_BANISH)) - { - // removing banish aura - me->RemoveAurasDueToSpell(AURA_BANISH); + // Leotheras is getting immune again + me->ApplySpellImmune(AURA_BANISH, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); - // Leotheras is getting immune again - me->ApplySpellImmune(AURA_BANISH, IMMUNITY_MECHANIC, MECHANIC_BANISH, true); - - // changing model to bloodelf - me->SetDisplayId(MODEL_NIGHTELF); + // changing model to bloodelf + me->SetDisplayId(MODEL_NIGHTELF); - // and reseting equipment - me->LoadEquipment(); + // and reseting equipment + me->LoadEquipment(); - if (!instance->GetGuidData(DATA_LEOTHERAS_EVENT_STARTER).IsEmpty()) - { - if (Unit* victim = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_LEOTHERAS_EVENT_STARTER))) - AddThreat(victim, 1); - StartEvent(); - } - } - else if (AliveChannelers != 0 && !me->HasAura(AURA_BANISH)) + if (!instance->GetGuidData(DATA_LEOTHERAS_EVENT_STARTER).IsEmpty()) { - // channelers != 0 apply banish aura - // removing Leotheras banish immune to apply AURA_BANISH - me->ApplySpellImmune(AURA_BANISH, IMMUNITY_MECHANIC, MECHANIC_BANISH, false); - DoCast(me, AURA_BANISH); + if (Unit* victim = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_LEOTHERAS_EVENT_STARTER))) + AddThreat(victim, 1); + StartEvent(); + } + } + else if (AliveChannelers != 0 && !me->HasAura(AURA_BANISH)) + { + // channelers != 0 apply banish aura + // removing Leotheras banish immune to apply AURA_BANISH + me->ApplySpellImmune(AURA_BANISH, IMMUNITY_MECHANIC, MECHANIC_BANISH, false); + DoCast(me, AURA_BANISH); - // changing model - me->SetDisplayId(MODEL_DEMON); + // changing model + me->SetDisplayId(MODEL_DEMON); - // and removing weapons - me->SetVirtualItem(0, 0); - me->SetVirtualItem(1, 0); - } + // and removing weapons + me->SetVirtualItem(0, 0); + me->SetVirtualItem(1, 0); } + } - //Despawn all Inner Demon summoned - void DespawnDemon() + //Despawn all Inner Demon summoned + void DespawnDemon() + { + for (uint8 i=0; i<5; ++i) { - for (uint8 i = 0; i < 5; ++i) + if (!InnderDemon[i].IsEmpty()) { - if (!InnderDemon[i].IsEmpty()) - { - //delete creature - Creature* creature = ObjectAccessor::GetCreature((*me), InnderDemon[i]); - if (creature && creature->IsAlive()) - creature->DespawnOrUnsummon(); + //delete creature + Creature* creature = ObjectAccessor::GetCreature((*me), InnderDemon[i]); + if (creature && creature->IsAlive()) + creature->DespawnOrUnsummon(); - InnderDemon[i].Clear(); - } + InnderDemon[i].Clear(); } - - InnerDemon_Count = 0; } - void CastConsumingMadness() //remove this once SPELL_INSIDIOUS_WHISPER is supported by core + InnerDemon_Count = 0; + } + + void CastConsumingMadness() //remove this once SPELL_INSIDIOUS_WHISPER is supported by core + { + for (uint8 i = 0; i < 5; ++i) { - for (uint8 i = 0; i < 5; ++i) + if (!InnderDemon[i].IsEmpty()) { - if (!InnderDemon[i].IsEmpty()) + Creature* unit = ObjectAccessor::GetCreature((*me), InnderDemon[i]); + if (unit && unit->IsAlive()) { - Creature* unit = ObjectAccessor::GetCreature((*me), InnderDemon[i]); - if (unit && unit->IsAlive()) + Unit* unit_target = ObjectAccessor::GetUnit(*unit, unit->AI()->GetGUID(INNER_DEMON_VICTIM)); + if (unit_target && unit_target->IsAlive()) { - Unit* unit_target = ObjectAccessor::GetUnit(*unit, unit->AI()->GetGUID(INNER_DEMON_VICTIM)); - if (unit_target && unit_target->IsAlive()) - { - unit->CastSpell(unit_target, SPELL_CONSUMING_MADNESS, true); - ModifyThreatByPercent(unit_target, -100); - } + unit->CastSpell(unit_target, SPELL_CONSUMING_MADNESS, true); + ModifyThreatByPercent(unit_target, -100); } } } } + } - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() != TYPEID_PLAYER) - return; + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() != TYPEID_PLAYER) + return; - Talk(DemonForm ? SAY_DEMON_SLAY : SAY_NIGHTELF_SLAY); - } + Talk(DemonForm ? SAY_DEMON_SLAY : SAY_NIGHTELF_SLAY); + } + + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); - void JustDied(Unit* /*killer*/) override + //despawn copy + if (!Demon.IsEmpty()) { - Talk(SAY_DEATH); + if (Creature* pDemon = ObjectAccessor::GetCreature(*me, Demon)) + pDemon->DespawnOrUnsummon(); + } + _JustDied(); + } - //despawn copy - if (!Demon.IsEmpty()) - if (Creature* pDemon = ObjectAccessor::GetCreature(*me, Demon)) - pDemon->DespawnOrUnsummon(); + void JustEngagedWith(Unit* /*who*/) override + { + if (me->HasAura(AURA_BANISH)) + return; - instance->SetData(DATA_LEOTHERASTHEBLINDEVENT, DONE); - } + me->LoadEquipment(); + } - void JustEngagedWith(Unit* /*who*/) override + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (me->HasAura(AURA_BANISH) || !UpdateVictim()) { - if (me->HasAura(AURA_BANISH)) + if (BanishTimer <= diff) + { + CheckBanish();//no need to check every update tick + BanishTimer = 1000; + } else BanishTimer -= diff; return; - - me->LoadEquipment(); } - - void UpdateAI(uint32 diff) override + if (me->HasAura(SPELL_WHIRLWIND)) { - //Return since we have no target - if (me->HasAura(AURA_BANISH) || !UpdateVictim()) + if (Whirlwind_Timer <= diff) { - if (BanishTimer <= diff) + Unit* newTarget = SelectTarget(SelectTargetMethod::Random, 0); + if (newTarget) { - CheckBanish();//no need to check every update tick - BanishTimer = 1000; - } else BanishTimer -= diff; - return; - } - if (me->HasAura(SPELL_WHIRLWIND)) + ResetThreatList(); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MovePoint(0, newTarget->GetPositionX(), newTarget->GetPositionY(), newTarget->GetPositionZ()); + } + Whirlwind_Timer = 2000; + } else Whirlwind_Timer -= diff; + } + + // reseting after changing forms and after ending whirlwind + if (NeedThreatReset && !me->HasAura(SPELL_WHIRLWIND)) + { + // when changing forms seting timers (or when ending whirlwind - to avoid adding new variable i use Whirlwind_Timer to countdown 2s while whirlwinding) + if (DemonForm) + InnerDemons_Timer = 30000; + else + Whirlwind_Timer = 15000; + + NeedThreatReset = false; + ResetThreatList(); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveChase(me->GetVictim()); + } + + //Enrage_Timer (10 min) + if (Berserk_Timer < diff && !EnrageUsed) + { + me->InterruptNonMeleeSpells(false); + DoCast(me, SPELL_BERSERK); + EnrageUsed = true; + } else Berserk_Timer -= diff; + + if (!DemonForm) + { + //Whirldind Timer + if (!me->HasAura(SPELL_WHIRLWIND)) { if (Whirlwind_Timer <= diff) { - Unit* newTarget = SelectTarget(SelectTargetMethod::Random, 0); - if (newTarget) - { - ResetThreatList(); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MovePoint(0, newTarget->GetPositionX(), newTarget->GetPositionY(), newTarget->GetPositionZ()); - } + DoCast(me, SPELL_WHIRLWIND); + // while whirlwinding this variable is used to countdown target's change Whirlwind_Timer = 2000; + NeedThreatReset = true; } else Whirlwind_Timer -= diff; } + //Switch_Timer - // reseting after changing forms and after ending whirlwind - if (NeedThreatReset && !me->HasAura(SPELL_WHIRLWIND)) + if (!IsFinalForm) { - // when changing forms seting timers (or when ending whirlwind - to avoid adding new variable i use Whirlwind_Timer to countdown 2s while whirlwinding) - if (DemonForm) - InnerDemons_Timer = 30000; - else - Whirlwind_Timer = 15000; - - NeedThreatReset = false; - ResetThreatList(); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveChase(me->GetVictim()); + if (SwitchToDemon_Timer <= diff) + { + //switch to demon form + me->RemoveAurasDueToSpell(SPELL_WHIRLWIND); + me->SetDisplayId(MODEL_DEMON); + Talk(SAY_SWITCH_TO_DEMON); + me->SetVirtualItem(0, 0); + me->SetVirtualItem(1, 0); + DemonForm = true; + NeedThreatReset = true; + SwitchToDemon_Timer = 45000; + } else SwitchToDemon_Timer -= diff; } - - //Enrage_Timer (10 min) - if (Berserk_Timer < diff && !EnrageUsed) - { - me->InterruptNonMeleeSpells(false); - DoCast(me, SPELL_BERSERK); - EnrageUsed = true; - } else Berserk_Timer -= diff; - - if (!DemonForm) + DoMeleeAttackIfReady(); + } + else + { + //ChaosBlast_Timer + if (!me->GetVictim()) + return; + if (me->IsWithinDist(me->GetVictim(), 30)) + me->StopMoving(); + if (ChaosBlast_Timer <= diff) { - //Whirldind Timer - if (!me->HasAura(SPELL_WHIRLWIND)) - { - if (Whirlwind_Timer <= diff) - { - DoCast(me, SPELL_WHIRLWIND); - // while whirlwinding this variable is used to countdown target's change - Whirlwind_Timer = 2000; - NeedThreatReset = true; - } else Whirlwind_Timer -= diff; - } - //Switch_Timer - - if (!IsFinalForm) + // will cast only when in range of spell + if (me->IsWithinDist(me->GetVictim(), 30)) { - if (SwitchToDemon_Timer <= diff) - { - //switch to demon form - me->RemoveAurasDueToSpell(SPELL_WHIRLWIND); - me->SetDisplayId(MODEL_DEMON); - Talk(SAY_SWITCH_TO_DEMON); - me->SetVirtualItem(0, 0); - me->SetVirtualItem(1, 0); - DemonForm = true; - NeedThreatReset = true; - SwitchToDemon_Timer = 45000; - } else SwitchToDemon_Timer -= diff; + //DoCastVictim(SPELL_CHAOS_BLAST, true); + me->CastSpell(me->GetVictim(), SPELL_CHAOS_BLAST, CastSpellExtraArgs().SetOriginalCaster(me->GetGUID()).AddSpellBP0(100)); } - DoMeleeAttackIfReady(); - } - else + ChaosBlast_Timer = 3000; + } else ChaosBlast_Timer -= diff; + //Summon Inner Demon + if (InnerDemons_Timer <= diff) { - //ChaosBlast_Timer - if (!me->GetVictim()) - return; - if (me->IsWithinDist(me->GetVictim(), 30)) - me->StopMoving(); - if (ChaosBlast_Timer <= diff) + ThreatManager const& mgr = me->GetThreatManager(); + std::list<Unit*> TargetList; + Unit* currentVictim = mgr.GetLastVictim(); + for (ThreatReference const* ref : mgr.GetSortedThreatList()) { - // will cast only when in range of spell - if (me->IsWithinDist(me->GetVictim(), 30)) - { - //DoCastVictim(SPELL_CHAOS_BLAST, true); - me->CastSpell(me->GetVictim(), SPELL_CHAOS_BLAST, CastSpellExtraArgs().SetOriginalCaster(me->GetGUID()).AddSpellBP0(100)); - } - ChaosBlast_Timer = 3000; - } else ChaosBlast_Timer -= diff; - //Summon Inner Demon - if (InnerDemons_Timer <= diff) + if (Player* tempTarget = ref->GetVictim()->ToPlayer()) + if (tempTarget != currentVictim && TargetList.size()<5) + TargetList.push_back(tempTarget); + } + //SpellInfo* spell = GET_SPELL(SPELL_INSIDIOUS_WHISPER); + for (auto itr = TargetList.begin(), end = TargetList.end(); itr != end; ++itr) { - ThreatManager const& mgr = me->GetThreatManager(); - std::list<Unit*> TargetList; - Unit* currentVictim = mgr.GetLastVictim(); - for (ThreatReference const* ref : mgr.GetSortedThreatList()) + if ((*itr) && (*itr)->IsAlive()) { - if (Player* tempTarget = ref->GetVictim()->ToPlayer()) - if (tempTarget != currentVictim && TargetList.size()<5) - TargetList.push_back(tempTarget); - } - //SpellInfo* spell = GET_SPELL(SPELL_INSIDIOUS_WHISPER); - for (auto itr = TargetList.begin(), end = TargetList.end(); itr != end; ++itr) - { - if ((*itr) && (*itr)->IsAlive()) + Creature* demon = me->SummonCreature(INNER_DEMON_ID, (*itr)->GetPositionX()+10, (*itr)->GetPositionY()+10, (*itr)->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s); + if (demon) { - Creature* demon = me->SummonCreature(INNER_DEMON_ID, (*itr)->GetPositionX()+10, (*itr)->GetPositionY()+10, (*itr)->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s); - if (demon) - { - demon->AI()->AttackStart((*itr)); - demon->AI()->SetGUID((*itr)->GetGUID(), INNER_DEMON_VICTIM); + demon->AI()->AttackStart((*itr)); + demon->AI()->SetGUID((*itr)->GetGUID(), INNER_DEMON_VICTIM); - (*itr)->AddAura(SPELL_INSIDIOUS_WHISPER, *itr); + (*itr)->AddAura(SPELL_INSIDIOUS_WHISPER, *itr); - if (InnerDemon_Count > 4) - InnerDemon_Count = 0; + if (InnerDemon_Count > 4) + InnerDemon_Count = 0; - //Safe storing of creatures - InnderDemon[InnerDemon_Count] = demon->GetGUID(); + //Safe storing of creatures + InnderDemon[InnerDemon_Count] = demon->GetGUID(); - //Update demon count - ++InnerDemon_Count; - } + //Update demon count + ++InnerDemon_Count; } } - Talk(SAY_INNER_DEMONS); - - InnerDemons_Timer = 999999; - } else InnerDemons_Timer -= diff; - - //Switch_Timer - if (SwitchToHuman_Timer <= diff) - { - //switch to nightelf form - me->SetDisplayId(MODEL_NIGHTELF); - me->LoadEquipment(); - - CastConsumingMadness(); - DespawnDemon(); - - DemonForm = false; - NeedThreatReset = true; + } + Talk(SAY_INNER_DEMONS); - SwitchToHuman_Timer = 60000; - } else SwitchToHuman_Timer -= diff; - } + InnerDemons_Timer = 999999; + } else InnerDemons_Timer -= diff; - if (!IsFinalForm && HealthBelowPct(15)) + //Switch_Timer + if (SwitchToHuman_Timer <= diff) { - //at this point he divides himself in two parts + //switch to nightelf form + me->SetDisplayId(MODEL_NIGHTELF); + me->LoadEquipment(); + CastConsumingMadness(); DespawnDemon(); - if (Creature* Copy = DoSpawnCreature(DEMON_FORM, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 6s)) - { - Demon = Copy->GetGUID(); - if (me->GetVictim()) - Copy->AI()->AttackStart(me->GetVictim()); - } - //set nightelf final form - IsFinalForm = true; + DemonForm = false; + NeedThreatReset = true; - Talk(SAY_FINAL_FORM); - me->SetDisplayId(MODEL_NIGHTELF); - me->LoadEquipment(); + SwitchToHuman_Timer = 60000; + } else SwitchToHuman_Timer -= diff; + } + + if (!IsFinalForm && HealthBelowPct(15)) + { + //at this point he divides himself in two parts + CastConsumingMadness(); + DespawnDemon(); + if (Creature* Copy = DoSpawnCreature(DEMON_FORM, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 6s)) + { + Demon = Copy->GetGUID(); + if (me->GetVictim()) + Copy->AI()->AttackStart(me->GetVictim()); } + //set nightelf final form + IsFinalForm = true; + DemonForm = false; + + Talk(SAY_FINAL_FORM); + me->SetDisplayId(MODEL_NIGHTELF); + me->LoadEquipment(); } - }; + } }; //Leotheras the Blind Demon Form AI -class boss_leotheras_the_blind_demonform : public CreatureScript +struct boss_leotheras_the_blind_demonform : public ScriptedAI { -public: - boss_leotheras_the_blind_demonform() : CreatureScript("boss_leotheras_the_blind_demonform") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_leotheras_the_blind_demonform(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<boss_leotheras_the_blind_demonformAI>(creature); + Initialize(); } - struct boss_leotheras_the_blind_demonformAI : public ScriptedAI + void Initialize() { - boss_leotheras_the_blind_demonformAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - } + ChaosBlast_Timer = 1000; + DealDamage = true; + } - void Initialize() - { - ChaosBlast_Timer = 1000; - DealDamage = true; - } + uint32 ChaosBlast_Timer; + bool DealDamage; - uint32 ChaosBlast_Timer; - bool DealDamage; + void Reset() override + { + Initialize(); + } - void Reset() override - { - Initialize(); - } + void StartEvent() + { + Talk(SAY_FREE); + } - void StartEvent() - { - Talk(SAY_FREE); - } + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() != TYPEID_PLAYER) + return; - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() != TYPEID_PLAYER) - return; + Talk(SAY_DEMON_SLAY); + } - Talk(SAY_DEMON_SLAY); - } + void JustDied(Unit* /*killer*/) override + { + //invisibility (blizzlike, at the end of the fight he doesn't die, he disappears) + DoCast(me, 8149, true); + } - void JustDied(Unit* /*killer*/) override - { - //invisibility (blizzlike, at the end of the fight he doesn't die, he disappears) - DoCast(me, 8149, true); - } + void JustEngagedWith(Unit* /*who*/) override + { + StartEvent(); + } - void JustEngagedWith(Unit* /*who*/) override - { - StartEvent(); - } + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; + //ChaosBlast_Timer + if (me->IsWithinDist(me->GetVictim(), 30)) + me->StopMoving(); - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) - return; - //ChaosBlast_Timer + if (ChaosBlast_Timer <= diff) + { + // will cast only when in range od spell if (me->IsWithinDist(me->GetVictim(), 30)) - me->StopMoving(); - - if (ChaosBlast_Timer <= diff) - { - // will cast only when in range od spell - if (me->IsWithinDist(me->GetVictim(), 30)) - { - //DoCastVictim(SPELL_CHAOS_BLAST, true); - me->CastSpell(me->GetVictim(), SPELL_CHAOS_BLAST, CastSpellExtraArgs().SetOriginalCaster(me->GetGUID()).AddSpellBP0(100)); - ChaosBlast_Timer = 3000; - } - } else ChaosBlast_Timer -= diff; + { + //DoCastVictim(SPELL_CHAOS_BLAST, true); + me->CastSpell(me->GetVictim(), SPELL_CHAOS_BLAST, CastSpellExtraArgs().SetOriginalCaster(me->GetGUID()).AddSpellBP0(100)); + ChaosBlast_Timer = 3000; + } + } else ChaosBlast_Timer -= diff; - //Do NOT deal any melee damage to the target. - } - }; + //Do NOT deal any melee damage to the target. + } }; -class npc_greyheart_spellbinder : public CreatureScript +struct npc_greyheart_spellbinder : public ScriptedAI { -public: - npc_greyheart_spellbinder() : CreatureScript("npc_greyheart_spellbinder") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_greyheart_spellbinder(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<npc_greyheart_spellbinderAI>(creature); + Initialize(); + instance = creature->GetInstanceScript(); + AddedBanish = false; } - struct npc_greyheart_spellbinderAI : public ScriptedAI + void Initialize() { - npc_greyheart_spellbinderAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - AddedBanish = false; - } + Mindblast_Timer = urand(3000, 8000); + Earthshock_Timer = urand(5000, 10000); + } - void Initialize() - { - Mindblast_Timer = urand(3000, 8000); - Earthshock_Timer = urand(5000, 10000); - } + InstanceScript* instance; + + ObjectGuid leotherasGUID; - InstanceScript* instance; + uint32 Mindblast_Timer; + uint32 Earthshock_Timer; - ObjectGuid leotherasGUID; + bool AddedBanish; - uint32 Mindblast_Timer; - uint32 Earthshock_Timer; + void Reset() override + { + Initialize(); - bool AddedBanish; + instance->SetGuidData(DATA_LEOTHERAS_EVENT_STARTER, ObjectGuid::Empty); + Creature* leotheras = ObjectAccessor::GetCreature(*me, leotherasGUID); + if (leotheras && leotheras->IsAlive()) + ENSURE_AI(boss_leotheras_the_blind, leotheras->AI())->CheckChannelers(/*false*/); + } - void Reset() override - { - Initialize(); + void JustEngagedWith(Unit* who) override + { + me->InterruptNonMeleeSpells(false); + instance->SetGuidData(DATA_LEOTHERAS_EVENT_STARTER, who->GetGUID()); + } - instance->SetGuidData(DATA_LEOTHERAS_EVENT_STARTER, ObjectGuid::Empty); - Creature* leotheras = ObjectAccessor::GetCreature(*me, leotherasGUID); - if (leotheras && leotheras->IsAlive()) - ENSURE_AI(boss_leotheras_the_blind::boss_leotheras_the_blindAI, leotheras->AI())->CheckChannelers(/*false*/); - } + void JustAppeared() override + { + AddedBanish = false; + Reset(); + } - void JustEngagedWith(Unit* who) override + void CastChanneling() + { + if (!me->IsInCombat() && !me->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) { - me->InterruptNonMeleeSpells(false); - instance->SetGuidData(DATA_LEOTHERAS_EVENT_STARTER, who->GetGUID()); + if (!leotherasGUID.IsEmpty()) + { + Creature* leotheras = ObjectAccessor::GetCreature(*me, leotherasGUID); + if (leotheras && leotheras->IsAlive()) + DoCast(leotheras, BANISH_BEAM); + } } + } + + void UpdateAI(uint32 diff) override + { + if (!leotherasGUID) + leotherasGUID = instance->GetGuidData(DATA_LEOTHERAS); - void JustAppeared() override + if (!me->IsInCombat() && !instance->GetGuidData(DATA_LEOTHERAS_EVENT_STARTER).IsEmpty()) { - AddedBanish = false; - Reset(); + if (Unit* victim = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_LEOTHERAS_EVENT_STARTER))) + AttackStart(victim); } - void CastChanneling() + if (!UpdateVictim()) { - if (!me->IsInCombat() && !me->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - { - if (!leotherasGUID.IsEmpty()) - { - Creature* leotheras = ObjectAccessor::GetCreature(*me, leotherasGUID); - if (leotheras && leotheras->IsAlive()) - DoCast(leotheras, BANISH_BEAM); - } - } + CastChanneling(); + return; } - void UpdateAI(uint32 diff) override + if (!instance->GetGuidData(DATA_LEOTHERAS_EVENT_STARTER)) { - if (!leotherasGUID) - leotherasGUID = instance->GetGuidData(DATA_LEOTHERAS); - - if (!me->IsInCombat() && !instance->GetGuidData(DATA_LEOTHERAS_EVENT_STARTER).IsEmpty()) - { - if (Unit* victim = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_LEOTHERAS_EVENT_STARTER))) - AttackStart(victim); - } - - if (!UpdateVictim()) - { - CastChanneling(); - return; - } - - if (!instance->GetGuidData(DATA_LEOTHERAS_EVENT_STARTER)) - { - EnterEvadeMode(); - return; - } + EnterEvadeMode(); + return; + } - if (Mindblast_Timer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - DoCast(target, SPELL_MINDBLAST); + if (Mindblast_Timer <= diff) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + DoCast(target, SPELL_MINDBLAST); - Mindblast_Timer = urand(10000, 15000); - } else Mindblast_Timer -= diff; + Mindblast_Timer = urand(10000, 15000); + } else Mindblast_Timer -= diff; - if (Earthshock_Timer <= diff) + if (Earthshock_Timer <= diff) + { + Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); + for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) { - Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); - for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) + if (Player* i_pl = itr->GetSource()) { - if (Player* i_pl = itr->GetSource()) - { - bool isCasting = false; - for (uint8 i = 0; i < CURRENT_MAX_SPELL; ++i) - if (i_pl->GetCurrentSpell(i)) - isCasting = true; + bool isCasting = false; + for (uint8 i = 0; i < CURRENT_MAX_SPELL; ++i) + if (i_pl->GetCurrentSpell(i)) + isCasting = true; - if (isCasting) - { - DoCast(i_pl, SPELL_EARTHSHOCK); - break; - } + if (isCasting) + { + DoCast(i_pl, SPELL_EARTHSHOCK); + break; } } - Earthshock_Timer = urand(8000, 15000); - } else Earthshock_Timer -= diff; - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override { } - }; + } + Earthshock_Timer = urand(8000, 15000); + } else Earthshock_Timer -= diff; + DoMeleeAttackIfReady(); + } }; void AddSC_boss_leotheras_the_blind() { - new boss_leotheras_the_blind(); - new boss_leotheras_the_blind_demonform(); - new npc_greyheart_spellbinder(); - new npc_inner_demon(); + RegisterSerpentshrineCavernCreatureAI(boss_leotheras_the_blind); + RegisterSerpentshrineCavernCreatureAI(boss_leotheras_the_blind_demonform); + RegisterSerpentshrineCavernCreatureAI(npc_greyheart_spellbinder); + RegisterSerpentshrineCavernCreatureAI(npc_inner_demon); } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp index 5afdb989f40..a3e16887b68 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp @@ -79,408 +79,360 @@ float AddPos[9][3] = {42.471519f, -445.115295f, -19.769423f} }; -class boss_the_lurker_below : public CreatureScript +struct boss_the_lurker_below : public BossAI { -public: - boss_the_lurker_below() : CreatureScript("boss_the_lurker_below") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_the_lurker_below(Creature* creature) : BossAI(creature, BOSS_THE_LURKER_BELOW) { - return GetSerpentshrineCavernAI<boss_the_lurker_belowAI>(creature); + Initialize(); + SetCombatMovement(false); } - struct boss_the_lurker_belowAI : public ScriptedAI + void Initialize() { - boss_the_lurker_belowAI(Creature* creature) : ScriptedAI(creature), Summons(me) - { - Initialize(); - SetCombatMovement(false); - instance = creature->GetInstanceScript(); - } + SpoutAnimTimer = 1000; + RotTimer = 0; + WaterboltTimer = 15000; // give time to get in range when fight starts + SpoutTimer = 45000; + WhirlTimer = 18000; // after avery spout + PhaseTimer = 120000; + GeyserTimer = rand32() % 5000 + 15000; + CheckTimer = 15000; // give time to get in range when fight starts + WaitTimer = 60000; // never reached + WaitTimer2 = 60000; // never reached + + Submerged = true; // will be false at combat start + Spawned = false; + InRange = false; + CanStartEvent = false; + } - void Initialize() - { - SpoutAnimTimer = 1000; - RotTimer = 0; - WaterboltTimer = 15000; // give time to get in range when fight starts - SpoutTimer = 45000; - WhirlTimer = 18000; // after avery spout - PhaseTimer = 120000; - GeyserTimer = rand32() % 5000 + 15000; - CheckTimer = 15000; // give time to get in range when fight starts - WaitTimer = 60000; // never reached - WaitTimer2 = 60000; // never reached - - Submerged = true; // will be false at combat start - Spawned = false; - InRange = false; - CanStartEvent = false; - } + bool Spawned; + bool Submerged; + bool InRange; + bool CanStartEvent; + uint32 RotTimer; + uint32 SpoutAnimTimer; + uint32 WaterboltTimer; + uint32 SpoutTimer; + uint32 WhirlTimer; + uint32 PhaseTimer; + uint32 GeyserTimer; + uint32 CheckTimer; + uint32 WaitTimer; + uint32 WaitTimer2; + + bool CheckCanStart()//check if players fished + { + if (instance->GetData(DATA_STRANGE_POOL) == NOT_STARTED) + return false; + return true; + } - InstanceScript* instance; - SummonList Summons; - - bool Spawned; - bool Submerged; - bool InRange; - bool CanStartEvent; - uint32 RotTimer; - uint32 SpoutAnimTimer; - uint32 WaterboltTimer; - uint32 SpoutTimer; - uint32 WhirlTimer; - uint32 PhaseTimer; - uint32 GeyserTimer; - uint32 CheckTimer; - uint32 WaitTimer; - uint32 WaitTimer2; - - bool CheckCanStart()//check if players fished - { - if (instance->GetData(DATA_STRANGE_POOL) == NOT_STARTED) - return false; - return true; - } + void Reset() override + { + me->SetSwim(true); + me->SetDisableGravity(true); + Initialize(); + + _Reset(); + instance->SetData(DATA_STRANGE_POOL, NOT_STARTED); + DoCast(me, SPELL_SUBMERGE); // submerge anim + me->SetVisible(false); // we start invis under water, submerged + me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE); + me->SetImmuneToPC(true); + } - void Reset() override - { - me->SetSwim(true); - me->SetDisableGravity(true); - Initialize(); - - Summons.DespawnAll(); - - instance->SetData(DATA_THELURKERBELOWEVENT, NOT_STARTED); - instance->SetData(DATA_STRANGE_POOL, NOT_STARTED); - DoCast(me, SPELL_SUBMERGE); // submerge anim - me->SetVisible(false); // we start invis under water, submerged - me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE); - me->SetImmuneToPC(true); - } + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + instance->SetData(DATA_STRANGE_POOL, IN_PROGRESS); + } - void JustDied(Unit* /*killer*/) override + void MoveInLineOfSight(Unit* who) override + { + if (!CanStartEvent) // boss is invisible, don't attack + return; + if (!me->GetVictim() && who->IsValidAttackTarget(me)) { - instance->SetData(DATA_THELURKERBELOWEVENT, DONE); - instance->SetData(DATA_STRANGE_POOL, IN_PROGRESS); - - Summons.DespawnAll(); + float attackRadius = me->GetAttackDistance(who); + if (me->IsWithinDistInMap(who, attackRadius)) + AttackStart(who); } + } - void JustEngagedWith(Unit* /*who*/) override - { - instance->SetData(DATA_THELURKERBELOWEVENT, IN_PROGRESS); - } + void MovementInform(uint32 type, uint32 /*id*/) override + { + if (type == ROTATE_MOTION_TYPE) + me->SetReactState(REACT_AGGRESSIVE); + } - void MoveInLineOfSight(Unit* who) override + void UpdateAI(uint32 diff) override + { + if (!CanStartEvent) // boss is invisible, don't attack { - if (!CanStartEvent) // boss is invisible, don't attack - return; - if (!me->GetVictim() && who->IsValidAttackTarget(me)) + if (CheckCanStart()) { - float attackRadius = me->GetAttackDistance(who); - if (me->IsWithinDistInMap(who, attackRadius)) - AttackStart(who); + if (Submerged) + { + me->SetVisible(true); + Submerged = false; + WaitTimer2 = 500; + } + else if (WaitTimer2 <= diff) // wait 500ms before emerge anim + { + me->RemoveAllAuras(); + me->SetEmoteState(EMOTE_ONESHOT_NONE); + DoCast(me, SPELL_EMERGE, false); + WaitTimer2 = 60000; // never reached + WaitTimer = 3000; + } + else + WaitTimer2 -= diff; + + if (WaitTimer <= diff) // wait 3secs for emerge anim, then attack + { + WaitTimer = 3000; + CanStartEvent = true; // fresh fished from pool + me->SetImmuneToPC(false); + me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE); + } + else + WaitTimer -= diff; } + return; } - void MovementInform(uint32 type, uint32 /*id*/) override + if (!me->IsThreatened()) // check if should evade { - if (type == ROTATE_MOTION_TYPE) - me->SetReactState(REACT_AGGRESSIVE); + if (me->IsEngaged()) + EnterEvadeMode(); + return; } - - void UpdateAI(uint32 diff) override + if (!Submerged) { - if (!CanStartEvent) // boss is invisible, don't attack + if (PhaseTimer <= diff) { - if (CheckCanStart()) - { - if (Submerged) - { - me->SetVisible(true); - Submerged = false; - WaitTimer2 = 500; - } - else if (WaitTimer2 <= diff) // wait 500ms before emerge anim - { - me->RemoveAllAuras(); - me->SetEmoteState(EMOTE_ONESHOT_NONE); - DoCast(me, SPELL_EMERGE, false); - WaitTimer2 = 60000; // never reached - WaitTimer = 3000; - } - else - WaitTimer2 -= diff; + me->InterruptNonMeleeSpells(false); + DoCast(me, SPELL_SUBMERGE); + PhaseTimer = 60000; // 60secs submerged + Submerged = true; + } + else + PhaseTimer -= diff; - if (WaitTimer <= diff) // wait 3secs for emerge anim, then attack - { - WaitTimer = 3000; - CanStartEvent = true; // fresh fished from pool - me->SetImmuneToPC(false); - me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE); - } - else - WaitTimer -= diff; - } + if (SpoutTimer <= diff) + { + Talk(EMOTE_SPOUT); + me->SetReactState(REACT_PASSIVE); + me->GetMotionMaster()->MoveRotate(0, 20000, urand(0, 1) ? ROTATE_DIRECTION_LEFT : ROTATE_DIRECTION_RIGHT); + SpoutTimer = 45000; + WhirlTimer = 20000; // whirl directly after spout + RotTimer = 20000; return; } + else + SpoutTimer -= diff; - if (!me->IsThreatened()) // check if should evade + // Whirl directly after a Spout and at random times + if (WhirlTimer <= diff) { - if (me->IsEngaged()) - EnterEvadeMode(); - return; + WhirlTimer = 18000; + DoCast(me, SPELL_WHIRL); } - if (!Submerged) + else + WhirlTimer -= diff; + + if (CheckTimer <= diff) // check if there are players in melee range { - if (PhaseTimer <= diff) + InRange = false; + Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); + if (!PlayerList.isEmpty()) { - me->InterruptNonMeleeSpells(false); - DoCast(me, SPELL_SUBMERGE); - PhaseTimer = 60000; // 60secs submerged - Submerged = true; + for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + { + if (me->IsWithinMeleeRange(i->GetSource())) + InRange = true; + } } - else - PhaseTimer -= diff; + CheckTimer = 2000; + } + else + CheckTimer -= diff; - if (SpoutTimer <= diff) + if (RotTimer) + { + instance->instance->DoOnPlayers([&](Player* player) { - Talk(EMOTE_SPOUT); - me->SetReactState(REACT_PASSIVE); - me->GetMotionMaster()->MoveRotate(0, 20000, urand(0, 1) ? ROTATE_DIRECTION_LEFT : ROTATE_DIRECTION_RIGHT); - SpoutTimer = 45000; - WhirlTimer = 20000; // whirl directly after spout - RotTimer = 20000; - return; - } - else - SpoutTimer -= diff; + if (player->IsAlive() && me->HasInArc(diff/20000.f*float(M_PI)*2.f, player) && me->IsWithinDist(player, SPOUT_DIST) && !player->IsInWater()) + DoCast(player, SPELL_SPOUT, true); // only knock back players in arc, in 100yards, not in water + }); - // Whirl directly after a Spout and at random times - if (WhirlTimer <= diff) + if (SpoutAnimTimer <= diff) { - WhirlTimer = 18000; - DoCast(me, SPELL_WHIRL); - } - else - WhirlTimer -= diff; + DoCast(me, SPELL_SPOUT_ANIM, true); + SpoutAnimTimer = 1000; + } else SpoutAnimTimer -= diff; - if (CheckTimer <= diff) // check if there are players in melee range + if (RotTimer <= diff) { - InRange = false; - Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers(); - if (!PlayerList.isEmpty()) - { - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - if (me->IsWithinMeleeRange(i->GetSource())) - InRange = true; - } - } - CheckTimer = 2000; + RotTimer = 0; } else - CheckTimer -= diff; - - if (RotTimer) - { - instance->instance->DoOnPlayers([this, diff](Player* player) - { - if (player->IsAlive() && me->HasInArc(diff / 20000.f * float(M_PI) * 2.f, player) && me->IsWithinDist(player, SPOUT_DIST) && !player->IsInWater()) - DoCast(player, SPELL_SPOUT, true); // only knock back players in arc, in 100yards, not in water - }); - - if (SpoutAnimTimer <= diff) - { - DoCast(me, SPELL_SPOUT_ANIM, true); - SpoutAnimTimer = 1000; - } else SpoutAnimTimer -= diff; + RotTimer -= diff; + return; + } - if (RotTimer <= diff) - { - RotTimer = 0; - } - else - RotTimer -= diff; - return; - } + if (GeyserTimer <= diff) + { + Unit* target = SelectTarget(SelectTargetMethod::Random, 1); + if (!target && me->GetVictim()) + target = me->GetVictim(); + if (target) + DoCast(target, SPELL_GEYSER, true); + GeyserTimer = rand32() % 5000 + 15000; + } + else + GeyserTimer -= diff; - if (GeyserTimer <= diff) + if (!InRange) // if on players in melee range cast Waterbolt + { + if (WaterboltTimer <= diff) { - Unit* target = SelectTarget(SelectTargetMethod::Random, 1); + Unit* target = SelectTarget(SelectTargetMethod::Random, 0); if (!target && me->GetVictim()) target = me->GetVictim(); if (target) - DoCast(target, SPELL_GEYSER, true); - GeyserTimer = rand32() % 5000 + 15000; + DoCast(target, SPELL_WATERBOLT, true); + WaterboltTimer = 3000; } else - GeyserTimer -= diff; - - if (!InRange) // if on players in melee range cast Waterbolt - { - if (WaterboltTimer <= diff) - { - Unit* target = SelectTarget(SelectTargetMethod::Random, 0); - if (!target && me->GetVictim()) - target = me->GetVictim(); - if (target) - DoCast(target, SPELL_WATERBOLT, true); - WaterboltTimer = 3000; - } - else - WaterboltTimer -= diff; - } + WaterboltTimer -= diff; + } - if (!UpdateVictim()) - return; + if (!UpdateVictim()) + return; - DoMeleeAttackIfReady(); + DoMeleeAttackIfReady(); - } - else // submerged + } + else // submerged + { + if (PhaseTimer <= diff) { - if (PhaseTimer <= diff) - { - Submerged = false; - me->InterruptNonMeleeSpells(false); // shouldn't be any - me->RemoveAllAuras(); - me->SetImmuneToPC(false); - me->SetEmoteState(EMOTE_ONESHOT_NONE); - DoCast(me, SPELL_EMERGE, true); - Spawned = false; - SpoutTimer = 3000; // directly cast Spout after emerging! - PhaseTimer = 120000; - return; - } - else - PhaseTimer -= diff; + Submerged = false; + me->InterruptNonMeleeSpells(false); // shouldn't be any + me->RemoveAllAuras(); + me->SetImmuneToPC(false); + me->SetEmoteState(EMOTE_ONESHOT_NONE); + DoCast(me, SPELL_EMERGE, true); + Spawned = false; + SpoutTimer = 3000; // directly cast Spout after emerging! + PhaseTimer = 120000; + return; + } + else + PhaseTimer -= diff; - if (!me->IsThreatened()) // check if should evade - { - EnterEvadeMode(); - return; - } + if (!me->IsThreatened()) // check if should evade + { + EnterEvadeMode(); + return; + } - if (!me->IsInCombat()) - DoZoneInCombat(); + if (!me->IsInCombat()) + DoZoneInCombat(); - if (!Spawned) - { - me->ReplaceAllUnitFlags(UNIT_FLAG_IMMUNE_TO_PC); - // spawn adds - for (uint8 i = 0; i < 9; ++i) - if (Creature* summoned = me->SummonCreature(i < 6 ? NPC_COILFANG_AMBUSHER : NPC_COILFANG_GUARDIAN, AddPos[i][0], AddPos[i][1], AddPos[i][2], 0, TEMPSUMMON_CORPSE_DESPAWN)) - Summons.Summon(summoned); - Spawned = true; - } + if (!Spawned) + { + me->ReplaceAllUnitFlags(UNIT_FLAG_IMMUNE_TO_PC); + // spawn adds + for (uint8 i = 0; i < 9; ++i) + me->SummonCreature(i < 6 ? NPC_COILFANG_AMBUSHER : NPC_COILFANG_GUARDIAN, AddPos[i][0], AddPos[i][1], AddPos[i][2], 0, TEMPSUMMON_CORPSE_DESPAWN); + Spawned = true; } } - }; -}; + } + }; -class npc_coilfang_ambusher : public CreatureScript +struct npc_coilfang_ambusher : public ScriptedAI { -public: - npc_coilfang_ambusher() : CreatureScript("npc_coilfang_ambusher") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_coilfang_ambusher(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<npc_coilfang_ambusherAI>(creature); + Initialize(); + SetCombatMovement(false); } - struct npc_coilfang_ambusherAI : public ScriptedAI + void Initialize() { - npc_coilfang_ambusherAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - SetCombatMovement(false); - } - - void Initialize() - { - MultiShotTimer = 10000; - ShootBowTimer = 4000; - } + MultiShotTimer = 10000; + ShootBowTimer = 4000; + } - uint32 MultiShotTimer; - uint32 ShootBowTimer; + uint32 MultiShotTimer; + uint32 ShootBowTimer; - void Reset() override - { - Initialize(); - } + void Reset() override + { + Initialize(); + } - void MoveInLineOfSight(Unit* who) override + void MoveInLineOfSight(Unit* who) override - { - if (!who || me->GetVictim()) - return; + { + if (!who || me->GetVictim()) + return; - if (who->isInAccessiblePlaceFor(me) && me->IsValidAttackTarget(who) && me->IsWithinDistInMap(who, 45)) - AttackStart(who); - } + if (who->isInAccessiblePlaceFor(me) && me->IsValidAttackTarget(who) && me->IsWithinDistInMap(who, 45)) + AttackStart(who); + } - void UpdateAI(uint32 diff) override + void UpdateAI(uint32 diff) override + { + if (MultiShotTimer <= diff) { - if (MultiShotTimer <= diff) - { - if (me->GetVictim()) - DoCastVictim(SPELL_SPREAD_SHOT, true); + if (me->GetVictim()) + DoCastVictim(SPELL_SPREAD_SHOT, true); - MultiShotTimer = 10000 + rand32() % 10000; - ShootBowTimer += 1500; // add global cooldown - } else MultiShotTimer -= diff; - - if (ShootBowTimer <= diff) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_SHOOT, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(1100)); - ShootBowTimer = 4000 + rand32() % 5000; - MultiShotTimer += 1500; // add global cooldown - } else ShootBowTimer -= diff; - } - }; + MultiShotTimer = 10000 + rand32() % 10000; + ShootBowTimer += 1500; // add global cooldown + } else MultiShotTimer -= diff; + if (ShootBowTimer <= diff) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + me->CastSpell(target, SPELL_SHOOT, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellBP0(1100)); + ShootBowTimer = 4000 + rand32() % 5000; + MultiShotTimer += 1500; // add global cooldown + } else ShootBowTimer -= diff; + } }; -class go_strange_pool : public GameObjectScript +struct go_strange_pool : public GameObjectAI { - public: - go_strange_pool() : GameObjectScript("go_strange_pool") { } - - struct go_strange_poolAI : public GameObjectAI - { - go_strange_poolAI(GameObject* go) : GameObjectAI(go), instance(go->GetInstanceScript()) { } + go_strange_pool(GameObject* go) : GameObjectAI(go), instance(go->GetInstanceScript()) { } - InstanceScript* instance; + InstanceScript* instance; - bool OnGossipHello(Player* player) override + bool OnGossipHello(Player* player) override + { + // 25% + if (!urand(0, 3)) + { + if (instance->GetData(DATA_STRANGE_POOL) == NOT_STARTED) { - // 25% - if (!urand(0, 3)) - { - if (instance->GetData(DATA_STRANGE_POOL) == NOT_STARTED) - { - me->CastSpell(player, 54587); - instance->SetData(DATA_STRANGE_POOL, IN_PROGRESS); - } - return true; - } - - return false; + me->CastSpell(player, 54587); + instance->SetData(DATA_STRANGE_POOL, IN_PROGRESS); } - }; - - GameObjectAI* GetAI(GameObject* go) const override - { - return GetSerpentshrineCavernAI<go_strange_poolAI>(go); + return true; } + + return false; + } }; void AddSC_boss_the_lurker_below() { - new boss_the_lurker_below(); - new npc_coilfang_ambusher(); - new go_strange_pool(); + RegisterSerpentshrineCavernCreatureAI(boss_the_lurker_below); + RegisterSerpentshrineCavernCreatureAI(npc_coilfang_ambusher); + RegisterSerpentshrineCavernGameObjectAI(go_strange_pool); } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp index a752c81adaa..f3273232950 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp @@ -86,286 +86,253 @@ float MurlocCords[10][4] = }; //Morogrim Tidewalker AI -class boss_morogrim_tidewalker : public CreatureScript +struct boss_morogrim_tidewalker : public BossAI { -public: - boss_morogrim_tidewalker() : CreatureScript("boss_morogrim_tidewalker") { } - - CreatureAI* GetAI(Creature* creature) const override + boss_morogrim_tidewalker(Creature* creature) : BossAI(creature, BOSS_MOROGRIM_TIDEWALKER) { - return GetSerpentshrineCavernAI<boss_morogrim_tidewalkerAI>(creature); + Initialize(); + Playercount = 0; + counter = 0; } - struct boss_morogrim_tidewalkerAI : public ScriptedAI + void Initialize() { - boss_morogrim_tidewalkerAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - instance = creature->GetInstanceScript(); - Playercount = 0; - counter = 0; - } + TidalWave_Timer = 10000; + WateryGrave_Timer = 30000; + Earthquake_Timer = 40000; + WateryGlobules_Timer = 0; + globulespell[0] = SPELL_SUMMON_WATER_GLOBULE_1; + globulespell[1] = SPELL_SUMMON_WATER_GLOBULE_2; + globulespell[2] = SPELL_SUMMON_WATER_GLOBULE_3; + globulespell[3] = SPELL_SUMMON_WATER_GLOBULE_4; + + Earthquake = false; + Phase2 = false; + } - void Initialize() - { - TidalWave_Timer = 10000; - WateryGrave_Timer = 30000; - Earthquake_Timer = 40000; - WateryGlobules_Timer = 0; - globulespell[0] = SPELL_SUMMON_WATER_GLOBULE_1; - globulespell[1] = SPELL_SUMMON_WATER_GLOBULE_2; - globulespell[2] = SPELL_SUMMON_WATER_GLOBULE_3; - globulespell[3] = SPELL_SUMMON_WATER_GLOBULE_4; - - Earthquake = false; - Phase2 = false; - } + uint32 TidalWave_Timer; + uint32 WateryGrave_Timer; + uint32 Earthquake_Timer; + uint32 WateryGlobules_Timer; + uint32 globulespell[4]; + int8 Playercount; + int8 counter; - InstanceScript* instance; + bool Earthquake; + bool Phase2; - uint32 TidalWave_Timer; - uint32 WateryGrave_Timer; - uint32 Earthquake_Timer; - uint32 WateryGlobules_Timer; - uint32 globulespell[4]; - int8 Playercount; - int8 counter; + void Reset() override + { + Initialize(); - bool Earthquake; - bool Phase2; + _Reset(); + } - void Reset() override - { - Initialize(); + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_SLAY); + } - instance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, NOT_STARTED); - } + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEATH); - void StartEvent() - { - Talk(SAY_AGGRO); + _JustDied(); + } - instance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, IN_PROGRESS); - } + void JustEngagedWith(Unit* who) override + { + Playercount = me->GetMap()->GetPlayers().getSize(); + Talk(SAY_AGGRO); + _JustEngagedWith(who); + } - void KilledUnit(Unit* /*victim*/) override + void ApplyWateryGrave(Unit* player, uint8 i) + { + switch (i) { - Talk(SAY_SLAY); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - - instance->SetData(DATA_MOROGRIMTIDEWALKEREVENT, DONE); + case 0: player->CastSpell(player, SPELL_WATERY_GRAVE_1, true); break; + case 1: player->CastSpell(player, SPELL_WATERY_GRAVE_2, true); break; + case 2: player->CastSpell(player, SPELL_WATERY_GRAVE_3, true); break; + case 3: player->CastSpell(player, SPELL_WATERY_GRAVE_4, true); break; } + } - void JustEngagedWith(Unit* /*who*/) override - { - Playercount = me->GetMap()->GetPlayers().getSize(); - StartEvent(); - } + void UpdateAI(uint32 diff) override + { + //Return since we have no target + if (!UpdateVictim()) + return; - void ApplyWateryGrave(Unit* player, uint8 i) + //Earthquake_Timer + if (Earthquake_Timer <= diff) { - switch (i) + if (!Earthquake) { - case 0: player->CastSpell(player, SPELL_WATERY_GRAVE_1, true); break; - case 1: player->CastSpell(player, SPELL_WATERY_GRAVE_2, true); break; - case 2: player->CastSpell(player, SPELL_WATERY_GRAVE_3, true); break; - case 3: player->CastSpell(player, SPELL_WATERY_GRAVE_4, true); break; + DoCastVictim(SPELL_EARTHQUAKE); + Earthquake = true; + Earthquake_Timer = 10000; } - } - - void UpdateAI(uint32 diff) override - { - //Return since we have no target - if (!UpdateVictim()) - return; - - //Earthquake_Timer - if (Earthquake_Timer <= diff) + else { - if (!Earthquake) - { - DoCastVictim(SPELL_EARTHQUAKE); - Earthquake = true; - Earthquake_Timer = 10000; - } - else - { - Talk(SAY_SUMMON); + Talk(SAY_SUMMON); - for (uint8 i = 0; i < 10; ++i) - { - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - if (Creature* Murloc = me->SummonCreature(NPC_TIDEWALKER_LURKER, MurlocCords[i][0], MurlocCords[i][1], MurlocCords[i][2], MurlocCords[i][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10s)) - Murloc->AI()->AttackStart(target); - } - Talk(EMOTE_EARTHQUAKE); - Earthquake = false; - Earthquake_Timer = 40000 + rand32() % 5000; + for (uint8 i = 0; i < 10; ++i) + { + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) + if (Creature* Murloc = me->SummonCreature(NPC_TIDEWALKER_LURKER, MurlocCords[i][0], MurlocCords[i][1], MurlocCords[i][2], MurlocCords[i][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10s)) + Murloc->AI()->AttackStart(target); } - } else Earthquake_Timer -= diff; + Talk(EMOTE_EARTHQUAKE); + Earthquake = false; + Earthquake_Timer = 40000 + rand32() % 5000; + } + } else Earthquake_Timer -= diff; - //TidalWave_Timer - if (TidalWave_Timer <= diff) - { - DoCastVictim(SPELL_TIDAL_WAVE); - TidalWave_Timer = 20000; - } else TidalWave_Timer -= diff; + //TidalWave_Timer + if (TidalWave_Timer <= diff) + { + DoCastVictim(SPELL_TIDAL_WAVE); + TidalWave_Timer = 20000; + } else TidalWave_Timer -= diff; - if (!Phase2) + if (!Phase2) + { + //WateryGrave_Timer + if (WateryGrave_Timer <= diff) { - //WateryGrave_Timer - if (WateryGrave_Timer <= diff) + //Teleport 4 players under the waterfalls + GuidSet targets; + GuidSet::const_iterator itr = targets.begin(); + for (uint8 i = 0; i < 4; ++i) { - //Teleport 4 players under the waterfalls - GuidSet targets; - GuidSet::const_iterator itr = targets.begin(); - for (uint8 i = 0; i < 4; ++i) + counter = 0; + Unit* target; + do { - counter = 0; - Unit* target; - do - { - target = SelectTarget(SelectTargetMethod::Random, 1, 50, true); //target players only - if (counter < Playercount) - break; - if (target) - itr = targets.find(target->GetGUID()); - ++counter; - } while (itr != targets.end()); - + target = SelectTarget(SelectTargetMethod::Random, 1, 50, true); //target players only + if (counter < Playercount) + break; if (target) - { - targets.insert(target->GetGUID()); - ApplyWateryGrave(target, i); - } + itr = targets.find(target->GetGUID()); + ++counter; + } while (itr != targets.end()); + + if (target) + { + targets.insert(target->GetGUID()); + ApplyWateryGrave(target, i); } + } - Talk(SAY_SUMMON_BUBL); + Talk(SAY_SUMMON_BUBL); - Talk(EMOTE_WATERY_GRAVE); - WateryGrave_Timer = 30000; - } else WateryGrave_Timer -= diff; + Talk(EMOTE_WATERY_GRAVE); + WateryGrave_Timer = 30000; + } else WateryGrave_Timer -= diff; - //Start Phase2 - if (HealthBelowPct(25)) - Phase2 = true; - } - else + //Start Phase2 + if (HealthBelowPct(25)) + Phase2 = true; + } + else + { + //WateryGlobules_Timer + if (WateryGlobules_Timer <= diff) { - //WateryGlobules_Timer - if (WateryGlobules_Timer <= diff) + GuidSet globules; + GuidSet::const_iterator itr = globules.begin(); + for (uint8 g = 0; g < 4; g++) //one unit can't cast more than one spell per update, so some players have to cast for us XD { - GuidSet globules; - GuidSet::const_iterator itr = globules.begin(); - for (uint8 g = 0; g < 4; g++) //one unit can't cast more than one spell per update, so some players have to cast for us XD + counter = 0; + Unit* pGlobuleTarget; + do { - counter = 0; - Unit* pGlobuleTarget; - do - { - pGlobuleTarget = SelectTarget(SelectTargetMethod::Random, 0, 50, true); - if (pGlobuleTarget) - itr = globules.find(pGlobuleTarget->GetGUID()); - if (counter > Playercount) - break; - ++counter; - } while (itr != globules.end()); - + pGlobuleTarget = SelectTarget(SelectTargetMethod::Random, 0, 50, true); if (pGlobuleTarget) - { - globules.insert(pGlobuleTarget->GetGUID()); - pGlobuleTarget->CastSpell(pGlobuleTarget, globulespell[g], true); - } - } - Talk(EMOTE_WATERY_GLOBULES); - WateryGlobules_Timer = 25000; - } else WateryGlobules_Timer -= diff; - } + itr = globules.find(pGlobuleTarget->GetGUID()); + if (counter > Playercount) + break; + ++counter; + } while (itr != globules.end()); - DoMeleeAttackIfReady(); + if (pGlobuleTarget) + { + globules.insert(pGlobuleTarget->GetGUID()); + pGlobuleTarget->CastSpell(pGlobuleTarget, globulespell[g], true); + } + } + Talk(EMOTE_WATERY_GLOBULES); + WateryGlobules_Timer = 25000; + } else WateryGlobules_Timer -= diff; } - }; + DoMeleeAttackIfReady(); + } }; -class npc_water_globule : public CreatureScript +struct npc_water_globule : public ScriptedAI { -public: - npc_water_globule() : CreatureScript("npc_water_globule") { } - - CreatureAI* GetAI(Creature* creature) const override + npc_water_globule(Creature* creature) : ScriptedAI(creature) { - return GetSerpentshrineCavernAI<npc_water_globuleAI>(creature); + Initialize(); } - struct npc_water_globuleAI : public ScriptedAI + void Initialize() { - npc_water_globuleAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - } + Check_Timer = 1000; + } - void Initialize() - { - Check_Timer = 1000; - } + uint32 Check_Timer; - uint32 Check_Timer; + void Reset() override + { + Initialize(); - void Reset() override - { - Initialize(); + me->SetFaction(FACTION_MONSTER); + } - me->SetFaction(FACTION_MONSTER); - } + void JustEngagedWith(Unit* /*who*/) override { } - void JustEngagedWith(Unit* /*who*/) override { } + void MoveInLineOfSight(Unit* who) override - void MoveInLineOfSight(Unit* who) override + { + if (!who || me->GetVictim()) + return; + if (me->CanCreatureAttack(who)) { - if (!who || me->GetVictim()) - return; - - if (me->CanCreatureAttack(who)) - { - //no attack radius check - it attacks the first target that moves in his los - //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); - AttackStart(who); - } + //no attack radius check - it attacks the first target that moves in his los + //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); + AttackStart(who); } + } - 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; - if (Check_Timer <= diff) + if (Check_Timer <= diff) + { + if (me->IsWithinDistInMap(me->GetVictim(), 5)) { - if (me->IsWithinDistInMap(me->GetVictim(), 5)) - { - DoCastVictim(SPELL_GLOBULE_EXPLOSION); - - //despawn - me->DespawnOrUnsummon(); - return; - } - Check_Timer = 500; - } else Check_Timer -= diff; + DoCastVictim(SPELL_GLOBULE_EXPLOSION); - //do NOT deal any melee damage to the target. - } - }; + //despawn + me->DespawnOrUnsummon(); + return; + } + Check_Timer = 500; + } else Check_Timer -= diff; + //do NOT deal any melee damage to the target. + } }; void AddSC_boss_morogrim_tidewalker() { - new boss_morogrim_tidewalker(); - new npc_water_globule(); + RegisterSerpentshrineCavernCreatureAI(boss_morogrim_tidewalker); + RegisterSerpentshrineCavernCreatureAI(npc_water_globule); } diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp index ab2586716e2..ebde8fa0ccc 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp @@ -97,7 +97,7 @@ class instance_serpent_shrine : public InstanceMapScript instance_serpentshrine_cavern_InstanceMapScript(InstanceMap* map) : InstanceScript(map) { SetHeaders(DataHeader); - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + SetBossNumber(MAX_ENCOUNTER); StrangePool = 0; Water = WATERSTATE_FRENZY; @@ -113,15 +113,6 @@ class instance_serpent_shrine : public InstanceMapScript TrashCount = 0; } - bool IsEncounterInProgress() const override - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - - return false; - } - void Update(uint32 diff) override { //Water checks @@ -299,32 +290,6 @@ class instance_serpent_shrine : public InstanceMapScript case DATA_WATER: Water = data; break; - case DATA_HYDROSSTHEUNSTABLEEVENT: - m_auiEncounter[0] = data; - break; - case DATA_LEOTHERASTHEBLINDEVENT: - m_auiEncounter[1] = data; - break; - case DATA_THELURKERBELOWEVENT: - m_auiEncounter[2] = data; - break; - case DATA_KARATHRESSEVENT: - m_auiEncounter[3] = data; - break; - case DATA_MOROGRIMTIDEWALKEREVENT: - m_auiEncounter[4] = data; - break; - //Lady Vashj - case DATA_LADYVASHJEVENT: - if (data == NOT_STARTED) - { - ShieldGeneratorDeactivated[0] = false; - ShieldGeneratorDeactivated[1] = false; - ShieldGeneratorDeactivated[2] = false; - ShieldGeneratorDeactivated[3] = false; - } - m_auiEncounter[5] = data; - break; case DATA_SHIELDGENERATOR1: ShieldGeneratorDeactivated[0] = data != 0; break; @@ -340,28 +305,28 @@ class instance_serpent_shrine : public InstanceMapScript default: break; } + } + + bool SetBossState(uint32 id, EncounterState state) override + { + if (!InstanceScript::SetBossState(id, state)) + return false; + + if (id == BOSS_LADY_VASHJ && state == NOT_STARTED) + { + ShieldGeneratorDeactivated[0] = false; + ShieldGeneratorDeactivated[1] = false; + ShieldGeneratorDeactivated[2] = false; + ShieldGeneratorDeactivated[3] = false; + } - if (data == DONE) - SaveToDB(); + return true; } uint32 GetData(uint32 type) const override { switch (type) { - case DATA_HYDROSSTHEUNSTABLEEVENT: - return m_auiEncounter[0]; - case DATA_LEOTHERASTHEBLINDEVENT: - return m_auiEncounter[1]; - case DATA_THELURKERBELOWEVENT: - return m_auiEncounter[2]; - case DATA_KARATHRESSEVENT: - return m_auiEncounter[3]; - case DATA_MOROGRIMTIDEWALKEREVENT: - return m_auiEncounter[4]; - //Lady Vashj - case DATA_LADYVASHJEVENT: - return m_auiEncounter[5]; case DATA_SHIELDGENERATOR1: return ShieldGeneratorDeactivated[0]; case DATA_SHIELDGENERATOR2: @@ -385,34 +350,14 @@ class instance_serpent_shrine : public InstanceMapScript return 0; } - std::string GetSaveData() override + void WriteSaveDataMore(std::ostringstream& stream) override { - OUT_SAVE_INST_DATA; - std::ostringstream stream; - stream << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' ' - << m_auiEncounter[3] << ' ' << m_auiEncounter[4] << ' ' << m_auiEncounter[5] << ' ' << TrashCount; - OUT_SAVE_INST_DATA_COMPLETE; - return stream.str(); + stream << TrashCount; } - void Load(char const* in) override + void ReadSaveDataMore(std::istringstream& stream) override { - if (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(in); - std::istringstream stream(in); - stream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> TrashCount; - - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. - m_auiEncounter[i] = NOT_STARTED; - - OUT_LOAD_INST_DATA_COMPLETE; + stream >> TrashCount; } private: @@ -436,7 +381,6 @@ class instance_serpent_shrine : public InstanceMapScript uint32 TrashCount; bool ShieldGeneratorDeactivated[4]; - uint32 m_auiEncounter[MAX_ENCOUNTER]; bool DoSpawnFrenzy; }; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/serpent_shrine.h b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/serpent_shrine.h index b7ad1f73512..2228a36d8c8 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/serpent_shrine.h +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/serpent_shrine.h @@ -30,33 +30,37 @@ enum SSWaterEventState WATERSTATE_SCALDING = 2 }; +enum SSBosses +{ + BOSS_HYDROSS_THE_UNSTABLE = 0, + BOSS_THE_LURKER_BELOW = 1, + BOSS_LEOTHERAS_THE_BLIND = 2, + BOSS_FATHOM_LORD_KARATHRESS = 3, + BOSS_MOROGRIM_TIDEWALKER = 4, + BOSS_LADY_VASHJ = 5 +}; + enum SSDataTypes { DATA_CANSTARTPHASE3 = 1, DATA_CARIBDIS = 2, - DATA_HYDROSSTHEUNSTABLEEVENT = 3, - DATA_KARATHRESS = 4, - DATA_KARATHRESSEVENT = 5, - DATA_KARATHRESSEVENT_STARTER = 6, - DATA_LADYVASHJ = 7, - DATA_LADYVASHJEVENT = 8, - DATA_LEOTHERASTHEBLINDEVENT = 9, - DATA_MOROGRIMTIDEWALKEREVENT = 10, - DATA_SHARKKIS = 11, - DATA_SHIELDGENERATOR1 = 12, - DATA_SHIELDGENERATOR2 = 13, - DATA_SHIELDGENERATOR3 = 14, - DATA_SHIELDGENERATOR4 = 15, - DATA_THELURKERBELOW = 16, - DATA_THELURKERBELOWEVENT = 17, - DATA_TIDALVESS = 18, - DATA_FATHOMLORDKARATHRESSEVENT = 19, - DATA_LEOTHERAS = 20, - DATA_LEOTHERAS_EVENT_STARTER = 21, - DATA_CONTROL_CONSOLE = 22, - DATA_STRANGE_POOL = 23, - DATA_WATER = 24, - DATA_TRASH = 25, + DATA_KARATHRESS = 3, + DATA_KARATHRESSEVENT_STARTER = 4, + DATA_LADYVASHJ = 5, + DATA_SHARKKIS = 6, + DATA_SHIELDGENERATOR1 = 7, + DATA_SHIELDGENERATOR2 = 8, + DATA_SHIELDGENERATOR3 = 9, + DATA_SHIELDGENERATOR4 = 10, + DATA_THELURKERBELOW = 11, + DATA_TIDALVESS = 12, + DATA_FATHOMLORDKARATHRESSEVENT = 13, + DATA_LEOTHERAS = 14, + DATA_LEOTHERAS_EVENT_STARTER = 15, + DATA_CONTROL_CONSOLE = 16, + DATA_STRANGE_POOL = 17, + DATA_WATER = 18, + DATA_TRASH = 19, }; template <class AI, class T> @@ -65,4 +69,7 @@ inline AI* GetSerpentshrineCavernAI(T* obj) return GetInstanceAI<AI>(obj, SSCScriptName); } +#define RegisterSerpentshrineCavernCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetSerpentshrineCavernAI) +#define RegisterSerpentshrineCavernGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetSerpentshrineCavernAI) + #endif |