From 09c2b7e5fbadabb51991f868ef4a285c0a68a9b1 Mon Sep 17 00:00:00 2001 From: Andrew <47818697+Nyeriah@users.noreply.github.com> Date: Sun, 28 Sep 2025 07:02:35 -0300 Subject: [PATCH 1/8] fix(Scripts/UtgardePinnacle): Fix Skadi start and reset checks (#23034) --- .../rev_1758977613173748600.sql | 9 ++++ .../UtgardePinnacle/boss_skadi.cpp | 52 +++++++++---------- .../instance_utgarde_pinnacle.cpp | 15 +++--- 3 files changed, 42 insertions(+), 34 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1758977613173748600.sql diff --git a/data/sql/updates/pending_db_world/rev_1758977613173748600.sql b/data/sql/updates/pending_db_world/rev_1758977613173748600.sql new file mode 100644 index 000000000..a63f432ef --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1758977613173748600.sql @@ -0,0 +1,9 @@ +-- +DELETE FROM `areatrigger_scripts` WHERE `entry` = 4991; +INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES (4991, 'SmartTrigger'); + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 4991) AND (`source_type` = 2) AND (`id` IN (0)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(4991, 2, 0, 0, 46, 0, 100, 0, 4991, 0, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 0, 205, 2, 1, 0, 0, 0, 0, 0, 0, 'Areatrigger - On Trigger - Do Action ID 1'); + +UPDATE `creature_template` SET `unit_flags` = `unit_flags`|64|256, `flags_extra` = `flags_extra`|2147483648 WHERE `entry` IN (26693, 30807); diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp index c67253561..cf6318747 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -143,10 +143,7 @@ public: SecondPhase = false; EventStarted = false; - me->RemoveAllAuras(); - me->SetControlled(false, UNIT_STATE_ROOT); - me->UpdatePosition(343.02f, -507.325f, 104.567f, M_PI, true); - me->StopMovingOnCurrentPos(); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); if (m_pInstance) { @@ -160,29 +157,28 @@ public: Creature* GetGrauf() { return ObjectAccessor::GetCreature(*me, GraufGUID); } - void JustEngagedWith(Unit* /*pWho*/) override - { - if (!EventStarted) - { - EventStarted = true; - Talk(SAY_AGGRO); - if (m_pInstance) - { - if (IsHeroic()) - m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_LODI_DODI); - - m_pInstance->SetData(DATA_SKADI_THE_RUTHLESS, IN_PROGRESS); - } - - me->SetControlled(true, UNIT_STATE_ROOT); - me->SetInCombatWithZone(); - events.RescheduleEvent(EVENT_SKADI_START, 2s); - } - } - void DoAction(int32 param) override { - if (param == ACTION_PHASE2) + if (param == ACTION_START_EVENT) + { + if (!EventStarted) + { + EventStarted = true; + Talk(SAY_AGGRO); + if (m_pInstance) + { + if (IsHeroic()) + m_pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_LODI_DODI); + + m_pInstance->SetData(DATA_SKADI_THE_RUTHLESS, IN_PROGRESS); + } + + me->SetControlled(true, UNIT_STATE_ROOT); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + events.RescheduleEvent(EVENT_SKADI_START, 2s); + } + } + else if (param == ACTION_PHASE2) { SecondPhase = true; events.ScheduleEvent(EVENT_SKADI_CRUSH, 8s); @@ -190,7 +186,7 @@ public: events.ScheduleEvent(EVENT_SKADI_WHIRLWIND, 15s); if (me->GetVictim()) - me->GetMotionMaster()->MoveChase(me->GetVictim()); + me->ResumeChasingVictim(); else me->SetInCombatWithZone(); } @@ -415,7 +411,7 @@ public: Map::PlayerList const& pList = me->GetMap()->GetPlayers(); for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) { - if (itr->GetSource()->GetPositionX() < 320.0f || itr->GetSource()->IsGameMaster() || !itr->GetSource()->IsAlive()) + if (itr->GetSource()->GetPositionY() > -490.0f || itr->GetSource()->IsGameMaster() || !itr->GetSource()->IsAlive()) continue; return; @@ -456,7 +452,7 @@ public: SpawnHelpers(0); SpawnHelpers(0); - events.ScheduleEvent(EVENT_GRAUF_MOVE, 15s); + events.ScheduleEvent(EVENT_GRAUF_MOVE, 5s); events.ScheduleEvent(EVENT_GRAUF_SUMMON_HELPERS, 20s); break; } diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp index 5a36f5e84..47588a7bf 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp @@ -20,6 +20,12 @@ #include "ScriptedCreature.h" #include "utgarde_pinnacle.h" +ObjectData const creatureData[] = +{ + { NPC_SKADI_THE_RUTHLESS, DATA_SKADI_THE_RUTHLESS }, + { 0, 0 } +}; + class instance_utgarde_pinnacle : public InstanceMapScript { public: @@ -36,7 +42,6 @@ public: ObjectGuid SvalaSorrowgrave; ObjectGuid GortokPalehoof; - ObjectGuid SkadiRuthless; ObjectGuid KingYmiron; ObjectGuid FrenziedWorgen; ObjectGuid RavenousFurbolg; @@ -59,6 +64,7 @@ public: void Initialize() override { SetHeaders(DataHeader); + LoadObjectData(creatureData, nullptr); SkadiHits = 0; SkadiInRange = 0; @@ -88,9 +94,6 @@ public: case NPC_GORTOK_PALEHOOF: GortokPalehoof = pCreature->GetGUID(); break; - case NPC_SKADI_THE_RUTHLESS: - SkadiRuthless = pCreature->GetGUID(); - break; case NPC_KING_YMIRON: KingYmiron = pCreature->GetGUID(); break; @@ -110,6 +113,8 @@ public: Grauf = pCreature->GetGUID(); break; } + + InstanceScript::OnCreatureCreate(pCreature); } void OnGameObjectCreate(GameObject* pGo) override @@ -238,8 +243,6 @@ public: return SvalaSorrowgrave; case DATA_GORTOK_PALEHOOF: return GortokPalehoof; - case DATA_SKADI_THE_RUTHLESS: - return SkadiRuthless; case DATA_KING_YMIRON: return KingYmiron; case DATA_NPC_FRENZIED_WORGEN: From bac2ae4e113260b966a1af4884ff95d3a5aa43cb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 28 Sep 2025 10:03:36 +0000 Subject: [PATCH 2/8] chore(DB): import pending files Referenced commit(s): 09c2b7e5fbadabb51991f868ef4a285c0a68a9b1 --- .../rev_1758977613173748600.sql => db_world/2025_09_28_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1758977613173748600.sql => db_world/2025_09_28_00.sql} (95%) diff --git a/data/sql/updates/pending_db_world/rev_1758977613173748600.sql b/data/sql/updates/db_world/2025_09_28_00.sql similarity index 95% rename from data/sql/updates/pending_db_world/rev_1758977613173748600.sql rename to data/sql/updates/db_world/2025_09_28_00.sql index a63f432ef..14d13d7b9 100644 --- a/data/sql/updates/pending_db_world/rev_1758977613173748600.sql +++ b/data/sql/updates/db_world/2025_09_28_00.sql @@ -1,3 +1,4 @@ +-- DB update 2025_09_27_03 -> 2025_09_28_00 -- DELETE FROM `areatrigger_scripts` WHERE `entry` = 4991; INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES (4991, 'SmartTrigger'); From 0d1f885b57f2d2125cfda064d166a4ed4ca548f7 Mon Sep 17 00:00:00 2001 From: sogladev Date: Sun, 28 Sep 2025 12:47:01 +0200 Subject: [PATCH 3/8] fix(Core/Spells): updates trajectory target selection (#23031) Co-authored-by: xinef1 --- .../rev_1758965186881591714.sql | 5 + src/server/game/Entities/Object/Position.cpp | 7 + src/server/game/Entities/Object/Position.h | 1 + src/server/game/Handlers/SpellHandler.cpp | 3 + src/server/game/Spells/Spell.cpp | 172 +++++------------- src/server/game/Spells/Spell.h | 1 + src/server/game/Spells/SpellMgr.cpp | 9 - 7 files changed, 65 insertions(+), 133 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1758965186881591714.sql diff --git a/data/sql/updates/pending_db_world/rev_1758965186881591714.sql b/data/sql/updates/pending_db_world/rev_1758965186881591714.sql new file mode 100644 index 000000000..92ed4fcab --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1758965186881591714.sql @@ -0,0 +1,5 @@ +-- +DELETE FROM `spell_cooldown_overrides` WHERE `Id` IN (56570, 56585); +INSERT INTO `spell_cooldown_overrides` (`Id`, `RecoveryTime`, `CategoryRecoveryTime`, `StartRecoveryTime`, `StartRecoveryCategory`, `Comment`) VALUES +(56570, 200, 200, 0, 0, 'Jotunheim Rapid-Fire Harpoon: Rapid-Fire Harpoon'), +(56585, 30000, 30000, 0, 0, 'Jotunheim Rapid-Fire Harpoon: Energy Reserve'); diff --git a/src/server/game/Entities/Object/Position.cpp b/src/server/game/Entities/Object/Position.cpp index fee50be6e..65c2ede21 100644 --- a/src/server/game/Entities/Object/Position.cpp +++ b/src/server/game/Entities/Object/Position.cpp @@ -41,10 +41,17 @@ void Position::RelocatePolarOffset(float angle, float dist, float z /*= 0.0f*/) } bool Position::HasInLine(Position const* pos, float width) const +{ + return HasInLine(pos, 0, width); +} + +bool Position::HasInLine(Position const* pos, float objSize, float width) const { if (!HasInArc(float(M_PI), pos)) return false; + width += objSize; + float angle = GetRelativeAngle(pos); return std::fabs(std::sin(angle)) * GetExactDist2d(pos->GetPositionX(), pos->GetPositionY()) < width; } diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h index 39751a12a..baeff5a80 100644 --- a/src/server/game/Entities/Object/Position.h +++ b/src/server/game/Entities/Object/Position.h @@ -231,6 +231,7 @@ struct Position [[nodiscard]] bool IsWithinBox(const Position& center, float xradius, float yradius, float zradius) const; bool HasInArc(float arcangle, const Position* pos, float targetRadius = 0.0f) const; bool HasInLine(Position const* pos, float width) const; + bool HasInLine(Position const* pos, float objSize, float width) const; [[nodiscard]] std::string ToString() const; // modulos a radian orientation to the range of 0..2PI diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 7d6b5bd2e..6117637db 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -855,6 +855,9 @@ void WorldSession::HandleUpdateProjectilePosition(WorldPacket& recvPacket) pos.Relocate(x, y, z); spell->m_targets.ModDst(pos); + // we changed dest, recalculate flight time + spell->RecalculateDelayMomentForDst(); + WorldPacket data(SMSG_SET_PROJECTILE_POSITION, 21); data << casterGuid; data << uint8(castCount); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index e851a039b..4ae8bfca4 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1744,9 +1744,6 @@ void Spell::SelectImplicitDestDestTargets(SpellEffIndex effIndex, SpellImplicitT case TARGET_DEST_DYNOBJ_NONE: case TARGET_DEST_DEST: return; - case TARGET_DEST_TRAJ: - SelectImplicitTrajTargets(effIndex, targetType); - return; default: { float angle = targetType.CalcDirectionAngle(); @@ -1885,14 +1882,14 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge if (!dist2d) return; - float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - m_targets.GetSrcPos()->m_positionZ; + Position srcPos = *m_targets.GetSrcPos(); + srcPos.SetOrientation(m_caster->GetOrientation()); + float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - srcPos.m_positionZ; - // xinef: supply correct target type, DEST_DEST and similar are ALWAYS undefined - // xinef: correct target is stored in TRIGGERED SPELL, however as far as i noticed, all checks are ENTRY, ENEMY std::list targets; - Acore::WorldObjectSpellTrajTargetCheck check(dist2d, m_targets.GetSrcPos(), m_caster, m_spellInfo, TARGET_CHECK_ENEMY /*targetCheckType*/, m_spellInfo->Effects[effIndex].ImplicitTargetConditions); + Acore::WorldObjectSpellTrajTargetCheck check(dist2d, &srcPos, m_caster, m_spellInfo, targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions); Acore::WorldObjectListSearcher searcher(m_caster, targets, check, GRID_MAP_TYPE_MASK_ALL); - SearchTargets > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, m_targets.GetSrcPos(), dist2d); + SearchTargets > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, &srcPos, dist2d); if (targets.empty()) return; @@ -1901,136 +1898,59 @@ void Spell::SelectImplicitTrajTargets(SpellEffIndex effIndex, SpellImplicitTarge float b = tangent(m_targets.GetElevation()); float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d); if (a > -0.0001f) - a = 0; + a = 0.f; - LOG_DEBUG("spells", "Spell::SelectTrajTargets: a {} b {}", a, b); + // We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range) + // limit max range to 300 yards, sometimes triggered spells can have 50000yds + float bestDist = m_spellInfo->GetMaxRange(false); + if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(m_spellInfo->Effects[effIndex].TriggerSpell)) + bestDist = std::min(std::max(bestDist, triggerSpellInfo->GetMaxRange(false)), std::min(dist2d, 300.0f)); - // Xinef: hack for distance, many trajectory spells have RangeEntry 1 (self) - float bestDist = m_spellInfo->GetMaxRange(false) * 2; - if (bestDist < 1.0f) - bestDist = 300.0f; - - std::list::const_iterator itr = targets.begin(); - for (; itr != targets.end(); ++itr) + // GameObjects don't cast traj + Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit()); + for (auto itr = targets.begin(); itr != targets.end(); ++itr) { - if (Unit* unitTarget = (*itr)->ToUnit()) - if (m_caster == *itr || m_caster->IsOnVehicle(unitTarget) || (unitTarget)->GetVehicle())//(*itr)->IsOnVehicle(m_caster)) + if (m_spellInfo->CheckTarget(unitCaster, *itr, true) != SPELL_CAST_OK) + continue; + + if (Unit* unit = (*itr)->ToUnit()) + { + if (unitCaster == *itr || unitCaster->IsOnVehicle(unit) || unit->GetVehicle()) continue; - const float size = std::max((*itr)->GetObjectSize() * 0.7f, 1.0f); // 1/sqrt(3) - /// @todo: all calculation should be based on src instead of m_caster - const float objDist2d = std::fabs(m_targets.GetSrcPos()->GetExactDist2d(*itr) * cos(m_targets.GetSrcPos()->GetRelativeAngle(*itr))); - const float dz = std::fabs((*itr)->GetPositionZ() - m_targets.GetSrcPos()->m_positionZ); + if (Creature* creatureTarget = unit->ToCreature()) + { + if (!(creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_COLLIDE_WITH_MISSILES)) + continue; + } + } - LOG_DEBUG("spells", "Spell::SelectTrajTargets: check {}, dist between {} {}, height between {} {}.", - (*itr)->GetEntry(), objDist2d - size, objDist2d + size, dz - size, dz + size); + float const size = std::max((*itr)->GetCombatReach(), 1.0f); + float const objDist2d = srcPos.GetExactDist2d(*itr); + float const dz = (*itr)->GetPositionZ() - srcPos.m_positionZ; - float dist = objDist2d - size; - float height = dist * (a * dist + b); + float const horizontalDistToTraj = std::fabs(objDist2d * std::sin(srcPos.GetRelativeAngle(*itr))); + float const sizeFactor = std::cos((horizontalDistToTraj / size) * (M_PI / 2.0f)); + float const distToHitPoint = std::max(objDist2d * std::cos(srcPos.GetRelativeAngle(*itr)) - size * sizeFactor, 0.0f); + float const height = distToHitPoint * (a * distToHitPoint + b); - LOG_DEBUG("spells", "Spell::SelectTrajTargets: dist {}, height {}.", dist, height); + if (fabs(dz - height) > size + b / 2.0f + TRAJECTORY_MISSILE_SIZE) + continue; - if (dist < bestDist && height < dz + size && height > dz - size) + if (distToHitPoint < bestDist) { - bestDist = dist > 0 ? dist : 0; + bestDist = distToHitPoint; break; } - -#define CHECK_DIST {\ - LOG_DEBUG("spells", "Spell::SelectTrajTargets: dist {}, height {}.", dist, height);\ - if (dist > bestDist)\ - continue;\ - if (dist < objDist2d + size && dist > objDist2d - size)\ - {\ - bestDist = dist;\ - break;\ - }\ - } - - // RP-GG only, search in straight line, as item have no trajectory - if (m_CastItem) - { - if (dist < bestDist && std::fabs(dz) < 6.0f) // closes target, also check Z difference) - { - bestDist = dist; - break; - } - - continue; - } - - if (!a) - { - // Xinef: everything remade - dist = m_targets.GetSrcPos()->GetExactDist(*itr); - height = m_targets.GetSrcPos()->GetExactDist2d(*itr) * b; - - if (height < dz + size * (b + 1) && height > dz - size * (b + 1) && dist < bestDist) - { - bestDist = dist; - break; - } - - continue; - } - - height = dz - size; - float sqrt1 = b * b + 4 * a * height; - if (sqrt1 > 0) - { - sqrt1 = std::sqrt(sqrt1); - dist = (sqrt1 - b) / (2 * a); - CHECK_DIST; - } - - height = dz + size; - float sqrt2 = b * b + 4 * a * height; - if (sqrt2 > 0) - { - sqrt2 = std::sqrt(sqrt2); - dist = (sqrt2 - b) / (2 * a); - CHECK_DIST; - - dist = (-sqrt2 - b) / (2 * a); - CHECK_DIST; - } - - if (sqrt1 > 0) - { - dist = (-sqrt1 - b) / (2 * a); - CHECK_DIST; - } } - if (m_targets.GetSrcPos()->GetExactDist2d(m_targets.GetDstPos()) > bestDist) + if (dist2d > bestDist) { - float x = m_targets.GetSrcPos()->m_positionX + cos(m_caster->GetOrientation()) * bestDist; - float y = m_targets.GetSrcPos()->m_positionY + std::sin(m_caster->GetOrientation()) * bestDist; + float x = m_targets.GetSrcPos()->m_positionX + std::cos(unitCaster->GetOrientation()) * bestDist; + float y = m_targets.GetSrcPos()->m_positionY + std::sin(unitCaster->GetOrientation()) * bestDist; float z = m_targets.GetSrcPos()->m_positionZ + bestDist * (a * bestDist + b); - if (itr != targets.end()) - { - float distSq = (*itr)->GetExactDistSq(x, y, z); - float sizeSq = (*itr)->GetObjectSize(); - sizeSq *= sizeSq; - LOG_DEBUG("spells", "Spell::SelectTrajTargets: Initial {} {} {} {} {}", x, y, z, distSq, sizeSq); - if (distSq > sizeSq) - { - float factor = 1 - std::sqrt(sizeSq / distSq); - x += factor * ((*itr)->GetPositionX() - x); - y += factor * ((*itr)->GetPositionY() - y); - z += factor * ((*itr)->GetPositionZ() - z); - - distSq = (*itr)->GetExactDistSq(x, y, z); - LOG_DEBUG("spells", "Spell::SelectTrajTargets: Initial {} {} {} {} {}", x, y, z, distSq, sizeSq); - } - } - - Position trajDst; - trajDst.Relocate(x, y, z, m_caster->GetOrientation()); - SpellDestination dest(*m_targets.GetDst()); - dest.Relocate(trajDst); - + SpellDestination dest(x, y, z, unitCaster->GetOrientation()); CallScriptDestinationTargetSelectHandlers(dest, effIndex, targetType); m_targets.ModDst(dest); } @@ -9119,7 +9039,7 @@ namespace Acore } else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE)) { - if (!_caster->HasInLine(target, _caster->GetObjectSize() + target->GetObjectSize())) + if (!_caster->HasInLine(target, target->GetObjectSize(), _caster->GetObjectSize())) return false; } else @@ -9139,9 +9059,13 @@ namespace Acore bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target) { // return all targets on missile trajectory (0 - size of a missile) - if (!_caster->HasInLine(target, target->GetObjectSize())) + if (!_caster->HasInLine(target, target->GetCombatReach(), TRAJECTORY_MISSILE_SIZE)) return false; - return WorldObjectSpellAreaTargetCheck::operator ()(target); + + if (target->GetExactDist2d(_position) > _range) + return false; + + return WorldObjectSpellTargetCheck::operator ()(target); } } //namespace Acore diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index bb8f2cb7b..3025e803e 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -39,6 +39,7 @@ class ByteBuffer; class BasicEvent; #define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILLISECONDS) +#define TRAJECTORY_MISSILE_SIZE 3.0f enum SpellCastFlags { diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 534388fd4..b9ee0a9b3 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3405,15 +3405,6 @@ void SpellMgr::LoadSpellInfoCustomAttributes() } // Xinef: Cooldown overwrites - // Jotunheim Rapid-Fire Harpoon: Energy Reserve - case 56585: - spellInfo->RecoveryTime = 30000; - spellInfo->_requireCooldownInfo = true; - break; - // Jotunheim Rapid-Fire Harpoon: Rapid-Fire Harpoon - case 56570: - spellInfo->RecoveryTime = 200; - break; // Burst of Speed case 57493: spellInfo->RecoveryTime = 60000; From 5f171211179feed3cfc1ff4d691d9c49f24795d9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 28 Sep 2025 10:48:11 +0000 Subject: [PATCH 4/8] chore(DB): import pending files Referenced commit(s): 0d1f885b57f2d2125cfda064d166a4ed4ca548f7 --- .../rev_1758965186881591714.sql => db_world/2025_09_28_01.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/rev_1758965186881591714.sql => db_world/2025_09_28_01.sql} (89%) diff --git a/data/sql/updates/pending_db_world/rev_1758965186881591714.sql b/data/sql/updates/db_world/2025_09_28_01.sql similarity index 89% rename from data/sql/updates/pending_db_world/rev_1758965186881591714.sql rename to data/sql/updates/db_world/2025_09_28_01.sql index 92ed4fcab..13f7b906f 100644 --- a/data/sql/updates/pending_db_world/rev_1758965186881591714.sql +++ b/data/sql/updates/db_world/2025_09_28_01.sql @@ -1,3 +1,4 @@ +-- DB update 2025_09_28_00 -> 2025_09_28_01 -- DELETE FROM `spell_cooldown_overrides` WHERE `Id` IN (56570, 56585); INSERT INTO `spell_cooldown_overrides` (`Id`, `RecoveryTime`, `CategoryRecoveryTime`, `StartRecoveryTime`, `StartRecoveryCategory`, `Comment`) VALUES From 22f93eaca648152aa6b8d6f13abeee97115d510a Mon Sep 17 00:00:00 2001 From: Takenbacon Date: Mon, 29 Sep 2025 07:43:30 -0700 Subject: [PATCH 5/8] fix(Core/Weather): Improve weather system thread safety (#22772) Co-authored-by: Shauren Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../game/Entities/Player/PlayerUpdates.cpp | 10 +- src/server/game/Handlers/CharacterHandler.cpp | 1 - src/server/game/Maps/Map.cpp | 146 ++++++++++++------ src/server/game/Maps/Map.h | 13 +- src/server/game/Server/WorldSessionMgr.cpp | 31 ---- src/server/game/Server/WorldSessionMgr.h | 2 - src/server/game/Weather/Weather.cpp | 14 +- src/server/game/Weather/Weather.h | 5 +- src/server/game/Weather/WeatherMgr.cpp | 77 +-------- src/server/game/Weather/WeatherMgr.h | 11 +- src/server/game/World/World.cpp | 8 - src/server/game/World/World.h | 1 - src/server/scripts/Commands/cs_misc.cpp | 8 +- .../scripts/OutdoorPvP/OutdoorPvPEP.cpp | 40 +++-- .../scripts/OutdoorPvP/OutdoorPvPHP.cpp | 8 +- .../scripts/OutdoorPvP/OutdoorPvPNA.cpp | 10 +- .../scripts/OutdoorPvP/OutdoorPvPSI.cpp | 4 +- .../scripts/OutdoorPvP/OutdoorPvPTF.cpp | 8 +- .../scripts/OutdoorPvP/OutdoorPvPZM.cpp | 16 +- src/server/scripts/World/scourge_invasion.cpp | 20 +-- 20 files changed, 186 insertions(+), 247 deletions(-) diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp index fd41f73aa..d3798a083 100644 --- a/src/server/game/Entities/Player/PlayerUpdates.cpp +++ b/src/server/game/Entities/Player/PlayerUpdates.cpp @@ -1289,13 +1289,9 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea, bool force) return; if (sWorld->getBoolConfig(CONFIG_WEATHER)) - { - if (Weather* weather = WeatherMgr::FindWeather(zone->ID)) - weather->SendWeatherUpdateToPlayer(this); - else if (!WeatherMgr::AddWeather(zone->ID)) - // send fine weather packet to remove old zone's weather - WeatherMgr::SendFineWeatherUpdateToPlayer(this); - } + GetMap()->GetOrGenerateZoneDefaultWeather(newZone); + + GetMap()->SendZoneDynamicInfo(newZone, this); sScriptMgr->OnPlayerUpdateZone(this, newZone, newArea); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 2169cb531..259bf3415 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1179,7 +1179,6 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar) // necessary actions from AddPlayerToMap: pCurrChar->GetMap()->SendInitTransports(pCurrChar); pCurrChar->GetMap()->SendInitSelf(pCurrChar); - pCurrChar->GetMap()->SendZoneDynamicInfo(pCurrChar); // If we are logging into an existing player, simply clear visibility references // so player will receive a fresh list of new objects on the next vis update. diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index d8dde935e..de0e4a9bd 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -43,10 +43,11 @@ #include "Vehicle.h" #include "VMapMgr2.h" #include "Weather.h" +#include "WeatherMgr.h" #define MAP_INVALID_ZONE 0xFFFFFFFF -ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), WeatherId(WEATHER_STATE_FINE), +ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), DefaultWeather(nullptr), WeatherId(WEATHER_STATE_FINE), WeatherGrade(0.0f), OverrideLightId(0), LightFadeInTime(0) { } Map::~Map() @@ -74,6 +75,7 @@ Map::Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : //lets initialize visibility distance for map Map::InitVisibilityDistance(); + _weatherUpdateTimer.SetInterval(1 * IN_MILLISECONDS); _corpseUpdateTimer.SetInterval(20 * MINUTE * IN_MILLISECONDS); } @@ -268,7 +270,6 @@ bool Map::AddPlayerToMap(Player* player) SendInitTransports(player); SendInitSelf(player); - SendZoneDynamicInfo(player); player->UpdateObjectVisibility(false); @@ -500,6 +501,7 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/) HandleDelayedVisibility(); + UpdateWeather(t_diff); UpdateExpiredCorpses(t_diff); sScriptMgr->OnMapUpdate(this, t_diff); @@ -2767,9 +2769,37 @@ void Map::ScheduleCreatureRespawn(ObjectGuid creatureGuid, Milliseconds respawnT }); } -void Map::SendZoneDynamicInfo(Player* player) +/// Send a packet to all players (or players selected team) in the zone (except self if mentioned) +bool Map::SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession const* self, TeamId teamId) const +{ + bool foundPlayerToSend = false; + + for (MapReference const& ref : GetPlayers()) + { + Player* player = ref.GetSource(); + if (player->IsInWorld() && + player->GetZoneId() == zone && + player->GetSession() != self && + (teamId == TEAM_NEUTRAL || player->GetTeamId() == teamId)) + { + player->SendDirectMessage(packet); + foundPlayerToSend = true; + } + } + + return foundPlayerToSend; +} + +/// Send a System Message to all players in the zone (except self if mentioned) +void Map::SendZoneText(uint32 zoneId, char const* text, WorldSession const* self, TeamId teamId) const +{ + WorldPacket data; + ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, text); + SendZoneMessage(zoneId, &data, self, teamId); +} + +void Map::SendZoneDynamicInfo(uint32 zoneId, Player* player) const { - uint32 zoneId = player->GetZoneId(); ZoneDynamicInfoMap::const_iterator itr = _zoneDynamicInfo.find(zoneId); if (itr == _zoneDynamicInfo.end()) return; @@ -2777,15 +2807,11 @@ void Map::SendZoneDynamicInfo(Player* player) if (uint32 music = itr->second.MusicId) player->SendDirectMessage(WorldPackets::Misc::PlayMusic(music).Write()); - if (WeatherState weatherId = itr->second.WeatherId) - { - WorldPackets::Misc::Weather weather(weatherId, itr->second.WeatherGrade); - player->SendDirectMessage(weather.Write()); - } + SendZoneWeather(itr->second, player); if (uint32 overrideLight = itr->second.OverrideLightId) { - WorldPacket data(SMSG_OVERRIDE_LIGHT, 4 + 4 + 1); + WorldPacket data(SMSG_OVERRIDE_LIGHT, 4 + 4 + 4); data << uint32(_defaultLight); data << uint32(overrideLight); data << uint32(itr->second.LightFadeInTime); @@ -2793,6 +2819,41 @@ void Map::SendZoneDynamicInfo(Player* player) } } +void Map::SendZoneWeather(uint32 zoneId, Player* player) const +{ + ZoneDynamicInfoMap::const_iterator itr = _zoneDynamicInfo.find(zoneId); + if (itr == _zoneDynamicInfo.end()) + return; + + SendZoneWeather(itr->second, player); +} + +void Map::SendZoneWeather(ZoneDynamicInfo const& zoneDynamicInfo, Player* player) const +{ + if (WeatherState weatherId = zoneDynamicInfo.WeatherId) + { + WorldPackets::Misc::Weather weather(weatherId, zoneDynamicInfo.WeatherGrade); + player->SendDirectMessage(weather.Write()); + } + else if (zoneDynamicInfo.DefaultWeather) + zoneDynamicInfo.DefaultWeather->SendWeatherUpdateToPlayer(player); + else + Weather::SendFineWeatherUpdateToPlayer(player); +} + +void Map::UpdateWeather(uint32 const diff) +{ + _weatherUpdateTimer.Update(diff); + if (!_weatherUpdateTimer.Passed()) + return; + + for (auto&& zoneInfo : _zoneDynamicInfo) + if (zoneInfo.second.DefaultWeather && !zoneInfo.second.DefaultWeather->Update(_weatherUpdateTimer.GetInterval())) + zoneInfo.second.DefaultWeather.reset(); + + _weatherUpdateTimer.Reset(); +} + void Map::PlayDirectSoundToMap(uint32 soundId, uint32 zoneId) { Map::PlayerList const& players = GetPlayers(); @@ -2810,67 +2871,50 @@ void Map::PlayDirectSoundToMap(uint32 soundId, uint32 zoneId) void Map::SetZoneMusic(uint32 zoneId, uint32 musicId) { - if (_zoneDynamicInfo.find(zoneId) == _zoneDynamicInfo.end()) - _zoneDynamicInfo.insert(ZoneDynamicInfoMap::value_type(zoneId, ZoneDynamicInfo())); - _zoneDynamicInfo[zoneId].MusicId = musicId; - Map::PlayerList const& players = GetPlayers(); - if (!players.IsEmpty()) - { - WorldPackets::Misc::PlayMusic playMusic(musicId); - playMusic.Write(); + WorldPackets::Misc::PlayMusic playMusic(musicId); + SendZoneMessage(zoneId, WorldPackets::Misc::PlayMusic(musicId).Write()); +} - for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - if (Player* player = itr->GetSource()) - if (player->GetZoneId() == zoneId) - player->SendDirectMessage(playMusic.GetRawPacket()); +Weather* Map::GetOrGenerateZoneDefaultWeather(uint32 zoneId) +{ + WeatherData const* weatherData = WeatherMgr::GetWeatherData(zoneId); + if (!weatherData) + return nullptr; + + ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId]; + + if (!info.DefaultWeather) + { + info.DefaultWeather = std::make_unique(this, zoneId, weatherData); + info.DefaultWeather->ReGenerate(); + info.DefaultWeather->UpdateWeather(); } + + return info.DefaultWeather.get(); } void Map::SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade) { - if (_zoneDynamicInfo.find(zoneId) == _zoneDynamicInfo.end()) - _zoneDynamicInfo.insert(ZoneDynamicInfoMap::value_type(zoneId, ZoneDynamicInfo())); - ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId]; info.WeatherId = weatherId; info.WeatherGrade = weatherGrade; - Map::PlayerList const& players = GetPlayers(); - if (!players.IsEmpty()) - { - WorldPackets::Misc::Weather weather(weatherId, weatherGrade); - - for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - if (Player* player = itr->GetSource()) - if (player->GetZoneId() == zoneId) - player->SendDirectMessage(weather.Write()); - } + SendZoneMessage(zoneId, WorldPackets::Misc::Weather(weatherId, weatherGrade).Write()); } void Map::SetZoneOverrideLight(uint32 zoneId, uint32 lightId, Milliseconds fadeInTime) { - if (_zoneDynamicInfo.find(zoneId) == _zoneDynamicInfo.end()) - _zoneDynamicInfo.insert(ZoneDynamicInfoMap::value_type(zoneId, ZoneDynamicInfo())); - ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId]; info.OverrideLightId = lightId; info.LightFadeInTime = static_cast(fadeInTime.count()); - Map::PlayerList const& players = GetPlayers(); - if (!players.IsEmpty()) - { - WorldPacket data(SMSG_OVERRIDE_LIGHT, 4 + 4 + 4); - data << uint32(_defaultLight); - data << uint32(lightId); - data << uint32(static_cast(fadeInTime.count())); - - for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) - if (Player* player = itr->GetSource()) - if (player->GetZoneId() == zoneId) - player->SendDirectMessage(&data); - } + WorldPacket data(SMSG_OVERRIDE_LIGHT, 4 + 4 + 4); + data << uint32(_defaultLight); + data << uint32(lightId); + data << uint32(static_cast(fadeInTime.count())); + SendZoneMessage(zoneId, &data); } void Map::DoForAllPlayers(std::function exec) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index c875e4eaa..20551da8a 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -47,6 +47,7 @@ class InstanceScript; class Group; class InstanceSave; class Object; +class Weather; class WorldObject; class TempSummon; class Player; @@ -62,6 +63,7 @@ class Transport; class StaticTransport; class MotionTransport; class PathGenerator; +class WorldSession; enum WeatherState : uint32; @@ -132,6 +134,7 @@ struct ZoneDynamicInfo ZoneDynamicInfo(); uint32 MusicId; + std::unique_ptr DefaultWeather; WeatherState WeatherId; float WeatherGrade; uint32 OverrideLightId; @@ -440,15 +443,22 @@ public: static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId); + bool SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession const* self = nullptr, TeamId teamId = TEAM_NEUTRAL) const; + void SendZoneText(uint32 zoneId, char const* text, WorldSession const* self = nullptr, TeamId teamId = TEAM_NEUTRAL) const; + void SendInitTransports(Player* player); void SendRemoveTransports(Player* player); - void SendZoneDynamicInfo(Player* player); + void SendZoneDynamicInfo(uint32 zoneId, Player* player) const; + void SendZoneWeather(uint32 zoneId, Player* player) const; + void SendZoneWeather(ZoneDynamicInfo const& zoneDynamicInfo, Player* player) const; void SendInitSelf(Player* player); + void UpdateWeather(uint32 const diff); void UpdateExpiredCorpses(uint32 const diff); void PlayDirectSoundToMap(uint32 soundId, uint32 zoneId = 0); void SetZoneMusic(uint32 zoneId, uint32 musicId); + Weather* GetOrGenerateZoneDefaultWeather(uint32 zoneId); void SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade); void SetZoneOverrideLight(uint32 zoneId, uint32 lightId, Milliseconds fadeInTime); @@ -584,6 +594,7 @@ private: std::unordered_map _zonePlayerCountMap; ZoneDynamicInfoMap _zoneDynamicInfo; + IntervalTimer _weatherUpdateTimer; uint32 _defaultLight; IntervalTimer _corpseUpdateTimer; diff --git a/src/server/game/Server/WorldSessionMgr.cpp b/src/server/game/Server/WorldSessionMgr.cpp index 5bad2e10a..e033b6628 100644 --- a/src/server/game/Server/WorldSessionMgr.cpp +++ b/src/server/game/Server/WorldSessionMgr.cpp @@ -398,29 +398,6 @@ void WorldSessionMgr::SendGlobalGMMessage(WorldPacket const* packet, WorldSessio } } -/// Send a packet to all players (or players selected team) in the zone (except self if mentioned) -bool WorldSessionMgr::SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession* self, TeamId teamId) -{ - bool foundPlayerToSend = false; - SessionMap::const_iterator itr; - - for (itr = _sessions.begin(); itr != _sessions.end(); ++itr) - { - if (itr->second && - itr->second->GetPlayer() && - itr->second->GetPlayer()->IsInWorld() && - itr->second->GetPlayer()->GetZoneId() == zone && - itr->second != self && - (teamId == TEAM_NEUTRAL || itr->second->GetPlayer()->GetTeamId() == teamId)) - { - itr->second->SendPacket(packet); - foundPlayerToSend = true; - } - } - - return foundPlayerToSend; -} - /// Send a server message to the user(s) void WorldSessionMgr::SendServerMessage(ServerMessageType messageID, std::string stringParam /*= ""*/, Player* player /*= nullptr*/) { @@ -435,14 +412,6 @@ void WorldSessionMgr::SendServerMessage(ServerMessageType messageID, std::string SendGlobalMessage(chatServerMessage.Write()); } -/// Send a System Message to all players in the zone (except self if mentioned) -void WorldSessionMgr::SendZoneText(uint32 zone, std::string text, WorldSession* self, TeamId teamId) -{ - WorldPacket data; - ChatHandler::BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, text.c_str()); - SendZoneMessage(zone, &data, self, teamId); -} - void WorldSessionMgr::DoForAllOnlinePlayers(std::function exec) { std::shared_lock lock(*HashMapHolder::GetLock()); diff --git a/src/server/game/Server/WorldSessionMgr.h b/src/server/game/Server/WorldSessionMgr.h index 364dad1ed..ba818da48 100644 --- a/src/server/game/Server/WorldSessionMgr.h +++ b/src/server/game/Server/WorldSessionMgr.h @@ -81,8 +81,6 @@ public: void SendGlobalMessage(WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL); void SendGlobalGMMessage(WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL); - bool SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL); - void SendZoneText(uint32 zone, std::string text, WorldSession* self = nullptr, TeamId teamId = TEAM_NEUTRAL); void SendServerMessage(ServerMessageType messageID, std::string stringParam = "", Player* player = nullptr); void DoForAllOnlinePlayers(std::function exec); diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp index bc22e7db6..6f4f51e64 100644 --- a/src/server/game/Weather/Weather.cpp +++ b/src/server/game/Weather/Weather.cpp @@ -20,16 +20,16 @@ */ #include "Weather.h" +#include "Map.h" #include "MiscPackets.h" #include "Player.h" #include "ScriptMgr.h" #include "Util.h" #include "World.h" -#include "WorldSessionMgr.h" /// Create the Weather object -Weather::Weather(uint32 zone, WeatherData const* weatherChances) - : m_zone(zone), m_weatherChances(weatherChances) +Weather::Weather(Map* map, uint32 zone, WeatherData const* weatherChances) + : m_map(map), m_zone(zone), m_weatherChances(weatherChances) { m_timer.SetInterval(sWorld->getIntConfig(CONFIG_INTERVAL_CHANGEWEATHER)); m_type = WEATHER_TYPE_FINE; @@ -190,6 +190,12 @@ void Weather::SendWeatherUpdateToPlayer(Player* player) player->SendDirectMessage(weather.Write()); } +void Weather::SendFineWeatherUpdateToPlayer(Player* player) +{ + WorldPackets::Misc::Weather weather(WEATHER_STATE_FINE); + player->SendDirectMessage(weather.Write()); +} + /// Send the new weather to all players in the zone bool Weather::UpdateWeather() { @@ -204,7 +210,7 @@ bool Weather::UpdateWeather() WorldPackets::Misc::Weather weather(state, m_grade); //- Returns false if there were no players found to update - if (!sWorldSessionMgr->SendZoneMessage(m_zone, weather.Write())) + if (!m_map->SendZoneMessage(m_zone, weather.Write())) return false; ///- Log the event diff --git a/src/server/game/Weather/Weather.h b/src/server/game/Weather/Weather.h index 9bba94527..ebad65835 100644 --- a/src/server/game/Weather/Weather.h +++ b/src/server/game/Weather/Weather.h @@ -25,6 +25,7 @@ #include "SharedDefines.h" #include "Timer.h" +class Map; class Player; #define WEATHER_SEASONS 4 @@ -63,7 +64,7 @@ enum WeatherState : uint32 class Weather { public: - Weather(uint32 zone, WeatherData const* weatherChances); + Weather(Map* map, uint32 zone, WeatherData const* weatherChances); ~Weather() = default; bool Update(uint32 diff); @@ -71,6 +72,7 @@ public: bool UpdateWeather(); void SendWeatherUpdateToPlayer(Player* player); + static void SendFineWeatherUpdateToPlayer(Player* player); void SetWeather(WeatherType type, float grade); /// For which zone is this weather? @@ -79,6 +81,7 @@ public: private: [[nodiscard]] WeatherState GetWeatherState() const; + Map* m_map; uint32 m_zone; WeatherType m_type; float m_grade; diff --git a/src/server/game/Weather/WeatherMgr.cpp b/src/server/game/Weather/WeatherMgr.cpp index f7b98911e..73161edbd 100644 --- a/src/server/game/Weather/WeatherMgr.cpp +++ b/src/server/game/Weather/WeatherMgr.cpp @@ -20,63 +20,25 @@ */ #include "WeatherMgr.h" +#include "Containers.h" +#include "DatabaseEnv.h" #include "Log.h" -#include "MiscPackets.h" #include "ObjectMgr.h" -#include "Player.h" +#include "QueryResult.h" +#include "Timer.h" #include "Weather.h" -#include "WorldSession.h" namespace WeatherMgr { namespace { - typedef std::unordered_map> WeatherMap; - typedef std::unordered_map WeatherZoneMap; - - WeatherMap m_weathers; - WeatherZoneMap mWeatherZoneMap; - - WeatherData const* GetWeatherData(uint32 zone_id) - { - WeatherZoneMap::const_iterator itr = mWeatherZoneMap.find(zone_id); - return (itr != mWeatherZoneMap.end()) ? &itr->second : nullptr; - } + std::unordered_map _weatherData; } - /// Find a Weather object by the given zoneid - Weather* FindWeather(uint32 id) + WeatherData const* GetWeatherData(uint32 zone_id) { - WeatherMap::const_iterator itr = m_weathers.find(id); - return (itr != m_weathers.end()) ? itr->second.get() : 0; - } - - /// Remove a Weather object for the given zoneid - void RemoveWeather(uint32 id) - { - // not called at the moment. Kept for completeness - WeatherMap::iterator itr = m_weathers.find(id); - - if (itr != m_weathers.end()) - m_weathers.erase(itr); - } - - /// Add a Weather object to the list - Weather* AddWeather(uint32 zone_id) - { - WeatherData const* weatherChances = GetWeatherData(zone_id); - - // zone does not have weather, ignore - if (!weatherChances) - return nullptr; - - Weather* w = new Weather(zone_id, weatherChances); - m_weathers[w->GetZone()].reset(w); - w->ReGenerate(); - w->UpdateWeather(); - - return w; + return Acore::Containers::MapGetValuePtr(_weatherData, zone_id); } void LoadWeatherData() @@ -105,7 +67,7 @@ namespace WeatherMgr uint32 zone_id = fields[0].Get(); - WeatherData& wzc = mWeatherZoneMap[zone_id]; + WeatherData& wzc = _weatherData[zone_id]; for (uint8 season = 0; season < WEATHER_SEASONS; ++season) { @@ -140,27 +102,4 @@ namespace WeatherMgr LOG_INFO("server.loading", ">> Loaded {} Weather Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); LOG_INFO("server.loading", " "); } - - void SendFineWeatherUpdateToPlayer(Player* player) - { - WorldPackets::Misc::Weather weather(WEATHER_STATE_FINE); - player->SendDirectMessage(weather.Write()); - } - - void Update(uint32 diff) - { - ///- Send an update signal to Weather objects - WeatherMap::iterator itr, next; - for (itr = m_weathers.begin(); itr != m_weathers.end(); itr = next) - { - next = itr; - ++next; - - ///- and remove Weather objects for zones with no player - // As interval > WorldTick - if (!itr->second->Update(diff)) - m_weathers.erase(itr); - } - } - } // namespace diff --git a/src/server/game/Weather/WeatherMgr.h b/src/server/game/Weather/WeatherMgr.h index 046934d8b..ddd5f8fdf 100644 --- a/src/server/game/Weather/WeatherMgr.h +++ b/src/server/game/Weather/WeatherMgr.h @@ -25,19 +25,12 @@ #include "Define.h" class Weather; -class Player; +struct WeatherData; namespace WeatherMgr { void LoadWeatherData(); - - Weather* FindWeather(uint32 id); - Weather* AddWeather(uint32 zone_id); - void RemoveWeather(uint32 zone_id); - - void SendFineWeatherUpdateToPlayer(Player* player); - - void Update(uint32 diff); + WeatherData const* GetWeatherData(uint32 zone_id); } #endif diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index fd56951ed..651d85785 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -884,7 +884,6 @@ void World::SetInitialWorldSettings() stmt->SetData(2, GitRevision::GetFullVersion()); LoginDatabase.Execute(stmt); - _timers[WUPDATE_WEATHERS].SetInterval(1 * IN_MILLISECONDS); _timers[WUPDATE_UPTIME].SetInterval(getIntConfig(CONFIG_UPTIME_UPDATE)*MINUTE * IN_MILLISECONDS); //Update "uptime" table based on configuration entry in minutes. @@ -1186,13 +1185,6 @@ void World::Update(uint32 diff) sWorldSessionMgr->UpdateSessions(diff); } - ///
  • Handle weather updates when the timer has passed - if (_timers[WUPDATE_WEATHERS].Passed()) - { - _timers[WUPDATE_WEATHERS].Reset(); - WeatherMgr::Update(uint32(_timers[WUPDATE_WEATHERS].GetInterval())); - } - ///
  • Clean logs table if (getIntConfig(CONFIG_LOGDB_CLEARTIME) > 0) // if not enabled, ignore the timer { diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 2f9169605..1674c975d 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -58,7 +58,6 @@ enum ShutdownExitCode : uint8 /// Timers for different object refresh rates enum WorldTimers { - WUPDATE_WEATHERS, WUPDATE_UPTIME, WUPDATE_EVENTS, WUPDATE_CLEANDB, diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 41546214c..4ca8b5b37 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1895,13 +1895,7 @@ public: Player* player = handler->GetSession()->GetPlayer(); uint32 zoneid = player->GetZoneId(); - Weather* weather = WeatherMgr::FindWeather(zoneid); - - if (!weather) - { - weather = WeatherMgr::AddWeather(zoneid); - } - + Weather* weather = player->GetMap()->GetOrGenerateZoneDefaultWeather(zoneid); if (!weather) { handler->SendErrorMessage(LANG_NO_WEATHER); diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPEP.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPEP.cpp index 57feefa55..af9c9a50a 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPEP.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPEP.cpp @@ -43,12 +43,12 @@ void OPvPCapturePointEP_EWT::ChangeState() // if changing from controlling alliance to horde or vice versa if (_oldState == OBJECTIVESTATE_ALLIANCE && _oldState != _state) { - sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_EWT_A)); + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_EWT_A).c_str()); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_EWT, TEAM_NEUTRAL); } else if (_oldState == OBJECTIVESTATE_HORDE && _oldState != _state) { - sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_EWT_H)); + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_EWT_H).c_str()); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_EWT, TEAM_NEUTRAL); } @@ -61,14 +61,16 @@ void OPvPCapturePointEP_EWT::ChangeState() artkit = 2; SummonSupportUnitAtNorthpassTower(TEAM_ALLIANCE); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_EWT, TEAM_ALLIANCE); - if (_oldState != _state) sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_EWT_A)); + if (_oldState != _state) + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_EWT_A).c_str()); break; case OBJECTIVESTATE_HORDE: m_TowerState = EP_TS_H; artkit = 1; SummonSupportUnitAtNorthpassTower(TEAM_HORDE); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_EWT, TEAM_HORDE); - if (_oldState != _state) sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_EWT_H)); + if (_oldState != _state) + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_EWT_H).c_str()); break; case OBJECTIVESTATE_NEUTRAL: m_TowerState = EP_TS_N; @@ -176,12 +178,12 @@ void OPvPCapturePointEP_NPT::ChangeState() // if changing from controlling alliance to horde or vice versa if (_oldState == OBJECTIVESTATE_ALLIANCE && _oldState != _state) { - sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_NPT_A)); + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_NPT_A).c_str()); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_NPT, TEAM_NEUTRAL); } else if (_oldState == OBJECTIVESTATE_HORDE && _oldState != _state) { - sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_NPT_H)); + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_NPT_H).c_str()); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_NPT, TEAM_NEUTRAL); } @@ -194,14 +196,16 @@ void OPvPCapturePointEP_NPT::ChangeState() artkit = 2; SummonGO(TEAM_ALLIANCE); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_NPT, TEAM_ALLIANCE); - if (_oldState != _state) sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_NPT_A)); + if (_oldState != _state) + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_NPT_A).c_str()); break; case OBJECTIVESTATE_HORDE: m_TowerState = EP_TS_H; artkit = 1; SummonGO(TEAM_HORDE); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_NPT, TEAM_HORDE); - if (_oldState != _state) sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_NPT_H)); + if (_oldState != _state) + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_NPT_H).c_str()); break; case OBJECTIVESTATE_NEUTRAL: m_TowerState = EP_TS_N; @@ -319,12 +323,12 @@ void OPvPCapturePointEP_CGT::ChangeState() // if changing from controlling alliance to horde or vice versa if (_oldState == OBJECTIVESTATE_ALLIANCE && _oldState != _state) { - sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_CGT_A)); + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_CGT_A).c_str()); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_CGT, TEAM_NEUTRAL); } else if (_oldState == OBJECTIVESTATE_HORDE && _oldState != _state) { - sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_CGT_H)); + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_CGT_H).c_str()); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_CGT, TEAM_NEUTRAL); } @@ -337,14 +341,16 @@ void OPvPCapturePointEP_CGT::ChangeState() artkit = 2; LinkGraveyard(TEAM_ALLIANCE); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_CGT, TEAM_ALLIANCE); - if (_oldState != _state) sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_CGT_A)); + if (_oldState != _state) + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_CGT_A).c_str()); break; case OBJECTIVESTATE_HORDE: m_TowerState = EP_TS_H; artkit = 1; LinkGraveyard(TEAM_HORDE); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_CGT, TEAM_HORDE); - if (_oldState != _state) sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_CGT_H)); + if (_oldState != _state) + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_CGT_H).c_str()); break; case OBJECTIVESTATE_NEUTRAL: m_TowerState = EP_TS_N; @@ -447,12 +453,12 @@ void OPvPCapturePointEP_PWT::ChangeState() // if changing from controlling alliance to horde or vice versa if (_oldState == OBJECTIVESTATE_ALLIANCE && _oldState != _state) { - sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_PWT_A)); + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_PWT_A).c_str()); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_PWT, TEAM_NEUTRAL); } else if (_oldState == OBJECTIVESTATE_HORDE && _oldState != _state) { - sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_PWT_H)); + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_LOSE_PWT_H).c_str()); ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_PWT, TEAM_NEUTRAL); } @@ -465,14 +471,16 @@ void OPvPCapturePointEP_PWT::ChangeState() SummonFlightMaster(TEAM_ALLIANCE); artkit = 2; ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_PWT, TEAM_ALLIANCE); - if (_oldState != _state) sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_PWT_A)); + if (_oldState != _state) + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_PWT_A).c_str()); break; case OBJECTIVESTATE_HORDE: m_TowerState = EP_TS_H; SummonFlightMaster(TEAM_HORDE); artkit = 1; ((OutdoorPvPEP*)_pvp)->SetControlledState(EP_PWT, TEAM_HORDE); - if (_oldState != _state) sWorldSessionMgr->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_PWT_H)); + if (_oldState != _state) + _pvp->GetMap()->SendZoneText(EP_GraveyardZone, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_EP_CAPTURE_PWT_H).c_str()); break; case OBJECTIVESTATE_NEUTRAL: m_TowerState = EP_TS_N; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp index c7c4f2297..16c7714e2 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp @@ -184,13 +184,13 @@ void OPvPCapturePointHP::ChangeState() field = HP_MAP_A[m_TowerType]; if (uint32 alliance_towers = ((OutdoorPvPHP*)_pvp)->GetAllianceTowersControlled()) ((OutdoorPvPHP*)_pvp)->SetAllianceTowersControlled(--alliance_towers); - sWorldSessionMgr->SendZoneText(OutdoorPvPHPBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(HP_LANG_LOSE_A[m_TowerType])); + _pvp->GetMap()->SendZoneText(OutdoorPvPHPBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(HP_LANG_LOSE_A[m_TowerType]).c_str()); break; case OBJECTIVESTATE_HORDE: field = HP_MAP_H[m_TowerType]; if (uint32 horde_towers = ((OutdoorPvPHP*)_pvp)->GetHordeTowersControlled()) ((OutdoorPvPHP*)_pvp)->SetHordeTowersControlled(--horde_towers); - sWorldSessionMgr->SendZoneText(OutdoorPvPHPBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(HP_LANG_LOSE_H[m_TowerType])); + _pvp->GetMap()->SendZoneText(OutdoorPvPHPBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(HP_LANG_LOSE_H[m_TowerType]).c_str()); break; case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: field = HP_MAP_N[m_TowerType]; @@ -227,7 +227,7 @@ void OPvPCapturePointHP::ChangeState() uint32 alliance_towers = ((OutdoorPvPHP*)_pvp)->GetAllianceTowersControlled(); if (alliance_towers < 3) ((OutdoorPvPHP*)_pvp)->SetAllianceTowersControlled(++alliance_towers); - sWorldSessionMgr->SendZoneText(OutdoorPvPHPBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(HP_LANG_CAPTURE_A[m_TowerType])); + _pvp->GetMap()->SendZoneText(OutdoorPvPHPBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(HP_LANG_CAPTURE_A[m_TowerType]).c_str()); break; } case OBJECTIVESTATE_HORDE: @@ -238,7 +238,7 @@ void OPvPCapturePointHP::ChangeState() uint32 horde_towers = ((OutdoorPvPHP*)_pvp)->GetHordeTowersControlled(); if (horde_towers < 3) ((OutdoorPvPHP*)_pvp)->SetHordeTowersControlled(++horde_towers); - sWorldSessionMgr->SendZoneText(OutdoorPvPHPBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(HP_LANG_CAPTURE_H[m_TowerType])); + _pvp->GetMap()->SendZoneText(OutdoorPvPHPBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(HP_LANG_CAPTURE_H[m_TowerType]).c_str()); break; } case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp index 712b8ad57..c659296de 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp @@ -197,9 +197,9 @@ void OPvPCapturePointNA::FactionTakeOver(TeamId teamId) if (m_ControllingFaction != TEAM_NEUTRAL) sGraveyard->RemoveGraveyardLink(NA_HALAA_GRAVEYARD, NA_HALAA_GRAVEYARD_ZONE, m_ControllingFaction, false); if (m_ControllingFaction == TEAM_ALLIANCE) - sWorldSessionMgr->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_LOSE_A)); + _pvp->GetMap()->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_LOSE_A).c_str()); else if (m_ControllingFaction == TEAM_HORDE) - sWorldSessionMgr->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_LOSE_H)); + _pvp->GetMap()->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_LOSE_H).c_str()); DespawnCreatures(GetControllingFaction() == TEAM_HORDE ? halaaNPCHorde : halaaNPCAlly); m_ControllingFaction = teamId; if (m_ControllingFaction != TEAM_NEUTRAL) @@ -221,7 +221,7 @@ void OPvPCapturePointNA::FactionTakeOver(TeamId teamId) _pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_HORDE_GUARDS_SHOW, 0); _pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_ALLIANCE_GUARDS_SHOW, 1); _pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_GUARDS_LEFT, m_GuardsAlive); - sWorldSessionMgr->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_CAPTURE_A)); + _pvp->GetMap()->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_CAPTURE_A).c_str()); } else { @@ -233,7 +233,7 @@ void OPvPCapturePointNA::FactionTakeOver(TeamId teamId) _pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_HORDE_GUARDS_SHOW, 1); _pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_ALLIANCE_GUARDS_SHOW, 0); _pvp->SendUpdateWorldState(WORLD_STATE_OPVP_NA_UI_GUARDS_LEFT, m_GuardsAlive); - sWorldSessionMgr->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_CAPTURE_H)); + _pvp->GetMap()->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_CAPTURE_H).c_str()); } UpdateWyvernRoostWorldState(NA_ROOST_S); UpdateWyvernRoostWorldState(NA_ROOST_N); @@ -637,7 +637,7 @@ bool OPvPCapturePointNA::Update(uint32 diff) { m_capturable = true; m_RespawnTimer = NA_RESPAWN_TIME; - sWorldSessionMgr->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_DEFENSELESS)); + _pvp->GetMap()->SendZoneText(NA_HALAA_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_NA_DEFENSELESS).c_str()); } else m_capturable = false; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp index 56449ef3e..5f020c3a4 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp @@ -106,7 +106,7 @@ bool OutdoorPvPSI::HandleAreaTrigger(Player* player, uint32 trigger) if (m_Gathered_A >= SI_MAX_RESOURCES) { TeamApplyBuff(TEAM_ALLIANCE, SI_CENARION_FAVOR, 0, player); - sWorldSessionMgr->SendZoneText(OutdoorPvPSIBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_SI_CAPTURE_A)); + GetMap()->SendZoneText(OutdoorPvPSIBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_SI_CAPTURE_A).c_str()); m_LastController = TEAM_ALLIANCE; m_Gathered_A = 0; m_Gathered_H = 0; @@ -132,7 +132,7 @@ bool OutdoorPvPSI::HandleAreaTrigger(Player* player, uint32 trigger) if (m_Gathered_H >= SI_MAX_RESOURCES) { TeamApplyBuff(TEAM_HORDE, SI_CENARION_FAVOR, 0, player); - sWorldSessionMgr->SendZoneText(OutdoorPvPSIBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_SI_CAPTURE_H)); + GetMap()->SendZoneText(OutdoorPvPSIBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_SI_CAPTURE_H).c_str()); m_LastController = TEAM_HORDE; m_Gathered_A = 0; m_Gathered_H = 0; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp index 595f3530d..e255c6708 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp @@ -400,14 +400,14 @@ void OPvPCapturePointTF::ChangeState() { if (uint32 alliance_towers = ((OutdoorPvPTF*)_pvp)->GetAllianceTowersControlled()) ((OutdoorPvPTF*)_pvp)->SetAllianceTowersControlled(--alliance_towers); - sWorldSessionMgr->SendZoneText(OutdoorPvPTFBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_TF_LOSE_A)); + _pvp->GetMap()->SendZoneText(OutdoorPvPTFBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_TF_LOSE_A).c_str()); } // if changing from controlling horde to alliance else if (_oldState == OBJECTIVESTATE_HORDE) { if (uint32 horde_towers = ((OutdoorPvPTF*)_pvp)->GetHordeTowersControlled()) ((OutdoorPvPTF*)_pvp)->SetHordeTowersControlled(--horde_towers); - sWorldSessionMgr->SendZoneText(OutdoorPvPTFBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_TF_LOSE_H)); + _pvp->GetMap()->SendZoneText(OutdoorPvPTFBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_TF_LOSE_H).c_str()); } uint32 artkit = 21; @@ -422,7 +422,7 @@ void OPvPCapturePointTF::ChangeState() if (alliance_towers < TF_TOWER_NUM) ((OutdoorPvPTF*)_pvp)->SetAllianceTowersControlled(++alliance_towers); - sWorldSessionMgr->SendZoneText(OutdoorPvPTFBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_TF_CAPTURE_A)); + _pvp->GetMap()->SendZoneText(OutdoorPvPTFBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_TF_CAPTURE_A).c_str()); for (PlayerSet::iterator itr = _activePlayers[0].begin(); itr != _activePlayers[0].end(); ++itr) if (Player* player = ObjectAccessor::FindPlayer(*itr)) @@ -437,7 +437,7 @@ void OPvPCapturePointTF::ChangeState() if (horde_towers < TF_TOWER_NUM) ((OutdoorPvPTF*)_pvp)->SetHordeTowersControlled(++horde_towers); - sWorldSessionMgr->SendZoneText(OutdoorPvPTFBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_TF_CAPTURE_H)); + _pvp->GetMap()->SendZoneText(OutdoorPvPTFBuffZones[0], sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_TF_CAPTURE_H).c_str()); for (PlayerSet::iterator itr = _activePlayers[1].begin(); itr != _activePlayers[1].end(); ++itr) if (Player* player = ObjectAccessor::FindPlayer(*itr)) diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.cpp index 9dfd2876f..9a601edc6 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.cpp @@ -82,14 +82,14 @@ void OPvPCapturePointZM_Beacon::ChangeState() { if (uint32 alliance_towers = ((OutdoorPvPZM*)_pvp)->GetAllianceTowersControlled()) ((OutdoorPvPZM*)_pvp)->SetAllianceTowersControlled(--alliance_towers); - sWorldSessionMgr->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(ZMBeaconLoseA[m_TowerType])); + _pvp->GetMap()->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(ZMBeaconLoseA[m_TowerType]).c_str()); } // if changing from controlling horde to alliance else if (_oldState == OBJECTIVESTATE_HORDE) { if (uint32 horde_towers = ((OutdoorPvPZM*)_pvp)->GetHordeTowersControlled()) ((OutdoorPvPZM*)_pvp)->SetHordeTowersControlled(--horde_towers); - sWorldSessionMgr->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(ZMBeaconLoseH[m_TowerType])); + _pvp->GetMap()->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(ZMBeaconLoseH[m_TowerType]).c_str()); } switch (_state) @@ -100,7 +100,7 @@ void OPvPCapturePointZM_Beacon::ChangeState() uint32 alliance_towers = ((OutdoorPvPZM*)_pvp)->GetAllianceTowersControlled(); if (alliance_towers < ZM_NUM_BEACONS) ((OutdoorPvPZM*)_pvp)->SetAllianceTowersControlled(++alliance_towers); - sWorldSessionMgr->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(ZMBeaconCaptureA[m_TowerType])); + _pvp->GetMap()->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(ZMBeaconCaptureA[m_TowerType]).c_str()); break; } case OBJECTIVESTATE_HORDE: @@ -109,7 +109,7 @@ void OPvPCapturePointZM_Beacon::ChangeState() uint32 horde_towers = ((OutdoorPvPZM*)_pvp)->GetHordeTowersControlled(); if (horde_towers < ZM_NUM_BEACONS) ((OutdoorPvPZM*)_pvp)->SetHordeTowersControlled(++horde_towers); - sWorldSessionMgr->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(ZMBeaconCaptureH[m_TowerType])); + _pvp->GetMap()->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(ZMBeaconCaptureH[m_TowerType]).c_str()); break; } case OBJECTIVESTATE_NEUTRAL: @@ -227,7 +227,7 @@ int32 OPvPCapturePointZM_Graveyard::HandleOpenGo(Player* player, GameObject* go) if (player->HasAura(ZM_BATTLE_STANDARD_A) && m_GraveyardState != ZM_GRAVEYARD_A) { if (m_GraveyardState == ZM_GRAVEYARD_H) - sWorldSessionMgr->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_ZM_LOSE_GY_H)); + _pvp->GetMap()->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_ZM_LOSE_GY_H).c_str()); m_GraveyardState = ZM_GRAVEYARD_A; DelObject(0); // only one gotype is used in the whole outdoor pvp, no need to call it a constant AddObject(0, ZM_Banner_A.entry, ZM_Banner_A.map, ZM_Banner_A.x, ZM_Banner_A.y, ZM_Banner_A.z, ZM_Banner_A.o, ZM_Banner_A.rot0, ZM_Banner_A.rot1, ZM_Banner_A.rot2, ZM_Banner_A.rot3); @@ -235,12 +235,12 @@ int32 OPvPCapturePointZM_Graveyard::HandleOpenGo(Player* player, GameObject* go) sGraveyard->AddGraveyardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, TEAM_ALLIANCE, false); // add gy _pvp->TeamApplyBuff(TEAM_ALLIANCE, ZM_CAPTURE_BUFF, 0, player); player->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_A); - sWorldSessionMgr->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_ZM_CAPTURE_GY_A)); + _pvp->GetMap()->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_ZM_CAPTURE_GY_A).c_str()); } else if (player->HasAura(ZM_BATTLE_STANDARD_H) && m_GraveyardState != ZM_GRAVEYARD_H) { if (m_GraveyardState == ZM_GRAVEYARD_A) - sWorldSessionMgr->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_ZM_LOSE_GY_A)); + _pvp->GetMap()->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_ZM_LOSE_GY_A).c_str()); m_GraveyardState = ZM_GRAVEYARD_H; DelObject(0); // only one gotype is used in the whole outdoor pvp, no need to call it a constant AddObject(0, ZM_Banner_H.entry, ZM_Banner_H.map, ZM_Banner_H.x, ZM_Banner_H.y, ZM_Banner_H.z, ZM_Banner_H.o, ZM_Banner_H.rot0, ZM_Banner_H.rot1, ZM_Banner_H.rot2, ZM_Banner_H.rot3); @@ -248,7 +248,7 @@ int32 OPvPCapturePointZM_Graveyard::HandleOpenGo(Player* player, GameObject* go) sGraveyard->AddGraveyardLink(ZM_GRAVEYARD_ID, ZM_GRAVEYARD_ZONE, TEAM_HORDE, false); // add gy _pvp->TeamApplyBuff(TEAM_HORDE, ZM_CAPTURE_BUFF, 0, player); player->RemoveAurasDueToSpell(ZM_BATTLE_STANDARD_H); - sWorldSessionMgr->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_ZM_CAPTURE_GY_H)); + _pvp->GetMap()->SendZoneText(ZM_GRAVEYARD_ZONE, sObjectMgr->GetAcoreStringForDBCLocale(LANG_OPVP_ZM_CAPTURE_GY_H).c_str()); } UpdateTowerState(); } diff --git a/src/server/scripts/World/scourge_invasion.cpp b/src/server/scripts/World/scourge_invasion.cpp index dc61a79ce..9169d3d97 100644 --- a/src/server/scripts/World/scourge_invasion.cpp +++ b/src/server/scripts/World/scourge_invasion.cpp @@ -63,14 +63,8 @@ struct npc_herald_of_the_lich_king : public ScriptedAI void UpdateWeather(bool startEvent) { - if (Weather* weather = WeatherMgr::FindWeather(me->GetZoneId())) - { - if (startEvent) - weather->SetWeather(WEATHER_TYPE_STORM, 0.25f); - else - weather->SetWeather(WEATHER_TYPE_RAIN, 0.0f); - } - else if (Weather* weather = WeatherMgr::AddWeather(me->GetZoneId())) + Weather* weather = me->GetMap()->GetOrGenerateZoneDefaultWeather(me->GetZoneId()); + if (weather) { if (startEvent) weather->SetWeather(WEATHER_TYPE_STORM, 0.25f); @@ -956,14 +950,8 @@ struct npc_pallid_horror : public ScriptedAI void UpdateWeather(bool startEvent) { - if (Weather* weather = WeatherMgr::FindWeather(me->GetZoneId())) - { - if (startEvent) - weather->SetWeather(WEATHER_TYPE_STORM, 0.25f); - else - weather->SetWeather(WEATHER_TYPE_RAIN, 0.0f); - } - else if (Weather* weather = WeatherMgr::AddWeather(me->GetZoneId())) + Weather* weather = me->GetMap()->GetOrGenerateZoneDefaultWeather(me->GetZoneId()); + if (weather) { if (startEvent) weather->SetWeather(WEATHER_TYPE_STORM, 0.25f); From 5f61d641efc21a212cc91fa65cc1b7d065538b2d Mon Sep 17 00:00:00 2001 From: Seamthesis Date: Mon, 29 Sep 2025 16:44:24 +0200 Subject: [PATCH 6/8] refactor(Core/Player): small clean in Player.h (#23018) Co-authored-by: Rykles <219719782+Seamthesis@users.noreply.github.com> --- src/server/game/Entities/Player/Player.h | 7 ------- src/server/game/Entities/Player/PlayerStorage.cpp | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 3204f4241..c8dd9fc7a 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1090,11 +1090,6 @@ public: SetFloatValue(UNIT_FIELD_COMBATREACH, scale * DEFAULT_COMBAT_REACH); } - [[nodiscard]] bool hasSpanishClient() - { - return GetSession()->GetSessionDbLocaleIndex() == LOCALE_esES || GetSession()->GetSessionDbLocaleIndex() == LOCALE_esMX; - } - bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0, Unit* target = nullptr, bool newInstance = false); bool TeleportTo(WorldLocation const& loc, uint32 options = 0, Unit* target = nullptr) { @@ -1339,7 +1334,6 @@ public: { return StoreItem(dest, pItem, update); } - Item* BankItem(uint16 pos, Item* pItem, bool update); void RemoveItem(uint8 bag, uint8 slot, bool update, bool swap = false); void MoveItemFromInventory(uint8 bag, uint8 slot, bool update); // in trade, auction, guild bank, mail.... @@ -1600,7 +1594,6 @@ public: void SetBindPoint(ObjectGuid guid); void SendTalentWipeConfirm(ObjectGuid guid); void ResetPetTalents(); - void CalcRage(uint32 damage, bool attacker); void RegenerateAll(); void Regenerate(Powers power); void RegenerateHealth(); diff --git a/src/server/game/Entities/Player/PlayerStorage.cpp b/src/server/game/Entities/Player/PlayerStorage.cpp index 78c1ad0ef..d45533ad6 100644 --- a/src/server/game/Entities/Player/PlayerStorage.cpp +++ b/src/server/game/Entities/Player/PlayerStorage.cpp @@ -1536,7 +1536,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& des } ////////////////////////////////////////////////////////////////////////// -InventoryResult Player::CanStoreItems(Item** pItems, int count) const +InventoryResult Player::CanStoreItems(Item** pItems, int32 count) const { Item* pItem2; From 6ad664fa8f9174e360b68c23e596fe43cf224e14 Mon Sep 17 00:00:00 2001 From: Rocco Silipo <108557877+Rorschach91@users.noreply.github.com> Date: Mon, 29 Sep 2025 16:58:46 +0200 Subject: [PATCH 7/8] fix(DB/SmartAI) Update Bleeding Hollow Necrolyte and Tunneler AI. (#23057) --- .../pending_db_world/Update_SmartAI.sql | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 data/sql/updates/pending_db_world/Update_SmartAI.sql diff --git a/data/sql/updates/pending_db_world/Update_SmartAI.sql b/data/sql/updates/pending_db_world/Update_SmartAI.sql new file mode 100644 index 000000000..8bbf5a1df --- /dev/null +++ b/data/sql/updates/pending_db_world/Update_SmartAI.sql @@ -0,0 +1,18 @@ + +-- Update SmartAI (Bleeding Hollow Necrolyte and Tunneler) +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE (`entry` IN (16968, 19422)); + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` IN (16968, 19422)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(19422, 0, 0, 0, 0, 0, 100, 0, 0, 0, 2400, 3800, 0, 0, 11, 9053, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Bleeding Hollow Necrolyte - In Combat - Cast \'Fireball\''), +(19422, 0, 1, 0, 0, 0, 100, 0, 8000, 12000, 30000, 45000, 0, 0, 11, 34073, 33, 0, 0, 0, 0, 5, 0, 0, 0, 34073, 0, 0, 0, 0, 'Bleeding Hollow Necrolyte - In Combat - Cast \'Curse of the Bleeding Hollow\''), +(19422, 0, 2, 0, 2, 0, 100, 512, 0, 15, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bleeding Hollow Necrolyte - Between 0-15% Health - Flee For Assist'), +(19422, 0, 3, 0, 5, 0, 100, 1, 0, 0, 0, 0, 0, 0, 11, 34019, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Bleeding Hollow Necrolyte - On Killed Unit - Cast \'Raise Dead\' (No Repeat)'), +(16968, 0, 0, 1, 25, 0, 100, 512, 0, 0, 0, 0, 0, 0, 18, 33554432, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tunneler - On Reset - Set Flags Not Selectable'), +(16968, 0, 1, 2, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 11, 29147, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tunneler - On Reset - Cast \'Tunnel Bore Passive\''), +(16968, 0, 2, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 90, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tunneler - On Reset - Set Flag Standstate Submerged'), +(16968, 0, 3, 4, 4, 0, 100, 512, 0, 0, 0, 0, 0, 0, 19, 33554432, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tunneler - On Aggro - Remove Flags Not Selectable'), +(16968, 0, 4, 5, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 28, 29147, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tunneler - On Aggro - Remove Aura \'Tunnel Bore Passive\''), +(16968, 0, 5, 0, 61, 0, 100, 513, 0, 0, 0, 0, 0, 0, 91, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Tunneler - On Aggro - Remove FlagStandstate Submerged'), +(16968, 0, 6, 0, 0, 0, 100, 0, 1000, 6000, 8000, 11000, 0, 0, 11, 32738, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Tunneler - In Combat - Cast \'Bore\''), +(16968, 0, 7, 0, 9, 0, 100, 0, 0, 0, 2000, 3500, 4, 50, 11, 31747, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Tunneler - Within 4-50 Range - Cast \'Poison\''); From 5cbfacfdff6e5b44bae63e4864470234eff01a28 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 29 Sep 2025 15:03:42 +0000 Subject: [PATCH 8/8] chore(DB): import pending files Referenced commit(s): 6ad664fa8f9174e360b68c23e596fe43cf224e14 --- .../Update_SmartAI.sql => db_world/2025_09_29_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/Update_SmartAI.sql => db_world/2025_09_29_00.sql} (98%) diff --git a/data/sql/updates/pending_db_world/Update_SmartAI.sql b/data/sql/updates/db_world/2025_09_29_00.sql similarity index 98% rename from data/sql/updates/pending_db_world/Update_SmartAI.sql rename to data/sql/updates/db_world/2025_09_29_00.sql index 8bbf5a1df..4fb84247d 100644 --- a/data/sql/updates/pending_db_world/Update_SmartAI.sql +++ b/data/sql/updates/db_world/2025_09_29_00.sql @@ -1,3 +1,4 @@ +-- DB update 2025_09_28_01 -> 2025_09_29_00 -- Update SmartAI (Bleeding Hollow Necrolyte and Tunneler) UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE (`entry` IN (16968, 19422));