Core/GameObjects: Implemented GAMEOBJECT_TYPE_CAPTURE_POINT (#27034)

This commit is contained in:
Jeremy
2022-02-26 19:01:00 +01:00
committed by GitHub
parent ee835671b4
commit 19f64e66e5
10 changed files with 331 additions and 4 deletions

View File

@@ -32,6 +32,14 @@ class Unit;
class WorldObject;
enum class QuestGiverStatus : uint32;
namespace WorldPackets
{
namespace Battleground
{
enum class BattlegroundCapturePointState : uint8;
}
}
class TC_GAME_API GameObjectAI
{
private:
@@ -107,6 +115,11 @@ class TC_GAME_API GameObjectAI
virtual void SummonedCreatureDespawn(Creature* /*summon*/) { }
virtual void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) { }
// Called when the capture point gets assaulted by a player. Return true to disable default behaviour.
virtual bool OnCapturePointAssaulted(Player* /*player*/) { return false; }
// Called when the capture point state gets updated. Return true to disable default behaviour.
virtual bool OnCapturePointUpdated(WorldPackets::Battleground::BattlegroundCapturePointState /*state*/) { return false; }
};
class TC_GAME_API NullGameObjectAI : public GameObjectAI

View File

@@ -340,6 +340,7 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundQueueTypeId que
bg = new BattlegroundWS(*(BattlegroundWS*)bg_template);
break;
case BATTLEGROUND_AB:
case BATTLEGROUND_DOM_AB:
bg = new BattlegroundAB(*(BattlegroundAB*)bg_template);
break;
case BATTLEGROUND_NA:
@@ -411,6 +412,7 @@ bool BattlegroundMgr::CreateBattleground(BattlegroundTemplate const* bgTemplate)
bg = new BattlegroundWS(bgTemplate);
break;
case BATTLEGROUND_AB:
case BATTLEGROUND_DOM_AB:
bg = new BattlegroundAB(bgTemplate);
break;
case BATTLEGROUND_NA:

View File

