From 546c4f8942f8aa511012599bf4161f582861d735 Mon Sep 17 00:00:00 2001 From: SilentCLD Date: Sun, 27 Mar 2022 05:28:41 +0100 Subject: [PATCH] feat(Core/Scripts): Spirit towers reset to neutral 6 hours after capture and save WorldState (#11030) --- .../scripts/OutdoorPvP/OutdoorPvPTF.cpp | 122 ++++++++++++++++-- src/server/scripts/OutdoorPvP/OutdoorPvPTF.h | 20 ++- 2 files changed, 132 insertions(+), 10 deletions(-) diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp index cb611c3ec..6cc2876fd 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp @@ -20,17 +20,18 @@ #include "MapMgr.h" #include "ObjectMgr.h" #include "OutdoorPvP.h" -#include "OutdoorPvPMgr.h" #include "Player.h" #include "ScriptMgr.h" #include "World.h" #include "WorldPacket.h" +#include "GameTime.h" OutdoorPvPTF::OutdoorPvPTF() { m_TypeId = OUTDOOR_PVP_TF; m_IsLocked = false; + m_JustLocked = false; m_LockTimer = TF_LOCK_TIME; m_LockTimerUpdate = 0; @@ -105,6 +106,71 @@ void OutdoorPvPTF::SendRemoveWorldStates(Player* player) } } +void OutdoorPvPTF::SaveRequiredWorldStates() const +{ + sWorld->setWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled); + sWorld->setWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled); + + sWorld->setWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, m_IsLocked); + + // Save expiry as unix + uint32 const lockExpireTime = GameTime::GetGameTime().count() + (m_LockTimer / IN_MILLISECONDS); + sWorld->setWorldState(TF_UI_LOCKED_TIME_HOURS, lockExpireTime); +} + +void OutdoorPvPTF::ResetZoneToTeamControlled(TeamId team) +{ + switch (team) + { + case TEAM_HORDE: + m_HordeTowersControlled = TF_TOWER_NUM; + m_AllianceTowersControlled = 0; + break; + case TEAM_ALLIANCE: + m_HordeTowersControlled = 0; + m_AllianceTowersControlled = TF_TOWER_NUM; + break; + case TEAM_NEUTRAL: + m_HordeTowersControlled = 0; + m_AllianceTowersControlled = 0; + break; + } + + for (auto& [guid, tower] : m_capturePoints) + { + dynamic_cast(tower)->ResetToTeamControlled(team); + } + + SendUpdateWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled); + SendUpdateWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled); +} + +void OPvPCapturePointTF::ResetToTeamControlled(TeamId team) +{ + switch (team) + { + case TEAM_HORDE: + m_State = OBJECTIVESTATE_HORDE; + m_OldState = OBJECTIVESTATE_HORDE; + m_team = TEAM_HORDE; + break; + case TEAM_ALLIANCE: + m_State = OBJECTIVESTATE_ALLIANCE; + m_OldState = OBJECTIVESTATE_ALLIANCE; + m_team = TEAM_ALLIANCE; + break; + case TEAM_NEUTRAL: + m_State = OBJECTIVESTATE_NEUTRAL; + m_OldState = OBJECTIVESTATE_NEUTRAL; + m_team = TEAM_NEUTRAL; + break; + } + + m_value = 0.0f; + ChangeState(); + SendChangePhase(); +} + void OPvPCapturePointTF::UpdateTowerState() { m_PvP->SendUpdateWorldState(uint32(TFTowerWorldStates[m_TowerType].n), uint32(bool(m_TowerState & TF_TOWERSTATE_N))); @@ -141,6 +207,7 @@ bool OutdoorPvPTF::Update(uint32 diff) { TeamApplyBuff(TEAM_ALLIANCE, TF_CAPTURE_BUFF); m_IsLocked = true; + m_JustLocked = true; SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, uint32(0)); SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE, uint32(0)); SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE, uint32(1)); @@ -150,6 +217,7 @@ bool OutdoorPvPTF::Update(uint32 diff) { TeamApplyBuff(TEAM_HORDE, TF_CAPTURE_BUFF); m_IsLocked = true; + m_JustLocked = true; SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, uint32(0)); SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE, uint32(1)); SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE, uint32(0)); @@ -160,17 +228,29 @@ bool OutdoorPvPTF::Update(uint32 diff) TeamCastSpell(TEAM_ALLIANCE, -TF_CAPTURE_BUFF); TeamCastSpell(TEAM_HORDE, -TF_CAPTURE_BUFF); } + SendUpdateWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled); SendUpdateWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled); } + if (m_IsLocked) { + if (m_JustLocked) + { + m_JustLocked = false; + SaveRequiredWorldStates(); + } + // lock timer is down, release lock if (m_LockTimer < diff) { m_LockTimer = TF_LOCK_TIME; m_LockTimerUpdate = 0; m_IsLocked = false; + + ResetZoneToTeamControlled(TEAM_NEUTRAL); + SaveRequiredWorldStates(); + SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, uint32(1)); SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, uint32(0)); SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE, uint32(0)); @@ -182,20 +262,21 @@ bool OutdoorPvPTF::Update(uint32 diff) if (m_LockTimerUpdate < diff) { m_LockTimerUpdate = TF_LOCK_TIME_UPDATE; - uint32 minutes_left = m_LockTimer / 60000; - hours_left = minutes_left / 60; - minutes_left -= hours_left * 60; - second_digit = minutes_left % 10; - first_digit = minutes_left / 10; + RecalculateClientUILockTime(); SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT, first_digit); SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT, second_digit); SendUpdateWorldState(TF_UI_LOCKED_TIME_HOURS, hours_left); } - else m_LockTimerUpdate -= diff; + else + { + m_LockTimerUpdate -= diff; + } + m_LockTimer -= diff; } } + return changed; } @@ -251,7 +332,8 @@ bool OutdoorPvPTF::SetupOutdoorPvP() m_AllianceTowersControlled = 0; m_HordeTowersControlled = 0; - m_IsLocked = false; + m_IsLocked = bool(sWorld->getWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY)); + m_JustLocked = false; m_LockTimer = TF_LOCK_TIME; m_LockTimerUpdate = 0; hours_left = 6; @@ -270,6 +352,30 @@ bool OutdoorPvPTF::SetupOutdoorPvP() AddCapturePoint(new OPvPCapturePointTF(this, TF_TOWER_SE)); AddCapturePoint(new OPvPCapturePointTF(this, TF_TOWER_S)); + if (m_IsLocked) + { + // Core shutdown while locked -- init from latest known data in WorldState + // Convert from unix + int32 const lockRemainingTime = int32((sWorld->getWorldState(TF_UI_LOCKED_TIME_HOURS) - GameTime::GetGameTime().count()) * IN_MILLISECONDS); + if (lockRemainingTime > 0) + { + m_LockTimer = lockRemainingTime; + RecalculateClientUILockTime(); + + uint32 const hordeTowers = uint32(sWorld->getWorldState(TF_UI_TOWER_COUNT_H)); + uint32 const allianceTowers = uint32(sWorld->getWorldState(TF_UI_TOWER_COUNT_A)); + TeamId const controllingTeam = hordeTowers > allianceTowers ? TEAM_HORDE : TEAM_ALLIANCE; + + ResetZoneToTeamControlled(controllingTeam); + } + else + { + // Lock expired while core was offline + m_IsLocked = false; + SaveRequiredWorldStates(); + } + } + return true; } diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h index c91f6a3be..9900c644b 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h @@ -32,10 +32,10 @@ const uint32 OutdoorPvPTFBuffZones[OutdoorPvPTFBuffZonesNum] = }; // locked for 6 hours after capture -const uint32 TF_LOCK_TIME = 3600 * 6 * 1000; +const uint32 TF_LOCK_TIME = 6 * HOUR * IN_MILLISECONDS; // update lock timer every 1/4 minute (overkill, but this way it's sure the timer won't "jump" 2 minutes at once.) -const uint32 TF_LOCK_TIME_UPDATE = 15000; +const uint32 TF_LOCK_TIME_UPDATE = 15 * IN_MILLISECONDS; // blessing of auchindoun #define TF_CAPTURE_BUFF 33377 @@ -138,6 +138,8 @@ public: bool HandlePlayerEnter(Player* player) override; void HandlePlayerLeave(Player* player) override; + void ResetToTeamControlled(TeamId team); + void UpdateTowerState(); protected: @@ -162,6 +164,19 @@ public: void SendRemoveWorldStates(Player* player) override; + void SaveRequiredWorldStates() const; + + void ResetZoneToTeamControlled(TeamId team); + + void RecalculateClientUILockTime() + { + uint32 minutes_left = m_LockTimer / 60000; + hours_left = minutes_left / 60; + minutes_left -= hours_left * 60; + second_digit = minutes_left % 10; + first_digit = minutes_left / 10; + } + uint32 GetAllianceTowersControlled() const; void SetAllianceTowersControlled(uint32 count); @@ -172,6 +187,7 @@ public: private: bool m_IsLocked; + bool m_JustLocked; uint32 m_LockTimer; uint32 m_LockTimerUpdate;