diff options
23 files changed, 1410 insertions, 1564 deletions
diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index 030ca20fec8..ba2d14e9500 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -62,9 +62,6 @@ Battlefield::Battlefield(Map* map) Battlefield::~Battlefield() { - for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - delete itr->second; - for (GraveyardVect::const_iterator itr = m_GraveyardList.begin(); itr != m_GraveyardList.end(); ++itr) delete *itr; } @@ -114,9 +111,6 @@ void Battlefield::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/) } } - for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - itr->second->HandlePlayerLeave(player); - m_InvitedPlayers[player->GetTeamId()].erase(player->GetGUID()); m_PlayersWillBeKick[player->GetTeamId()].erase(player->GetGUID()); m_players[player->GetTeamId()].erase(player->GetGUID()); @@ -145,7 +139,6 @@ bool Battlefield::Update(uint32 diff) OnStartGrouping(); } - bool objective_changed = false; if (IsWarTime()) { if (m_uiKickAfkPlayersTimer <= diff) @@ -175,13 +168,9 @@ bool Battlefield::Update(uint32 diff) } else m_uiKickDontAcceptTimer -= diff; - - for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - if (itr->second->Update(diff)) - objective_changed = true; } - return objective_changed; + return false; } void Battlefield::InvitePlayersInZoneToQueue() @@ -285,6 +274,42 @@ void Battlefield::InitStalker(uint32 entry, Position const& pos) TC_LOG_ERROR("bg.battlefield", "Battlefield::InitStalker: Could not spawn Stalker (Creature entry {}), zone messages will be unavailable!", entry); } +void Battlefield::ProcessEvent(WorldObject* target, uint32 eventId, WorldObject* invoker) +{ + ZoneScript::ProcessEvent(target, eventId, invoker); + + if (invoker) + { + if (GameObject* gameobject = invoker->ToGameObject()) + { + if (gameobject->GetGoType() == GAMEOBJECT_TYPE_CONTROL_ZONE) + { + if (!ControlZoneHandlers.contains(gameobject->GetEntry())) + return; + + auto controlzone = gameobject->GetGOInfo()->controlZone; + BattlefieldControlZoneHandler& handler = *ControlZoneHandlers[invoker->GetEntry()]; + if (eventId == controlzone.CaptureEventAlliance) + handler.HandleCaptureEventAlliance(gameobject); + else if (eventId == controlzone.CaptureEventHorde) + handler.HandleCaptureEventHorde(gameobject); + else if (eventId == controlzone.ContestedEventAlliance) + handler.HandleContestedEventAlliance(gameobject); + else if (eventId == controlzone.ContestedEventHorde) + handler.HandleContestedEventHorde(gameobject); + else if (eventId == controlzone.NeutralEventAlliance) + handler.HandleNeutralEventAlliance(gameobject); + else if (eventId == controlzone.NeutralEventHorde) + handler.HandleNeutralEventHorde(gameobject); + else if (eventId == controlzone.ProgressEventAlliance) + handler.HandleProgressEventAlliance(gameobject); + else if (eventId == controlzone.ProgressEventHorde) + handler.HandleProgressEventHorde(gameobject); + } + } + } +} + void Battlefield::KickAfkPlayers() { for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team) @@ -435,25 +460,6 @@ void Battlefield::SendWarning(uint8 id, WorldObject const* target /*= nullptr*/) sCreatureTextMgr->SendChat(stalker, id, target); } -void Battlefield::AddCapturePoint(BfCapturePoint* cp) -{ - Battlefield::BfCapturePointMap::iterator i = m_capturePoints.find(cp->GetCapturePointEntry()); - if (i != m_capturePoints.end()) - { - TC_LOG_ERROR("bg.battlefield", "Battlefield::AddCapturePoint: CapturePoint {} already exists!", cp->GetCapturePointEntry()); - delete i->second; - } - m_capturePoints[cp->GetCapturePointEntry()] = cp; -} - -BfCapturePoint* Battlefield::GetCapturePoint(uint32 entry) const -{ - Battlefield::BfCapturePointMap::const_iterator itr = m_capturePoints.find(entry); - if (itr != m_capturePoints.end()) - return itr->second; - return nullptr; -} - void Battlefield::RegisterZone(uint32 zoneId) { sBattlefieldMgr->AddZone(zoneId, this); @@ -722,275 +728,11 @@ GameObject* Battlefield::GetGameObject(ObjectGuid guid) // ******************* CapturePoint ********************** // ******************************************************* -BfCapturePoint::BfCapturePoint(Battlefield* battlefield) : m_Bf(battlefield), m_capturePointGUID() -{ - m_team = TEAM_NEUTRAL; - m_value = 0; - m_minValue = 0.0f; - m_maxValue = 0.0f; - m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL; - m_OldState = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL; - m_capturePointEntry = 0; - m_neutralValuePct = 0; - m_maxSpeed = 0; -} - -bool BfCapturePoint::HandlePlayerEnter(Player* player) -{ - if (!m_capturePointGUID.IsEmpty()) - { - if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID)) - { - player->SendUpdateWorldState(capturePoint->GetGOInfo()->controlZone.worldState1, 1); - player->SendUpdateWorldState(capturePoint->GetGOInfo()->controlZone.worldstate2, uint32(ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f))); - player->SendUpdateWorldState(capturePoint->GetGOInfo()->controlZone.worldstate3, m_neutralValuePct); - } - } - - return m_activePlayers[player->GetTeamId()].insert(player->GetGUID()).second; -} - -GuidSet::iterator BfCapturePoint::HandlePlayerLeave(Player* player) +BattlefieldControlZoneHandler::BattlefieldControlZoneHandler(Battlefield* bf) : _battlefield(bf) { - if (!m_capturePointGUID.IsEmpty()) - if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID)) - player->SendUpdateWorldState(capturePoint->GetGOInfo()->controlZone.worldState1, 0); - - GuidSet::iterator current = m_activePlayers[player->GetTeamId()].find(player->GetGUID()); - - if (current == m_activePlayers[player->GetTeamId()].end()) - return current; // return end() - - m_activePlayers[player->GetTeamId()].erase(current++); - return current; -} - -void BfCapturePoint::SendChangePhase() -{ - if (!m_capturePointGUID) - return; - - if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID)) - { - // send this too, sometimes the slider disappears, dunno why :( - SendUpdateWorldState(capturePoint->GetGOInfo()->controlZone.worldState1, 1); - // send these updates to only the ones in this objective - SendUpdateWorldState(capturePoint->GetGOInfo()->controlZone.worldstate2, (uint32)std::ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f)); - // send this too, sometimes it resets :S - SendUpdateWorldState(capturePoint->GetGOInfo()->controlZone.worldstate3, m_neutralValuePct); - } -} - -bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint) -{ - ASSERT(capturePoint); - - TC_LOG_DEBUG("bg.battlefield", "Creating capture point {}", capturePoint->GetEntry()); - - m_capturePointGUID = capturePoint->GetGUID(); - m_capturePointEntry = capturePoint->GetEntry(); - - // check info existence - GameObjectTemplate const* goinfo = capturePoint->GetGOInfo(); - if (goinfo->type != GAMEOBJECT_TYPE_CONTROL_ZONE) - { - TC_LOG_ERROR("misc", "OutdoorPvP: GO {} is not a capture point!", capturePoint->GetEntry()); - return false; - } - - // get the needed values from goinfo - m_maxValue = goinfo->controlZone.maxTime; - m_maxSpeed = m_maxValue / (goinfo->controlZone.minTime ? goinfo->controlZone.minTime : 60); - m_neutralValuePct = goinfo->controlZone.neutralPercent; - m_minValue = m_maxValue * goinfo->controlZone.neutralPercent / 100; - - if (m_team == TEAM_ALLIANCE) - { - m_value = m_maxValue; - m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE; - } - else - { - m_value = -m_maxValue; - m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE; - } - - return true; -} - -GameObject* BfCapturePoint::GetCapturePointGo() -{ - return m_Bf->GetGameObject(m_capturePointGUID); -} - -bool BfCapturePoint::DelCapturePoint() -{ - if (!m_capturePointGUID.IsEmpty()) - { - if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID)) - { - capturePoint->SetRespawnTime(0); // not save respawn time - capturePoint->Delete(); - capturePoint = nullptr; - } - m_capturePointGUID.Clear(); - } - - return true; -} - -bool BfCapturePoint::Update(uint32 diff) -{ - if (!m_capturePointGUID) - return false; - - if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID)) - { - float radius = capturePoint->GetGOInfo()->controlZone.radius; - - for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team) - { - for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end();) - { - if (Player* player = ObjectAccessor::FindPlayer(*itr)) - { - if (!capturePoint->IsWithinDistInMap(player, radius) || !player->IsOutdoorPvPActive()) - itr = HandlePlayerLeave(player); - else - ++itr; - } - else - ++itr; - } - } - - std::list<Player*> players; - Trinity::AnyPlayerInObjectRangeCheck checker(capturePoint, radius); - Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(capturePoint, players, checker); - Cell::VisitWorldObjects(capturePoint, searcher, radius); - - for (std::list<Player*>::iterator itr = players.begin(); itr != players.end(); ++itr) - if ((*itr)->IsOutdoorPvPActive()) - if (m_activePlayers[(*itr)->GetTeamId()].insert((*itr)->GetGUID()).second) - HandlePlayerEnter(*itr); - } - - // get the difference of numbers - float fact_diff = ((float) m_activePlayers[TEAM_ALLIANCE].size() - (float) m_activePlayers[TEAM_HORDE].size()) * diff / float(BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL); - if (G3D::fuzzyEq(fact_diff, 0.0f)) - return false; - - uint32 Challenger = 0; - float maxDiff = m_maxSpeed * diff; - - if (fact_diff < 0) - { - // horde is in majority, but it's already horde-controlled -> no change - if (m_State == BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE && m_value <= -m_maxValue) - return false; - - if (fact_diff < -maxDiff) - fact_diff = -maxDiff; - - Challenger = HORDE; - } - else - { - // ally is in majority, but it's already ally-controlled -> no change - if (m_State == BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE && m_value >= m_maxValue) - return false; - - if (fact_diff > maxDiff) - fact_diff = maxDiff; - - Challenger = ALLIANCE; - } - - float oldValue = m_value; - TeamId oldTeam = m_team; - - m_OldState = m_State; - - m_value += fact_diff; - - if (m_value < -m_minValue) // red - { - if (m_value < -m_maxValue) - m_value = -m_maxValue; - m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE; - m_team = TEAM_HORDE; - } - else if (m_value > m_minValue) // blue - { - if (m_value > m_maxValue) - m_value = m_maxValue; - m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE; - m_team = TEAM_ALLIANCE; - } - else if (oldValue * m_value <= 0) // grey, go through mid point - { - // if challenger is ally, then n->a challenge - if (Challenger == ALLIANCE) - m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE; - // if challenger is horde, then n->h challenge - else if (Challenger == HORDE) - m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE; - m_team = TEAM_NEUTRAL; - } - else // grey, did not go through mid point - { - // old phase and current are on the same side, so one team challenges the other - if (Challenger == ALLIANCE && (m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE || m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE)) - m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE; - else if (Challenger == HORDE && (m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE || m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE)) - m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE; - m_team = TEAM_NEUTRAL; - } - - if (G3D::fuzzyNe(m_value, oldValue)) - SendChangePhase(); - - if (m_OldState != m_State) - { - //TC_LOG_ERROR("bg.battlefield", "{}->{}", m_OldState, m_State); - if (oldTeam != m_team) - ChangeTeam(oldTeam); - return true; - } - - return false; -} - -void BfCapturePoint::SendUpdateWorldState(uint32 field, uint32 value) -{ - for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team) - for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) // send to all players present in the area - if (Player* player = ObjectAccessor::FindPlayer(*itr)) - player->SendUpdateWorldState(field, value); -} - -void BfCapturePoint::SendObjectiveComplete(uint32 id, ObjectGuid guid) -{ - uint8 team; - switch (m_State) - { - case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE: - team = TEAM_ALLIANCE; - break; - case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE: - team = TEAM_HORDE; - break; - default: - return; - } - - // send to all players present in the area - for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) - if (Player* player = ObjectAccessor::FindPlayer(*itr)) - player->KilledMonsterCredit(id, guid); } -bool BfCapturePoint::IsInsideObjective(Player* player) const +Battlefield* BattlefieldControlZoneHandler::GetBattlefield() { - return m_activePlayers[player->GetTeamId()].find(player->GetGUID()) != m_activePlayers[player->GetTeamId()].end(); + return _battlefield; } diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index fb95918d7a5..4d293eeaf5c 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -22,6 +22,7 @@ #include "SharedDefines.h" #include "ZoneScript.h" #include <map> +#include <memory> enum BattlefieldTypes { @@ -92,70 +93,16 @@ namespace WorldPackets typedef std::vector<BfGraveyard*> GraveyardVect; typedef std::map<ObjectGuid, time_t> PlayerTimerMap; -class TC_GAME_API BfCapturePoint +class TC_GAME_API BattlefieldControlZoneHandler : public ControlZoneHandler { - public: - BfCapturePoint(Battlefield* bf); - - virtual ~BfCapturePoint() { } - - // Send world state update to all players present - void SendUpdateWorldState(uint32 field, uint32 value); - - // Send kill notify to players in the controlling faction - void SendObjectiveComplete(uint32 id, ObjectGuid guid); - - // Used when player is activated/inactivated in the area - virtual bool HandlePlayerEnter(Player* player); - virtual GuidSet::iterator HandlePlayerLeave(Player* player); - //virtual void HandlePlayerActivityChanged(Player* player); - - // Checks if player is in range of a capture credit marker - bool IsInsideObjective(Player* player) const; - - // Returns true if the state of the objective has changed, in this case, the OutdoorPvP must send a world state ui update. - virtual bool Update(uint32 diff); - virtual void ChangeTeam(TeamId /*oldTeam*/) { } - virtual void SendChangePhase(); - - bool SetCapturePointData(GameObject* capturePoint); - bool DelCapturePoint(); - GameObject* GetCapturePointGo(); - uint32 GetCapturePointEntry() const { return m_capturePointEntry; } - - TeamId GetTeamId() const { return m_team; } - BattlefieldObjectiveStates GetObjectiveState() const { return m_State; } - - protected: - // active Players in the area of the objective, 0 - alliance, 1 - horde - GuidSet m_activePlayers[PVP_TEAMS_COUNT]; - - // Total shift needed to capture the objective - float m_maxValue; - float m_minValue; - - // Maximum speed of capture - float m_maxSpeed; - - // The status of the objective - float m_value; - TeamId m_team; - - // Objective states - BattlefieldObjectiveStates m_OldState; - BattlefieldObjectiveStates m_State; - - // Neutral value on capture bar - uint32 m_neutralValuePct; - - // Pointer to the Battlefield this objective belongs to - Battlefield* m_Bf; - - // Capture point entry - uint32 m_capturePointEntry; - - // Gameobject related to that capture point - ObjectGuid m_capturePointGUID; +public: + explicit BattlefieldControlZoneHandler(Battlefield* bf); + virtual ~BattlefieldControlZoneHandler() = default; + +protected: + Battlefield* GetBattlefield(); +private: + Battlefield* _battlefield; }; class TC_GAME_API BfGraveyard @@ -205,7 +152,8 @@ class TC_GAME_API Battlefield : public ZoneScript virtual ~Battlefield(); /// typedef of map witch store capturepoint and the associate gameobject entry - typedef std::map<uint32 /*lowguid */, BfCapturePoint*> BfCapturePointMap; + + typedef std::unordered_map<uint32 /*control zone entry*/, std::unique_ptr<BattlefieldControlZoneHandler>> ControlZoneHandlerMap; /// Call this to init the Battlefield virtual bool SetupBattlefield() { return true; } @@ -346,6 +294,7 @@ class TC_GAME_API Battlefield : public ZoneScript void InitStalker(uint32 entry, Position const& pos); + void ProcessEvent(WorldObject* target, uint32 eventId, WorldObject* invoker) override; protected: ObjectGuid StalkerGuid; uint32 m_Timer; // Global timer for event @@ -354,7 +303,7 @@ class TC_GAME_API Battlefield : public ZoneScript TeamId m_DefenderTeam; // Map of the objectives belonging to this OutdoorPvP - BfCapturePointMap m_capturePoints; + ControlZoneHandlerMap ControlZoneHandlers; // Players info maps GuidUnorderedSet m_players[PVP_TEAMS_COUNT]; // Players in zone @@ -402,10 +351,6 @@ class TC_GAME_API Battlefield : public ZoneScript void BroadcastPacketToQueue(WorldPacket const* data) const; void BroadcastPacketToWar(WorldPacket const* data) const; - // CapturePoint system - void AddCapturePoint(BfCapturePoint* cp); - BfCapturePoint* GetCapturePoint(uint32 entry) const; - void RegisterZone(uint32 zoneid); bool HasPlayer(Player* player) const; void TeamCastSpell(TeamId team, int32 spellId); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index c842de57e3d..d05e2473ed0 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -91,20 +91,6 @@ void BattlegroundEY::PostUpdateImpl(uint32 diff) RespawnFlagAfterDrop(); } } - - m_TowerCapCheckTimer -= diff; - if (m_TowerCapCheckTimer <= 0) - { - //check if player joined point - /*I used this order of calls, because although we will check if one player is in gameobject's distance 2 times - but we can count of players on current point in CheckSomeoneLeftPoint - */ - CheckSomeoneJoinedPoint(); - //check if player left point - CheckSomeoneLeftPoint(); - UpdatePointStatuses(); - m_TowerCapCheckTimer = BG_EY_FPOINTS_TICK_TIME; - } } } @@ -164,149 +150,6 @@ BattlegroundPointCaptureStatus BattlegroundEY::GetPointCaptureStatus(uint32 poin : BattlegroundPointCaptureStatus::HordeCapturing; } -void BattlegroundEY::CheckSomeoneJoinedPoint() -{ - GameObject* obj = nullptr; - for (uint8 i = 0; i < EY_POINTS_MAX; ++i) - { - obj = GetBgMap()->GetGameObject(BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REAVER + i]); - if (obj) - { - uint8 j = 0; - while (j < m_PlayersNearPoint[EY_POINTS_MAX].size()) - { - Player* player = ObjectAccessor::FindPlayer(m_PlayersNearPoint[EY_POINTS_MAX][j]); - if (!player) - { - TC_LOG_ERROR("bg.battleground", "BattlegroundEY:CheckSomeoneJoinedPoint: Player ({}) could not be found!", m_PlayersNearPoint[EY_POINTS_MAX][j].ToString()); - ++j; - continue; - } - if (player->CanCaptureTowerPoint() && player->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS)) - { - //player joined point! - //show progress bar - player->SendUpdateWorldState(PROGRESS_BAR_PERCENT_GREY, BG_EY_PROGRESS_BAR_PERCENT_GREY); - player->SendUpdateWorldState(PROGRESS_BAR_STATUS, m_PointBarStatus[i]); - player->SendUpdateWorldState(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_SHOW); - //add player to point - m_PlayersNearPoint[i].push_back(m_PlayersNearPoint[EY_POINTS_MAX][j]); - //remove player from "free space" - m_PlayersNearPoint[EY_POINTS_MAX].erase(m_PlayersNearPoint[EY_POINTS_MAX].begin() + j); - } - else - ++j; - } - } - } -} - -void BattlegroundEY::CheckSomeoneLeftPoint() -{ - //reset current point counts - for (uint8 i = 0; i < 2*EY_POINTS_MAX; ++i) - m_CurrentPointPlayersCount[i] = 0; - GameObject* obj = nullptr; - for (uint8 i = 0; i < EY_POINTS_MAX; ++i) - { - obj = GetBgMap()->GetGameObject(BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REAVER + i]); - if (obj) - { - uint8 j = 0; - while (j < m_PlayersNearPoint[i].size()) - { - Player* player = ObjectAccessor::FindPlayer(m_PlayersNearPoint[i][j]); - if (!player) - { - TC_LOG_ERROR("bg.battleground", "BattlegroundEY:CheckSomeoneLeftPoint Player ({}) could not be found!", m_PlayersNearPoint[i][j].ToString()); - //move non-existing players to "free space" - this will cause many errors showing in log, but it is a very important bug - m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]); - m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j); - continue; - } - if (!player->CanCaptureTowerPoint() || !player->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS)) - //move player out of point (add him to players that are out of points - { - m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]); - m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j); - player->SendUpdateWorldState(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_DONT_SHOW); - } - else - { - //player is neat flag, so update count: - m_CurrentPointPlayersCount[2 * i + GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID()))]++; - ++j; - } - } - } - } -} - -void BattlegroundEY::UpdatePointStatuses() -{ - for (uint8 point = 0; point < EY_POINTS_MAX; ++point) - { - if (!m_PlayersNearPoint[point].empty()) - { - //count new point bar status: - int32 pointDelta = int32(m_CurrentPointPlayersCount[2 * point]) - int32(m_CurrentPointPlayersCount[2 * point + 1]); - RoundToInterval<int32>(pointDelta, -BG_EY_POINT_MAX_CAPTURERS_COUNT, BG_EY_POINT_MAX_CAPTURERS_COUNT); - m_PointBarStatus[point] += pointDelta; - - if (m_PointBarStatus[point] > BG_EY_PROGRESS_BAR_ALI_CONTROLLED) - //point is fully alliance's - m_PointBarStatus[point] = BG_EY_PROGRESS_BAR_ALI_CONTROLLED; - if (m_PointBarStatus[point] < BG_EY_PROGRESS_BAR_HORDE_CONTROLLED) - //point is fully horde's - m_PointBarStatus[point] = BG_EY_PROGRESS_BAR_HORDE_CONTROLLED; - - uint32 pointOwnerTeamId = 0; - //find which team should own this point - if (m_PointBarStatus[point] <= BG_EY_PROGRESS_BAR_NEUTRAL_LOW) - pointOwnerTeamId = HORDE; - else if (m_PointBarStatus[point] >= BG_EY_PROGRESS_BAR_NEUTRAL_HIGH) - pointOwnerTeamId = ALLIANCE; - else - pointOwnerTeamId = EY_POINT_NO_OWNER; - - for (uint8 i = 0; i < m_PlayersNearPoint[point].size(); ++i) - { - Player* player = ObjectAccessor::FindPlayer(m_PlayersNearPoint[point][i]); - if (player) - { - player->SendUpdateWorldState(PROGRESS_BAR_STATUS, m_PointBarStatus[point]); - uint32 team = GetPlayerTeam(player->GetGUID()); - //if point owner changed we must evoke event! - if (pointOwnerTeamId != m_PointOwnedByTeam[point]) - { - //point was uncontrolled and player is from team which captured point - if (m_PointState[point] == EY_POINT_STATE_UNCONTROLLED && team == pointOwnerTeamId) - this->EventTeamCapturedPoint(player, point); - - //point was under control and player isn't from team which controlled it - if (m_PointState[point] == EY_POINT_UNDER_CONTROL && team != m_PointOwnedByTeam[point]) - this->EventTeamLostPoint(player, point); - } - - /// @workaround The original AreaTrigger is covered by a bigger one and not triggered on client side. - if (point == FEL_REAVER && m_PointOwnedByTeam[point] == team) - if (m_FlagState && GetFlagPickerGUID() == player->GetGUID()) - if (player->GetDistance(2044.0f, 1729.729f, 1190.03f) < 3.0f) - EventPlayerCapturedFlag(player, BG_EY_OBJECT_FLAG_FEL_REAVER); - } - } - } - - BattlegroundPointCaptureStatus captureStatus = GetPointCaptureStatus(point); - if (m_LastPointCaptureStatus[point] != captureStatus) - { - UpdateWorldState(m_PointsIconStruct[point].WorldStateAllianceStatusBarIcon, captureStatus == BattlegroundPointCaptureStatus::AllianceControlled ? 2 : (captureStatus == BattlegroundPointCaptureStatus::AllianceCapturing ? 1 : 0)); - UpdateWorldState(m_PointsIconStruct[point].WorldStateHordeStatusBarIcon, captureStatus == BattlegroundPointCaptureStatus::HordeControlled ? 2 : (captureStatus == BattlegroundPointCaptureStatus::HordeCapturing ? 1 : 0)); - m_LastPointCaptureStatus[point] = captureStatus; - } - } -} - void BattlegroundEY::UpdateTeamScore(uint32 Team) { uint32 score = GetTeamScore(Team); @@ -541,6 +384,11 @@ bool BattlegroundEY::SetupBattleground() UpdateWorldState(EY_MAX_RESOURCES, BG_EY_MAX_TEAM_SCORE); + ControlZoneHandlers[BG_OBJECT_FR_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(this, FEL_REAVER); + ControlZoneHandlers[BG_OBJECT_BE_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(this, BLOOD_ELF); + ControlZoneHandlers[BG_OBJECT_DR_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(this, DRAENEI_RUINS); + ControlZoneHandlers[BG_OBJECT_HU_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(this, MAGE_TOWER); + return true; } @@ -684,112 +532,109 @@ void BattlegroundEY::EventPlayerClickedOnFlag(Player* player, GameObject* target SendBroadcastText(BG_EY_TEXT_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, player); } -void BattlegroundEY::EventTeamLostPoint(Player* player, uint32 Point) +void BattlegroundEY::EventTeamLostPoint(Team team, uint32 point, WorldObject* controlZone) { if (GetStatus() != STATUS_IN_PROGRESS) return; //Natural point - uint32 Team = m_PointOwnedByTeam[Point]; - if (!Team) + if (!team) return; - if (Team == ALLIANCE) + if (team == ALLIANCE) { m_TeamPointsCount[TEAM_ALLIANCE]--; - SpawnBGObject(m_LosingPointTypes[Point].DespawnObjectTypeAlliance, RESPAWN_ONE_DAY); - SpawnBGObject(m_LosingPointTypes[Point].DespawnObjectTypeAlliance + 1, RESPAWN_ONE_DAY); - SpawnBGObject(m_LosingPointTypes[Point].DespawnObjectTypeAlliance + 2, RESPAWN_ONE_DAY); + SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance, RESPAWN_ONE_DAY); + SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance + 1, RESPAWN_ONE_DAY); + SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance + 2, RESPAWN_ONE_DAY); } else { m_TeamPointsCount[TEAM_HORDE]--; - SpawnBGObject(m_LosingPointTypes[Point].DespawnObjectTypeHorde, RESPAWN_ONE_DAY); - SpawnBGObject(m_LosingPointTypes[Point].DespawnObjectTypeHorde + 1, RESPAWN_ONE_DAY); - SpawnBGObject(m_LosingPointTypes[Point].DespawnObjectTypeHorde + 2, RESPAWN_ONE_DAY); + SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde, RESPAWN_ONE_DAY); + SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde + 1, RESPAWN_ONE_DAY); + SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde + 2, RESPAWN_ONE_DAY); } - SpawnBGObject(m_LosingPointTypes[Point].SpawnNeutralObjectType, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_LosingPointTypes[Point].SpawnNeutralObjectType + 1, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_LosingPointTypes[Point].SpawnNeutralObjectType + 2, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_LosingPointTypes[point].SpawnNeutralObjectType, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_LosingPointTypes[point].SpawnNeutralObjectType + 1, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_LosingPointTypes[point].SpawnNeutralObjectType + 2, RESPAWN_IMMEDIATELY); //buff isn't despawned - m_PointOwnedByTeam[Point] = EY_POINT_NO_OWNER; - m_PointState[Point] = EY_POINT_NO_OWNER; + m_PointOwnedByTeam[point] = EY_POINT_NO_OWNER; + m_PointState[point] = EY_POINT_NO_OWNER; - if (Team == ALLIANCE) - SendBroadcastText(m_LosingPointTypes[Point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, player); + if (team == ALLIANCE) + SendBroadcastText(m_LosingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, controlZone); else - SendBroadcastText(m_LosingPointTypes[Point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE, player); + SendBroadcastText(m_LosingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE, controlZone); - UpdatePointsIcons(Team, Point); - UpdatePointsCount(Team); + UpdatePointsIcons(team, point); + UpdatePointsCount(team); //remove bonus honor aura trigger creature when node is lost - DelCreature(Point + 6);//NULL checks are in DelCreature! 0-5 spirit guides + DelCreature(point + 6);//NULL checks are in DelCreature! 0-5 spirit guides } -void BattlegroundEY::EventTeamCapturedPoint(Player* player, uint32 Point) +void BattlegroundEY::EventTeamCapturedPoint(Team team, uint32 point, WorldObject* controlZone) { if (GetStatus() != STATUS_IN_PROGRESS) return; - uint32 Team = GetPlayerTeam(player->GetGUID()); - - SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType, RESPAWN_ONE_DAY); - SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType + 1, RESPAWN_ONE_DAY); - SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType + 2, RESPAWN_ONE_DAY); + SpawnBGObject(m_CapturingPointTypes[point].DespawnNeutralObjectType, RESPAWN_ONE_DAY); + SpawnBGObject(m_CapturingPointTypes[point].DespawnNeutralObjectType + 1, RESPAWN_ONE_DAY); + SpawnBGObject(m_CapturingPointTypes[point].DespawnNeutralObjectType + 2, RESPAWN_ONE_DAY); - if (Team == ALLIANCE) + if (team == ALLIANCE) { m_TeamPointsCount[TEAM_ALLIANCE]++; - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 1, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 2, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance + 1, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance + 2, RESPAWN_IMMEDIATELY); } else { m_TeamPointsCount[TEAM_HORDE]++; - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 1, RESPAWN_IMMEDIATELY); - SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 2, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde + 1, RESPAWN_IMMEDIATELY); + SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde + 2, RESPAWN_IMMEDIATELY); } //buff isn't respawned - m_PointOwnedByTeam[Point] = Team; - m_PointState[Point] = EY_POINT_UNDER_CONTROL; + m_PointOwnedByTeam[point] = team; + m_PointState[point] = EY_POINT_UNDER_CONTROL; - if (Team == ALLIANCE) - SendBroadcastText(m_CapturingPointTypes[Point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, player); + if (team == ALLIANCE) + SendBroadcastText(m_CapturingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, controlZone); else - SendBroadcastText(m_CapturingPointTypes[Point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE, player); + SendBroadcastText(m_CapturingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE, controlZone); - if (!BgCreatures[Point].IsEmpty()) - DelCreature(Point); + if (!BgCreatures[point].IsEmpty()) + DelCreature(point); - WorldSafeLocsEntry const* sg = sObjectMgr->GetWorldSafeLoc(m_CapturingPointTypes[Point].GraveyardId); - if (!sg || !AddSpiritGuide(Point, sg->Loc.GetPositionX(), sg->Loc.GetPositionY(), sg->Loc.GetPositionZ(), 3.124139f, GetTeamIndexByTeamId(Team))) + WorldSafeLocsEntry const* sg = sObjectMgr->GetWorldSafeLoc(m_CapturingPointTypes[point].GraveyardId); + if (!sg || !AddSpiritGuide(point, sg->Loc.GetPositionX(), sg->Loc.GetPositionY(), sg->Loc.GetPositionZ(), 3.124139f, GetTeamIndexByTeamId(team))) TC_LOG_ERROR("bg.battleground", "BatteGroundEY: Failed to spawn spirit guide. point: {}, team: {}, graveyard_id: {}", - Point, Team, m_CapturingPointTypes[Point].GraveyardId); + point, team, m_CapturingPointTypes[point].GraveyardId); // SpawnBGCreature(Point, RESPAWN_IMMEDIATELY); - UpdatePointsIcons(Team, Point); - UpdatePointsCount(Team); + UpdatePointsIcons(team, point); + UpdatePointsCount(team); - Creature* trigger = GetBGCreature(Point + 6, false);//0-5 spirit guides + Creature* trigger = GetBGCreature(point + 6, false);//0-5 spirit guides if (!trigger) - trigger = AddCreature(WORLD_TRIGGER, Point+6, BG_EY_TriggerPositions[Point], GetTeamIndexByTeamId(Team)); + trigger = AddCreature(WORLD_TRIGGER, point+6, BG_EY_TriggerPositions[point], GetTeamIndexByTeamId(team)); //add bonus honor aura trigger creature when node is accupied //cast bonus aura (+50% honor in 25yards) //aura should only apply to players who have accupied the node, set correct faction for trigger if (trigger) { - trigger->SetFaction(Team == ALLIANCE ? FACTION_ALLIANCE_GENERIC : FACTION_HORDE_GENERIC); + trigger->SetFaction(team == ALLIANCE ? FACTION_ALLIANCE_GENERIC : FACTION_HORDE_GENERIC); trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false); } } @@ -920,3 +765,64 @@ uint32 BattlegroundEY::GetPrematureWinner() return Battleground::GetPrematureWinner(); } + +void BattlegroundEY::ProcessEvent(WorldObject* target, uint32 eventId, WorldObject* invoker) +{ + Battleground::ProcessEvent(target, eventId, invoker); + + if (invoker) + { + if (GameObject* gameobject = invoker->ToGameObject()) + { + if (gameobject->GetGoType() == GAMEOBJECT_TYPE_CONTROL_ZONE) + { + if (!ControlZoneHandlers.contains(gameobject->GetEntry())) + return; + + auto controlzone = gameobject->GetGOInfo()->controlZone; + BattlegroundEYControlZoneHandler& handler = *ControlZoneHandlers[invoker->GetEntry()]; + if (eventId == controlzone.CaptureEventAlliance) + handler.HandleCaptureEventAlliance(gameobject); + else if (eventId == controlzone.CaptureEventHorde) + handler.HandleCaptureEventHorde(gameobject); + else if (eventId == controlzone.ContestedEventAlliance) + handler.HandleContestedEventAlliance(gameobject); + else if (eventId == controlzone.ContestedEventHorde) + handler.HandleContestedEventHorde(gameobject); + else if (eventId == controlzone.NeutralEventAlliance) + handler.HandleNeutralEventAlliance(gameobject); + else if (eventId == controlzone.NeutralEventHorde) + handler.HandleNeutralEventHorde(gameobject); + else if (eventId == controlzone.ProgressEventAlliance) + handler.HandleProgressEventAlliance(gameobject); + else if (eventId == controlzone.ProgressEventHorde) + handler.HandleProgressEventHorde(gameobject); + } + } + } +} + +BattlegroundEYControlZoneHandler::BattlegroundEYControlZoneHandler(BattlegroundEY* bg, uint32 point) : ControlZoneHandler(), + _battleground(bg), _point(point) +{ +} + +void BattlegroundEYControlZoneHandler::HandleProgressEventHorde(GameObject* controlZone) +{ + _battleground->EventTeamCapturedPoint(HORDE, _point, controlZone); +} + +void BattlegroundEYControlZoneHandler::HandleProgressEventAlliance(GameObject* controlZone) +{ + _battleground->EventTeamCapturedPoint(ALLIANCE, _point, controlZone); +} + +void BattlegroundEYControlZoneHandler::HandleNeutralEventHorde(GameObject* controlZone) +{ + _battleground->EventTeamLostPoint(HORDE, _point, controlZone); +} + +void BattlegroundEYControlZoneHandler::HandleNeutralEventAlliance(GameObject* controlZone) +{ + _battleground->EventTeamLostPoint(ALLIANCE, _point, controlZone); +} diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h index 6b047836742..3b5576fc703 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h @@ -355,6 +355,23 @@ struct BattlegroundEYCapturingPointStruct uint32 GraveyardId; }; +class BattlegroundEY; + +class BattlegroundEYControlZoneHandler : public ControlZoneHandler +{ +public: + explicit BattlegroundEYControlZoneHandler(BattlegroundEY* bg, uint32 point); + + void HandleProgressEventHorde(GameObject* controlZone) override; + void HandleProgressEventAlliance(GameObject* controlZone) override; + void HandleNeutralEventHorde(GameObject* controlZone) override; + void HandleNeutralEventAlliance(GameObject* controlZone) override; + +private: + BattlegroundEY* _battleground; + uint32 _point; +}; + const uint8 BG_EY_TickPoints[EY_POINTS_MAX] = {1, 2, 5, 10}; const uint32 BG_EY_FlagPoints[EY_POINTS_MAX] = {75, 85, 100, 500}; @@ -450,21 +467,17 @@ class BattlegroundEY : public Battleground void EventPlayerDroppedFlag(Player* Source) override; uint32 GetPrematureWinner() override; -protected: + + void ProcessEvent(WorldObject* target, uint32 eventId, WorldObject* invoker) override; void PostUpdateImpl(uint32 diff) override; void EventPlayerCapturedFlag(Player* Source, uint32 BgObjectType); - void EventTeamCapturedPoint(Player* Source, uint32 Point); - void EventTeamLostPoint(Player* Source, uint32 Point); + void EventTeamCapturedPoint(Team team, uint32 point, WorldObject* controlZone); + void EventTeamLostPoint(Team team, uint32 point, WorldObject* controlZone); void UpdatePointsCount(uint32 Team); void UpdatePointsIcons(uint32 Team, uint32 Point); private: - /* Point status updating procedures */ - void CheckSomeoneLeftPoint(); - void CheckSomeoneJoinedPoint(); - void UpdatePointStatuses(); - /* Scorekeeping */ void AddPoints(uint32 Team, uint32 Points); @@ -493,5 +506,7 @@ protected: int32 m_PointAddingTimer; uint32 m_HonorTics; + + std::unordered_map<uint32, std::unique_ptr<BattlegroundEYControlZoneHandler>> ControlZoneHandlers; }; #endif diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 04ffbf5dcf8..1fd5ce84570 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -49,6 +49,7 @@ #include "PhasingHandler.h" #include "PoolMgr.h" #include "QueryPackets.h" +#include "Util.h" #include "SpellAuras.h" #include "SpellMgr.h" #include "Transport.h" @@ -507,7 +508,7 @@ void SetTransportAutoCycleBetweenStopFrames::Execute(GameObjectTypeBase& type) c class NewFlag : public GameObjectTypeBase { public: - explicit NewFlag(GameObject& owner) : GameObjectTypeBase(owner), _state(FlagState::InBase), _respawnTime(0), _takenFromBaseTime(0){ } + explicit NewFlag(GameObject& owner) : GameObjectTypeBase(owner), _state(FlagState::InBase), _respawnTime(0), _takenFromBaseTime(0) { } void SetState(FlagState newState, Player* player) { @@ -569,6 +570,244 @@ void SetNewFlagState::Execute(GameObjectTypeBase& type) const if (NewFlag* newFlag = dynamic_cast<NewFlag*>(&type)) newFlag->SetState(_state, _player); } + +class ControlZone : public GameObjectTypeBase +{ +public: + explicit ControlZone(GameObject& owner) : GameObjectTypeBase(owner), _value(static_cast<float>(owner.GetGOInfo()->controlZone.startingValue)) + { + if (owner.GetMap()->Instanceable()) + _heartbeatRate = 1s; + else if (owner.GetGOInfo()->controlZone.FrequentHeartbeat) + _heartbeatRate = 2500ms; + else + _heartbeatRate = 5s; + + _heartbeatTracker.Reset(_heartbeatRate); + _previousTeamId = GetControllingTeam(); + _contestedTriggered = false; + } + + void Update(uint32 diff) override + { + if (_owner.HasFlag(GO_FLAG_NOT_SELECTABLE)) + return; + + _heartbeatTracker.Update(diff); + if (_heartbeatTracker.Passed()) + { + _heartbeatTracker.Reset(_heartbeatRate); + HandleHeartbeat(); + } + } + + TeamId GetControllingTeam() const + { + if (_value < GetMaxHordeValue()) + return TEAM_HORDE; + + if (_value > GetMinAllianceValue()) + return TEAM_ALLIANCE; + + return TEAM_NEUTRAL; + } + + GuidUnorderedSet const* GetInsidePlayers() const { return &_insidePlayers; } + + void ActivateObject(GameObjectActions action, int32 /*param*/, WorldObject* /*spellCaster*/, uint32 /*spellId*/, int32 /*effectIndex*/) override + { + switch (action) + { + case GameObjectActions::MakeInert: + for (ObjectGuid const& guid : _insidePlayers) + if (Player* player = ObjectAccessor::GetPlayer(_owner, guid)) + player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldState1, 0); + + _insidePlayers.clear(); + break; + default: + break; + } + } + + void SetValue(float value) + { + _value = RoundToInterval<float>(value, 0.0f, 100.0f); + } + + void HandleHeartbeat() + { + // update player list inside control zone + std::vector<Player*> targetList; + SearchTargets(targetList); + + TeamId oldControllingTeam = GetControllingTeam(); + float pointsGained = CalculatePointsPerSecond(targetList) * _heartbeatRate.count() / 1000.0f; + if (pointsGained == 0) + return; + + int32 oldRoundedValue = static_cast<int32>(_value); + SetValue(_value + pointsGained); + int32 roundedValue = static_cast<int32>(_value); + if (oldRoundedValue == roundedValue) + return; + + TeamId newControllingTeam = GetControllingTeam(); + TeamId assaultingTeam = pointsGained > 0 ? TEAM_ALLIANCE : TEAM_HORDE; + + if (oldControllingTeam != newControllingTeam) + _contestedTriggered = false; + + if (oldControllingTeam != TEAM_ALLIANCE && newControllingTeam == TEAM_ALLIANCE) + TriggerEvent(_owner.GetGOInfo()->controlZone.ProgressEventAlliance); + else if (oldControllingTeam != TEAM_HORDE && newControllingTeam == TEAM_HORDE) + TriggerEvent(_owner.GetGOInfo()->controlZone.ProgressEventHorde); + else if (oldControllingTeam == TEAM_HORDE && newControllingTeam == TEAM_NEUTRAL) + TriggerEvent(_owner.GetGOInfo()->controlZone.NeutralEventHorde); + else if (oldControllingTeam == TEAM_ALLIANCE && newControllingTeam == TEAM_NEUTRAL) + TriggerEvent(_owner.GetGOInfo()->controlZone.NeutralEventAlliance); + + if (roundedValue == 100 && newControllingTeam == TEAM_ALLIANCE && assaultingTeam == TEAM_ALLIANCE) + TriggerEvent(_owner.GetGOInfo()->controlZone.CaptureEventAlliance); + else if (roundedValue == 0 && newControllingTeam == TEAM_HORDE && assaultingTeam == TEAM_HORDE) + TriggerEvent(_owner.GetGOInfo()->controlZone.CaptureEventHorde); + + if (oldRoundedValue == 100 && assaultingTeam == TEAM_HORDE && !_contestedTriggered) + { + TriggerEvent(_owner.GetGOInfo()->controlZone.ContestedEventHorde); + _contestedTriggered = true; + } + else if (oldRoundedValue == 0 && assaultingTeam == TEAM_ALLIANCE && !_contestedTriggered) + { + TriggerEvent(_owner.GetGOInfo()->controlZone.ContestedEventAlliance); + _contestedTriggered = true; + } + + for (Player* player : targetList) + player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldstate2, roundedValue); + } + + void SearchTargets(std::vector<Player*>& targetList) + { + Trinity::AnyUnitInObjectRangeCheck check(&_owner, _owner.GetGOInfo()->controlZone.radius, true); + Trinity::PlayerListSearcher<Trinity::AnyUnitInObjectRangeCheck> searcher(&_owner, targetList, check); + Cell::VisitWorldObjects(&_owner, searcher, _owner.GetGOInfo()->controlZone.radius); + HandleUnitEnterExit(targetList); + } + + float CalculatePointsPerSecond(std::vector<Player*> const& targetList) + { + int32 delta = 0; + + for (Player* player : targetList) + { + if (!player->IsOutdoorPvPActive()) + continue; + + if (player->GetTeamId() == TEAM_HORDE) + delta--; + else + delta++; + } + + uint32 minTime = _owner.GetGOInfo()->controlZone.minTime; + uint32 maxTime = _owner.GetGOInfo()->controlZone.maxTime; + uint32 minSuperiority = _owner.GetGOInfo()->controlZone.minSuperiority; + uint32 maxSuperiority = _owner.GetGOInfo()->controlZone.maxSuperiority; + + if (static_cast<uint32>(std::abs(delta)) < minSuperiority) + return 0; + + float slope = (static_cast<float>(minTime) - maxTime) / (maxSuperiority - minSuperiority); + float intercept = maxTime - slope * minSuperiority; + float timeNeeded = slope * std::abs(delta) + intercept; + float percentageIncrease = 100.0f / timeNeeded; + + if (delta < 0) + percentageIncrease *= -1; + + return percentageIncrease; + } + + void HandleUnitEnterExit(std::vector<Player*> const& newTargetList) + { + GuidUnorderedSet exitPlayers(std::move(_insidePlayers)); + + std::vector<Player*> enteringPlayers; + + for (Player* unit : newTargetList) + { + if (exitPlayers.erase(unit->GetGUID()) == 0) // erase(key_type) returns number of elements erased + enteringPlayers.push_back(unit); + + _insidePlayers.insert(unit->GetGUID()); + } + + for (Player* player : enteringPlayers) + { + player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldState1, 1); + player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldstate2, static_cast<int32>(_value)); + player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldstate3, _owner.GetGOInfo()->controlZone.neutralPercent); + } + + for (ObjectGuid const& exitPlayerGuid : exitPlayers) + { + if (Player* player = ObjectAccessor::GetPlayer(_owner, exitPlayerGuid)) + { + player->SendUpdateWorldState(_owner.GetGOInfo()->controlZone.worldState1, 0); + } + } + } + + float GetMaxHordeValue() const + { + // ex: if neutralPercent is 40; then 0 - 30 is Horde Controlled + return 50.0f - _owner.GetGOInfo()->controlZone.neutralPercent / 2.0f; + } + + float GetMinAllianceValue() const + { + // ex: if neutralPercent is 40; then 70 - 100 is Alliance Controlled + return 50.0f + _owner.GetGOInfo()->controlZone.neutralPercent / 2.0f; + } + + void TriggerEvent(uint32 eventId) const + { + if (eventId <= 0) + return; + + GameEvents::Trigger(eventId, &_owner, nullptr); + } + + uint32 GetStartingValue() const + { + return _owner.GetGOInfo()->controlZone.startingValue; + } + +private: + Milliseconds _heartbeatRate; + TimeTracker _heartbeatTracker; + GuidUnorderedSet _insidePlayers; + TeamId _previousTeamId; + float _value; + bool _contestedTriggered; +}; + +SetControlZoneValue::SetControlZoneValue(Optional<uint32> value /*= { }*/) : _value(value) +{ +} + +void SetControlZoneValue::Execute(GameObjectTypeBase& type) const +{ + if (ControlZone* controlZone = dynamic_cast<ControlZone*>(&type)) + { + uint32 value = controlZone->GetStartingValue(); + if (_value.has_value()) + value = *_value; + + controlZone->SetValue(value); + } +} } GameObject::GameObject() : WorldObject(false), MapObject(), @@ -863,6 +1102,10 @@ bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionD m_invisibility.AddValue(INVISIBILITY_TRAP, 300); } break; + case GAMEOBJECT_TYPE_CONTROL_ZONE: + m_goTypeImpl = std::make_unique<GameObjectType::ControlZone>(*this); + setActive(true); + break; case GAMEOBJECT_TYPE_NEW_FLAG: m_goTypeImpl = std::make_unique<GameObjectType::NewFlag>(*this); if (map->Instanceable()) @@ -2216,6 +2459,10 @@ void GameObject::ActivateObject(GameObjectActions action, int32 param, WorldObje TC_LOG_ERROR("spell", "Spell {} has unhandled action {} in effect {}", spellId, int32(action), effectIndex); break; } + + // Apply side effects of type + if (m_goTypeImpl) + m_goTypeImpl->ActivateObject(action, param, spellCaster, spellId, effectIndex); } void GameObject::SetGoArtKit(uint32 kit) @@ -4118,6 +4365,14 @@ time_t GameObject::GetFlagTakenFromBaseTime() const return newFlag->GetTakenFromBaseTime(); } +GuidUnorderedSet const* GameObject::GetInsidePlayers() const +{ + if (GameObjectType::ControlZone const* controlZone = dynamic_cast<GameObjectType::ControlZone const*>(m_goTypeImpl.get())) + return controlZone->GetInsidePlayers(); + + return nullptr; +} + bool GameObject::MeetsInteractCondition(Player const* user) const { if (!m_goInfo->GetConditionID1()) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index bb6282e8fd0..bf54c9cf2a6 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -71,6 +71,7 @@ public: virtual void OnStateChanged([[maybe_unused]] GOState oldState, [[maybe_unused]] GOState newState) { } virtual void OnRelocated() { } virtual bool IsNeverVisibleFor([[maybe_unused]] WorldObject const* seer, [[maybe_unused]] bool allowServersideObjects) const { return false; } + virtual void ActivateObject([[maybe_unused]] GameObjectActions action, [[maybe_unused]] int32 param, [[maybe_unused]] WorldObject* spellCaster = nullptr, [[maybe_unused]] uint32 spellId = 0, [[maybe_unused]] int32 effectIndex = -1) { } protected: GameObject& _owner; @@ -100,6 +101,18 @@ private: FlagState _state; Player* _player; }; + +class TC_GAME_API SetControlZoneValue : public GameObjectTypeBase::CustomCommand +{ +public: + explicit SetControlZoneValue(Optional<uint32> value = { }); + + void Execute(GameObjectTypeBase& type) const override; + +private: + Optional<uint32> _value; +}; + } union GameObjectValue @@ -413,6 +426,8 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> ObjectGuid const& GetFlagCarrierGUID() const; time_t GetFlagTakenFromBaseTime() const; + GuidUnorderedSet const* GetInsidePlayers() const; + bool MeetsInteractCondition(Player const* user) const; void AIM_Destroy(); diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h index f782d2645c7..7ea1a9a6f57 100644 --- a/src/server/game/Maps/ZoneScript.h +++ b/src/server/game/Maps/ZoneScript.h @@ -38,6 +38,23 @@ enum class EncounterType : uint8 MythicPlusRun }; +class TC_GAME_API ControlZoneHandler +{ +public: + explicit ControlZoneHandler() = default; + virtual ~ControlZoneHandler() = default; + + virtual void HandleCaptureEventHorde([[maybe_unused]] GameObject* controlZone) { } + virtual void HandleCaptureEventAlliance([[maybe_unused]] GameObject* controlZone) { } + virtual void HandleContestedEventHorde([[maybe_unused]] GameObject* controlZone) { } + virtual void HandleContestedEventAlliance([[maybe_unused]] GameObject* controlZone) { } + virtual void HandleProgressEventHorde([[maybe_unused]] GameObject* controlZone) { } + virtual void HandleProgressEventAlliance([[maybe_unused]] GameObject* controlZone) { } + virtual void HandleNeutralEventHorde([[maybe_unused]] GameObject* controlZone) { HandleNeutralEvent(controlZone); } + virtual void HandleNeutralEventAlliance([[maybe_unused]] GameObject* controlZone) { HandleNeutralEvent(controlZone); } + virtual void HandleNeutralEvent([[maybe_unused]] GameObject* controlZone) { } +}; + class TC_GAME_API ZoneScript { public: diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp index 319d6aeb938..0379f8b15e5 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp +++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp @@ -53,62 +53,10 @@ class DefenseMessageBuilder }; OPvPCapturePoint::OPvPCapturePoint(OutdoorPvP* pvp): - m_capturePointSpawnId(), m_capturePoint(nullptr), m_maxValue(0.0f), m_minValue(0.0f), m_maxSpeed(0), - m_value(0), m_team(TEAM_NEUTRAL), m_OldState(OBJECTIVESTATE_NEUTRAL), - m_State(OBJECTIVESTATE_NEUTRAL), m_neutralValuePct(0), m_PvP(pvp) + m_team(TEAM_NEUTRAL), m_OldState(OBJECTIVESTATE_NEUTRAL), + m_State(OBJECTIVESTATE_NEUTRAL), m_PvP(pvp) { } -bool OPvPCapturePoint::HandlePlayerEnter(Player* player) -{ - if (m_capturePoint) - { - player->SendUpdateWorldState(m_capturePoint->GetGOInfo()->controlZone.worldState1, 1); - player->SendUpdateWorldState(m_capturePoint->GetGOInfo()->controlZone.worldstate2, (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f)); - player->SendUpdateWorldState(m_capturePoint->GetGOInfo()->controlZone.worldstate3, m_neutralValuePct); - } - return m_activePlayers[player->GetTeamId()].insert(player->GetGUID()).second; -} - -void OPvPCapturePoint::HandlePlayerLeave(Player* player) -{ - if (m_capturePoint) - player->SendUpdateWorldState(m_capturePoint->GetGOInfo()->controlZone.worldState1, 0); - m_activePlayers[player->GetTeamId()].erase(player->GetGUID()); -} - -void OPvPCapturePoint::SendChangePhase() -{ - if (!m_capturePoint) - return; - - // send this too, sometimes the slider disappears, dunno why :( - SendUpdateWorldState(m_capturePoint->GetGOInfo()->controlZone.worldState1, 1); - // send these updates to only the ones in this objective - SendUpdateWorldState(m_capturePoint->GetGOInfo()->controlZone.worldstate2, (uint32)ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f)); - // send this too, sometimes it resets :S - SendUpdateWorldState(m_capturePoint->GetGOInfo()->controlZone.worldstate3, m_neutralValuePct); -} - -bool OPvPCapturePoint::SetCapturePointData(uint32 entry) -{ - TC_LOG_DEBUG("outdoorpvp", "Creating capture point {}", entry); - - // check info existence - GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry); - if (!goinfo || goinfo->type != GAMEOBJECT_TYPE_CONTROL_ZONE) - { - TC_LOG_ERROR("outdoorpvp", "OutdoorPvP: GO {} is not capture point!", entry); - return false; - } - - // get the needed values from goinfo - m_maxValue = (float)goinfo->controlZone.maxTime; - m_maxSpeed = m_maxValue / (goinfo->controlZone.minTime ? goinfo->controlZone.minTime : 60); - m_neutralValuePct = goinfo->controlZone.neutralPercent; - m_minValue = CalculatePct(m_maxValue, m_neutralValuePct); - return true; -} - OutdoorPvP::OutdoorPvP(Map* map) : m_TypeId(0), m_map(map) { } OutdoorPvP::~OutdoorPvP() = default; @@ -120,9 +68,6 @@ void OutdoorPvP::HandlePlayerEnterZone(Player* player, uint32 /*zone*/) void OutdoorPvP::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/) { - // inform the objectives of the leaving - for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - itr->second->HandlePlayerLeave(player); // remove the world state information from the player (we can't keep everyone up to date, so leave out those who are not in the concerning zones) if (!player->GetSession()->PlayerLogout()) SendRemoveWorldStates(player); @@ -132,137 +77,10 @@ void OutdoorPvP::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/) void OutdoorPvP::HandlePlayerResurrects(Player* /*player*/, uint32 /*zone*/) { } -bool OutdoorPvP::Update(uint32 diff) +void OutdoorPvP::Update(uint32 diff) { - bool objective_changed = false; for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - { - if (itr->second->Update(diff)) - objective_changed = true; - } - return objective_changed; -} - -bool OPvPCapturePoint::Update(uint32 diff) -{ - if (!m_capturePoint) - return false; - - float radius = (float)m_capturePoint->GetGOInfo()->controlZone.radius; - - for (uint32 team = 0; team < 2; ++team) - { - for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end();) - { - ObjectGuid playerGuid = *itr; - ++itr; - - if (Player* player = ObjectAccessor::FindPlayer(playerGuid)) - if (!m_capturePoint->IsWithinDistInMap(player, radius) || !player->IsOutdoorPvPActive()) - HandlePlayerLeave(player); - } - } - - std::list<Player*> players; - Trinity::AnyPlayerInObjectRangeCheck checker(m_capturePoint, radius); - Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(m_capturePoint, players, checker); - Cell::VisitWorldObjects(m_capturePoint, searcher, radius); - - for (std::list<Player*>::iterator itr = players.begin(); itr != players.end(); ++itr) - { - Player* const player = *itr; - if (player->IsOutdoorPvPActive()) - { - if (m_activePlayers[player->GetTeamId()].insert(player->GetGUID()).second) - HandlePlayerEnter(*itr); - } - } - - // get the difference of numbers - float fact_diff = ((float)m_activePlayers[0].size() - (float)m_activePlayers[1].size()) * diff / OUTDOORPVP_OBJECTIVE_UPDATE_INTERVAL; - if (!fact_diff) - return false; - - uint32 Challenger = 0; - float maxDiff = m_maxSpeed * diff; - - if (fact_diff < 0) - { - // horde is in majority, but it's already horde-controlled -> no change - if (m_State == OBJECTIVESTATE_HORDE && m_value <= -m_maxValue) - return false; - - if (fact_diff < -maxDiff) - fact_diff = -maxDiff; - - Challenger = HORDE; - } - else - { - // ally is in majority, but it's already ally-controlled -> no change - if (m_State == OBJECTIVESTATE_ALLIANCE && m_value >= m_maxValue) - return false; - - if (fact_diff > maxDiff) - fact_diff = maxDiff; - - Challenger = ALLIANCE; - } - - float oldValue = m_value; - TeamId oldTeam = m_team; - - m_OldState = m_State; - - m_value += fact_diff; - - if (m_value < -m_minValue) // red - { - if (m_value < -m_maxValue) - m_value = -m_maxValue; - m_State = OBJECTIVESTATE_HORDE; - m_team = TEAM_HORDE; - } - else if (m_value > m_minValue) // blue - { - if (m_value > m_maxValue) - m_value = m_maxValue; - m_State = OBJECTIVESTATE_ALLIANCE; - m_team = TEAM_ALLIANCE; - } - else if (oldValue * m_value <= 0) // grey, go through mid point - { - // if challenger is ally, then n->a challenge - if (Challenger == ALLIANCE) - m_State = OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE; - // if challenger is horde, then n->h challenge - else if (Challenger == HORDE) - m_State = OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE; - m_team = TEAM_NEUTRAL; - } - else // grey, did not go through mid point - { - // old phase and current are on the same side, so one team challenges the other - if (Challenger == ALLIANCE && (m_OldState == OBJECTIVESTATE_HORDE || m_OldState == OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE)) - m_State = OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE; - else if (Challenger == HORDE && (m_OldState == OBJECTIVESTATE_ALLIANCE || m_OldState == OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE)) - m_State = OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE; - m_team = TEAM_NEUTRAL; - } - - if (m_value != oldValue) - SendChangePhase(); - - if (m_OldState != m_State) - { - //TC_LOG_ERROR("outdoorpvp", "{}->{}", m_OldState, m_State); - if (oldTeam != m_team) - ChangeTeam(oldTeam); - ChangeState(); - return true; - } - - return false; + itr->second->Update(diff); } int32 OutdoorPvP::GetWorldState(int32 worldStateId) const @@ -275,38 +93,6 @@ void OutdoorPvP::SetWorldState(int32 worldStateId, int32 value) sWorldStateMgr->SetValue(worldStateId, value, false, m_map); } -void OPvPCapturePoint::SendUpdateWorldState(uint32 field, uint32 value) -{ - for (uint32 team = 0; team < 2; ++team) - { - // send to all players present in the area - for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) - if (Player* const player = ObjectAccessor::FindPlayer(*itr)) - player->SendUpdateWorldState(field, value); - } -} - -void OPvPCapturePoint::SendObjectiveComplete(uint32 id, ObjectGuid guid) -{ - uint32 team; - switch (m_State) - { - case OBJECTIVESTATE_ALLIANCE: - team = 0; - break; - case OBJECTIVESTATE_HORDE: - team = 1; - break; - default: - return; - } - - // send to all players present in the area - for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) - if (Player* const player = ObjectAccessor::FindPlayer(*itr)) - player->KilledMonsterCredit(id, guid); -} - void OutdoorPvP::HandleKill(Player* killer, Unit* killed) { if (Group* group = killer->GetGroup()) @@ -324,33 +110,18 @@ void OutdoorPvP::HandleKill(Player* killer, Unit* killed) // creature kills must be notified, even if not inside objective / not outdoor pvp active // player kills only count if active and inside objective - if ((groupGuy->IsOutdoorPvPActive() && IsInsideObjective(groupGuy)) || killed->GetTypeId() == TYPEID_UNIT) + if ((groupGuy->IsOutdoorPvPActive()) || killed->GetTypeId() == TYPEID_UNIT) HandleKillImpl(groupGuy, killed); } } else { // creature kills must be notified, even if not inside objective / not outdoor pvp active - if ((killer->IsOutdoorPvPActive() && IsInsideObjective(killer)) || killed->GetTypeId() == TYPEID_UNIT) + if ((killer->IsOutdoorPvPActive()) || killed->GetTypeId() == TYPEID_UNIT) HandleKillImpl(killer, killed); } } -bool OutdoorPvP::IsInsideObjective(Player* player) const -{ - for (OPvPCapturePointMap::const_iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - if (itr->second->IsInsideObjective(player)) - return true; - - return false; -} - -bool OPvPCapturePoint::IsInsideObjective(Player* player) const -{ - GuidSet const& plSet = m_activePlayers[player->GetTeamId()]; - return plSet.find(player->GetGUID()) != plSet.end(); -} - bool OutdoorPvP::HandleCustomSpell(Player* player, uint32 spellId, GameObject* go) { for (OPvPCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) @@ -399,26 +170,6 @@ void OutdoorPvP::BroadcastPacket(WorldPacket const* data) const player->SendDirectMessage(data); } -void OutdoorPvP::AddCapturePoint(OPvPCapturePoint* cp) -{ - OPvPCapturePointMap::iterator i = m_capturePoints.find(cp->m_capturePointSpawnId); - if (i != m_capturePoints.end()) - { - TC_LOG_ERROR("outdoorpvp", "OutdoorPvP::AddCapturePoint: CapturePoint {} already exists!", cp->m_capturePointSpawnId); - if (i->second.get() == cp) - return; - } - m_capturePoints[cp->m_capturePointSpawnId].reset(cp); -} - -OPvPCapturePoint* OutdoorPvP::GetCapturePoint(ObjectGuid::LowType guid) const -{ - OutdoorPvP::OPvPCapturePointMap::const_iterator itr = m_capturePoints.find(guid); - if (itr != m_capturePoints.end()) - return itr->second.get(); - return nullptr; -} - void OutdoorPvP::RegisterZone(uint32 zoneId) { sOutdoorPvPMgr->AddZone(zoneId, this); @@ -452,24 +203,6 @@ void OutdoorPvP::TeamApplyBuff(TeamId team, uint32 spellId, uint32 spellId2) TeamCastSpell(OTHER_TEAM(team), spellId2 ? -(int32)spellId2 : -(int32)spellId); } -void OutdoorPvP::OnGameObjectCreate(GameObject* go) -{ - if (go->GetGoType() != GAMEOBJECT_TYPE_CONTROL_ZONE) - return; - - if (OPvPCapturePoint *cp = GetCapturePoint(go->GetSpawnId())) - cp->m_capturePoint = go; -} - -void OutdoorPvP::OnGameObjectRemove(GameObject* go) -{ - if (go->GetGoType() != GAMEOBJECT_TYPE_CONTROL_ZONE) - return; - - if (OPvPCapturePoint *cp = GetCapturePoint(go->GetSpawnId())) - cp->m_capturePoint = nullptr; -} - void OutdoorPvP::SendDefenseMessage(uint32 zoneId, uint32 id) { DefenseMessageBuilder builder(zoneId, id); @@ -477,6 +210,40 @@ void OutdoorPvP::SendDefenseMessage(uint32 zoneId, uint32 id) BroadcastWorker(localizer, zoneId); } +void OutdoorPvP::ProcessEvent([[maybe_unused]] WorldObject * target, [[maybe_unused]] uint32 eventId, [[maybe_unused]] WorldObject * invoker) +{ + if (invoker) + { + if (GameObject* gameobject = invoker->ToGameObject()) + { + if (gameobject->GetGoType() == GAMEOBJECT_TYPE_CONTROL_ZONE) + { + if (!ControlZoneHandlers.contains(gameobject->GetEntry())) + return; + + auto controlzone = gameobject->GetGOInfo()->controlZone; + OutdoorPvPControlZoneHandler& handler = *ControlZoneHandlers[invoker->GetEntry()]; + if (eventId == controlzone.CaptureEventAlliance) + handler.HandleCaptureEventAlliance(gameobject); + else if (eventId == controlzone.CaptureEventHorde) + handler.HandleCaptureEventHorde(gameobject); + else if (eventId == controlzone.ContestedEventAlliance) + handler.HandleContestedEventAlliance(gameobject); + else if (eventId == controlzone.ContestedEventHorde) + handler.HandleContestedEventHorde(gameobject); + else if (eventId == controlzone.NeutralEventAlliance) + handler.HandleNeutralEventAlliance(gameobject); + else if (eventId == controlzone.NeutralEventHorde) + handler.HandleNeutralEventHorde(gameobject); + else if (eventId == controlzone.ProgressEventAlliance) + handler.HandleProgressEventAlliance(gameobject); + else if (eventId == controlzone.ProgressEventHorde) + handler.HandleProgressEventHorde(gameobject); + } + } + } +} + template<class Worker> void OutdoorPvP::BroadcastWorker(Worker& _worker, uint32 zoneId) { diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.h b/src/server/game/OutdoorPvP/OutdoorPvP.h index d6cc931459a..dae6bd6cac6 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.h +++ b/src/server/game/OutdoorPvP/OutdoorPvP.h @@ -88,68 +88,41 @@ class TC_GAME_API OPvPCapturePoint OPvPCapturePoint& operator=(OPvPCapturePoint const& right) = delete; OPvPCapturePoint& operator=(OPvPCapturePoint&& right) = delete; - // send world state update to all players present - void SendUpdateWorldState(uint32 field, uint32 value); - - // send kill notify to players in the controlling faction - void SendObjectiveComplete(uint32 id, ObjectGuid guid); - - // used when player is activated/inactivated in the area - virtual bool HandlePlayerEnter(Player* player); - virtual void HandlePlayerLeave(Player* player); - - // checks if player is in range of a capture credit marker - bool IsInsideObjective(Player* player) const; + virtual void Update([[maybe_unused]] uint32 diff) { } virtual bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go); virtual int32 HandleOpenGo(Player* player, GameObject* go); - // returns true if the state of the objective has changed, in this case, the OutdoorPvP must send a world state ui update. - virtual bool Update(uint32 diff); - virtual void ChangeState() = 0; virtual void ChangeTeam(TeamId /*oldTeam*/) { } - virtual void SendChangePhase(); - virtual bool HandleDropFlag(Player* /*player*/, uint32 /*spellId*/) { return false; } - ObjectGuid::LowType m_capturePointSpawnId; - - GameObject* m_capturePoint; - - bool SetCapturePointData(uint32 entry); - protected: - // active players in the area of the objective, 0 - alliance, 1 - horde - GuidSet m_activePlayers[2]; - - // total shift needed to capture the objective - float m_maxValue; - float m_minValue; - - // maximum speed of capture - float m_maxSpeed; - - // the status of the objective - float m_value; - TeamId m_team; // objective states ObjectiveStates m_OldState; ObjectiveStates m_State; - // neutral value on capture bar - uint32 m_neutralValuePct; - // pointer to the OutdoorPvP this objective belongs to OutdoorPvP* m_PvP; }; +class TC_GAME_API OutdoorPvPControlZoneHandler : public ControlZoneHandler +{ +public: + explicit OutdoorPvPControlZoneHandler(OutdoorPvP* pvp) : _pvp(pvp) { } + virtual ~OutdoorPvPControlZoneHandler() = default; + + OutdoorPvP* GetOutdoorPvP() const { return _pvp; } +private: + OutdoorPvP* _pvp; +}; + // base class for specific outdoor pvp handlers class TC_GAME_API OutdoorPvP : public ZoneScript { @@ -168,6 +141,7 @@ class TC_GAME_API OutdoorPvP : public ZoneScript virtual ~OutdoorPvP(); typedef std::map<ObjectGuid::LowType/*spawnId*/, std::unique_ptr<OPvPCapturePoint>> OPvPCapturePointMap; + typedef std::unordered_map<uint32 /*control zone entry*/, std::unique_ptr<OutdoorPvPControlZoneHandler>> ControlZoneHandlerMap; // called when a player triggers an areatrigger virtual bool HandleAreaTrigger(Player* /*player*/, uint32 /*trigger*/, bool /*entered*/) { return false; } @@ -181,24 +155,19 @@ class TC_GAME_API OutdoorPvP : public ZoneScript // setup stuff virtual bool SetupOutdoorPvP() {return true;} - void OnGameObjectCreate(GameObject* go) override; - void OnGameObjectRemove(GameObject* go) override; void OnCreatureCreate(Creature*) override { } // send world state update to all players present int32 GetWorldState(int32 worldStateId) const; void SetWorldState(int32 worldStateId, int32 value); - // called by OutdoorPvPMgr, updates the objectives and if needed, sends new worldstateui information - virtual bool Update(uint32 diff); + // called by OutdoorPvPMgr + virtual void Update(uint32 diff); // handle npc/player kill virtual void HandleKill(Player* killer, Unit* killed); virtual void HandleKillImpl(Player* /*killer*/, Unit* /*killed*/) { } - // checks if player is in range of a capture credit marker - bool IsInsideObjective(Player* player) const; - // awards rewards for player kill virtual void AwardKillBonus(Player* /*player*/) { } @@ -225,11 +194,15 @@ class TC_GAME_API OutdoorPvP : public ZoneScript Map* GetMap() const { return m_map; } + void ProcessEvent([[maybe_unused]] WorldObject* target, [[maybe_unused]] uint32 eventId, [[maybe_unused]] WorldObject* invoker) override; + protected: // the map of the objectives belonging to this outdoorpvp OPvPCapturePointMap m_capturePoints; + ControlZoneHandlerMap ControlZoneHandlers; + GuidSet m_players[2]; uint32 m_TypeId; @@ -244,10 +217,6 @@ class TC_GAME_API OutdoorPvP : public ZoneScript virtual void HandlePlayerResurrects(Player* player, uint32 zone); - void AddCapturePoint(OPvPCapturePoint* cp); - - OPvPCapturePoint* GetCapturePoint(ObjectGuid::LowType guid) const; - void RegisterZone(uint32 zoneid); bool HasPlayer(Player const* player) const; diff --git a/src/server/scripts/Battlefield/BattlefieldTB.cpp b/src/server/scripts/Battlefield/BattlefieldTB.cpp index 9d9902adbe2..05222f50052 100644 --- a/src/server/scripts/Battlefield/BattlefieldTB.cpp +++ b/src/server/scripts/Battlefield/BattlefieldTB.cpp @@ -100,15 +100,25 @@ bool BattlefieldTB::SetupBattlefield() // Create capture points for (uint8 i = 0; i < TB_BASE_COUNT; i++) { - TolBaradCapturePoint* capturePoint = new TolBaradCapturePoint(this, GetDefenderTeam()); - //Spawn flag pole if (GameObject* go = SpawnGameObject(TBCapturePoints[i].entryFlagPole[GetDefenderTeam()], TBCapturePoints[i].pos, QuaternionData::fromEulerAnglesZYX(TBCapturePoints[i].pos.GetOrientation(), 0.0f, 0.0f))) { - go->SetGoArtKit(GetDefenderTeam() == TEAM_ALLIANCE ? TB_GO_ARTKIT_FLAG_ALLIANCE : TB_GO_ARTKIT_FLAG_HORDE); - capturePoint->SetCapturePointData(go); + std::unique_ptr<TolBaradCapturePoint> controlZone = std::make_unique<TolBaradCapturePoint>(this, TBCapturePoints[i]); + if (GetDefenderTeam() == TEAM_ALLIANCE) + { + sWorldStateMgr->SetValue(controlZone->GetWorldStateAllianceControlled(), 1, false, GetMap()); + go->HandleCustomTypeCommand(GameObjectType::SetControlZoneValue(100)); + go->SetGoArtKit(TB_GO_ARTKIT_FLAG_ALLIANCE); + } + else if (GetDefenderTeam() == TEAM_HORDE) + { + sWorldStateMgr->SetValue(controlZone->GetWorldStateHordeControlled(), 1, false, GetMap()); + go->HandleCustomTypeCommand(GameObjectType::SetControlZoneValue(0)); + go->SetGoArtKit(TB_GO_ARTKIT_FLAG_HORDE); + } + + ControlZoneHandlers[go->GetEntry()] = std::move(controlZone); } - AddCapturePoint(capturePoint); } // Spawn towers @@ -379,23 +389,29 @@ void BattlefieldTB::UpdateNPCsAndGameObjects() if (GetState() == BATTLEFIELD_INACTIVE) { // Delete capture points - for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - itr->second->DelCapturePoint(); - m_capturePoints.clear(); + ControlZoneHandlers.clear(); // Create capture points for (uint8 i = 0; i < TB_BASE_COUNT; i++) { - TolBaradCapturePoint* capturePoint = new TolBaradCapturePoint(this, GetDefenderTeam()); - - //Spawn flag pole if (GameObject* go = SpawnGameObject(TBCapturePoints[i].entryFlagPole[GetDefenderTeam()], TBCapturePoints[i].pos, QuaternionData::fromEulerAnglesZYX(TBCapturePoints[i].pos.GetOrientation(), 0.0f, 0.0f))) { - go->SetGoArtKit(GetDefenderTeam() == TEAM_ALLIANCE ? TB_GO_ARTKIT_FLAG_ALLIANCE : TB_GO_ARTKIT_FLAG_HORDE); - capturePoint->SetCapturePointData(go); + std::unique_ptr<TolBaradCapturePoint> controlZone = std::make_unique<TolBaradCapturePoint>(this, TBCapturePoints[i]); + if (GetDefenderTeam() == TEAM_ALLIANCE) + { + sWorldStateMgr->SetValue(controlZone->GetWorldStateAllianceControlled(), 1, false, GetMap()); + go->HandleCustomTypeCommand(GameObjectType::SetControlZoneValue(100)); + go->SetGoArtKit(TB_GO_ARTKIT_FLAG_ALLIANCE); + } + else if (GetDefenderTeam() == TEAM_HORDE) + { + sWorldStateMgr->SetValue(controlZone->GetWorldStateHordeControlled(), 1, false, GetMap()); + go->HandleCustomTypeCommand(GameObjectType::SetControlZoneValue(0)); + go->SetGoArtKit(TB_GO_ARTKIT_FLAG_HORDE); + } + + ControlZoneHandlers[go->GetEntry()] = std::move(controlZone); } - - AddCapturePoint(capturePoint); } for (ObjectGuid guid : BattleInactiveNPCs) @@ -558,8 +574,9 @@ void BattlefieldTB::OnGameObjectCreate(GameObject* go) } } -void BattlefieldTB::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* /*invoker*/) +void BattlefieldTB::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker) { + Battlefield::ProcessEvent(obj, eventId, invoker); if (!IsWarTime()) return; @@ -644,9 +661,19 @@ void BattlefieldTB::UpdateCapturedBaseCount() { uint32 numCapturedBases = 0; // How many bases attacker has captured - for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr) - if (itr->second->GetTeamId() == GetAttackerTeam()) - numCapturedBases += 1; + // these world states are either 0 or 1 + if (GetAttackerTeam() == TEAM_ALLIANCE) + { + numCapturedBases += sWorldStateMgr->GetValue(WS_BATTLEFIELD_TB_GARRISON_ALLIANCE_CONTROLLED, GetMap()); + numCapturedBases += sWorldStateMgr->GetValue(WS_BATTLEFIELD_TB_VIGIL_ALLIANCE_CONTROLLED, GetMap()); + numCapturedBases += sWorldStateMgr->GetValue(WS_BATTLEFIELD_TB_SLAGWORKS_ALLIANCE_CONTROLLED, GetMap()); + } + else if (GetAttackerTeam() == TEAM_HORDE) + { + numCapturedBases += sWorldStateMgr->GetValue(WS_BATTLEFIELD_TB_GARRISON_HORDE_CONTROLLED, GetMap()); + numCapturedBases += sWorldStateMgr->GetValue(WS_BATTLEFIELD_TB_VIGIL_HORDE_CONTROLLED, GetMap()); + numCapturedBases += sWorldStateMgr->GetValue(WS_BATTLEFIELD_TB_SLAGWORKS_HORDE_CONTROLLED, GetMap()); + } sWorldStateMgr->SetValue(WS_BATTLEFIELD_TB_BUILDINGS_CAPTURED, numCapturedBases, false, m_Map); @@ -676,76 +703,65 @@ void BattlefieldTB::PromotePlayer(Player* killer) killer->CastSpell(killer, SPELL_TB_VETERAN, true); } -TolBaradCapturePoint::TolBaradCapturePoint(BattlefieldTB* battlefield, TeamId teamInControl) : BfCapturePoint(battlefield) +TolBaradCapturePoint::TolBaradCapturePoint(BattlefieldTB* battlefield, TBCapturePointSpawnData const& data) : BattlefieldControlZoneHandler(battlefield), + _textIdHordeCaptured(data.textGained[TEAM_HORDE]), _textIdAllianceCaptured(data.textGained[TEAM_ALLIANCE]), + _textIdHordeLost(data.textLost[TEAM_HORDE]), _textIdAllianceLost(data.textLost[TEAM_ALLIANCE]), + _worldstateHordeControlled(data.wsControlled[TEAM_HORDE]), _worldstateAllianceControlled(data.wsControlled[TEAM_ALLIANCE]), + _worldstateHordeCapturing(data.wsCapturing[TEAM_HORDE]), _worldstateAllianceCapturing(data.wsCapturing[TEAM_ALLIANCE]), + _worldstateNeutral(data.wsNeutral) { - m_Bf = battlefield; - m_team = teamInControl; - m_value = teamInControl == TEAM_ALLIANCE ? m_maxValue : -m_maxValue; - m_State = teamInControl == TEAM_ALLIANCE ? BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE : BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE; } -void TolBaradCapturePoint::SendChangePhase() +void TolBaradCapturePoint::HandleContestedEventHorde(GameObject* controlZone) { - if (m_OldState == m_State) - return; + BattlefieldControlZoneHandler::HandleContestedEventHorde(controlZone); +} - // Find out index - uint8 iBase = TB_BASE_COUNT; - for (uint8 i = 0; i < TB_BASE_COUNT; i++) - if (GetCapturePointEntry() == TBCapturePoints[i].entryFlagPole[m_Bf->GetDefenderTeam()]) - iBase = i; +void TolBaradCapturePoint::HandleContestedEventAlliance(GameObject* controlZone) +{ + BattlefieldControlZoneHandler::HandleContestedEventAlliance(controlZone); +} - if (iBase == TB_BASE_COUNT) - return; +void TolBaradCapturePoint::HandleProgressEventHorde(GameObject* controlZone) +{ + BattlefieldControlZoneHandler::HandleProgressEventHorde(controlZone); + GetBattlefield()->SendWarning(_textIdHordeCaptured); + controlZone->SetGoArtKit(TB_GO_ARTKIT_FLAG_HORDE); + sWorldStateMgr->SetValue(_worldstateHordeControlled, 1, false, controlZone->GetMap()); + sWorldStateMgr->SetValue(_worldstateHordeCapturing, 0, false, controlZone->GetMap()); + GetBattlefield()->ProcessEvent(nullptr, EVENT_COUNT_CAPTURED_BASE, nullptr); +} - // Turn off previous world state icon - switch (m_OldState) - { - case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE: - case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE: - sWorldStateMgr->SetValue(TBCapturePoints[iBase].wsControlled[GetTeamId()], 0, false, m_Bf->GetMap()); - break; - case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - sWorldStateMgr->SetValue(TBCapturePoints[iBase].wsCapturing[TEAM_ALLIANCE], 0, false, m_Bf->GetMap()); - break; - case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - sWorldStateMgr->SetValue(TBCapturePoints[iBase].wsCapturing[TEAM_HORDE], 0, false, m_Bf->GetMap()); - break; - default: - break; - } +void TolBaradCapturePoint::HandleProgressEventAlliance(GameObject* controlZone) +{ + BattlefieldControlZoneHandler::HandleProgressEventAlliance(controlZone); + GetBattlefield()->SendWarning(_textIdAllianceCaptured); + controlZone->SetGoArtKit(TB_GO_ARTKIT_FLAG_ALLIANCE); + sWorldStateMgr->SetValue(_worldstateAllianceControlled, 1, false, controlZone->GetMap()); + sWorldStateMgr->SetValue(_worldstateAllianceCapturing, 0, false, controlZone->GetMap()); + GetBattlefield()->ProcessEvent(nullptr, EVENT_COUNT_CAPTURED_BASE, nullptr); +} - // Turn on new world state icon and send warning - switch (m_State) - { - case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE: - case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE: - m_Bf->SendWarning(TBCapturePoints[iBase].textGained[GetTeamId()]); - sWorldStateMgr->SetValue(TBCapturePoints[iBase].wsControlled[GetTeamId()], 1, false, m_Bf->GetMap()); - GetCapturePointGo()->SetGoArtKit(GetTeamId() == TEAM_ALLIANCE ? TB_GO_ARTKIT_FLAG_ALLIANCE : TB_GO_ARTKIT_FLAG_HORDE); - break; - case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_Bf->SendWarning(TBCapturePoints[iBase].textLost[TEAM_HORDE]); - [[fallthrough]]; - case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - sWorldStateMgr->SetValue(TBCapturePoints[iBase].wsCapturing[TEAM_ALLIANCE], 1, false, m_Bf->GetMap()); - GetCapturePointGo()->SetGoArtKit(TB_GO_ARTKIT_FLAG_NONE); - break; - case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - m_Bf->SendWarning(TBCapturePoints[iBase].textLost[TEAM_ALLIANCE]); - [[fallthrough]]; - case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - sWorldStateMgr->SetValue(TBCapturePoints[iBase].wsCapturing[TEAM_HORDE], 1, false, m_Bf->GetMap()); - GetCapturePointGo()->SetGoArtKit(TB_GO_ARTKIT_FLAG_NONE); - break; - default: - break; - } +void TolBaradCapturePoint::HandleNeutralEventHorde(GameObject* controlZone) +{ + GetBattlefield()->SendWarning(_textIdHordeLost); + sWorldStateMgr->SetValue(_worldstateHordeControlled, 0, false, controlZone->GetMap()); + sWorldStateMgr->SetValue(_worldstateAllianceCapturing, 1, false, controlZone->GetMap()); + BattlefieldControlZoneHandler::HandleNeutralEventHorde(controlZone); +} - // Update counter - m_Bf->ProcessEvent(nullptr, EVENT_COUNT_CAPTURED_BASE, nullptr); +void TolBaradCapturePoint::HandleNeutralEventAlliance(GameObject* controlZone) +{ + GetBattlefield()->SendWarning(_textIdAllianceLost); + sWorldStateMgr->SetValue(_worldstateAllianceControlled, 0, false, controlZone->GetMap()); + sWorldStateMgr->SetValue(_worldstateHordeCapturing, 1, false, controlZone->GetMap()); + BattlefieldControlZoneHandler::HandleNeutralEventAlliance(controlZone); +} + +void TolBaradCapturePoint::HandleNeutralEvent(GameObject* controlZone) +{ + BattlefieldControlZoneHandler::HandleNeutralEvent(controlZone); + controlZone->SetGoArtKit(TB_GO_ARTKIT_FLAG_NONE); } class Battlefield_tol_barad : public BattlefieldScript diff --git a/src/server/scripts/Battlefield/BattlefieldTB.h b/src/server/scripts/Battlefield/BattlefieldTB.h index f39e39d690c..5abc463fed0 100644 --- a/src/server/scripts/Battlefield/BattlefieldTB.h +++ b/src/server/scripts/Battlefield/BattlefieldTB.h @@ -533,12 +533,32 @@ TBGraveyardInfo const TBGraveyards[BATTLEFIELD_TB_GRAVEYARD_MAX] = * Tol Barad capture point * * ####################### */ -class TolBaradCapturePoint : public BfCapturePoint +class TolBaradCapturePoint : public BattlefieldControlZoneHandler { public: - TolBaradCapturePoint(BattlefieldTB* battlefield, TeamId teamInControl); - - void SendChangePhase() override; + TolBaradCapturePoint(BattlefieldTB* battlefield, TBCapturePointSpawnData const& data); + + void HandleContestedEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleContestedEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleProgressEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleProgressEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEvent([[maybe_unused]] GameObject* controlZone) override; + + uint32 GetWorldStateHordeControlled() const { return _worldstateHordeControlled; } + uint32 GetWorldStateAllianceControlled() const { return _worldstateAllianceControlled; } + + private: + uint32 _textIdHordeCaptured; + uint32 _textIdAllianceCaptured; + uint32 _textIdHordeLost; + uint32 _textIdAllianceLost; + uint32 _worldstateHordeControlled; + uint32 _worldstateAllianceControlled; + uint32 _worldstateHordeCapturing; + uint32 _worldstateAllianceCapturing; + uint32 _worldstateNeutral; }; /* ##################### * diff --git a/src/server/scripts/Battlefield/BattlefieldWG.cpp b/src/server/scripts/Battlefield/BattlefieldWG.cpp index f5ee13db181..a44916c10ec 100644 --- a/src/server/scripts/Battlefield/BattlefieldWG.cpp +++ b/src/server/scripts/Battlefield/BattlefieldWG.cpp @@ -928,11 +928,18 @@ void BattlefieldWG::OnGameObjectCreate(GameObject* go) { if (workshop->GetId() == workshopId) { - WintergraspCapturePoint* capturePoint = new WintergraspCapturePoint(this, GetAttackerTeam()); + ControlZoneHandlers[go->GetEntry()] = std::make_unique<WintergraspCapturePoint>(this, workshop); + if (GetAttackerTeam() == TEAM_ALLIANCE) + { + //go->SetGoArtKit(); // todo set art kit + go->HandleCustomTypeCommand(GameObjectType::SetControlZoneValue(100)); + } + else if (GetAttackerTeam() == TEAM_HORDE) + { + //go->SetGoArtKit(); // todo set art kit + go->HandleCustomTypeCommand(GameObjectType::SetControlZoneValue(0)); + } - capturePoint->SetCapturePointData(go); - capturePoint->LinkToWorkshop(workshop); - AddCapturePoint(capturePoint); break; } } @@ -1185,8 +1192,9 @@ void BattlefieldWG::UpdatedDestroyedTowerCount(TeamId team) } } -void BattlefieldWG::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* /*invoker*/) +void BattlefieldWG::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker) { + Battlefield::ProcessEvent(obj, eventId, invoker); if (!obj || !IsWarTime()) return; @@ -1311,17 +1319,34 @@ void BattlefieldWG::UpdateTenacity() m_tenacityTeam = TEAM_NEUTRAL; } -WintergraspCapturePoint::WintergraspCapturePoint(BattlefieldWG* battlefield, TeamId teamInControl) : BfCapturePoint(battlefield) +WintergraspCapturePoint::WintergraspCapturePoint(BattlefieldWG* battlefield, WintergraspWorkshop* workshop) : BattlefieldControlZoneHandler(battlefield), m_Workshop(workshop) { - m_Bf = battlefield; - m_team = teamInControl; - m_Workshop = nullptr; } -void WintergraspCapturePoint::ChangeTeam(TeamId /*oldTeam*/) +void WintergraspCapturePoint::HandleContestedEventHorde(GameObject* controlZone) +{ + ASSERT(m_Workshop); + BattlefieldControlZoneHandler::HandleContestedEventHorde(controlZone); + m_Workshop->GiveControlTo(TEAM_NEUTRAL); +} + +void WintergraspCapturePoint::HandleContestedEventAlliance(GameObject* controlZone) +{ + ASSERT(m_Workshop); + BattlefieldControlZoneHandler::HandleContestedEventAlliance(controlZone); + m_Workshop->GiveControlTo(TEAM_NEUTRAL); +} + +void WintergraspCapturePoint::HandleProgressEventHorde(GameObject* /*controlZone*/) +{ + ASSERT(m_Workshop); + m_Workshop->GiveControlTo(TEAM_HORDE); +} + +void WintergraspCapturePoint::HandleProgressEventAlliance(GameObject* /*controlZone*/) { ASSERT(m_Workshop); - m_Workshop->GiveControlTo(m_team); + m_Workshop->GiveControlTo(TEAM_ALLIANCE); } BfGraveyardWG::BfGraveyardWG(BattlefieldWG* battlefield) : BfGraveyard(battlefield) diff --git a/src/server/scripts/Battlefield/BattlefieldWG.h b/src/server/scripts/Battlefield/BattlefieldWG.h index 3f10861fe58..001c8f1a07a 100644 --- a/src/server/scripts/Battlefield/BattlefieldWG.h +++ b/src/server/scripts/Battlefield/BattlefieldWG.h @@ -179,15 +179,15 @@ enum WintergraspNpcs * WintergraspCapturePoint * * ######################### */ -class WintergraspCapturePoint : public BfCapturePoint +class WintergraspCapturePoint : public BattlefieldControlZoneHandler { public: - WintergraspCapturePoint(BattlefieldWG* battlefield, TeamId teamInControl); + WintergraspCapturePoint(BattlefieldWG* battlefield, WintergraspWorkshop* workshop); - void LinkToWorkshop(WintergraspWorkshop* workshop) { m_Workshop = workshop; } - - void ChangeTeam(TeamId oldteam) override; - TeamId GetTeam() const { return m_team; } + void HandleContestedEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleContestedEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleProgressEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleProgressEventAlliance([[maybe_unused]] GameObject* controlZone) override; protected: WintergraspWorkshop* m_Workshop; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp index 1a880c0748e..311ea43f84d 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPHP.cpp @@ -18,38 +18,52 @@ #include "OutdoorPvPHP.h" #include "GameObject.h" #include "Map.h" +#include "ObjectAccessor.h" #include "Player.h" #include "ScriptMgr.h" #include "WorldStatePackets.h" uint32 const OutdoorPvPHPBuffZonesNum = 6; uint32 const OutdoorPvPHPBuffZones[OutdoorPvPHPBuffZonesNum] = { 3483, 3563, 3562, 3713, 3714, 3836 }; // HP, citadel, ramparts, blood furnace, shattered halls, mag's lair -uint32 const HP_CREDITMARKER[HP_TOWER_NUM] = { 19032, 19028, 19029 }; -//uint32 const HP_CapturePointEvent_Enter[HP_TOWER_NUM] = { 11404, 11396, 11388 }; -//uint32 const HP_CapturePointEvent_Leave[HP_TOWER_NUM] = { 11403, 11395, 11387 }; -uint32 const HP_MAP_N[HP_TOWER_NUM] = { 2485, 2482, 2472 }; -uint32 const HP_MAP_A[HP_TOWER_NUM] = { 2483, 2480, 2471 }; -uint32 const HP_MAP_H[HP_TOWER_NUM] = { 2484, 2481, 2470 }; -uint32 const HP_TowerArtKit_A[HP_TOWER_NUM] = { 65, 62, 67 }; -uint32 const HP_TowerArtKit_H[HP_TOWER_NUM] = { 64, 61, 68 }; -uint32 const HP_TowerArtKit_N[HP_TOWER_NUM] = { 66, 63, 69 }; - -uint32 const HP_LANG_CAPTURE_A[HP_TOWER_NUM] = { TEXT_BROKEN_HILL_TAKEN_ALLIANCE, TEXT_OVERLOOK_TAKEN_ALLIANCE, TEXT_STADIUM_TAKEN_ALLIANCE }; -uint32 const HP_LANG_CAPTURE_H[HP_TOWER_NUM] = { TEXT_BROKEN_HILL_TAKEN_HORDE, TEXT_OVERLOOK_TAKEN_HORDE, TEXT_STADIUM_TAKEN_HORDE }; - -OPvPCapturePointHP::OPvPCapturePointHP(OutdoorPvP* pvp, OutdoorPvPHPTowerType type, GameObject* go, ObjectGuid::LowType const& flagSpawnId) - : OPvPCapturePoint(pvp), m_TowerType(type), m_flagSpawnId(flagSpawnId) -{ - m_capturePointSpawnId = go->GetSpawnId(); - m_capturePoint = go; - SetCapturePointData(go->GetEntry()); -} -OutdoorPvPHP::OutdoorPvPHP(Map* map) : OutdoorPvP(map), m_towerFlagSpawnIds() +OutdoorPvPHP::OutdoorPvPHP(Map* map) : OutdoorPvP(map) { m_TypeId = OUTDOOR_PVP_HP; m_AllianceTowersControlled = 0; m_HordeTowersControlled = 0; + + ControlZoneHandlers[HP_GO_ENTRY_TOWER_S] = std::make_unique<HPControlZoneHandler>(this); + GetControlZoneTowerSouthHandler().SetFlagArtKitAlliance(65); + GetControlZoneTowerSouthHandler().SetFlagArtKitHorde(64); + GetControlZoneTowerSouthHandler().SetFlagArtKitNeutral(66); + GetControlZoneTowerSouthHandler().SetTextCaptureAlliance(TEXT_BROKEN_HILL_TAKEN_ALLIANCE); + GetControlZoneTowerSouthHandler().SetTextCaptureHorde(TEXT_BROKEN_HILL_TAKEN_HORDE); + GetControlZoneTowerSouthHandler().SetWorldstateAlliance(HP_UI_TOWER_S_A); + GetControlZoneTowerSouthHandler().SetWorldstateHorde(HP_UI_TOWER_S_H); + GetControlZoneTowerSouthHandler().SetWorldstateNeutral(HP_UI_TOWER_S_N); + GetControlZoneTowerSouthHandler().SetKillCredit(HP_KILL_CREDIT_TOWER_S); + + ControlZoneHandlers[HP_GO_ENTRY_TOWER_N] = std::make_unique<HPControlZoneHandler>(this); + GetControlZoneTowerNorthHandler().SetFlagArtKitAlliance(62); + GetControlZoneTowerNorthHandler().SetFlagArtKitHorde(61); + GetControlZoneTowerNorthHandler().SetFlagArtKitNeutral(63); + GetControlZoneTowerNorthHandler().SetTextCaptureAlliance(TEXT_OVERLOOK_TAKEN_ALLIANCE); + GetControlZoneTowerNorthHandler().SetTextCaptureHorde(TEXT_OVERLOOK_TAKEN_HORDE); + GetControlZoneTowerNorthHandler().SetWorldstateAlliance(HP_UI_TOWER_N_A); + GetControlZoneTowerNorthHandler().SetWorldstateHorde(HP_UI_TOWER_N_H); + GetControlZoneTowerNorthHandler().SetWorldstateNeutral(HP_UI_TOWER_N_N); + GetControlZoneTowerNorthHandler().SetKillCredit(HP_KILL_CREDIT_TOWER_N); + + ControlZoneHandlers[HP_GO_ENTRY_TOWER_W] = std::make_unique<HPControlZoneHandler>(this); + GetControlZoneTowerWestHandler().SetFlagArtKitAlliance(67); + GetControlZoneTowerWestHandler().SetFlagArtKitHorde(68); + GetControlZoneTowerWestHandler().SetFlagArtKitNeutral(69); + GetControlZoneTowerWestHandler().SetTextCaptureAlliance(TEXT_STADIUM_TAKEN_ALLIANCE); + GetControlZoneTowerWestHandler().SetTextCaptureHorde(TEXT_STADIUM_TAKEN_HORDE); + GetControlZoneTowerWestHandler().SetWorldstateAlliance(HP_UI_TOWER_W_A); + GetControlZoneTowerWestHandler().SetWorldstateHorde(HP_UI_TOWER_W_H); + GetControlZoneTowerWestHandler().SetWorldstateNeutral(HP_UI_TOWER_W_N); + GetControlZoneTowerWestHandler().SetKillCredit(HP_KILL_CREDIT_TOWER_W); } bool OutdoorPvPHP::SetupOutdoorPvP() @@ -66,25 +80,19 @@ bool OutdoorPvPHP::SetupOutdoorPvP() void OutdoorPvPHP::OnGameObjectCreate(GameObject* go) { + if (go->GetGoType() == GAMEOBJECT_TYPE_CONTROL_ZONE) + _controlZoneGUIDs.insert(go->GetGUID()); + switch (go->GetEntry()) { - case 182175: - AddCapturePoint(new OPvPCapturePointHP(this, HP_TOWER_BROKEN_HILL, go, m_towerFlagSpawnIds[HP_TOWER_BROKEN_HILL])); - break; - case 182174: - AddCapturePoint(new OPvPCapturePointHP(this, HP_TOWER_OVERLOOK, go, m_towerFlagSpawnIds[HP_TOWER_OVERLOOK])); - break; - case 182173: - AddCapturePoint(new OPvPCapturePointHP(this, HP_TOWER_STADIUM, go, m_towerFlagSpawnIds[HP_TOWER_STADIUM])); - break; case 183514: - m_towerFlagSpawnIds[HP_TOWER_BROKEN_HILL] = go->GetSpawnId(); + GetControlZoneTowerSouthHandler().SetFlagGuid(go->GetGUID()); break; case 182525: - m_towerFlagSpawnIds[HP_TOWER_OVERLOOK] = go->GetSpawnId(); + GetControlZoneTowerNorthHandler().SetFlagGuid(go->GetGUID()); break; case 183515: - m_towerFlagSpawnIds[HP_TOWER_STADIUM] = go->GetSpawnId(); + GetControlZoneTowerWestHandler().SetFlagGuid(go->GetGUID()); break; default: break; @@ -123,24 +131,20 @@ void OutdoorPvPHP::HandlePlayerLeaveZone(Player* player, uint32 zone) OutdoorPvP::HandlePlayerLeaveZone(player, zone); } -bool OutdoorPvPHP::Update(uint32 diff) +void OutdoorPvPHP::Update(uint32 diff) { - bool changed = OutdoorPvP::Update(diff); - if (changed) + OutdoorPvP::Update(diff); + if (m_AllianceTowersControlled == 3) + TeamApplyBuff(TEAM_ALLIANCE, AllianceBuff, HordeBuff); + else if (m_HordeTowersControlled == 3) + TeamApplyBuff(TEAM_HORDE, HordeBuff, AllianceBuff); + else { - if (m_AllianceTowersControlled == 3) - TeamApplyBuff(TEAM_ALLIANCE, AllianceBuff, HordeBuff); - else if (m_HordeTowersControlled == 3) - TeamApplyBuff(TEAM_HORDE, HordeBuff, AllianceBuff); - else - { - TeamCastSpell(TEAM_ALLIANCE, -AllianceBuff); - TeamCastSpell(TEAM_HORDE, -HordeBuff); - } - SetWorldState(HP_UI_TOWER_COUNT_A, m_AllianceTowersControlled); - SetWorldState(HP_UI_TOWER_COUNT_H, m_HordeTowersControlled); + TeamCastSpell(TEAM_ALLIANCE, -AllianceBuff); + TeamCastSpell(TEAM_HORDE, -HordeBuff); } - return changed; + SetWorldState(HP_UI_TOWER_COUNT_A, m_AllianceTowersControlled); + SetWorldState(HP_UI_TOWER_COUNT_H, m_HordeTowersControlled); } void OutdoorPvPHP::SendRemoveWorldStates(Player* player) @@ -154,128 +158,46 @@ void OutdoorPvPHP::SendRemoveWorldStates(Player* player) initWorldStates.Worldstates.emplace_back(HP_UI_TOWER_COUNT_H, 0); initWorldStates.Worldstates.emplace_back(HP_UI_TOWER_COUNT_A, 0); - for (size_t i = 0; i < HP_TOWER_NUM; ++i) + for (auto& itr : ControlZoneHandlers) { - initWorldStates.Worldstates.emplace_back(HP_MAP_N[i], 0); - initWorldStates.Worldstates.emplace_back(HP_MAP_A[i], 0); - initWorldStates.Worldstates.emplace_back(HP_MAP_H[i], 0); + HPControlZoneHandler* handler = static_cast<HPControlZoneHandler*>(itr.second.get()); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateNeutral(), 0); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateHorde(), 0); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateAlliance(), 0); } player->SendDirectMessage(initWorldStates.Write()); } -void OPvPCapturePointHP::ChangeState() +void OutdoorPvPHP::HandleKillImpl(Player* player, Unit* killed) { - uint32 field = 0; - switch (m_OldState) - { - case OBJECTIVESTATE_NEUTRAL: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_ALLIANCE: - field = HP_MAP_A[m_TowerType]; - if (uint32 alliance_towers = ((OutdoorPvPHP*)m_PvP)->GetAllianceTowersControlled()) - ((OutdoorPvPHP*)m_PvP)->SetAllianceTowersControlled(--alliance_towers); - break; - case OBJECTIVESTATE_HORDE: - field = HP_MAP_H[m_TowerType]; - if (uint32 horde_towers = ((OutdoorPvPHP*)m_PvP)->GetHordeTowersControlled()) - ((OutdoorPvPHP*)m_PvP)->SetHordeTowersControlled(--horde_towers); - break; - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - field = HP_MAP_A[m_TowerType]; - break; - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - field = HP_MAP_H[m_TowerType]; - break; - } + if (killed->GetTypeId() != TYPEID_PLAYER) + return; - // send world state update - if (field) + // need to check if player is inside an capture zone + bool isInsideCaptureZone = false; + for (ObjectGuid const& guid : _controlZoneGUIDs) { - m_PvP->SetWorldState(field, 0); - field = 0; - } - uint32 artkit = 21; - uint32 artkit2 = HP_TowerArtKit_N[m_TowerType]; - switch (m_State) - { - case OBJECTIVESTATE_NEUTRAL: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_ALLIANCE: - { - field = HP_MAP_A[m_TowerType]; - artkit = 2; - artkit2 = HP_TowerArtKit_A[m_TowerType]; - uint32 alliance_towers = ((OutdoorPvPHP*)m_PvP)->GetAllianceTowersControlled(); - if (alliance_towers < 3) - ((OutdoorPvPHP*)m_PvP)->SetAllianceTowersControlled(++alliance_towers); - m_PvP->SendDefenseMessage(OutdoorPvPHPBuffZones[0], HP_LANG_CAPTURE_A[m_TowerType]); - break; + if (GameObject* gameObject = GetMap()->GetGameObject(guid)) + { + if (GuidUnorderedSet const* insidePlayerGuids = gameObject->GetInsidePlayers()) + { + if (insidePlayerGuids->contains(player->GetGUID())) + { + isInsideCaptureZone = true; + break; + } + } + } } - case OBJECTIVESTATE_HORDE: + + if (isInsideCaptureZone) { - field = HP_MAP_H[m_TowerType]; - artkit = 1; - artkit2 = HP_TowerArtKit_H[m_TowerType]; - uint32 horde_towers = ((OutdoorPvPHP*)m_PvP)->GetHordeTowersControlled(); - if (horde_towers < 3) - ((OutdoorPvPHP*)m_PvP)->SetHordeTowersControlled(++horde_towers); - m_PvP->SendDefenseMessage(OutdoorPvPHPBuffZones[0], HP_LANG_CAPTURE_H[m_TowerType]); - break; + if (player->GetTeam() == ALLIANCE && killed->ToPlayer()->GetTeam() != ALLIANCE) + player->CastSpell(player, AlliancePlayerKillReward, true); + else if (player->GetTeam() == HORDE && killed->ToPlayer()->GetTeam() != HORDE) + player->CastSpell(player, HordePlayerKillReward, true); } - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - field = HP_MAP_N[m_TowerType]; - break; - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - field = HP_MAP_A[m_TowerType]; - artkit = 2; - artkit2 = HP_TowerArtKit_A[m_TowerType]; - break; - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - field = HP_MAP_H[m_TowerType]; - artkit = 1; - artkit2 = HP_TowerArtKit_H[m_TowerType]; - break; - } - - Map* map = m_PvP->GetMap(); - auto bounds = map->GetGameObjectBySpawnIdStore().equal_range(m_capturePointSpawnId); - for (auto itr = bounds.first; itr != bounds.second; ++itr) - itr->second->SetGoArtKit(artkit); - - bounds = map->GetGameObjectBySpawnIdStore().equal_range(m_flagSpawnId); - for (auto itr = bounds.first; itr != bounds.second; ++itr) - itr->second->SetGoArtKit(artkit2); - - // send world state update - if (field) - m_PvP->SetWorldState(field, 1); - - // complete quest objective - if (m_State == OBJECTIVESTATE_ALLIANCE || m_State == OBJECTIVESTATE_HORDE) - SendObjectiveComplete(HP_CREDITMARKER[m_TowerType], ObjectGuid::Empty); -} - -void OutdoorPvPHP::HandleKillImpl(Player* player, Unit* killed) -{ - if (killed->GetTypeId() != TYPEID_PLAYER) - return; - - if (player->GetTeam() == ALLIANCE && killed->ToPlayer()->GetTeam() != ALLIANCE) - player->CastSpell(player, AlliancePlayerKillReward, true); - else if (player->GetTeam() == HORDE && killed->ToPlayer()->GetTeam() != HORDE) - player->CastSpell(player, HordePlayerKillReward, true); } uint32 OutdoorPvPHP::GetAllianceTowersControlled() const @@ -298,6 +220,88 @@ void OutdoorPvPHP::SetHordeTowersControlled(uint32 count) m_HordeTowersControlled = count; } +HPControlZoneHandler::HPControlZoneHandler(OutdoorPvPHP* pvp) : OutdoorPvPControlZoneHandler(pvp), + _flagGuid(ObjectGuid::Empty), _textCaptureAlliance(0), _textCaptureHorde(0), + _flagArtKitNeutral(0), _flagArtKitHorde(0), _flagArtKitAlliance(0), + _worldstateNeutral(0), _worldstateHorde(0), _worldstateAlliance(0), + _killCredit(0) +{ +} + +void HPControlZoneHandler::HandleProgressEventHorde(GameObject* controlZone) +{ + ControlZoneHandler::HandleProgressEventHorde(controlZone); + + controlZone->SetGoArtKit(1); + controlZone->SendCustomAnim(0); + if (GameObject* flag = controlZone->GetMap()->GetGameObject(_flagGuid)) + flag->SetGoArtKit(_flagArtKitHorde); + + controlZone->GetMap()->SetWorldStateValue(_worldstateHorde, 1, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateAlliance, 0, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateNeutral, 0, false); + + GetOutdoorPvPHP()->SendDefenseMessage(OutdoorPvPHPBuffZones[0], _textCaptureHorde); + + if (GuidUnorderedSet const* guidSet = controlZone->GetInsidePlayers()) + for (ObjectGuid const& guid : *guidSet) + if (Player* player = ObjectAccessor::GetPlayer(*controlZone, guid)) + if (player->GetTeam() == TEAM_HORDE) + player->KilledMonsterCredit(_killCredit); +} + +void HPControlZoneHandler::HandleProgressEventAlliance(GameObject* controlZone) +{ + ControlZoneHandler::HandleProgressEventAlliance(controlZone); + + controlZone->SetGoArtKit(2); + controlZone->SendCustomAnim(1); + if (GameObject* flag = controlZone->GetMap()->GetGameObject(_flagGuid)) + flag->SetGoArtKit(_flagArtKitAlliance); + + controlZone->GetMap()->SetWorldStateValue(_worldstateHorde, 0, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateAlliance, 1, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateNeutral, 0, false); + + GetOutdoorPvPHP()->SendDefenseMessage(OutdoorPvPHPBuffZones[0], _textCaptureAlliance); + + if (GuidUnorderedSet const* guidSet = controlZone->GetInsidePlayers()) + for (ObjectGuid const& guid : *guidSet) + if (Player* player = ObjectAccessor::GetPlayer(*controlZone, guid)) + if (player->GetTeam() == TEAM_ALLIANCE) + player->KilledMonsterCredit(_killCredit); +} + +void HPControlZoneHandler::HandleNeutralEventHorde(GameObject* controlZone) +{ + ControlZoneHandler::HandleNeutralEventHorde(controlZone); + GetOutdoorPvPHP()->SetHordeTowersControlled(GetOutdoorPvPHP()->GetHordeTowersControlled() - 1); +} + +void HPControlZoneHandler::HandleNeutralEventAlliance(GameObject* controlZone) +{ + ControlZoneHandler::HandleNeutralEventAlliance(controlZone); + GetOutdoorPvPHP()->SetAllianceTowersControlled(GetOutdoorPvPHP()->GetAllianceTowersControlled() - 1); +} + +void HPControlZoneHandler::HandleNeutralEvent(GameObject* controlZone) +{ + ControlZoneHandler::HandleNeutralEvent(controlZone); + controlZone->SetGoArtKit(21); + controlZone->SendCustomAnim(2); + if (GameObject* flag = controlZone->GetMap()->GetGameObject(_flagGuid)) + flag->SetGoArtKit(_flagArtKitNeutral); + + controlZone->GetMap()->SetWorldStateValue(_worldstateHorde, 0, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateAlliance, 0, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateNeutral, 1, false); +} + +OutdoorPvPHP* HPControlZoneHandler::GetOutdoorPvPHP() const +{ + return static_cast<OutdoorPvPHP*>(OutdoorPvPControlZoneHandler::GetOutdoorPvP()); +} + class OutdoorPvP_hellfire_peninsula : public OutdoorPvPScript { public: diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPHP.h b/src/server/scripts/OutdoorPvP/OutdoorPvPHP.h index 69b847c1107..416223e5e2d 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPHP.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPHP.h @@ -53,19 +53,94 @@ enum OutdoorPvPHPWorldStates HP_UI_TOWER_DISPLAY_H = 0x9b9, HP_UI_TOWER_COUNT_H = 0x9ae, - HP_UI_TOWER_COUNT_A = 0x9ac + HP_UI_TOWER_COUNT_A = 0x9ac, + + HP_UI_TOWER_S_A = 2483, + HP_UI_TOWER_S_H = 2484, + HP_UI_TOWER_S_N = 2485, + + HP_UI_TOWER_N_A = 2480, + HP_UI_TOWER_N_H = 2481, + HP_UI_TOWER_N_N = 2482, + + HP_UI_TOWER_W_A = 2471, + HP_UI_TOWER_W_H = 2470, + HP_UI_TOWER_W_N = 2472 }; -class OPvPCapturePointHP : public OPvPCapturePoint +enum OutdoorPvPHPEvents { - public: - OPvPCapturePointHP(OutdoorPvP* pvp, OutdoorPvPHPTowerType type, GameObject* go, ObjectGuid::LowType const& flagSpawnId); + HP_EVENT_TOWER_W_PROGRESS_HORDE = 11383, + HP_EVENT_TOWER_W_PROGRESS_ALLIANCE = 11387, + HP_EVENT_TOWER_W_NEUTRAL_HORDE = 11386, + HP_EVENT_TOWER_W_NEUTRAL_ALLIANCE = 11385, + + HP_EVENT_TOWER_N_PROGRESS_HORDE = 11396, + HP_EVENT_TOWER_N_PROGRESS_ALLIANCE = 11395, + HP_EVENT_TOWER_N_NEUTRAL_HORDE = 11394, + HP_EVENT_TOWER_N_NEUTRAL_ALLIANCE = 11393, + + HP_EVENT_TOWER_S_PROGRESS_HORDE = 11404, + HP_EVENT_TOWER_S_PROGRESS_ALLIANCE = 11403, + HP_EVENT_TOWER_S_NEUTRAL_HORDE = 11402, + HP_EVENT_TOWER_S_NEUTRAL_ALLIANCE = 11401 +}; - void ChangeState() override; +enum OutdoorPvPHPGameObjectEntries +{ + HP_GO_ENTRY_TOWER_W = 182173, + HP_GO_ENTRY_TOWER_N = 182174, + HP_GO_ENTRY_TOWER_S = 182175 +}; - private: - OutdoorPvPHPTowerType m_TowerType; - ObjectGuid::LowType const& m_flagSpawnId; +enum OutdoorPvPHPCredit +{ + HP_KILL_CREDIT_TOWER_S = 19032, + HP_KILL_CREDIT_TOWER_N = 19028, + HP_KILL_CREDIT_TOWER_W = 19029 +}; + +class OutdoorPvPHP; + +class HPControlZoneHandler : public OutdoorPvPControlZoneHandler +{ +public: + explicit HPControlZoneHandler(OutdoorPvPHP* pvp); + + void SetFlagGuid(ObjectGuid const& guid) { _flagGuid = guid; } + void SetTextCaptureHorde(uint32 text) { _textCaptureHorde = text; } + void SetTextCaptureAlliance(uint32 text) { _textCaptureAlliance = text; } + void SetFlagArtKitNeutral(uint32 artKit) { _flagArtKitNeutral = artKit; } + void SetFlagArtKitHorde(uint32 artKit) { _flagArtKitHorde = artKit; } + void SetFlagArtKitAlliance(uint32 artKit) { _flagArtKitAlliance = artKit; } + void SetWorldstateNeutral(uint32 id) { _worldstateNeutral = id; } + void SetWorldstateHorde(uint32 id) { _worldstateHorde = id; } + void SetWorldstateAlliance(uint32 id) { _worldstateAlliance = id; } + void SetKillCredit(uint32 credit) { _killCredit = credit; } + + void HandleProgressEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleProgressEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEvent([[maybe_unused]] GameObject* controlZone) override; + + uint32 GetWorldStateNeutral() { return _worldstateNeutral; } + uint32 GetWorldStateHorde() { return _worldstateHorde; } + uint32 GetWorldStateAlliance() { return _worldstateAlliance; } + + OutdoorPvPHP* GetOutdoorPvPHP() const; + +private: + ObjectGuid _flagGuid; + uint32 _textCaptureAlliance; + uint32 _textCaptureHorde; + uint32 _flagArtKitNeutral; + uint32 _flagArtKitHorde; + uint32 _flagArtKitAlliance; + uint32 _worldstateNeutral; + uint32 _worldstateHorde; + uint32 _worldstateAlliance; + uint32 _killCredit; }; class OutdoorPvPHP : public OutdoorPvP @@ -80,7 +155,7 @@ class OutdoorPvPHP : public OutdoorPvP void HandlePlayerEnterZone(Player* player, uint32 zone) override; void HandlePlayerLeaveZone(Player* player, uint32 zone) override; - bool Update(uint32 diff) override; + void Update(uint32 diff) override; void SendRemoveWorldStates(Player* player) override; void HandleKillImpl(Player* player, Unit* killed) override; @@ -92,7 +167,12 @@ class OutdoorPvPHP : public OutdoorPvP private: uint32 m_AllianceTowersControlled; // how many towers are controlled uint32 m_HordeTowersControlled; - std::array<ObjectGuid::LowType, HP_TOWER_NUM> m_towerFlagSpawnIds; + + GuidUnorderedSet _controlZoneGUIDs; + + HPControlZoneHandler& GetControlZoneTowerNorthHandler() { return *static_cast<HPControlZoneHandler*>(ControlZoneHandlers[HP_GO_ENTRY_TOWER_N].get()); } + HPControlZoneHandler& GetControlZoneTowerSouthHandler() { return *static_cast<HPControlZoneHandler*>(ControlZoneHandlers[HP_GO_ENTRY_TOWER_S].get()); } + HPControlZoneHandler& GetControlZoneTowerWestHandler() { return *static_cast<HPControlZoneHandler*>(ControlZoneHandlers[HP_GO_ENTRY_TOWER_W].get()); } }; #endif diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp index 06691aa8a0e..4453d9435cf 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.cpp @@ -40,6 +40,7 @@ OutdoorPvPNA::OutdoorPvPNA(Map* map) : OutdoorPvP(map) { m_TypeId = OUTDOOR_PVP_NA; m_obj = nullptr; + ControlZoneHandlers[182210] = std::make_unique<NAControlZoneHandler>(this); } void OutdoorPvPNA::OnGameObjectCreate(GameObject* go) @@ -47,8 +48,7 @@ void OutdoorPvPNA::OnGameObjectCreate(GameObject* go) switch (go->GetEntry()) { case 182210: - m_obj->m_capturePointSpawnId = go->GetSpawnId(); - AddCapturePoint(m_obj); + m_obj->SetControlZoneGUID(go->GetGUID()); break; } @@ -67,6 +67,91 @@ void OutdoorPvPNA::HandleKillImpl(Player* player, Unit* killed) } } +NAControlZoneHandler::NAControlZoneHandler(OutdoorPvPNA* pvp) : OutdoorPvPControlZoneHandler(pvp) +{ +} + +void NAControlZoneHandler::HandleCaptureEventHorde(GameObject* controlZone) +{ + OutdoorPvPControlZoneHandler::HandleCaptureEventHorde(controlZone); + + if (GetOutdoorPvPNA()->GetCapturePoint()->GetControllingFaction() != HORDE) + { + GetOutdoorPvPNA()->SendMapWorldStates(0, 0, 0, 1, 0); + GetOutdoorPvPNA()->GetCapturePoint()->FactionTakeOver(HORDE); + } +} + +void NAControlZoneHandler::HandleCaptureEventAlliance(GameObject* controlZone) +{ + OutdoorPvPControlZoneHandler::HandleCaptureEventAlliance(controlZone); + + if (GetOutdoorPvPNA()->GetCapturePoint()->GetControllingFaction() != ALLIANCE) + { + GetOutdoorPvPNA()->SendMapWorldStates(0, 0, 0, 0, 1); + GetOutdoorPvPNA()->GetCapturePoint()->FactionTakeOver(ALLIANCE); + } +} + +void NAControlZoneHandler::HandleContestedEventHorde(GameObject* controlZone) +{ + OutdoorPvPControlZoneHandler::HandleContestedEventHorde(controlZone); + + GetOutdoorPvPNA()->SendMapWorldStates(0, 1, 0, 0, 0); +} + +void NAControlZoneHandler::HandleContestedEventAlliance(GameObject* controlZone) +{ + OutdoorPvPControlZoneHandler::HandleContestedEventAlliance(controlZone); + + GetOutdoorPvPNA()->SendMapWorldStates(0, 0, 1, 0, 0); +} + +void NAControlZoneHandler::HandleProgressEventHorde(GameObject* controlZone) +{ + OutdoorPvPControlZoneHandler::HandleProgressEventHorde(controlZone); + + controlZone->SetGoArtKit(1); + GetOutdoorPvPNA()->SendMapWorldStates(0, 1, 0, 0, 0); +} + +void NAControlZoneHandler::HandleProgressEventAlliance(GameObject* controlZone) +{ + OutdoorPvPControlZoneHandler::HandleProgressEventAlliance(controlZone); + + controlZone->SetGoArtKit(2); + GetOutdoorPvPNA()->SendMapWorldStates(0, 0, 1, 0, 0); +} + +void NAControlZoneHandler::HandleNeutralEventHorde(GameObject* controlZone) +{ + OutdoorPvPControlZoneHandler::HandleNeutralEventHorde(controlZone); +} + +void NAControlZoneHandler::HandleNeutralEventAlliance(GameObject* controlZone) +{ + OutdoorPvPControlZoneHandler::HandleNeutralEventAlliance(controlZone); +} + +void NAControlZoneHandler::HandleNeutralEvent(GameObject* controlZone) +{ + OutdoorPvPControlZoneHandler::HandleNeutralEvent(controlZone); +} + +OutdoorPvPNA* NAControlZoneHandler::GetOutdoorPvPNA() const +{ + return static_cast<OutdoorPvPNA*>(OutdoorPvPControlZoneHandler::GetOutdoorPvP()); +} + +void OutdoorPvPNA::SendMapWorldStates(int32 neutral, int32 progressHorde, int32 progressAlliance, int32 capturedHorde, int32 captureAlliance) +{ + SetWorldState(NA_MAP_HALAA_NEUTRAL, neutral); + SetWorldState(NA_MAP_HALAA_NEU_H, progressHorde); + SetWorldState(NA_MAP_HALAA_NEU_A, progressAlliance); + SetWorldState(NA_MAP_HALAA_HORDE, capturedHorde); + SetWorldState(NA_MAP_HALAA_ALLIANCE, captureAlliance); +} + uint32 OPvPCapturePointNA::GetAliveGuardsCount() const { Position searchCenter = { -1572.57f, 7945.3f, -22.475f, 2.05949f }; @@ -89,7 +174,9 @@ void OPvPCapturePointNA::FactionTakeOver(uint32 team) m_ControllingFaction = team; m_GuardsAlive = NA_GUARDS_MAX; m_capturable = false; - UpdateHalaaWorldState(); + if (GameObject* gameObject = m_PvP->GetMap()->GetGameObject(_controlZoneGUID)) + gameObject->ActivateObject(GameObjectActions::MakeInert, 0); + if (team == ALLIANCE) { m_WyvernStateSouth = WYVERN_NEU_HORDE; @@ -121,9 +208,9 @@ void OPvPCapturePointNA::FactionTakeOver(uint32 team) } OPvPCapturePointNA::OPvPCapturePointNA(OutdoorPvP* pvp) : OPvPCapturePoint(pvp), m_capturable(true), m_GuardsAlive(0), m_ControllingFaction(0), m_WyvernStateNorth(0), m_WyvernStateSouth(0), m_WyvernStateEast(0), - m_WyvernStateWest(0), m_HalaaState(HALAA_N), m_RespawnTimer(NA_RESPAWN_TIME), m_GuardCheckTimer(NA_GUARD_CHECK_TIME) + m_WyvernStateWest(0), m_RespawnTimer(NA_RESPAWN_TIME), m_GuardCheckTimer(NA_GUARD_CHECK_TIME) { - SetCapturePointData(182210); + } bool OutdoorPvPNA::SetupOutdoorPvP() @@ -187,9 +274,9 @@ void OutdoorPvPNA::SendRemoveWorldStates(Player* player) player->SendDirectMessage(initWorldStates.Write()); } -bool OutdoorPvPNA::Update(uint32 diff) +void OutdoorPvPNA::Update(uint32 diff) { - return m_obj->Update(diff); + m_obj->Update(diff); } bool OPvPCapturePointNA::HandleCustomSpell(Player* player, uint32 spellId, GameObject* /*go*/) @@ -342,15 +429,8 @@ int32 OPvPCapturePointNA::HandleOpenGo(Player* player, GameObject* go) return 0; } -bool OPvPCapturePointNA::Update(uint32 diff) +void OPvPCapturePointNA::Update(uint32 diff) { - // let the controlling faction advance in phase - bool capturable = false; - if (m_ControllingFaction == ALLIANCE && m_activePlayers[0].size() > m_activePlayers[1].size()) - capturable = true; - else if (m_ControllingFaction == HORDE && m_activePlayers[0].size() < m_activePlayers[1].size()) - capturable = true; - if (m_GuardCheckTimer < diff) { m_GuardCheckTimer = NA_GUARD_CHECK_TIME; @@ -359,7 +439,11 @@ bool OPvPCapturePointNA::Update(uint32 diff) { m_capturable = true; m_RespawnTimer = NA_RESPAWN_TIME; + if (GameObject* gameObject = m_PvP->GetMap()->GetGameObject(_controlZoneGUID)) + gameObject->ActivateObject(GameObjectActions::MakeActive, 0); } + else if (GameObject* gameObject = m_PvP->GetMap()->GetGameObject(_controlZoneGUID)) + gameObject->ActivateObject(GameObjectActions::MakeInert, 0); // update the guard count for the players in zone m_PvP->SetWorldState(NA_UI_GUARDS_LEFT, m_GuardsAlive); } @@ -382,60 +466,8 @@ bool OPvPCapturePointNA::Update(uint32 diff) m_RespawnTimer -= diff; } - if (m_capturable || capturable) - return OPvPCapturePoint::Update(diff); - - return false; -} - -void OPvPCapturePointNA::ChangeState() -{ - uint32 artkit = 21; - switch (m_State) - { - case OBJECTIVESTATE_NEUTRAL: - m_HalaaState = HALAA_N; - break; - case OBJECTIVESTATE_ALLIANCE: - m_HalaaState = HALAA_A; - FactionTakeOver(ALLIANCE); - artkit = 2; - break; - case OBJECTIVESTATE_HORDE: - m_HalaaState = HALAA_H; - FactionTakeOver(HORDE); - artkit = 1; - break; - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - m_HalaaState = HALAA_N_A; - break; - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - m_HalaaState = HALAA_N_H; - break; - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - m_HalaaState = HALAA_N_A; - artkit = 2; - break; - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_HalaaState = HALAA_N_H; - artkit = 1; - break; - } - - auto bounds = m_PvP->GetMap()->GetGameObjectBySpawnIdStore().equal_range(m_capturePointSpawnId); - for (auto itr = bounds.first; itr != bounds.second; ++itr) - itr->second->SetGoArtKit(artkit); - - UpdateHalaaWorldState(); -} - -void OPvPCapturePointNA::UpdateHalaaWorldState() -{ - m_PvP->SetWorldState(NA_MAP_HALAA_NEUTRAL, uint32((m_HalaaState & HALAA_N) != 0)); - m_PvP->SetWorldState(NA_MAP_HALAA_NEU_A, uint32((m_HalaaState & HALAA_N_A) != 0)); - m_PvP->SetWorldState(NA_MAP_HALAA_NEU_H, uint32((m_HalaaState & HALAA_N_H) != 0)); - m_PvP->SetWorldState(NA_MAP_HALAA_HORDE, uint32((m_HalaaState & HALAA_H) != 0)); - m_PvP->SetWorldState(NA_MAP_HALAA_ALLIANCE, uint32((m_HalaaState & HALAA_A) != 0)); + if (m_capturable) + OPvPCapturePoint::Update(diff); } void OPvPCapturePointNA::UpdateWyvernRoostWorldState(uint32 roost) diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h index aff8e4c88fa..60c3e1f1c16 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h @@ -113,16 +113,47 @@ enum HalaaStates HALAA_H = 16 }; +enum HalaaEvents +{ + HALAA_EVENT_CAPTURE_HORDE = 11504, + HALAA_EVENT_CAPTURE_ALLIANCE = 11503, + HALAA_EVENT_CONTESTED_HORDE = 11559, + HALAA_EVENT_CONTESTED_ALLIANCE = 11558, + HALAA_EVENT_PROGRESS_HORDE = 11821, + HALAA_EVENT_PROGRESS_ALLIANCE = 11822 +}; + class Unit; class Creature; +class WorldObject; + +class OutdoorPvPNA; + +class NAControlZoneHandler : public OutdoorPvPControlZoneHandler +{ +public: + explicit NAControlZoneHandler(OutdoorPvPNA* pvp); + + void HandleCaptureEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleCaptureEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleContestedEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleContestedEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleProgressEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleProgressEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEvent([[maybe_unused]] GameObject* controlZone) override; + + OutdoorPvPNA* GetOutdoorPvPNA() const; +}; class OPvPCapturePointNA : public OPvPCapturePoint { public: OPvPCapturePointNA(OutdoorPvP* pvp); - bool Update(uint32 diff) override; - void ChangeState() override; + void Update(uint32 diff) override; + void ChangeState() override { } // todo remove? bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go) override; int32 HandleOpenGo(Player* player, GameObject* go) override; @@ -130,8 +161,8 @@ class OPvPCapturePointNA : public OPvPCapturePoint uint32 GetControllingFaction() const; void FactionTakeOver(uint32 team); // called when a faction takes control void UpdateWyvernRoostWorldState(uint32 roost); - void UpdateHalaaWorldState(); + void SetControlZoneGUID(ObjectGuid guid) { _controlZoneGUID = guid; } private: bool m_capturable; uint32 m_GuardsAlive; @@ -140,9 +171,9 @@ class OPvPCapturePointNA : public OPvPCapturePoint uint32 m_WyvernStateSouth; uint32 m_WyvernStateEast; uint32 m_WyvernStateWest; - uint32 m_HalaaState; uint32 m_RespawnTimer; uint32 m_GuardCheckTimer; + ObjectGuid _controlZoneGUID; }; class OutdoorPvPNA : public OutdoorPvP @@ -155,10 +186,11 @@ class OutdoorPvPNA : public OutdoorPvP bool SetupOutdoorPvP() override; void HandlePlayerEnterZone(Player* player, uint32 zone) override; void HandlePlayerLeaveZone(Player* player, uint32 zone) override; - bool Update(uint32 diff) override; + void Update(uint32 diff) override; void SendRemoveWorldStates(Player* player) override; void HandleKillImpl(Player* player, Unit* killed) override; - + void SendMapWorldStates(int32 neutral, int32 progressHorde, int32 progressAlliance, int32 capturedHorde, int32 captureAlliance); + OPvPCapturePointNA* GetCapturePoint() const { return m_obj; } private: OPvPCapturePointNA* m_obj; }; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp index f625cc8dd88..d652f9f8689 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp @@ -66,9 +66,8 @@ bool OutdoorPvPSI::SetupOutdoorPvP() return true; } -bool OutdoorPvPSI::Update(uint32 /*diff*/) +void OutdoorPvPSI::Update(uint32 /*diff*/) { - return false; } void OutdoorPvPSI::HandlePlayerEnterZone(Player* player, uint32 zone) diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.h b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.h index 71debd9012b..1c3630e42f5 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.h @@ -43,7 +43,7 @@ class OutdoorPvPSI : public OutdoorPvP bool SetupOutdoorPvP() override; void HandlePlayerEnterZone(Player* player, uint32 zone) override; void HandlePlayerLeaveZone(Player* player, uint32 zone) override; - bool Update(uint32 diff) override; + void Update(uint32 diff) override; void SendRemoveWorldStates(Player* player) override; bool HandleAreaTrigger(Player* player, uint32 trigger, bool entered) override; bool HandleDropFlag(Player* player, uint32 spellId) override; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp index 9ef73f70db8..dcc918ebc31 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.cpp @@ -45,42 +45,6 @@ int32 const TF_CAPTURE_BUFF = 33377; uint32 const TF_ALLY_QUEST = 11505; uint32 const TF_HORDE_QUEST = 11506; -struct tf_tower_world_state -{ - int32 n; - int32 h; - int32 a; -}; - -tf_tower_world_state const TFTowerWorldStates[TF_TOWER_NUM] = -{ - { 2681, 2682, 2683 }, - { 2686, 2685, 2684 }, - { 2690, 2689, 2688 }, - { 2696, 2695, 2694 }, - { 2693, 2692, 2691 } -}; - -/* -uint32 const TFTowerPlayerEnterEvents[TF_TOWER_NUM] = -{ - 12226, - 12497, - 12486, - 12499, - 12501 -}; - -uint32 const TFTowerPlayerLeaveEvents[TF_TOWER_NUM] = -{ - 12225, - 12496, - 12487, - 12498, - 12500 -}; -*/ - OutdoorPvPTF::OutdoorPvPTF(Map* map) : OutdoorPvP(map) { m_TypeId = OUTDOOR_PVP_TF; @@ -92,13 +56,12 @@ OutdoorPvPTF::OutdoorPvPTF(Map* map) : OutdoorPvP(map) hours_left = 6; second_digit = 0; first_digit = 0; -} -OPvPCapturePointTF::OPvPCapturePointTF(OutdoorPvP* pvp, OutdoorPvPTF_TowerType type, GameObject* go) : OPvPCapturePoint(pvp), m_TowerType(type), m_TowerState(TF_TOWERSTATE_N) -{ - m_capturePointSpawnId = go->GetSpawnId(); - m_capturePoint = go; - SetCapturePointData(go->GetEntry()); + ControlZoneHandlers[TF_ENTRY_TOWER_NW] = std::make_unique<TFControlZoneHandler>(this, 2682, 2683, 2681); + ControlZoneHandlers[TF_ENTRY_TOWER_N] = std::make_unique<TFControlZoneHandler>(this, 2685, 2684, 2686); + ControlZoneHandlers[TF_ENTRY_TOWER_NE] = std::make_unique<TFControlZoneHandler>(this, 2689, 2688, 2690); + ControlZoneHandlers[TF_ENTRY_TOWER_SE] = std::make_unique<TFControlZoneHandler>(this, 2695, 2694, 2696); + ControlZoneHandlers[TF_ENTRY_TOWER_S] = std::make_unique<TFControlZoneHandler>(this, 2692, 2691, 2693); } void OutdoorPvPTF::SendRemoveWorldStates(Player* player) @@ -119,55 +82,21 @@ void OutdoorPvPTF::SendRemoveWorldStates(Player* player) initWorldStates.Worldstates.emplace_back(TF_UI_LOCKED_DISPLAY_HORDE, 0); initWorldStates.Worldstates.emplace_back(TF_UI_LOCKED_DISPLAY_ALLIANCE, 0); - for (tf_tower_world_state const& towerWorldStates : TFTowerWorldStates) + for (auto& itr : ControlZoneHandlers) { - initWorldStates.Worldstates.emplace_back(towerWorldStates.n, 0); - initWorldStates.Worldstates.emplace_back(towerWorldStates.h, 0); - initWorldStates.Worldstates.emplace_back(towerWorldStates.a, 0); + TFControlZoneHandler* handler = static_cast<TFControlZoneHandler*>(itr.second.get()); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateNeutral(), 0); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateHorde(), 0); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateAlliance(), 0); } player->SendDirectMessage(initWorldStates.Write()); } -void OPvPCapturePointTF::UpdateTowerState() +void OutdoorPvPTF::Update(uint32 diff) { - m_PvP->SetWorldState(TFTowerWorldStates[m_TowerType].n, int32((m_TowerState & TF_TOWERSTATE_N) != 0)); - m_PvP->SetWorldState(TFTowerWorldStates[m_TowerType].h, int32((m_TowerState & TF_TOWERSTATE_H) != 0)); - m_PvP->SetWorldState(TFTowerWorldStates[m_TowerType].a, int32((m_TowerState & TF_TOWERSTATE_A) != 0)); -} - -bool OutdoorPvPTF::Update(uint32 diff) -{ - bool changed = OutdoorPvP::Update(diff); + OutdoorPvP::Update(diff); - if (changed) - { - if (m_AllianceTowersControlled == TF_TOWER_NUM) - { - TeamApplyBuff(TEAM_ALLIANCE, TF_CAPTURE_BUFF); - m_IsLocked = true; - SetWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, 0); - SetWorldState(TF_UI_LOCKED_DISPLAY_HORDE, 0); - SetWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE, 1); - SetWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, 0); - } - else if (m_HordeTowersControlled == TF_TOWER_NUM) - { - TeamApplyBuff(TEAM_HORDE, TF_CAPTURE_BUFF); - m_IsLocked = true; - SetWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, 0); - SetWorldState(TF_UI_LOCKED_DISPLAY_HORDE, 1); - SetWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE, 0); - SetWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, 0); - } - else - { - TeamCastSpell(TEAM_ALLIANCE, -TF_CAPTURE_BUFF); - TeamCastSpell(TEAM_HORDE, -TF_CAPTURE_BUFF); - } - SetWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled); - SetWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled); - } if (m_IsLocked) { // lock timer is down, release lock @@ -176,6 +105,16 @@ bool OutdoorPvPTF::Update(uint32 diff) m_LockTimer = TF_LOCK_TIME; m_LockTimerUpdate = 0; m_IsLocked = false; + + for (ObjectGuid const& controlZoneGUID : _controlZoneGUIDs) + { + if (GameObject* gameObject = GetMap()->GetGameObject(controlZoneGUID)) + { + gameObject->HandleCustomTypeCommand(GameObjectType::SetControlZoneValue()); + gameObject->ActivateObject(GameObjectActions::MakeActive, 0); + } + } + SetWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, 1); SetWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, 0); SetWorldState(TF_UI_LOCKED_DISPLAY_HORDE, 0); @@ -200,7 +139,6 @@ bool OutdoorPvPTF::Update(uint32 diff) m_LockTimer -= diff; } } - return changed; } void OutdoorPvPTF::HandlePlayerEnterZone(Player* player, uint32 zone) @@ -250,6 +188,40 @@ bool OutdoorPvPTF::IsLocked() const return m_IsLocked; } +void OutdoorPvPTF::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker) +{ + OutdoorPvP::ProcessEvent(obj, eventId, invoker); + + SetWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled); + SetWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled); + + // now check if everything is capped + if (m_HordeTowersControlled == TF_TOWER_NUM) + HandleCapture(TEAM_HORDE); + else if (m_AllianceTowersControlled == TF_TOWER_NUM) + HandleCapture(TEAM_ALLIANCE); + else + { + TeamCastSpell(TEAM_ALLIANCE, -TF_CAPTURE_BUFF); + TeamCastSpell(TEAM_HORDE, -TF_CAPTURE_BUFF); + } +} + +void OutdoorPvPTF::HandleCapture(TeamId team) +{ + m_IsLocked = true; + + for (ObjectGuid const& controlZoneGUID : _controlZoneGUIDs) + if (GameObject* gameObject = GetMap()->GetGameObject(controlZoneGUID)) + gameObject->ActivateObject(GameObjectActions::MakeInert, 0); + + TeamApplyBuff(team, TF_CAPTURE_BUFF); + SetWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, 0); + SetWorldState(TF_UI_LOCKED_DISPLAY_HORDE, team == TEAM_HORDE ? 1 : 0); + SetWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE, team == TEAM_ALLIANCE ? 1 : 0); + SetWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, 0); +} + bool OutdoorPvPTF::SetupOutdoorPvP() { m_AllianceTowersControlled = 0; @@ -273,20 +245,12 @@ void OutdoorPvPTF::OnGameObjectCreate(GameObject* go) { switch (go->GetEntry()) { - case 183104: - AddCapturePoint(new OPvPCapturePointTF(this, TF_TOWER_NW, go)); - break; - case 183411: - AddCapturePoint(new OPvPCapturePointTF(this, TF_TOWER_N, go)); - break; - case 183412: - AddCapturePoint(new OPvPCapturePointTF(this, TF_TOWER_NE, go)); - break; - case 183413: - AddCapturePoint(new OPvPCapturePointTF(this, TF_TOWER_SE, go)); - break; - case 183414: - AddCapturePoint(new OPvPCapturePointTF(this, TF_TOWER_S, go)); + case TF_ENTRY_TOWER_NW: + case TF_ENTRY_TOWER_N: + case TF_ENTRY_TOWER_NE: + case TF_ENTRY_TOWER_SE: + case TF_ENTRY_TOWER_S: + _controlZoneGUIDs.insert(go->GetGUID()); break; default: break; @@ -295,81 +259,73 @@ void OutdoorPvPTF::OnGameObjectCreate(GameObject* go) OutdoorPvP::OnGameObjectCreate(go); } -bool OPvPCapturePointTF::Update(uint32 diff) +TFControlZoneHandler::TFControlZoneHandler(OutdoorPvPTF* pvp, uint32 worldstateHorde, uint32 worldstateAlliance, uint32 worldstateNeutral) : OutdoorPvPControlZoneHandler(pvp), +_worldstateHorde(worldstateHorde), _worldstateAlliance(worldstateAlliance), _worldstateNeutral(worldstateNeutral) { - // can update even in locked state if gathers the controlling faction - bool canupdate = ((((OutdoorPvPTF*)m_PvP)->GetAllianceTowersControlled() > 0) && m_activePlayers[0].size() > m_activePlayers[1].size()) || - ((((OutdoorPvPTF*)m_PvP)->GetHordeTowersControlled() > 0) && m_activePlayers[0].size() < m_activePlayers[1].size()); - // if gathers the other faction, then only update if the pvp is unlocked - canupdate = canupdate || !((OutdoorPvPTF*)m_PvP)->IsLocked(); - return canupdate && OPvPCapturePoint::Update(diff); } -void OPvPCapturePointTF::ChangeState() +void TFControlZoneHandler::HandleProgressEventHorde(GameObject* controlZone) { - // if changing from controlling alliance to horde - if (m_OldState == OBJECTIVESTATE_ALLIANCE) - { - if (uint32 alliance_towers = ((OutdoorPvPTF*)m_PvP)->GetAllianceTowersControlled()) - ((OutdoorPvPTF*)m_PvP)->SetAllianceTowersControlled(--alliance_towers); - m_PvP->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_LOSE_ALLIANCE); - } - // if changing from controlling horde to alliance - else if (m_OldState == OBJECTIVESTATE_HORDE) - { - if (uint32 horde_towers = ((OutdoorPvPTF*)m_PvP)->GetHordeTowersControlled()) - ((OutdoorPvPTF*)m_PvP)->SetHordeTowersControlled(--horde_towers); - m_PvP->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_LOSE_HORDE); - } - - uint32 artkit = 21; - - switch (m_State) - { - case OBJECTIVESTATE_ALLIANCE: - { - m_TowerState = TF_TOWERSTATE_A; - artkit = 2; - uint32 alliance_towers = ((OutdoorPvPTF*)m_PvP)->GetAllianceTowersControlled(); - if (alliance_towers < TF_TOWER_NUM) - ((OutdoorPvPTF*)m_PvP)->SetAllianceTowersControlled(++alliance_towers); + controlZone->SetGoArtKit(1); + GetOutdoorPvPTF()->SetHordeTowersControlled(GetOutdoorPvPTF()->GetHordeTowersControlled() + 1); + GetOutdoorPvP()->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_TAKEN_HORDE); + controlZone->GetMap()->SetWorldStateValue(_worldstateHorde, 1, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateAlliance, 0, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateNeutral, 0, false); + + if (GuidUnorderedSet const* guidSet = controlZone->GetInsidePlayers()) + for (ObjectGuid const& guid : *guidSet) + if (Player* player = ObjectAccessor::GetPlayer(*controlZone, guid)) + if (player->GetTeam() == TEAM_HORDE) + player->AreaExploredOrEventHappens(TF_HORDE_QUEST); - m_PvP->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_TAKEN_ALLIANCE); + OutdoorPvPControlZoneHandler::HandleProgressEventHorde(controlZone); +} - for (GuidSet::iterator itr = m_activePlayers[0].begin(); itr != m_activePlayers[0].end(); ++itr) - if (Player* player = ObjectAccessor::FindPlayer(*itr)) +void TFControlZoneHandler::HandleProgressEventAlliance(GameObject* controlZone) +{ + controlZone->SetGoArtKit(2); + GetOutdoorPvPTF()->SetAllianceTowersControlled(GetOutdoorPvPTF()->GetAllianceTowersControlled() + 1); + GetOutdoorPvP()->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_TAKEN_ALLIANCE); + controlZone->GetMap()->SetWorldStateValue(_worldstateHorde, 0, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateAlliance, 1, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateNeutral, 0, false); + + if (GuidUnorderedSet const* guidSet = controlZone->GetInsidePlayers()) + for (ObjectGuid const& guid : *guidSet) + if (Player* player = ObjectAccessor::GetPlayer(*controlZone, guid)) + if (player->GetTeam() == TEAM_ALLIANCE) player->AreaExploredOrEventHappens(TF_ALLY_QUEST); - break; - } - case OBJECTIVESTATE_HORDE: - { - m_TowerState = TF_TOWERSTATE_H; - artkit = 1; - uint32 horde_towers = ((OutdoorPvPTF*)m_PvP)->GetHordeTowersControlled(); - if (horde_towers < TF_TOWER_NUM) - ((OutdoorPvPTF*)m_PvP)->SetHordeTowersControlled(++horde_towers); - m_PvP->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_TAKEN_HORDE); + OutdoorPvPControlZoneHandler::HandleProgressEventAlliance(controlZone); +} - for (GuidSet::iterator itr = m_activePlayers[1].begin(); itr != m_activePlayers[1].end(); ++itr) - if (Player* player = ObjectAccessor::FindPlayer(*itr)) - player->AreaExploredOrEventHappens(TF_HORDE_QUEST); - break; - } - case OBJECTIVESTATE_NEUTRAL: - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_TowerState = TF_TOWERSTATE_N; - break; - } +void TFControlZoneHandler::HandleNeutralEventHorde(GameObject* controlZone) +{ + GetOutdoorPvPTF()->SetHordeTowersControlled(GetOutdoorPvPTF()->GetHordeTowersControlled() - 1); + GetOutdoorPvP()->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_LOSE_HORDE); + OutdoorPvPControlZoneHandler::HandleNeutralEventHorde(controlZone); +} - auto bounds = m_PvP->GetMap()->GetGameObjectBySpawnIdStore().equal_range(m_capturePointSpawnId); - for (auto itr = bounds.first; itr != bounds.second; ++itr) - itr->second->SetGoArtKit(artkit); +void TFControlZoneHandler::HandleNeutralEventAlliance(GameObject* controlZone) +{ + GetOutdoorPvPTF()->SetAllianceTowersControlled(GetOutdoorPvPTF()->GetAllianceTowersControlled() - 1); + GetOutdoorPvP()->SendDefenseMessage(OutdoorPvPTFBuffZones[0], TEXT_SPIRIT_TOWER_LOSE_ALLIANCE); + OutdoorPvPControlZoneHandler::HandleNeutralEventAlliance(controlZone); +} - UpdateTowerState(); +void TFControlZoneHandler::HandleNeutralEvent(GameObject* controlZone) +{ + controlZone->SetGoArtKit(21); + controlZone->GetMap()->SetWorldStateValue(_worldstateHorde, 0, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateAlliance, 0, false); + controlZone->GetMap()->SetWorldStateValue(_worldstateNeutral, 1, false); + OutdoorPvPControlZoneHandler::HandleNeutralEvent(controlZone); +} + +OutdoorPvPTF* TFControlZoneHandler::GetOutdoorPvPTF() const +{ + return static_cast<OutdoorPvPTF*>(OutdoorPvPControlZoneHandler::GetOutdoorPvP()); } class OutdoorPvP_terokkar_forest : public OutdoorPvPScript diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h index e938877dc16..3dff1df2508 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPTF.h @@ -54,26 +54,66 @@ enum TFWorldStates TF_UI_LOCKED_DISPLAY_ALLIANCE = 2767 }; -enum TFTowerStates +enum TFGameEvents { - TF_TOWERSTATE_N = 1, - TF_TOWERSTATE_H = 2, - TF_TOWERSTATE_A = 4 + TF_EVENT_TOWER_NW_ALLIANCE_PROGRESS = 12225, + TF_EVENT_TOWER_NW_HORDE_PROGRESS = 12226, + TF_EVENT_TOWER_NW_NEUTRAL_ALLIANCE = 12227, + TF_EVENT_TOWER_NW_NEUTRAL_HORDE = 12228, + + TF_EVENT_TOWER_NE_HORDE_PROGRESS = 12486, + TF_EVENT_TOWER_NE_ALLIANCE_PROGRESS = 12487, + TF_EVENT_TOWER_NE_NEUTRAL_HORDE = 12488, + TF_EVENT_TOWER_NE_NEUTRAL_ALLIANCE = 12489, + + TF_EVENT_TOWER_N_NEUTRAL_HORDE = 12490, + TF_EVENT_TOWER_N_NEUTRAL_ALLIANCE = 12491, + TF_EVENT_TOWER_N_ALLIANCE_PROGRESS = 12496, + TF_EVENT_TOWER_N_HORDE_PROGRESS = 12497, + + TF_EVENT_TOWER_SE_NEUTRAL_HORDE = 12492, + TF_EVENT_TOWER_SE_NEUTRAL_ALLIANCE = 12493, + TF_EVENT_TOWER_SE_ALLIANCE_PROGRESS = 12498, + TF_EVENT_TOWER_SE_HORDE_PROGRESS = 12499, + + TF_EVENT_TOWER_S_NEUTRAL_HORDE = 12494, + TF_EVENT_TOWER_S_NEUTRAL_ALLIANCE = 12495, + TF_EVENT_TOWER_S_ALLIANCE_PROGRESS = 12500, + TF_EVENT_TOWER_S_HORDE_PROGRESS = 12501 }; -class OPvPCapturePointTF : public OPvPCapturePoint +enum TFGameObjects { - public: - OPvPCapturePointTF(OutdoorPvP* pvp, OutdoorPvPTF_TowerType type, GameObject* go); + TF_ENTRY_TOWER_NW = 183104, + TF_ENTRY_TOWER_N = 183411, + TF_ENTRY_TOWER_NE = 183412, + TF_ENTRY_TOWER_SE = 183413, + TF_ENTRY_TOWER_S = 183414 +}; + +class OutdoorPvPTF; + +class TFControlZoneHandler : public OutdoorPvPControlZoneHandler +{ +public: + explicit TFControlZoneHandler(OutdoorPvPTF* pvp, uint32 worldstateHorde, uint32 worldstateAlliance, uint32 worldstateNeutral); + + void HandleProgressEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleProgressEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEvent([[maybe_unused]] GameObject* controlZone) override; - bool Update(uint32 diff) override; - void ChangeState() override; + uint32 GetWorldStateHorde() { return _worldstateHorde; } + uint32 GetWorldStateAlliance() { return _worldstateAlliance; } + uint32 GetWorldStateNeutral() { return _worldstateNeutral; } - void UpdateTowerState(); + OutdoorPvPTF* GetOutdoorPvPTF() const; - protected: - OutdoorPvPTF_TowerType m_TowerType; - uint32 m_TowerState; +private: + uint32 _worldstateHorde; + uint32 _worldstateAlliance; + uint32 _worldstateNeutral; }; class OutdoorPvPTF : public OutdoorPvP @@ -85,7 +125,7 @@ class OutdoorPvPTF : public OutdoorPvP void OnGameObjectCreate(GameObject* go) override; void HandlePlayerEnterZone(Player* player, uint32 zone) override; void HandlePlayerLeaveZone(Player* player, uint32 zone) override; - bool Update(uint32 diff) override; + void Update(uint32 diff) override; void SendRemoveWorldStates(Player* player) override; uint32 GetAllianceTowersControlled() const; @@ -94,6 +134,8 @@ class OutdoorPvPTF : public OutdoorPvP void SetHordeTowersControlled(uint32 count); bool IsLocked() const; + void ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker) override; + void HandleCapture(TeamId team); private: bool m_IsLocked; uint32 m_LockTimer; @@ -101,6 +143,8 @@ class OutdoorPvPTF : public OutdoorPvP uint32 m_AllianceTowersControlled; uint32 m_HordeTowersControlled; uint32 hours_left, second_digit, first_digit; + GuidUnorderedSet _controlZoneGUIDs; + std::unordered_map<uint32 /*control zone entry*/, std::unique_ptr<TFControlZoneHandler>> _controlZoneHandlers; }; #endif diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.cpp index 1c8c7c1ae87..8937cddddbd 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.cpp @@ -36,113 +36,80 @@ uint32 const OutdoorPvPZMBuffZones[OutdoorPvPZMBuffZonesNum] = { 3521, 3607, 371 // linked when the central tower is controlled uint32 const ZM_GRAVEYARD_ZONE = 3521; -struct zm_beacon +ZMControlZoneHandler::ZMControlZoneHandler(OutdoorPvPZM* pvp, uint32 textBeaconTakenHorde, uint32 textBeaconTakenAlliance, uint32 worldstateNeutralUi, uint32 worldstateNeutralMap, uint32 worldstateHordeUi, uint32 worldstateHordeMap, uint32 worldstateAllianceUi, uint32 worldstateAllianceMap) + : OutdoorPvPControlZoneHandler(pvp), _textBeaconTakenHorde(textBeaconTakenHorde), _textBeaconTakenAlliance(textBeaconTakenAlliance), _worldstateNeutralUi(worldstateNeutralUi), _worldstateNeutralMap(worldstateNeutralMap), + _worldstateHordeUi(worldstateHordeUi), _worldstateHordeMap(worldstateHordeMap), _worldstateAllianceUi(worldstateAllianceUi), _worldstateAllianceMap(worldstateAllianceMap) { - int32 ui_tower_n; - int32 ui_tower_h; - int32 ui_tower_a; - int32 map_tower_n; - int32 map_tower_h; - int32 map_tower_a; - uint32 event_enter; - uint32 event_leave; -}; +} -zm_beacon const ZMBeaconInfo[ZM_NUM_BEACONS] = +void ZMControlZoneHandler::HandleProgressEventHorde(GameObject* controlZone) { - { ZM_UI_TOWER_EAST_N, ZM_UI_TOWER_EAST_H, ZM_UI_TOWER_EAST_A, ZM_MAP_TOWER_EAST_N, ZM_MAP_TOWER_EAST_H, ZM_MAP_TOWER_EAST_A, 11807, 11806 }, - { ZM_UI_TOWER_WEST_N, ZM_UI_TOWER_WEST_H, ZM_UI_TOWER_WEST_A, ZM_MAP_TOWER_WEST_N, ZM_MAP_TOWER_WEST_H, ZM_MAP_TOWER_WEST_A, 11805, 11804 } -}; + OutdoorPvPControlZoneHandler::HandleProgressEventHorde(controlZone); + GetOutdoorPvpZM()->SetHordeTowersControlled(GetOutdoorPvpZM()->GetHordeTowersControlled() + 1); + GetOutdoorPvpZM()->SendDefenseMessage(ZM_GRAVEYARD_ZONE, _textBeaconTakenHorde); + + GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceMap, 0); + GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceUi, 0); + GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralMap, 0); + GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralUi, 0); + GetOutdoorPvpZM()->SetWorldState(_worldstateHordeMap, 1); + GetOutdoorPvpZM()->SetWorldState(_worldstateHordeUi, 1); +} -uint32 const ZMBeaconCaptureA[ZM_NUM_BEACONS] = +void ZMControlZoneHandler::HandleProgressEventAlliance(GameObject* controlZone) { - TEXT_EAST_BEACON_TAKEN_ALLIANCE, - TEXT_WEST_BEACON_TAKEN_ALLIANCE -}; + OutdoorPvPControlZoneHandler::HandleProgressEventAlliance(controlZone); + GetOutdoorPvpZM()->SetAllianceTowersControlled(GetOutdoorPvpZM()->GetAllianceTowersControlled() + 1); + GetOutdoorPvpZM()->SendDefenseMessage(ZM_GRAVEYARD_ZONE, _textBeaconTakenAlliance); + + GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceMap, 1); + GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceUi, 1); + GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralMap, 0); + GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralUi, 0); + GetOutdoorPvpZM()->SetWorldState(_worldstateHordeMap, 0); + GetOutdoorPvpZM()->SetWorldState(_worldstateHordeUi, 0); +} -uint32 const ZMBeaconCaptureH[ZM_NUM_BEACONS] = +void ZMControlZoneHandler::HandleNeutralEventHorde(GameObject* controlZone) { - TEXT_EAST_BEACON_TAKEN_HORDE, - TEXT_WEST_BEACON_TAKEN_HORDE -}; + GetOutdoorPvpZM()->SetHordeTowersControlled(GetOutdoorPvpZM()->GetHordeTowersControlled() - 1); -OPvPCapturePointZM_Beacon::OPvPCapturePointZM_Beacon(OutdoorPvP* pvp, ZM_BeaconType type, GameObject* go) : OPvPCapturePoint(pvp), m_TowerType(type), m_TowerState(ZM_TOWERSTATE_N) -{ - m_capturePointSpawnId = go->GetSpawnId(); - m_capturePoint = go; - SetCapturePointData(go->GetEntry()); + OutdoorPvPControlZoneHandler::HandleNeutralEventHorde(controlZone); } -void OPvPCapturePointZM_Beacon::UpdateTowerState() +void ZMControlZoneHandler::HandleNeutralEventAlliance(GameObject* controlZone) { - m_PvP->SetWorldState(ZMBeaconInfo[m_TowerType].ui_tower_n, int32((m_TowerState & ZM_TOWERSTATE_N) != 0)); - m_PvP->SetWorldState(ZMBeaconInfo[m_TowerType].map_tower_n, int32((m_TowerState & ZM_TOWERSTATE_N) != 0)); - m_PvP->SetWorldState(ZMBeaconInfo[m_TowerType].ui_tower_a, int32((m_TowerState & ZM_TOWERSTATE_A) != 0)); - m_PvP->SetWorldState(ZMBeaconInfo[m_TowerType].map_tower_a, int32((m_TowerState & ZM_TOWERSTATE_A) != 0)); - m_PvP->SetWorldState(ZMBeaconInfo[m_TowerType].ui_tower_h, int32((m_TowerState & ZM_TOWERSTATE_H) != 0)); - m_PvP->SetWorldState(ZMBeaconInfo[m_TowerType].map_tower_h, int32((m_TowerState & ZM_TOWERSTATE_H) != 0)); + GetOutdoorPvpZM()->SetAllianceTowersControlled(GetOutdoorPvpZM()->GetAllianceTowersControlled() - 1); + + OutdoorPvPControlZoneHandler::HandleNeutralEventAlliance(controlZone); } -void OPvPCapturePointZM_Beacon::ChangeState() +void ZMControlZoneHandler::HandleNeutralEvent(GameObject* controlZone) { - // if changing from controlling alliance to horde - if (m_OldState == OBJECTIVESTATE_ALLIANCE) - { - if (uint32 alliance_towers = ((OutdoorPvPZM*)m_PvP)->GetAllianceTowersControlled()) - ((OutdoorPvPZM*)m_PvP)->SetAllianceTowersControlled(--alliance_towers); - } - // if changing from controlling horde to alliance - else if (m_OldState == OBJECTIVESTATE_HORDE) - { - if (uint32 horde_towers = ((OutdoorPvPZM*)m_PvP)->GetHordeTowersControlled()) - ((OutdoorPvPZM*)m_PvP)->SetHordeTowersControlled(--horde_towers); - } - - switch (m_State) - { - case OBJECTIVESTATE_ALLIANCE: - { - m_TowerState = ZM_TOWERSTATE_A; - uint32 alliance_towers = ((OutdoorPvPZM*)m_PvP)->GetAllianceTowersControlled(); - if (alliance_towers < ZM_NUM_BEACONS) - ((OutdoorPvPZM*)m_PvP)->SetAllianceTowersControlled(++alliance_towers); - m_PvP->SendDefenseMessage(ZM_GRAVEYARD_ZONE, ZMBeaconCaptureA[m_TowerType]); - break; - } - case OBJECTIVESTATE_HORDE: - { - m_TowerState = ZM_TOWERSTATE_H; - uint32 horde_towers = ((OutdoorPvPZM*)m_PvP)->GetHordeTowersControlled(); - if (horde_towers < ZM_NUM_BEACONS) - ((OutdoorPvPZM*)m_PvP)->SetHordeTowersControlled(++horde_towers); - m_PvP->SendDefenseMessage(ZM_GRAVEYARD_ZONE, ZMBeaconCaptureH[m_TowerType]); - break; - } - case OBJECTIVESTATE_NEUTRAL: - case OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE: - case OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE: - case OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE: - case OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE: - m_TowerState = ZM_TOWERSTATE_N; - break; - } + OutdoorPvPControlZoneHandler::HandleNeutralEvent(controlZone); + + GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceMap, 0); + GetOutdoorPvpZM()->SetWorldState(_worldstateAllianceUi, 0); + GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralMap, 1); + GetOutdoorPvpZM()->SetWorldState(_worldstateNeutralUi, 1); + GetOutdoorPvpZM()->SetWorldState(_worldstateHordeMap, 0); + GetOutdoorPvpZM()->SetWorldState(_worldstateHordeUi, 0); +} - UpdateTowerState(); +OutdoorPvPZM* ZMControlZoneHandler::GetOutdoorPvpZM() +{ + return static_cast<OutdoorPvPZM*>(OutdoorPvPControlZoneHandler::GetOutdoorPvP()); } -bool OutdoorPvPZM::Update(uint32 diff) +void OutdoorPvPZM::Update(uint32 diff) { - bool changed = OutdoorPvP::Update(diff); - if (changed) - { - if (m_AllianceTowersControlled == ZM_NUM_BEACONS) - m_Graveyard->SetBeaconState(ALLIANCE); - else if (m_HordeTowersControlled == ZM_NUM_BEACONS) - m_Graveyard->SetBeaconState(HORDE); - else - m_Graveyard->SetBeaconState(0); - } - return changed; + OutdoorPvP::Update(diff); + if (m_AllianceTowersControlled == ZM_NUM_BEACONS) + m_Graveyard->SetBeaconState(ALLIANCE); + else if (m_HordeTowersControlled == ZM_NUM_BEACONS) + m_Graveyard->SetBeaconState(HORDE); + else + m_Graveyard->SetBeaconState(0); } void OutdoorPvPZM::HandlePlayerEnterZone(Player* player, uint32 zone) @@ -176,6 +143,30 @@ OutdoorPvPZM::OutdoorPvPZM(Map* map) : OutdoorPvP(map) m_Graveyard = nullptr; m_AllianceTowersControlled = 0; m_HordeTowersControlled = 0; + + ControlZoneHandlers[ZM_GO_ENTRY_BEACON_EAST] = std::make_unique<ZMControlZoneHandler>( + this, + TEXT_EAST_BEACON_TAKEN_HORDE, + TEXT_EAST_BEACON_TAKEN_ALLIANCE, + ZM_UI_TOWER_EAST_N, + ZM_MAP_TOWER_EAST_N, + ZM_UI_TOWER_EAST_H, + ZM_MAP_TOWER_EAST_H, + ZM_UI_TOWER_EAST_A, + ZM_MAP_TOWER_EAST_A + ); + + ControlZoneHandlers[ZM_GO_ENTRY_BEACON_WEST] = std::make_unique<ZMControlZoneHandler>( + this, + TEXT_WEST_BEACON_TAKEN_HORDE, + TEXT_WEST_BEACON_TAKEN_ALLIANCE, + ZM_UI_TOWER_WEST_N, + ZM_MAP_TOWER_WEST_N, + ZM_UI_TOWER_WEST_H, + ZM_MAP_TOWER_WEST_H, + ZM_UI_TOWER_WEST_A, + ZM_MAP_TOWER_WEST_A + ); } bool OutdoorPvPZM::SetupOutdoorPvP() @@ -188,28 +179,10 @@ bool OutdoorPvPZM::SetupOutdoorPvP() RegisterZone(OutdoorPvPZMBuffZones[i]); m_Graveyard = new OPvPCapturePointZM_Graveyard(this); - AddCapturePoint(m_Graveyard); // though the update function isn't used, the handleusego is! return true; } -void OutdoorPvPZM::OnGameObjectCreate(GameObject* go) -{ - switch (go->GetEntry()) - { - case 182523: - AddCapturePoint(new OPvPCapturePointZM_Beacon(this, ZM_BEACON_EAST, go)); - break; - case 182522: - AddCapturePoint(new OPvPCapturePointZM_Beacon(this, ZM_BEACON_WEST, go)); - break; - default: - break; - } - - OutdoorPvP::OnGameObjectCreate(go); -} - void OutdoorPvPZM::HandleKillImpl(Player* player, Unit* killed) { if (killed->GetTypeId() != TYPEID_PLAYER) @@ -221,11 +194,9 @@ void OutdoorPvPZM::HandleKillImpl(Player* player, Unit* killed) player->CastSpell(player, ZM_HordePlayerKillReward, true); } -bool OPvPCapturePointZM_Graveyard::Update(uint32 /*diff*/) +void OPvPCapturePointZM_Graveyard::Update(uint32 /*diff*/) { - bool retval = m_State != m_OldState; m_State = m_OldState; - return retval; } int32 OPvPCapturePointZM_Graveyard::HandleOpenGo(Player* player, GameObject* go) @@ -368,21 +339,20 @@ void OutdoorPvPZM::SendRemoveWorldStates(Player* player) initWorldStates.MapID = player->GetMapId(); initWorldStates.AreaID = player->GetZoneId(); initWorldStates.SubareaID = player->GetAreaId(); - initWorldStates.Worldstates.emplace_back(ZM_UI_TOWER_EAST_N, 0); - initWorldStates.Worldstates.emplace_back(ZM_UI_TOWER_EAST_H, 0); - initWorldStates.Worldstates.emplace_back(ZM_UI_TOWER_EAST_A, 0); - initWorldStates.Worldstates.emplace_back(ZM_UI_TOWER_WEST_N, 0); - initWorldStates.Worldstates.emplace_back(ZM_UI_TOWER_WEST_H, 0); - initWorldStates.Worldstates.emplace_back(ZM_UI_TOWER_WEST_A, 0); - initWorldStates.Worldstates.emplace_back(ZM_MAP_TOWER_EAST_N, 0); - initWorldStates.Worldstates.emplace_back(ZM_MAP_TOWER_EAST_H, 0); - initWorldStates.Worldstates.emplace_back(ZM_MAP_TOWER_EAST_A, 0); + + for (auto& itr : ControlZoneHandlers) + { + ZMControlZoneHandler* handler = static_cast<ZMControlZoneHandler*>(itr.second.get()); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateNeutralUI(), 0); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateNeutralMap(), 0); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateHordeUI(), 0); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateHordeMap(), 0); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateAllianceUI(), 0); + initWorldStates.Worldstates.emplace_back(handler->GetWorldStateAllianceMap(), 0); + } initWorldStates.Worldstates.emplace_back(ZM_MAP_GRAVEYARD_H, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_GRAVEYARD_A, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_GRAVEYARD_N, 0); - initWorldStates.Worldstates.emplace_back(ZM_MAP_TOWER_WEST_N, 0); - initWorldStates.Worldstates.emplace_back(ZM_MAP_TOWER_WEST_H, 0); - initWorldStates.Worldstates.emplace_back(ZM_MAP_TOWER_WEST_A, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_HORDE_FLAG_READY, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_HORDE_FLAG_NOT_READY, 0); initWorldStates.Worldstates.emplace_back(ZM_MAP_ALLIANCE_FLAG_NOT_READY, 0); diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h index a8d22f1a784..d29f3d63369 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h @@ -93,18 +93,17 @@ enum ZM_TowerStateMask ZM_TOWERSTATE_H = 4 }; -class OPvPCapturePointZM_Beacon : public OPvPCapturePoint +enum ZM_WorldEvents { - public: - OPvPCapturePointZM_Beacon(OutdoorPvP* pvp, ZM_BeaconType type, GameObject* go); - - void ChangeState() override; - - void UpdateTowerState(); - - protected: - ZM_BeaconType m_TowerType; - uint32 m_TowerState; + ZM_EVENT_BEACON_EAST_PROGRESS_HORDE = 11807, + ZM_EVENT_BEACON_EAST_PROGRESS_ALLIANCE = 11806, + ZM_EVENT_BEACON_EAST_NEUTRAL_HORDE = 11814, + ZM_EVENT_BEACON_EAST_NEUTRAL_ALLIANCE = 11815, + + ZM_EVENT_BEACON_WEST_PROGRESS_HORDE = 11805, + ZM_EVENT_BEACON_WEST_PROGRESS_ALLIANCE = 11804, + ZM_EVENT_BEACON_WEST_NEUTRAL_HORDE = 11808, + ZM_EVENT_BEACON_WEST_NEUTRAL_ALLIANCE = 11809 }; enum ZM_GraveyardState @@ -114,12 +113,51 @@ enum ZM_GraveyardState ZM_GRAVEYARD_H = 4 }; +enum ZM_GameObjectEntries +{ + ZM_GO_ENTRY_BEACON_WEST = 182522, + ZM_GO_ENTRY_BEACON_EAST = 182523 +}; + +class OutdoorPvPZM; + +class ZMControlZoneHandler : public OutdoorPvPControlZoneHandler +{ +public: + ZMControlZoneHandler(OutdoorPvPZM* pvp, uint32 textBeaconTakenHorde, uint32 textBeaconTakenAlliance, uint32 worldstateNeutralUi, uint32 worldstateNeutralMap, uint32 worldstateHordeUi, uint32 worldstateHordeMap, uint32 worldstateAllianceUi, uint32 worldstateAllianceMap); + + void HandleProgressEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleProgressEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEventHorde([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEventAlliance([[maybe_unused]] GameObject* controlZone) override; + void HandleNeutralEvent([[maybe_unused]] GameObject* controlZone) override; + + uint32 GetWorldStateNeutralUI() { return _worldstateNeutralUi; } + uint32 GetWorldStateNeutralMap() { return _worldstateNeutralMap; } + uint32 GetWorldStateHordeUI() { return _worldstateHordeUi; } + uint32 GetWorldStateHordeMap() { return _worldstateHordeMap; } + uint32 GetWorldStateAllianceUI() { return _worldstateAllianceUi; } + uint32 GetWorldStateAllianceMap() { return _worldstateAllianceMap; } + + OutdoorPvPZM* GetOutdoorPvpZM(); + +private: + uint32 _textBeaconTakenHorde; + uint32 _textBeaconTakenAlliance; + uint32 _worldstateNeutralUi; + uint32 _worldstateNeutralMap; + uint32 _worldstateHordeUi; + uint32 _worldstateHordeMap; + uint32 _worldstateAllianceUi; + uint32 _worldstateAllianceMap; +}; + class OPvPCapturePointZM_Graveyard : public OPvPCapturePoint { public: OPvPCapturePointZM_Graveyard(OutdoorPvP* pvp); - bool Update(uint32 diff) override; + void Update(uint32 diff) override; void ChangeState() override { } int32 HandleOpenGo(Player* player, GameObject* go) override; bool HandleDropFlag(Player* player, uint32 spellId) override; @@ -144,10 +182,9 @@ class OutdoorPvPZM : public OutdoorPvP OutdoorPvPZM(Map* map); bool SetupOutdoorPvP() override; - void OnGameObjectCreate(GameObject* go) override; void HandlePlayerEnterZone(Player* player, uint32 zone) override; void HandlePlayerLeaveZone(Player* player, uint32 zone) override; - bool Update(uint32 diff) override; + void Update(uint32 diff) override; void SendRemoveWorldStates(Player* player) override; void HandleKillImpl(Player* player, Unit* killed) override; |