@@ -20,6 +20,7 @@
#include "AzeriteItem.h"
#include "AzeritePackets.h"
#include "Battleground.h"
#include "BattlegroundPackets.h"
#include "CellImpl.h"
#include "CreatureAISelector.h"
#include "DatabaseEnv.h"
@@ -442,6 +443,10 @@ bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionD
break;
case GAMEOBJECT_TYPE_CAPTURE_POINT:
SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::SpellVisualID), m_goInfo->capturePoint.SpellVisual1);
m_goValue.CapturePoint.AssaultTimer = 0;
m_goValue.CapturePoint.LastTeamCapture = TEAM_NEUTRAL;
m_goValue.CapturePoint.State = WorldPackets::Battleground::BattlegroundCapturePointState::Neutral;
UpdateCapturePoint();
break;
default:
SetGoAnimProgress(animProgress);
@@ -791,6 +796,47 @@ void GameObject::Update(uint32 diff)
SetLootState(GO_ACTIVATED, target);
}
else if (goInfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT)
{
bool hordeCapturing = m_goValue.CapturePoint.State == WorldPackets::Battleground::BattlegroundCapturePointState::ContestedHorde;
bool allianceCapturing = m_goValue.CapturePoint.State == WorldPackets::Battleground::BattlegroundCapturePointState::ContestedAlliance;
if (hordeCapturing || allianceCapturing)
{
if (m_goValue.CapturePoint.AssaultTimer <= diff)
{
m_goValue.CapturePoint.State = hordeCapturing ? WorldPackets::Battleground::BattlegroundCapturePointState::HordeCaptured : WorldPackets::Battleground::BattlegroundCapturePointState::AllianceCaptured;
if (hordeCapturing)
{
m_goValue.CapturePoint.State = WorldPackets::Battleground::BattlegroundCapturePointState::HordeCaptured;
if (BattlegroundMap* map = GetMap()->ToBattlegroundMap())
{
if (Battleground* bg = map->GetBG())
{
EventInform(GetGOInfo()->capturePoint.CaptureEventHorde);
bg->SendBroadcastText(GetGOInfo()->capturePoint.CaptureBroadcastHorde, CHAT_MSG_BG_SYSTEM_HORDE);
}
}
}
else
{
m_goValue.CapturePoint.State = WorldPackets::Battleground::BattlegroundCapturePointState::AllianceCaptured;
if (BattlegroundMap* map = GetMap()->ToBattlegroundMap())
{
if (Battleground* bg = map->GetBG())
{
EventInform(GetGOInfo()->capturePoint.CaptureEventAlliance);
bg->SendBroadcastText(GetGOInfo()->capturePoint.CaptureBroadcastAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE);
}
}
}
m_goValue.CapturePoint.LastTeamCapture = hordeCapturing ? TEAM_HORDE : TEAM_ALLIANCE;
UpdateCapturePoint();
}
else
m_goValue.CapturePoint.AssaultTimer -= diff;
}
}
else if (uint32 max_charges = goInfo->GetCharges())
{
if (m_usetimes >= max_charges)
@@ -1038,6 +1084,12 @@ void GameObject::Delete()
SetLootState(GO_NOT_READY);
RemoveFromOwner();
if (m_goInfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT)
{
WorldPackets::Battleground::CapturePointRemoved packet(GetGUID());
SendMessageToSet(packet.Write(), true);
}
SendGameObjectDespawn();
SetGoState(GO_STATE_READY);
@@ -2946,6 +2998,161 @@ void GameObject::SetSpellVisualId(int32 spellVisualId, ObjectGuid activatorGuid)
SendMessageToSet(packet.Write(), true);
}
void GameObject::AssaultCapturePoint(Player* player)
{
if (!CanInteractWithCapturePoint(player))
return;
if (GameObjectAI* ai = AI())
if (ai->OnCapturePointAssaulted(player))
return;
// only supported in battlegrounds
Battleground* battleground = nullptr;
if (BattlegroundMap* map = GetMap()->ToBattlegroundMap())
if (Battleground* bg = map->GetBG())
battleground = bg;
if (!battleground)
return;
// Cancel current timer
m_goValue.CapturePoint.AssaultTimer = 0;
if (player->GetBGTeam() == HORDE)
{
if (m_goValue.CapturePoint.LastTeamCapture == TEAM_HORDE)
{
// defended. capture instantly.
m_goValue.CapturePoint.State = WorldPackets::Battleground::BattlegroundCapturePointState::HordeCaptured;
battleground->SendBroadcastText(GetGOInfo()->capturePoint.DefendedBroadcastHorde, CHAT_MSG_BG_SYSTEM_HORDE, player);
UpdateCapturePoint();
EventInform(GetGOInfo()->capturePoint.DefendedEventHorde, player);
return;
}
switch (m_goValue.CapturePoint.State)
{
case WorldPackets::Battleground::BattlegroundCapturePointState::Neutral:
case WorldPackets::Battleground::BattlegroundCapturePointState::AllianceCaptured:
case WorldPackets::Battleground::BattlegroundCapturePointState::ContestedAlliance:
m_goValue.CapturePoint.State = WorldPackets::Battleground::BattlegroundCapturePointState::ContestedHorde;
battleground->SendBroadcastText(GetGOInfo()->capturePoint.AssaultBroadcastHorde, CHAT_MSG_BG_SYSTEM_HORDE, player);
UpdateCapturePoint();
EventInform(GetGOInfo()->capturePoint.AssaultBroadcastHorde, player);
m_goValue.CapturePoint.AssaultTimer = GetGOInfo()->capturePoint.CaptureTime;
break;
default:
break;
}
}
else
{
if (m_goValue.CapturePoint.LastTeamCapture == TEAM_ALLIANCE)
{
// defended. capture instantly.
m_goValue.CapturePoint.State = WorldPackets::Battleground::BattlegroundCapturePointState::AllianceCaptured;
battleground->SendBroadcastText(GetGOInfo()->capturePoint.DefendedBroadcastAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
UpdateCapturePoint();
EventInform(GetGOInfo()->capturePoint.DefendedEventAlliance, player);
return;
}
switch (m_goValue.CapturePoint.State)
{
case WorldPackets::Battleground::BattlegroundCapturePointState::Neutral:
case WorldPackets::Battleground::BattlegroundCapturePointState::HordeCaptured:
case WorldPackets::Battleground::BattlegroundCapturePointState::ContestedHorde:
m_goValue.CapturePoint.State = WorldPackets::Battleground::BattlegroundCapturePointState::ContestedAlliance;
battleground->SendBroadcastText(GetGOInfo()->capturePoint.AssaultBroadcastAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
UpdateCapturePoint();
EventInform(GetGOInfo()->capturePoint.ContestedEventAlliance, player);
m_goValue.CapturePoint.AssaultTimer = GetGOInfo()->capturePoint.CaptureTime;
break;
default:
break;
}
}
}
void GameObject::UpdateCapturePoint()
{
if (GetGoType() != GAMEOBJECT_TYPE_CAPTURE_POINT)
return;
if (GameObjectAI* ai = AI())
if (ai->OnCapturePointUpdated(m_goValue.CapturePoint.State))
return;
uint32 spellVisualId = 0;
uint32 customAnim = 0;
switch (m_goValue.CapturePoint.State)
{
case WorldPackets::Battleground::BattlegroundCapturePointState::Neutral:
spellVisualId = GetGOInfo()->capturePoint.SpellVisual1;
break;
case WorldPackets::Battleground::BattlegroundCapturePointState::ContestedHorde:
customAnim = 1;
spellVisualId = GetGOInfo()->capturePoint.SpellVisual2;
break;
case WorldPackets::Battleground::BattlegroundCapturePointState::ContestedAlliance:
customAnim = 2;
spellVisualId = GetGOInfo()->capturePoint.SpellVisual3;
break;
case WorldPackets::Battleground::BattlegroundCapturePointState::HordeCaptured:
customAnim = 3;
spellVisualId = GetGOInfo()->capturePoint.SpellVisual4;
break;
case WorldPackets::Battleground::BattlegroundCapturePointState::AllianceCaptured:
customAnim = 4;
spellVisualId = GetGOInfo()->capturePoint.SpellVisual5;
break;
default:
break;
}
if (customAnim != 0)
SendCustomAnim(customAnim);
SetSpellVisualId(spellVisualId);
UpdateDynamicFlagsForNearbyPlayers();
if (BattlegroundMap* map = GetMap()->ToBattlegroundMap())
{
if (Battleground* bg = map->GetBG())
{
WorldPackets::Battleground::UpdateCapturePoint packet;
packet.CapturePointInfo.State = m_goValue.CapturePoint.State;
packet.CapturePointInfo.Pos = GetPosition();
packet.CapturePointInfo.Guid = GetGUID();
packet.CapturePointInfo.CaptureTotalDuration = Milliseconds(GetGOInfo()->capturePoint.CaptureTime);
packet.CapturePointInfo.CaptureTime = m_goValue.CapturePoint.AssaultTimer;
bg->SendPacketToAll(packet.Write());
bg->UpdateWorldState(GetGOInfo()->capturePoint.worldState1, AsUnderlyingType(m_goValue.CapturePoint.State));
}
}
}
bool GameObject::CanInteractWithCapturePoint(Player const* target) const
{
if (m_goInfo->type != GAMEOBJECT_TYPE_CAPTURE_POINT)
return false;
if (m_goValue.CapturePoint.State == WorldPackets::Battleground::BattlegroundCapturePointState::Neutral)
return true;
if (target->GetBGTeam() == HORDE)
{
return m_goValue.CapturePoint.State == WorldPackets::Battleground::BattlegroundCapturePointState::ContestedAlliance
|| m_goValue.CapturePoint.State == WorldPackets::Battleground::BattlegroundCapturePointState::AllianceCaptured;
}
// For Alliance players
return m_goValue.CapturePoint.State == WorldPackets::Battleground::BattlegroundCapturePointState::ContestedHorde
|| m_goValue.CapturePoint.State == WorldPackets::Battleground::BattlegroundCapturePointState::HordeCaptured;
}
class GameObjectModelOwnerImpl : public GameObjectModelOwnerBase
{
public:
@@ -2965,6 +3172,14 @@ private:
GameObject* _owner;
};
void GameObject::UpdateDynamicFlagsForNearbyPlayers() const
{
ValuesUpdateForPlayerWithMaskSender sender(this);
sender.ObjectMask.MarkChanged(&UF::ObjectData::DynamicFlags);
Trinity::MessageDistDeliverer<ValuesUpdateForPlayerWithMaskSender> deliverer(this, sender, GetVisibilityRange());
Cell::VisitWorldObjects(this, deliverer, GetVisibilityRange());
}
void GameObject::CreateModel()
{
m_model = GameObjectModel::Create(std::make_unique<GameObjectModelOwnerImpl>(this), sWorld->GetDataPath());

View File

@@ -33,6 +33,14 @@ class Unit;
struct TransportAnimation;
enum TriggerCastFlags : uint32;
namespace WorldPackets
{
namespace Battleground
{
enum class BattlegroundCapturePointState : uint8;
}
}
union GameObjectValue
{
//11 GAMEOBJECT_TYPE_TRANSPORT
@@ -60,6 +68,13 @@ union GameObjectValue
uint32 Health;
uint32 MaxHealth;
} Building;
//42 GAMEOBJECT_TYPE_CAPTURE_POINT
struct
{
TeamId LastTeamCapture;
WorldPackets::Battleground::BattlegroundCapturePointState State;
uint32 AssaultTimer;
} CapturePoint;
};
// For containers: [GO_NOT_READY]->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED->GO_READY -> ...
@@ -324,12 +339,17 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
void SetWorldEffectID(uint32 worldEffectID) { _worldEffectID = worldEffectID; }
void SetSpellVisualId(int32 spellVisualId, ObjectGuid activatorGuid = ObjectGuid::Empty);
void AssaultCapturePoint(Player* player);
void UpdateCapturePoint();
bool CanInteractWithCapturePoint(Player const* target) const;
void AIM_Destroy();
bool AIM_Initialize();
std::string GetDebugInfo() const override;
void UpdateDynamicFlagsForNearbyPlayers() const;
UF::UpdateField<UF::GameObjectData, 0, TYPEID_GAMEOBJECT> m_gameObjectData;
protected:

View File

@@ -94,6 +94,12 @@ public:
}
break;
}
case GAMEOBJECT_TYPE_CAPTURE_POINT:
if (!gameObject->CanInteractWithCapturePoint(receiver))
dynFlags |= GO_DYNFLAG_LO_NO_INTERACT;
else
dynFlags &= ~GO_DYNFLAG_LO_NO_INTERACT;
break;
default:
break;
}

