aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/OutdoorPvP
diff options
context:
space:
mode:
authorJeremy <Golrag@users.noreply.github.com>2023-10-03 15:55:24 +0200
committerGitHub <noreply@github.com>2023-10-03 15:55:24 +0200
commitf96f041c3edadfb5f1f09705fe699c2d7a9ed423 (patch)
tree81a846b5cbce1fe493e96ee696f2f5269d7b172e /src/server/game/OutdoorPvP
parent4537b377385c71671665f507edac726716838003 (diff)
Core/GameObject: Implement ControlZone gameobject type (#29320)
Diffstat (limited to 'src/server/game/OutdoorPvP')
-rw-r--r--src/server/game/OutdoorPvP/OutdoorPvP.cpp313
-rw-r--r--src/server/game/OutdoorPvP/OutdoorPvP.h69
2 files changed, 59 insertions, 323 deletions
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;