From 63f17d776ad3e1db13f187a41bc49f59203c36b9 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Mon, 23 May 2022 17:11:04 -0400 Subject: [PATCH] Core/GameObjects: Implemented GAMEOBJECT_TYPE_CAPTURE_POINT Port From (https://github.com/TrinityCore/TrinityCore/commit/19f64e66e58d3d7ebed6437a474a134e7c673ed6) --- .../Framework/Constants/BattleGroundsConst.cs | 9 + Source/Game/AI/CoreAI/GameObjectAI.cs | 6 + Source/Game/BattleGrounds/BattleGround.cs | 2 +- .../Game/BattleGrounds/BattleGroundManager.cs | 1 + Source/Game/Entities/GameObject/GameObject.cs | 238 +++++++++++++++++- .../Entities/Object/Update/UpdateFields.cs | 6 + Source/Game/Entities/Player/Player.cs | 2 +- .../Networking/Packets/BattleGroundPackets.cs | 52 +++- Source/Game/Spells/SpellEffects.cs | 5 + 9 files changed, 315 insertions(+), 6 deletions(-) diff --git a/Source/Framework/Constants/BattleGroundsConst.cs b/Source/Framework/Constants/BattleGroundsConst.cs index 1d2554628..07bc9f1a9 100644 --- a/Source/Framework/Constants/BattleGroundsConst.cs +++ b/Source/Framework/Constants/BattleGroundsConst.cs @@ -450,4 +450,13 @@ namespace Framework.Constants PersonalRating = 6, End = 7 } + + public enum BattlegroundCapturePointState + { + Neutral = 1, + ContestedHorde = 2, + ContestedAlliance = 3, + HordeCaptured = 4, + AllianceCaptured = 5 + } } diff --git a/Source/Game/AI/CoreAI/GameObjectAI.cs b/Source/Game/AI/CoreAI/GameObjectAI.cs index 47780eb68..87de2ac64 100644 --- a/Source/Game/AI/CoreAI/GameObjectAI.cs +++ b/Source/Game/AI/CoreAI/GameObjectAI.cs @@ -105,5 +105,11 @@ namespace Game.AI public virtual void SummonedCreatureDespawn(Creature summon) { } public virtual void SummonedCreatureDies(Creature summon, Unit killer) { } + + // Called when the capture point gets assaulted by a player. Return true to disable default behaviour. + public virtual bool OnCapturePointAssaulted(Player player) { return false; } + + // Called when the capture point state gets updated. Return true to disable default behaviour. + public virtual bool OnCapturePointUpdated(BattlegroundCapturePointState state) { return false; } } } diff --git a/Source/Game/BattleGrounds/BattleGround.cs b/Source/Game/BattleGrounds/BattleGround.cs index bdc9e5cee..ad4853d5e 100644 --- a/Source/Game/BattleGrounds/BattleGround.cs +++ b/Source/Game/BattleGrounds/BattleGround.cs @@ -532,7 +532,7 @@ namespace Game.BattleGrounds return _battlegroundTemplate.MaxStartDistSq; } - void SendPacketToAll(ServerPacket packet) + public void SendPacketToAll(ServerPacket packet) { foreach (var pair in m_Players) { diff --git a/Source/Game/BattleGrounds/BattleGroundManager.cs b/Source/Game/BattleGrounds/BattleGroundManager.cs index ec16d68dc..51e1816bb 100644 --- a/Source/Game/BattleGrounds/BattleGroundManager.cs +++ b/Source/Game/BattleGrounds/BattleGroundManager.cs @@ -294,6 +294,7 @@ namespace Game.BattleGrounds bg = new BgWarsongGluch(bgTemplate); break; case BattlegroundTypeId.AB: + case BattlegroundTypeId.DomAb: bg = new BgArathiBasin(bgTemplate); break; case BattlegroundTypeId.NA: diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index 669b03c47..d49465fe8 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -367,6 +367,10 @@ namespace Game.Entities break; case GameObjectTypes.CapturePoint: SetUpdateFieldValue(m_values.ModifyValue(m_gameObjectData).ModifyValue(m_gameObjectData.SpellVisualID), m_goInfo.CapturePoint.SpellVisual1); + m_goValue.CapturePoint.AssaultTimer = 0; + m_goValue.CapturePoint.LastTeamCapture = TeamId.Neutral; + m_goValue.CapturePoint.State = BattlegroundCapturePointState.Neutral; + UpdateCapturePoint(); break; default: SetGoAnimProgress(animProgress); @@ -685,6 +689,51 @@ namespace Game.Entities if (target) SetLootState(LootState.Activated, target); } + else if (goInfo.type == GameObjectTypes.CapturePoint) + { + bool hordeCapturing = m_goValue.CapturePoint.State == BattlegroundCapturePointState.ContestedHorde; + bool allianceCapturing = m_goValue.CapturePoint.State == BattlegroundCapturePointState.ContestedAlliance; + if (hordeCapturing || allianceCapturing) + { + if (m_goValue.CapturePoint.AssaultTimer <= diff) + { + m_goValue.CapturePoint.State = hordeCapturing ? BattlegroundCapturePointState.HordeCaptured : BattlegroundCapturePointState.AllianceCaptured; + if (hordeCapturing) + { + m_goValue.CapturePoint.State = BattlegroundCapturePointState.HordeCaptured; + BattlegroundMap map = GetMap().ToBattlegroundMap(); + if (map != null) + { + Battleground bg = map.GetBG(); + if (bg != null) + { + EventInform(GetGoInfo().CapturePoint.CaptureEventHorde); + bg.SendBroadcastText(GetGoInfo().CapturePoint.CaptureBroadcastHorde, ChatMsg.BgSystemHorde); + } + } + } + else + { + m_goValue.CapturePoint.State = BattlegroundCapturePointState.AllianceCaptured; + BattlegroundMap map = GetMap().ToBattlegroundMap(); + if (map != null) + { + Battleground bg = map.GetBG(); + if (bg != null) + { + EventInform(GetGoInfo().CapturePoint.CaptureEventAlliance); + bg.SendBroadcastText(GetGoInfo().CapturePoint.CaptureBroadcastAlliance, ChatMsg.BgSystemAlliance); + } + } + } + + m_goValue.CapturePoint.LastTeamCapture = hordeCapturing ? TeamId.Horde : TeamId.Alliance; + UpdateCapturePoint(); + } + else + m_goValue.CapturePoint.AssaultTimer -= diff; + } + } else if ((max_charges = goInfo.GetCharges()) != 0) { if (m_usetimes >= max_charges) @@ -946,6 +995,9 @@ namespace Game.Entities SetLootState(LootState.NotReady); RemoveFromOwner(); + if (m_goInfo.type == GameObjectTypes.CapturePoint) + SendMessageToSet(new CapturePointRemoved(GetGUID()), true); + SendGameObjectDespawn(); SetGoState(GameObjectState.Ready); @@ -2891,6 +2943,169 @@ namespace Game.Entities SendMessageToSet(packet, true); } + public void AssaultCapturePoint(Player player) + { + if (!CanInteractWithCapturePoint(player)) + return; + + GameObjectAI ai = GetAI(); + if (ai != null) + if (ai.OnCapturePointAssaulted(player)) + return; + + // only supported in battlegrounds + Battleground battleground = null; + BattlegroundMap map = GetMap().ToBattlegroundMap(); + if (map != null) + { + Battleground bg = map.GetBG(); + if (bg != null) + battleground = bg; + } + + if (!battleground) + return; + + // Cancel current timer + m_goValue.CapturePoint.AssaultTimer = 0; + + if (player.GetBGTeam() == Team.Horde) + { + if (m_goValue.CapturePoint.LastTeamCapture == TeamId.Horde) + { + // defended. capture instantly. + m_goValue.CapturePoint.State = BattlegroundCapturePointState.HordeCaptured; + battleground.SendBroadcastText(GetGoInfo().CapturePoint.DefendedBroadcastHorde, ChatMsg.BgSystemHorde, player); + UpdateCapturePoint(); + EventInform(GetGoInfo().CapturePoint.DefendedEventHorde, player); + return; + } + + switch (m_goValue.CapturePoint.State) + { + case BattlegroundCapturePointState.Neutral: + case BattlegroundCapturePointState.AllianceCaptured: + case BattlegroundCapturePointState.ContestedAlliance: + m_goValue.CapturePoint.State = BattlegroundCapturePointState.ContestedHorde; + battleground.SendBroadcastText(GetGoInfo().CapturePoint.AssaultBroadcastHorde, ChatMsg.BgSystemHorde, player); + UpdateCapturePoint(); + EventInform(GetGoInfo().CapturePoint.AssaultBroadcastHorde, player); + m_goValue.CapturePoint.AssaultTimer = GetGoInfo().CapturePoint.CaptureTime; + break; + default: + break; + } + } + else + { + if (m_goValue.CapturePoint.LastTeamCapture == TeamId.Alliance) + { + // defended. capture instantly. + m_goValue.CapturePoint.State = BattlegroundCapturePointState.AllianceCaptured; + battleground.SendBroadcastText(GetGoInfo().CapturePoint.DefendedBroadcastAlliance, ChatMsg.BgSystemAlliance, player); + UpdateCapturePoint(); + EventInform(GetGoInfo().CapturePoint.DefendedEventAlliance, player); + return; + } + + switch (m_goValue.CapturePoint.State) + { + case BattlegroundCapturePointState.Neutral: + case BattlegroundCapturePointState.HordeCaptured: + case BattlegroundCapturePointState.ContestedHorde: + m_goValue.CapturePoint.State = BattlegroundCapturePointState.ContestedAlliance; + battleground.SendBroadcastText(GetGoInfo().CapturePoint.AssaultBroadcastAlliance, ChatMsg.BgSystemAlliance, player); + UpdateCapturePoint(); + EventInform(GetGoInfo().CapturePoint.ContestedEventAlliance, player); + m_goValue.CapturePoint.AssaultTimer = GetGoInfo().CapturePoint.CaptureTime; + break; + default: + break; + } + } + } + + void UpdateCapturePoint() + { + if (GetGoType() != GameObjectTypes.CapturePoint) + return; + + GameObjectAI ai = GetAI(); + if (ai != null) + if (ai.OnCapturePointUpdated(m_goValue.CapturePoint.State)) + return; + + uint spellVisualId = 0; + uint customAnim = 0; + + switch (m_goValue.CapturePoint.State) + { + case BattlegroundCapturePointState.Neutral: + spellVisualId = GetGoInfo().CapturePoint.SpellVisual1; + break; + case BattlegroundCapturePointState.ContestedHorde: + customAnim = 1; + spellVisualId = GetGoInfo().CapturePoint.SpellVisual2; + break; + case BattlegroundCapturePointState.ContestedAlliance: + customAnim = 2; + spellVisualId = GetGoInfo().CapturePoint.SpellVisual3; + break; + case BattlegroundCapturePointState.HordeCaptured: + customAnim = 3; + spellVisualId = GetGoInfo().CapturePoint.SpellVisual4; + break; + case BattlegroundCapturePointState.AllianceCaptured: + customAnim = 4; + spellVisualId = GetGoInfo().CapturePoint.SpellVisual5; + break; + default: + break; + } + + if (customAnim != 0) + SendCustomAnim(customAnim); + + SetSpellVisualId(spellVisualId); + UpdateDynamicFlagsForNearbyPlayers(); + + BattlegroundMap map = GetMap().ToBattlegroundMap(); + if (map != null) + { + Battleground bg = map.GetBG(); + if (bg != null) + { + UpdateCapturePoint packet = new(); + packet.CapturePointInfo.State = m_goValue.CapturePoint.State; + packet.CapturePointInfo.Pos = GetPosition(); + packet.CapturePointInfo.Guid = GetGUID(); + packet.CapturePointInfo.CaptureTotalDuration = TimeSpan.FromMilliseconds(GetGoInfo().CapturePoint.CaptureTime); + packet.CapturePointInfo.CaptureTime = m_goValue.CapturePoint.AssaultTimer; + bg.SendPacketToAll(packet); + bg.UpdateWorldState(GetGoInfo().CapturePoint.worldState1, (byte)m_goValue.CapturePoint.State); + } + } + } + + public bool CanInteractWithCapturePoint(Player target) + { + if (m_goInfo.type != GameObjectTypes.CapturePoint) + return false; + + if (m_goValue.CapturePoint.State == BattlegroundCapturePointState.Neutral) + return true; + + if (target.GetBGTeam() == Team.Horde) + { + return m_goValue.CapturePoint.State == BattlegroundCapturePointState.ContestedAlliance + || m_goValue.CapturePoint.State == BattlegroundCapturePointState.AllianceCaptured; + } + + // For Alliance players + return m_goValue.CapturePoint.State == BattlegroundCapturePointState.ContestedHorde + || m_goValue.CapturePoint.State == BattlegroundCapturePointState.HordeCaptured; + } + public override ushort GetAIAnimKitId() { return _animKitId; } public uint GetWorldEffectID() { return _worldEffectID; } @@ -3050,6 +3265,14 @@ namespace Game.Entities return IsInRange(obj.GetPositionX(), obj.GetPositionY(), obj.GetPositionZ(), dist2compare); } + void UpdateDynamicFlagsForNearbyPlayers() + { + ValuesUpdateForPlayerWithMaskSender sender = new(this); + sender.ObjectMask.MarkChanged(m_objectData.DynamicFlags); + MessageDistDeliverer deliverer = new(this, sender, GetVisibilityRange()); + Cell.VisitWorldObjects(this, deliverer, GetVisibilityRange()); + } + public void CreateModel() { m_model = GameObjectModel.Create(new GameObjectModelOwnerImpl(this)); @@ -3113,9 +3336,9 @@ namespace Game.Entities class ValuesUpdateForPlayerWithMaskSender : IDoWork { - GameObject Owner; - ObjectFieldData ObjectMask = new(); - GameObjectFieldData GameObjectMask = new(); + public GameObject Owner; + public ObjectFieldData ObjectMask = new(); + public GameObjectFieldData GameObjectMask = new(); public ValuesUpdateForPlayerWithMaskSender(GameObject owner) { @@ -3160,6 +3383,8 @@ namespace Game.Entities public building Building; + public capturePoint CapturePoint; + //11 GAMEOBJECT_TYPE_TRANSPORT public struct transport { @@ -3182,5 +3407,12 @@ namespace Game.Entities public uint Health; public uint MaxHealth; } + //42 GAMEOBJECT_TYPE_CAPTURE_POINT + public struct capturePoint + { + public int LastTeamCapture; + public BattlegroundCapturePointState State; + public uint AssaultTimer; + } } } \ No newline at end of file diff --git a/Source/Game/Entities/Object/Update/UpdateFields.cs b/Source/Game/Entities/Object/Update/UpdateFields.cs index 5851dd66f..b9f417ca1 100644 --- a/Source/Game/Entities/Object/Update/UpdateFields.cs +++ b/Source/Game/Entities/Object/Update/UpdateFields.cs @@ -136,6 +136,12 @@ namespace Game.Entities } break; } + case GameObjectTypes.CapturePoint: + if (!gameObject.CanInteractWithCapturePoint(receiver)) + dynFlags |= GameObjectDynamicLowFlags.NoInterract; + else + dynFlags &= ~GameObjectDynamicLowFlags.NoInterract; + break; default: break; } diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 660fbfadf..45f0251b5 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -3022,7 +3022,7 @@ namespace Game.Entities } break; case 3358: // Arathi Basin - if (bg && bg.GetTypeID(true) == BattlegroundTypeId.AB) + if (bg && (bg.GetTypeID(true) == BattlegroundTypeId.AB || bg.GetTypeID(true) == BattlegroundTypeId.DomAb)) bg.FillInitialWorldStates(packet); else { diff --git a/Source/Game/Networking/Packets/BattleGroundPackets.cs b/Source/Game/Networking/Packets/BattleGroundPackets.cs index a2bd8f3f5..83bba08e9 100644 --- a/Source/Game/Networking/Packets/BattleGroundPackets.cs +++ b/Source/Game/Networking/Packets/BattleGroundPackets.cs @@ -463,7 +463,7 @@ namespace Game.Networking.Packets BracketInfo[] Bracket = new BracketInfo[6]; } - + class PVPMatchInitialize : ServerPacket { public PVPMatchInitialize() : base(ServerOpcodes.PvpMatchInitialize, ConnectionType.Instance) { } @@ -520,6 +520,34 @@ namespace Game.Networking.Packets public uint SoloShuffleStatus; } + class UpdateCapturePoint : ServerPacket + { + public BattlegroundCapturePointInfo CapturePointInfo; + + public UpdateCapturePoint() : base(ServerOpcodes.UpdateCapturePoint) { } + + public override void Write() + { + CapturePointInfo.Write(_worldPacket); + } + } + + class CapturePointRemoved : ServerPacket + { + public ObjectGuid CapturePointGUID; + + public CapturePointRemoved() : base(ServerOpcodes.CapturePointRemoved) { } + public CapturePointRemoved(ObjectGuid capturePointGUID) : base(ServerOpcodes.CapturePointRemoved) + { + CapturePointGUID = capturePointGUID; + } + + public override void Write() + { + _worldPacket.WritePackedGuid(CapturePointGUID); + } + } + //Structs struct BracketInfo { @@ -747,4 +775,26 @@ namespace Game.Networking.Packets public sbyte IconID; public sbyte ArenaSlot; } + + struct BattlegroundCapturePointInfo + { + public ObjectGuid Guid; + public Vector2 Pos; + public BattlegroundCapturePointState State = BattlegroundCapturePointState.Neutral; + public long CaptureTime; + public TimeSpan CaptureTotalDuration; + + public void Write(WorldPacket data) + { + data.WritePackedGuid(Guid); + data.WriteVector2(Pos); + data.WriteInt8((sbyte)State); + + if (State == BattlegroundCapturePointState.ContestedHorde || State == BattlegroundCapturePointState.ContestedAlliance) + { + data.WriteInt64(CaptureTime); + data.WriteUInt32((uint)CaptureTotalDuration.TotalMilliseconds); + } + } + } } diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 93cd63d7a..53cc277ee 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -1281,6 +1281,11 @@ namespace Game.Spells return; } } + else if (goInfo.type == GameObjectTypes.CapturePoint) + { + gameObjTarget.AssaultCapturePoint(player); + return; + } else if (goInfo.type == GameObjectTypes.FlagStand) { //CanUseBattlegroundObject() already called in CheckCast()