View File

@@ -9333,7 +9333,7 @@ void Player::SendInitWorldStates(uint32 zoneId, uint32 areaId)
}
break;
case 3358: // Arathi Basin
if (battleground && battleground->GetTypeID(true) == BATTLEGROUND_AB)
if (battleground && (battleground->GetTypeID(true) == BATTLEGROUND_AB || battleground->GetTypeID(true) == BATTLEGROUND_DOM_AB))
battleground->FillInitialWorldStates(packet);
else
{

View File

@@ -373,3 +373,30 @@ WorldPacket const* WorldPackets::Battleground::PVPMatchComplete::Write()
return &_worldPacket;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Battleground::BattlegroundCapturePointInfo const& battlegroundCapturePointInfo)
{
data << battlegroundCapturePointInfo.Guid;
data << battlegroundCapturePointInfo.Pos;
data << int8(battlegroundCapturePointInfo.State);
if (battlegroundCapturePointInfo.State == WorldPackets::Battleground::BattlegroundCapturePointState::ContestedHorde || battlegroundCapturePointInfo.State == WorldPackets::Battleground::BattlegroundCapturePointState::ContestedAlliance)
{
data << battlegroundCapturePointInfo.CaptureTime;
data << battlegroundCapturePointInfo.CaptureTotalDuration;
}
return data;
}
WorldPacket const* WorldPackets::Battleground::UpdateCapturePoint::Write()
{
_worldPacket << CapturePointInfo;
return &_worldPacket;
}
WorldPacket const* WorldPackets::Battleground::CapturePointRemoved::Write()
{
_worldPacket << CapturePointGUID;
return &_worldPacket;
}

