diff --git a/data/sql/updates/pending_db_world/rev_1763618644137016700.sql b/data/sql/updates/pending_db_world/rev_1763618644137016700.sql new file mode 100644 index 000000000..e0d00a43d --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1763618644137016700.sql @@ -0,0 +1,28 @@ +-- +DELETE FROM `creature_formations` WHERE `leaderGUID` IN (12758, 12759, 12760); +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `groupAI`) VALUES +(12758, 12758, 7), +(12758, 12762, 7), +(12758, 12761, 7), +(12759, 12759, 7), +(12759, 12763, 7), +(12759, 12764, 7), +(12760, 12760, 7), +(12760, 12765, 7), +(12760, 12766, 7); + +DELETE FROM `linked_respawn` WHERE `linkedGuid` = 127214 AND `linkType` = 0; +INSERT INTO `linked_respawn` (`guid`, `linkedGuid`, `linkType`) VALUES +(12758, 127214, 0), +(12759, 127214, 0), +(12760, 127214, 0), +(12761, 127214, 0), +(12762, 127214, 0), +(12763, 127214, 0), +(12764, 127214, 0), +(12765, 127214, 0), +(12766, 127214, 0); + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28729) AND (`source_type` = 0) AND (`id` IN (5)); +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28730) AND (`source_type` = 0) AND (`id` IN (4)); +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28731) AND (`source_type` = 0) AND (`id` IN (5)); diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index 8afb585e0..b26ef4d9a 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -417,6 +417,15 @@ void CreatureGroup::LeaderMoveTo(float x, float y, float z, uint32 move_type) } } +void CreatureGroup::DespawnFormation(Milliseconds timeToDespawn /*=0ms*/, Seconds forcedRespawnTimer /*=0s*/) +{ + for (auto const& itr : m_members) + { + if (itr.first) + itr.first->DespawnOrUnsummon(timeToDespawn, forcedRespawnTimer); + } +} + void CreatureGroup::RespawnFormation(bool force) { for (auto const& itr : m_members) diff --git a/src/server/game/Entities/Creature/CreatureGroups.h b/src/server/game/Entities/Creature/CreatureGroups.h index 3e52ad00e..0ce3a7c90 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.h +++ b/src/server/game/Entities/Creature/CreatureGroups.h @@ -112,6 +112,7 @@ public: void MemberEngagingTarget(Creature* member, Unit* target); Unit* GetNewTargetForMember(Creature* member); void MemberEvaded(Creature* member); + void DespawnFormation(Milliseconds timeToDespawn = 0ms, Seconds forcedRespawnTimer = 0s); void RespawnFormation(bool force = false); [[nodiscard]] bool IsFormationInCombat(); [[nodiscard]] bool IsAnyMemberAlive(bool ignoreLeader = false); diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h index cf9ce5e93..7dbf96aff 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h @@ -41,6 +41,9 @@ enum ANIds NPC_WATCHER_NARJIL = 28729, NPC_WATCHER_GASHRA = 28730, NPC_WATCHER_SILTHIK = 28731, + NPC_ANUBAR_SKIRMISHER = 28734, + NPC_ANUBAR_SHADOWCASTER = 28733, + NPC_ANUBAR_WARRIOR = 28732, NPC_SKITTERING_SWARMER = 28735, NPC_SKITTERING_INFECTIOR = 28736, NPC_KRIKTHIR_THE_GATEWATCHER = 28684, @@ -60,6 +63,11 @@ enum ANIds SPELL_WEB_WRAP_TRIGGER = 52087 }; +enum ANActions +{ + ACTION_MINION_DIED = 2, +}; + template inline AI* GetAzjolNerubAI(T* obj) { diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp index 3f4ec5480..2e0eac307 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp @@ -19,6 +19,7 @@ #include "CreatureGroups.h" #include "CreatureScript.h" #include "ScriptedCreature.h" +#include "SpellInfo.h" #include "azjol_nerub.h" enum Spells @@ -30,13 +31,6 @@ enum Spells SPELL_FRENZY = 28747 }; -enum Npcs -{ - NPC_WARRIOR = 28732, - NPC_SKIRMISHER = 28734, - NPC_SHADOWCASTER = 28733 -}; - enum Yells { SAY_AGGRO = 0, @@ -50,7 +44,8 @@ enum Yells enum MiscActions { ACTION_MINION_ENGAGED = 1, - GROUP_SWARM = 1 + GROUP_SWARM = 1, + GROUP_WATCHERS = 2 }; class boss_krik_thir : public CreatureScript @@ -91,6 +86,11 @@ public: _canTalk = true; _minionInCombat = false; + _firstCall = true; + _minionsEngaged = 0; + + if (me->IsInEvadeMode()) + return; Creature* narjil = instance->GetCreature(DATA_NARJIL); Creature* gashra = instance->GetCreature(DATA_GASHRA); @@ -117,6 +117,9 @@ public: void DoAction(int32 actionId) override { + if (actionId == ACTION_MINION_ENGAGED) + ++_minionsEngaged; + if (actionId == ACTION_MINION_ENGAGED && !_minionInCombat) { _minionInCombat = true; @@ -124,20 +127,46 @@ public: Talk(SAY_SEND_GROUP, 10s); for (Seconds const& timer : { 60s, 120s }) - { - me->m_Events.AddEventAtOffset([this] { - Talk(SAY_SEND_GROUP); - - me->m_Events.AddEventAtOffset([this] { - me->CastCustomSpell(SPELL_SUBBOSS_AGGRO_TRIGGER, SPELLVALUE_MAX_TARGETS, 1, me, true); - }, 5s); - }, timer); - } + CallWatcher(timer); me->m_Events.AddEventAtOffset([this] { me->SetInCombatWithZone(); }, IsHeroic() ? 200s : 180s); } + else if (actionId == ACTION_MINION_DIED) + { + me->m_Events.CancelEventGroup(GROUP_WATCHERS); + + // Check if any of the watchers is alive + if (!me->FindNearestCreature(NPC_WATCHER_SILTHIK, 100.0f) && + !me->FindNearestCreature(NPC_WATCHER_NARJIL, 100.0f) && + !me->FindNearestCreature(NPC_WATCHER_GASHRA, 100.0f)) + return; + + me->m_Events.AddEventAtOffset([this] { + SummonWatcher(); + }, 5s, GROUP_WATCHERS); + + // Schedule the next (10s + 60s) + CallWatcher(70s); + } + } + + void CallWatcher(Seconds timer) + { + me->m_Events.AddEventAtOffset([this] { + _firstCall = false; + Talk(SAY_SEND_GROUP); + SummonWatcher(); + }, timer, GROUP_WATCHERS); + } + + void SummonWatcher() + { + me->m_Events.AddEventAtOffset([this] { + me->CastCustomSpell(SPELL_SUBBOSS_AGGRO_TRIGGER, SPELLVALUE_MAX_TARGETS, 1, me, true); + _firstCall = false; + }, 5s, GROUP_WATCHERS); } uint32 GetData(uint32 data) const override @@ -182,7 +211,26 @@ public: DoCastRandomTarget(SPELL_CURSE_OF_FATIGUE); }, 27s, 35s); - summons.DoZoneInCombat(); + if (Creature* narjil = instance->GetCreature(DATA_NARJIL)) + narjil->SetInCombatWithZone(); + + if (Creature* gashra = instance->GetCreature(DATA_GASHRA)) + gashra->SetInCombatWithZone(); + + if (Creature* silthik = instance->GetCreature(DATA_SILTHIK)) + silthik->SetInCombatWithZone(); + } + + void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_SUBBOSS_AGGRO_TRIGGER) + { + if (_minionsEngaged == 2 && _firstCall) + return; + + if (Creature* creature = target->ToCreature()) + creature->SetInCombatWithZone(); + } } void JustDied(Unit* killer) override @@ -212,6 +260,8 @@ public: bool _initTalk; bool _canTalk; bool _minionInCombat; + uint8 _minionsEngaged; + bool _firstCall; [[nodiscard]] bool IsInFrenzy() const { return me->HasAura(SPELL_FRENZY); } }; diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp index b2e3c2dec..67d975040 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp @@ -16,6 +16,7 @@ */ #include "AreaBoundary.h" +#include "CreatureGroups.h" #include "CreatureScript.h" #include "InstanceMapScript.h" #include "ScriptedCreature.h" @@ -80,9 +81,59 @@ public: void OnCreatureEvade(Creature* creature) override { - if (creature->EntryEquals(NPC_WATCHER_NARJIL, NPC_WATCHER_GASHRA, NPC_WATCHER_SILTHIK)) - if (Creature* krikthir = GetCreature(DATA_KRIKTHIR)) - krikthir->AI()->EnterEvadeMode(); + switch (creature->GetEntry()) + { + case NPC_WATCHER_NARJIL: + case NPC_WATCHER_GASHRA: + case NPC_WATCHER_SILTHIK: + if (Creature* krikthir = GetCreature(DATA_KRIKTHIR)) + krikthir->AI()->EnterEvadeMode(); + break; + case NPC_ANUBAR_SHADOWCASTER: + case NPC_ANUBAR_SKIRMISHER: + case NPC_ANUBAR_WARRIOR: + if (CreatureGroup* formation = creature->GetFormation()) + if (Creature* leader = formation->GetLeader()) + if (leader->EntryEquals(NPC_WATCHER_GASHRA, NPC_WATCHER_NARJIL, NPC_WATCHER_SILTHIK)) + if (Creature* krikthir = GetCreature(DATA_KRIKTHIR)) + krikthir->AI()->EnterEvadeMode(); + break; + case NPC_KRIKTHIR_THE_GATEWATCHER: + if (Creature* narjil = GetCreature(DATA_NARJIL)) + if (CreatureGroup* formation = narjil->GetFormation()) + formation->DespawnFormation(0s, 20s); + + if (Creature* gashra = GetCreature(DATA_GASHRA)) + if (CreatureGroup* formation = gashra->GetFormation()) + formation->DespawnFormation(0s, 20s); + + if (Creature* silthik = GetCreature(DATA_SILTHIK)) + if (CreatureGroup* formation = silthik->GetFormation()) + formation->DespawnFormation(0s, 20s); + break; + default: + break; + } + } + + void OnUnitDeath(Unit* unit) override + { + if (unit->EntryEquals(NPC_WATCHER_GASHRA, NPC_WATCHER_NARJIL, NPC_WATCHER_SILTHIK, NPC_ANUBAR_SHADOWCASTER, NPC_ANUBAR_SKIRMISHER, NPC_ANUBAR_WARRIOR)) + { + if (Creature* creature = unit->ToCreature()) + { + ObjectGuid creatureGuid = creature->GetGUID(); + scheduler.CancelAll(); + scheduler.Schedule(1s, [this, creatureGuid](TaskContext /*context*/) + { + if (Creature* creature = instance->GetCreature(creatureGuid)) + if (CreatureGroup* formation = creature->GetFormation()) + if (!formation->IsAnyMemberAlive()) + if (Creature* krikthir = GetCreature(DATA_KRIKTHIR)) + krikthir->AI()->DoAction(ACTION_MINION_DIED); + }); + } + } } };