From 73f4bfd7132179cfb13a567645a7442be6a41135 Mon Sep 17 00:00:00 2001 From: Gultask <100873791+Gultask@users.noreply.github.com> Date: Tue, 20 Jan 2026 19:47:49 -0300 Subject: [PATCH] fix(Scripts/Nexus): Improve Crystalline Frayer (#24480) --- .../rev_1768931548623695400.sql | 47 +++++ .../Northrend/Nexus/Nexus/instance_nexus.cpp | 165 ++++++++++++------ .../scripts/Northrend/Nexus/Nexus/nexus.h | 1 + 3 files changed, 161 insertions(+), 52 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1768931548623695400.sql diff --git a/data/sql/updates/pending_db_world/rev_1768931548623695400.sql b/data/sql/updates/pending_db_world/rev_1768931548623695400.sql new file mode 100644 index 000000000..35a5913af --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1768931548623695400.sql @@ -0,0 +1,47 @@ +-- +DELETE FROM `linked_respawn` WHERE `linkedGuid` = 126663 AND `linkType` = 0; +INSERT INTO `linked_respawn` (`guid`, `linkedGuid`, `linkType`) VALUES +(126619, 126663, 0), +(126620, 126663, 0), +(126621, 126663, 0), +(126622, 126663, 0), +(126623, 126663, 0), +(126624, 126663, 0), +(126625, 126663, 0), +(126626, 126663, 0), +(126627, 126663, 0), +(126628, 126663, 0), +(126629, 126663, 0), +(126630, 126663, 0), +(126631, 126663, 0), +(126632, 126663, 0), +(126633, 126663, 0), +(126634, 126663, 0), +(126635, 126663, 0), +(126636, 126663, 0), +(126637, 126663, 0), +(126638, 126663, 0), +(126639, 126663, 0), +(126640, 126663, 0), +(126641, 126663, 0), +(126642, 126663, 0), +(126643, 126663, 0), +(126644, 126663, 0), +(126645, 126663, 0), +(126646, 126663, 0), +(126647, 126663, 0), +(126648, 126663, 0), +(126649, 126663, 0), +(126650, 126663, 0), +(126651, 126663, 0), +(126652, 126663, 0), +(126653, 126663, 0), +(126654, 126663, 0), +(126655, 126663, 0), +(126656, 126663, 0), +(126657, 126663, 0), +(126658, 126663, 0), +(126659, 126663, 0), +(126660, 126663, 0), +(126661, 126663, 0), +(126662, 126663, 0); diff --git a/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp b/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp index 87dbcdfe9..51ead3e43 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/instance_nexus.cpp @@ -18,6 +18,7 @@ #include "CreatureScript.h" #include "InstanceMapScript.h" #include "ScriptedCreature.h" +#include "TaskScheduler.h" #include "nexus.h" #include "Player.h" #include "Group.h" @@ -44,6 +45,8 @@ public: { instance_nexus_InstanceMapScript(Map* map) : InstanceScript(map) {} + GuidVector _frayerGUIDs; + void Initialize() override { SetHeaders(DataHeader); @@ -80,6 +83,23 @@ public: if (GetTeamIdInInstance() == TEAM_ALLIANCE) creature->UpdateEntry(NPC_COMMANDER_KOLURG); break; + case NPC_CRYSTALLINE_FRAYER: + _frayerGUIDs.push_back(creature->GetGUID()); + break; + } + } + + void KillAllFrayers() + { + for (ObjectGuid const& guid : _frayerGUIDs) + { + if (Creature* frayer = instance->GetCreature(guid)) + { + frayer->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + frayer->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); + frayer->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC); + Unit::Kill(frayer, frayer); + } } } @@ -141,7 +161,13 @@ public: if (!InstanceScript::SetBossState(id, state)) return false; - if (state != DONE || id > DATA_ORMOROK_EVENT) + if (state != DONE) + return true; + + if (id == DATA_ORMOROK_EVENT) + KillAllFrayers(); + + if (id > DATA_ORMOROK_EVENT) return true; BossInfo const* bossInfo = GetBossInfo(id + DATA_TELESTRA_ORB); @@ -156,9 +182,17 @@ enum eFrayer { SPELL_SUMMON_SEED_POD = 52796, SPELL_SEED_POD = 48082, - SPELL_AURA_OF_REGENERATION = 52067, + SPELL_AURA_OF_REGENERATION = 57056, SPELL_CRYSTAL_BLOOM = 48058, - SPELL_ENSNARE = 48053 + SPELL_ENSNARE = 48053, + + SAY_EMOTE = 0 +}; + +enum FrayerGroups +{ + GROUP_COMBAT = 1, + GROUP_SEED_POD = 2 }; struct npc_crystalline_frayer : public ScriptedAI @@ -166,27 +200,44 @@ struct npc_crystalline_frayer : public ScriptedAI npc_crystalline_frayer(Creature* creature) : ScriptedAI(creature) { } bool _allowDeath; - uint32 restoreTimer; - uint32 abilityTimer1; - uint32 abilityTimer2; + bool _inSeedPod; + TaskScheduler _scheduler; void Reset() override { - restoreTimer = 0; - abilityTimer1 = 0; - abilityTimer2 = 30000; - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + _allowDeath = false; + _inSeedPod = false; + _scheduler.CancelAll(); + + me->RemoveAllAuras(); + me->SetObjectScale(1.0f); me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); + me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC); + me->SetRegeneratingHealth(true); + me->SetReactState(REACT_AGGRESSIVE); + me->GetMotionMaster()->MoveRandom(10.0f); } void JustEngagedWith(Unit*) override { - _allowDeath = me->GetInstanceScript()->GetBossState(DATA_ORMOROK_EVENT) == DONE; + if (InstanceScript* instance = me->GetInstanceScript()) + _allowDeath = instance->GetBossState(DATA_ORMOROK_EVENT) == DONE; + + _scheduler.Schedule(5s, GROUP_COMBAT, [this](TaskContext context) + { + DoCastVictim(SPELL_ENSNARE); + context.Repeat(5s); + }).Schedule(0s, GROUP_COMBAT, [this](TaskContext context) + { + DoCastVictim(SPELL_CRYSTAL_BLOOM); + context.Repeat(30s); + }); } void EnterEvadeMode(EvadeReason why) override { - if (me->isRegeneratingHealth()) + if (!_inSeedPod) ScriptedAI::EnterEvadeMode(why); } @@ -196,57 +247,67 @@ struct npc_crystalline_frayer : public ScriptedAI { if (!_allowDeath) { - me->RemoveAllAuras(); - me->GetThreatMgr().ClearAllThreat(); - me->CombatStop(true); damage = 0; - - me->SetReactState(REACT_PASSIVE); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetRegeneratingHealth(false); - me->CastSpell(me, SPELL_SUMMON_SEED_POD, true); - me->CastSpell(me, SPELL_SEED_POD, true); - me->CastSpell(me, SPELL_AURA_OF_REGENERATION, false); - restoreTimer = 1; + EnterSeedPod(); } } } + void EnterSeedPod() + { + _inSeedPod = true; + _scheduler.CancelGroup(GROUP_COMBAT); + + me->AttackStop(); + me->GetThreatMgr().ClearAllThreat(); + me->CombatStop(true); + me->RemoveAllAuras(); + + me->SetReactState(REACT_PASSIVE); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); + me->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC); + me->SetRegeneratingHealth(false); + me->SetObjectScale(0.6f); + + DoCastSelf(SPELL_SEED_POD, true); + DoCastSelf(SPELL_SUMMON_SEED_POD, true); + DoCastSelf(SPELL_AURA_OF_REGENERATION, true); + + _scheduler.Schedule(90s, GROUP_SEED_POD, [this](TaskContext /*context*/) + { + LeaveSeedPod(); + }); + } + + void LeaveSeedPod() + { + _inSeedPod = false; + + Talk(SAY_EMOTE); + + me->RemoveAurasDueToSpell(SPELL_SEED_POD); + me->RemoveAurasDueToSpell(SPELL_AURA_OF_REGENERATION); + + me->SetObjectScale(1.0f); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); + me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC); + me->SetRegeneratingHealth(true); + + me->SetReactState(REACT_AGGRESSIVE); + me->GetMotionMaster()->MoveRandom(10.0f); + } + void UpdateAI(uint32 diff) override { - if (restoreTimer) - { - restoreTimer += diff; - if (restoreTimer >= 90 * IN_MILLISECONDS) - { - Talk(0); - me->SetRegeneratingHealth(true); - restoreTimer = 0; - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - } + _scheduler.Update(diff); + + if (_inSeedPod) return; - } if (!UpdateVictim()) return; - - abilityTimer1 += diff; - abilityTimer2 += diff; - - if (abilityTimer1 >= 5000) - { - me->CastSpell(me->GetVictim(), SPELL_ENSNARE, false); - abilityTimer1 = 0; - } - - if (abilityTimer2 >= 30000) - { - me->CastSpell(me->GetVictim(), SPELL_CRYSTAL_BLOOM, false); - abilityTimer2 = 0; - } } }; diff --git a/src/server/scripts/Northrend/Nexus/Nexus/nexus.h b/src/server/scripts/Northrend/Nexus/Nexus/nexus.h index 4d84bfa96..cc4184802 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/nexus.h +++ b/src/server/scripts/Northrend/Nexus/Nexus/nexus.h @@ -50,6 +50,7 @@ enum Npcs NPC_COMMANDER_STOUTBEARD = 26796, NPC_COMMANDER_KOLURG = 26798, + NPC_CRYSTALLINE_FRAYER = 26793, GO_TELESTRA_SPHERE = 188526, GO_ANOMALUS_SPHERE = 188527,