View File

@@ -498,6 +498,45 @@ namespace WorldPackets
Optional<PVPMatchStatistics> LogData;
uint32 SoloShuffleStatus = 0;
};
enum class BattlegroundCapturePointState : uint8
{
Neutral = 1,
ContestedHorde = 2,
ContestedAlliance = 3,
HordeCaptured = 4,
AllianceCaptured = 5
};
struct BattlegroundCapturePointInfo
{
ObjectGuid Guid;
TaggedPosition<Position::XY> Pos;
BattlegroundCapturePointState State = BattlegroundCapturePointState::Neutral;
Timestamp<> CaptureTime;
Duration<Milliseconds, uint32> CaptureTotalDuration;
};
class UpdateCapturePoint final : public ServerPacket
{
public:
UpdateCapturePoint() : ServerPacket(SMSG_UPDATE_CAPTURE_POINT) { }
WorldPacket const* Write() override;
BattlegroundCapturePointInfo CapturePointInfo;
};
class CapturePointRemoved final : public ServerPacket
{
public:
CapturePointRemoved() : ServerPacket(SMSG_CAPTURE_POINT_REMOVED) { }
CapturePointRemoved(ObjectGuid capturePointGUID) : ServerPacket(SMSG_CAPTURE_POINT_REMOVED), CapturePointGUID(capturePointGUID) { }
WorldPacket const* Write() override;
ObjectGuid CapturePointGUID;
};
}
}

View File

@@ -1107,7 +1107,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CANCEL_SPELL_VISUAL_KIT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CAN_DUEL_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CAN_REDEEM_TOKEN_FOR_BALANCE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CAPTURE_POINT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CAPTURE_POINT_REMOVED, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CAST_FAILED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CATEGORY_COOLDOWN, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAIN_MISSILE_BOUNCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -1272,7 +1272,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_OBJECT_BASE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_OBJECT_CUSTOM_ANIM, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_OBJECT_DESPAWN, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_OBJECT_PLAY_SPELL_VISUAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_OBJECT_PLAY_SPELL_VISUAL, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_OBJECT_PLAY_SPELL_VISUAL_KIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_OBJECT_RESET_STATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_OBJECT_SET_STATE_LOCAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -2004,7 +2004,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_ACCOUNT_DATA, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_ACTION_BUTTONS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_BNET_SESSION_KEY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CAPTURE_POINT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CAPTURE_POINT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CELESTIAL_BODY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CHARACTER_FLAGS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CHARGE_CATEGORY_COOLDOWN, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);

View File

@@ -1605,6 +1605,11 @@ void Spell::EffectOpenLock()
return;
}
}
else if (goInfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT)
{
gameObjTarget->AssaultCapturePoint(player);
return;
}
else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
{
//CanUseBattlegroundObject() already called in CheckCast()