Files

1069 lines
42 KiB
C#

// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants;
using Game;
using Game.BattleGrounds;
using Game.Entities;
using Game.Maps;
using Game.Scripting;
using System;
using System.Collections.Generic;
namespace Scripts.Battlegrounds.StrandOfTheAncients
{
enum Status
{
NotStarted = 0,
Warmup,
RoundOne,
SecondWarmup,
RoundTwo,
BonusRound
}
enum GateState
{
// Alliance Is Defender
AllianceGateOk = 1,
AllianceGateDamaged = 2,
AllianceGateDestroyed = 3,
// Horde Is Defender
HordeGateOk = 4,
HordeGateDamaged = 5,
HordeGateDestroyed = 6,
}
enum GameObjectIds
{
SeaforiumBombH = 194086, // Used By Horde Players
SeaforiumBombA = 190753, // Used By Alliance Players
SeaforiumChargeH = 257572,
SeaforiumChargeA = 257565,
GraveyardWestH = 191307,
GraveyardWestA = 191308,
GraveyardEastH = 191305,
GraveyardEastA = 191306,
GraveyardCentralH = 191309,
GraveyardCentralA = 191310,
CollisionDoor = 194162,
TitanRelicA = 194083,
TitanRelicH = 194082,
GateOfTheGreenEmerald = 190722,
GateOfThePurpleAmethyst = 190723,
GateOfTheBlueSapphire = 190724,
GateOfTheRedSun = 190726,
GateOfTheYellowMoon = 190727,
ChamberOfAncientRelics = 192549,
BoatOneA = 208000,
BoatTwoH = 208001,
BoatOneH = 193184,
BoatTwoA = 193185
}
enum SoundIds
{
GraveyardTakenHorde = 8174,
GraveyardTakenAlliance = 8212,
DefeatHorde = 15905,
VictoryHorde = 15906,
VictoryAlliance = 15907,
DefeatAlliance = 15908,
WallDestroyedAlliance = 15909,
WallDestroyedHorde = 15910,
WallAttackedHorde = 15911,
WallAttackedAlliance = 15912
}
enum TextIds
{
// Kanrethad
RoundStarted = 1,
Round1Finished = 2,
// Rigger Sparklight / Gorgril Rigspark
SparklightRigsparkSpawn = 1,
// World Trigger
BlueGateUnderAttack = 1,
GreenGateUnderAttack = 2,
RedGateUnderAttack = 3,
PurpleGateUnderAttack = 4,
YellowGateUnderAttack = 5,
YellowGateDestroyed = 6,
PurpleGateDestroyed = 7,
RedGateDestroyed = 8,
GreenGateDestroyed = 9,
BlueGateDestroyed = 10,
EastGraveyardCapturedA = 11,
WestGraveyardCapturedA = 12,
SouthGraveyardCapturedA = 13,
EastGraveyardCapturedH = 14,
WestGraveyardCapturedH = 15,
SouthGraveyardCapturedH = 16,
AncientGateUnderAttack = 17,
AncientGateDestroyed = 18
}
enum WorldStateIds
{
Timer = 3557,
AllyAttacks = 4352,
HordeAttacks = 4353,
PurpleGate = 3614,
RedGate = 3617,
BlueGate = 3620,
GreenGate = 3623,
YellowGate = 3638,
AncientGate = 3849,
LeftGyAlliance = 3635,
RightGyAlliance = 3636,
CenterGyAlliance = 3637,
RightAttTokenAll = 3627,
LeftAttTokenAll = 3626,
LeftAttTokenHrd = 3629,
RightAttTokenHrd = 3628,
HordeDefenceToken = 3631,
AllianceDefenceToken = 3630,
RightGyHorde = 3632,
LeftGyHorde = 3633,
CenterGyHorde = 3634,
BonusTimer = 3571,
EnableTimer = 3564,
AttackerTeam = 3690,
DestroyedAllianceVehicles = 3955,
DestroyedHordeVehicles = 3956,
}
enum StrandOfTheAncientsGraveyard
{
West,
East,
Central
}
enum BroadcastTextIds
{
AllianceCapturedTitanPortal = 28944,
HordeCapturedTitanPortal = 28945,
RoundTwoStartOneMinute = 29448,
RoundTwoStartHalfMinute = 29449
}
enum DefenseLine
{
First,
Second,
Third,
Last
}
enum PvpStats
{
GatesDestroyed = 231,
DemolishersDestroyed = 232
}
enum EventIds
{
HordeAssaultStarted = 21702,
AllianceAssaultStarted = 23748,
TitanRelicActivated = 20572
}
enum CreatureIds
{
Kanrethad = 29,
Demolisher = 28781,
AntipersonnelCannon = 27894,
RiggerSparklight = 29260,
GorgrilRigspark = 29262,
WorldTrigger = 22515,
}
enum SpellIds
{
TeleportDefender = 52364,
TeleportAttackers = 60178,
EndOfRound = 52459,
RemoveSeaforium = 59077,
AllianceControlPhaseShift = 60027,
HordeControlPhaseShift = 60028,
CarryingSeaforiumCharge = 52415
}
struct Misc
{
public const uint DataAttackers = 1;
public const uint DataStatus = 2;
public const uint SpawnDefenders = 1399;
public const uint BoatStartTime = 60 * Time.InMilliseconds;
public const uint WarmupTime = 120 * Time.InMilliseconds;
public const uint RoundTime = 600 * Time.InMilliseconds;
public static uint[] Factions = { 1732, 1735, };
public static GateInfo[] Gates =
{
new GateInfo(GameObjectIds.GateOfTheGreenEmerald, WorldStateIds.GreenGate, TextIds.GreenGateUnderAttack, TextIds.GreenGateDestroyed, DefenseLine.First),
new GateInfo(GameObjectIds.GateOfTheYellowMoon, WorldStateIds.YellowGate, TextIds.YellowGateUnderAttack, TextIds.YellowGateDestroyed, DefenseLine.Third),
new GateInfo(GameObjectIds.GateOfTheBlueSapphire, WorldStateIds.BlueGate, TextIds.BlueGateUnderAttack, TextIds.BlueGateDestroyed, DefenseLine.First),
new GateInfo(GameObjectIds.GateOfTheRedSun, WorldStateIds.RedGate, TextIds.RedGateUnderAttack, TextIds.RedGateDestroyed, DefenseLine.Second),
new GateInfo(GameObjectIds.GateOfThePurpleAmethyst, WorldStateIds.PurpleGate, TextIds.PurpleGateUnderAttack, TextIds.PurpleGateDestroyed, DefenseLine.Second),
new GateInfo(GameObjectIds.ChamberOfAncientRelics, WorldStateIds.AncientGate, TextIds.AncientGateUnderAttack, TextIds.AncientGateDestroyed, DefenseLine.Last)
};
public static Position[] SpawnPositionOnTransport =
{
new Position(0.0f, 5.0f, 9.6f, 3.14f),
new Position(-6.0f, -3.0f, 8.6f, 0.0f)
};
}
class GateInfo
{
public uint GameObjectId;
public int WorldState;
public byte DamagedText;
public byte DestroyedText;
public DefenseLine LineOfDefense;
public GateInfo(GameObjectIds gameObjectId, WorldStateIds worldState, TextIds damagedText, TextIds destroyedText, DefenseLine lineOfDefense)
{
GameObjectId = (uint)gameObjectId;
WorldState = (int)worldState;
DamagedText = (byte)damagedText;
DestroyedText = (byte)destroyedText;
LineOfDefense = lineOfDefense;
}
}
class RoundScore
{
public int Winner;
public uint Time;
}
[Script(nameof(battleground_strand_of_the_ancients), 607)]
class battleground_strand_of_the_ancients : BattlegroundScript
{
/// Id of attacker team
int _attackers;
/// Totale elapsed time of current round
uint _totalTime;
/// Max time of round
uint _endRoundTimer;
/// For know if boats has start moving or not yet
bool _shipsStarted;
/// Statu of battle (Start or not, and what round)
Status _status;
/// Score of each round
RoundScore[] _roundScores = new RoundScore[2];
/// used for know we are in timer phase or not (used for worldstate update)
bool _timerEnabled;
/// 5secs before starting the 1min countdown for second round
uint _updateWaitTimer;
/// for know if warning about second round start has been sent
bool _signaledRoundTwo;
/// for know if warning about second round start has been sent
bool _signaledRoundTwoHalfMin;
/// for know if second round has been init
bool _initSecondRound;
// [team][boat_idx]
ObjectGuid[][] _boatGUIDs = new ObjectGuid[SharedConst.PvpTeamsCount][];
List<ObjectGuid>[] _staticBombGUIDs = new List<ObjectGuid>[SharedConst.PvpTeamsCount]; // bombs ready to be picked up
List<ObjectGuid> _dynamicBombGUIDs = new(); // bombs thrown by players, ready to explode/disarm
ObjectGuid _graveyardWest;
ObjectGuid _graveyardEast;
ObjectGuid _graveyardCentral;
List<ObjectGuid> _gateGUIDs = new();
ObjectGuid _collisionDoorGUID;
ObjectGuid _kanrethadGUID;
ObjectGuid _titanRelicGUID;
public battleground_strand_of_the_ancients(BattlegroundMap map) : base(map)
{
_timerEnabled = false;
_updateWaitTimer = 0;
_signaledRoundTwo = false;
_signaledRoundTwoHalfMin = false;
_initSecondRound = false;
_attackers = RandomHelper.IRand(BattleGroundTeamId.Alliance, BattleGroundTeamId.Horde);
_totalTime = 0;
_endRoundTimer = 0;
_shipsStarted = false;
_status = Status.NotStarted;
foreach (RoundScore roundScore in _roundScores)
{
roundScore.Winner = BattleGroundTeamId.Alliance;
roundScore.Time = 0;
}
for (var i = 0; i < SharedConst.PvpTeamsCount; i++)
{
_boatGUIDs[i] = new ObjectGuid[2];
_staticBombGUIDs[i] = new();
}
}
public override void OnInit()
{
base.OnInit();
_status = Status.Warmup;
ResetObjs();
}
public override void OnUpdate(uint diff)
{
base.OnUpdate(diff);
if (_initSecondRound)
{
if (_updateWaitTimer < diff)
{
if (!_signaledRoundTwo)
{
_signaledRoundTwo = true;
_initSecondRound = false;
battleground.SendBroadcastText((uint)BroadcastTextIds.RoundTwoStartOneMinute, ChatMsg.BgSystemNeutral);
}
}
else
{
_updateWaitTimer -= diff;
return;
}
}
_totalTime += diff;
if (_status == Status.Warmup)
{
_endRoundTimer = Misc.RoundTime;
UpdateWorldState((int)WorldStateIds.Timer, (int)(GameTime.GetGameTime() + (_endRoundTimer / 1000)));
if (_totalTime >= Misc.WarmupTime)
{
Creature c = FindKanrethad();
if (c != null)
battleground.SendChatMessage(c, (byte)TextIds.RoundStarted);
_totalTime = 0;
ToggleTimer();
_status = Status.RoundOne;
TriggerGameEvent((uint)((_attackers == BattleGroundTeamId.Alliance) ? EventIds.AllianceAssaultStarted : EventIds.HordeAssaultStarted));
}
if (_totalTime >= Misc.BoatStartTime)
StartShips();
return;
}
else if (_status == Status.SecondWarmup)
{
if (_roundScores[0].Time < Misc.RoundTime)
_endRoundTimer = _roundScores[0].Time;
else
_endRoundTimer = Misc.RoundTime;
UpdateWorldState((int)WorldStateIds.Timer, (int)(GameTime.GetGameTime() + (_endRoundTimer / 1000)));
if (_totalTime >= 60000)
{
Creature c = FindKanrethad();
if (c != null)
battleground.SendChatMessage(c, (byte)TextIds.RoundStarted);
_totalTime = 0;
ToggleTimer();
_status = Status.RoundTwo;
TriggerGameEvent((uint)(_attackers == BattleGroundTeamId.Alliance ? EventIds.AllianceAssaultStarted : EventIds.HordeAssaultStarted));
// status was set to STATUS_WAIT_JOIN manually for Preparation, set it back now
battleground.SetStatus(BattlegroundStatus.InProgress);
foreach (var (playerGuid, _) in battleground.GetPlayers())
{
Player p = Global.ObjAccessor.FindPlayer(playerGuid);
if (p != null)
p.RemoveAurasDueToSpell(BattlegroundConst.SpellPreparation);
}
}
if (_totalTime >= 30000)
{
if (!_signaledRoundTwoHalfMin)
{
_signaledRoundTwoHalfMin = true;
battleground.SendBroadcastText((uint)BroadcastTextIds.RoundTwoStartHalfMinute, ChatMsg.BgSystemNeutral);
}
}
StartShips();
return;
}
else if (battleground.GetStatus() == BattlegroundStatus.InProgress)
{
if (_status == Status.RoundOne)
{
if (_totalTime >= Misc.RoundTime)
{
EndRound();
return;
}
}
else if (_status == Status.RoundTwo)
{
if (_totalTime >= _endRoundTimer)
{
battleground.CastSpellOnTeam((uint)SpellIds.EndOfRound, Team.Alliance);
battleground.CastSpellOnTeam((uint)SpellIds.EndOfRound, Team.Horde);
_roundScores[1].Time = Misc.RoundTime;
_roundScores[1].Winner = (_attackers == BattleGroundTeamId.Alliance) ? BattleGroundTeamId.Horde : BattleGroundTeamId.Alliance;
if (_roundScores[0].Time == _roundScores[1].Time)
battleground.EndBattleground(Team.Other);
else if (_roundScores[0].Time < _roundScores[1].Time)
battleground.EndBattleground(_roundScores[0].Winner == BattleGroundTeamId.Alliance ? Team.Alliance : Team.Horde);
else
battleground.EndBattleground(_roundScores[1].Winner == BattleGroundTeamId.Alliance ? Team.Alliance : Team.Horde);
return;
}
}
}
}
void Reset()
{
_totalTime = 0;
_shipsStarted = false;
_status = Status.Warmup;
}
void ResetObjs()
{
foreach (ObjectGuid bombGuid in _dynamicBombGUIDs)
{
GameObject bomb = battlegroundMap.GetGameObject(bombGuid);
if (bomb != null)
bomb.Delete();
}
_dynamicBombGUIDs.Clear();
int defenders = _attackers == BattleGroundTeamId.Alliance ? BattleGroundTeamId.Horde : BattleGroundTeamId.Alliance;
_totalTime = 0;
_shipsStarted = false;
UpdateWorldState((int)WorldStateIds.AllyAttacks, _attackers == BattleGroundTeamId.Alliance);
UpdateWorldState((int)WorldStateIds.HordeAttacks, _attackers == BattleGroundTeamId.Horde);
UpdateWorldState((int)WorldStateIds.RightAttTokenAll, _attackers == BattleGroundTeamId.Alliance);
UpdateWorldState((int)WorldStateIds.LeftAttTokenAll, _attackers == BattleGroundTeamId.Alliance);
UpdateWorldState((int)WorldStateIds.RightAttTokenHrd, _attackers == BattleGroundTeamId.Horde);
UpdateWorldState((int)WorldStateIds.LeftAttTokenHrd, _attackers == BattleGroundTeamId.Horde);
UpdateWorldState((int)WorldStateIds.HordeDefenceToken, defenders == BattleGroundTeamId.Horde);
UpdateWorldState((int)WorldStateIds.AllianceDefenceToken, defenders == BattleGroundTeamId.Alliance);
CaptureGraveyard(StrandOfTheAncientsGraveyard.Central, defenders);
CaptureGraveyard(StrandOfTheAncientsGraveyard.West, defenders);
CaptureGraveyard(StrandOfTheAncientsGraveyard.East, defenders);
UpdateWorldState((int)WorldStateIds.AttackerTeam, _attackers);
foreach (ObjectGuid guid in _gateGUIDs)
{
GameObject gate = battlegroundMap.GetGameObject(guid);
if (gate != null)
gate.SetDestructibleState(GameObjectDestructibleState.Intact, null, true);
}
GateState state = _attackers == BattleGroundTeamId.Alliance ? GateState.HordeGateOk : GateState.AllianceGateOk;
UpdateWorldState((int)WorldStateIds.PurpleGate, (int)state);
UpdateWorldState((int)WorldStateIds.RedGate, (int)state);
UpdateWorldState((int)WorldStateIds.BlueGate, (int)state);
UpdateWorldState((int)WorldStateIds.GreenGate, (int)state);
UpdateWorldState((int)WorldStateIds.YellowGate, (int)state);
UpdateWorldState((int)WorldStateIds.AncientGate, (int)state);
battlegroundMap.UpdateSpawnGroupConditions();
GameObject door = battlegroundMap.GetGameObject(_collisionDoorGUID);
if (door != null)
door.ResetDoorOrButton();
battleground.SetStatus(BattlegroundStatus.WaitJoin);
battlegroundMap.DoOnPlayers(SendTransportInit);
TeleportPlayers();
}
void StartShips()
{
if (_shipsStarted)
return;
foreach (ObjectGuid guid in _boatGUIDs[_attackers])
{
GameObject boat = battlegroundMap.GetGameObject(guid);
if (boat != null)
{
boat.SetGoState(GameObjectState.TransportStopped);
// make sure every player knows the transport exists & is moving
foreach (var (playerGuid, _) in battleground.GetPlayers())
{
Player player = Global.ObjAccessor.FindPlayer(playerGuid);
if (player != null)
boat.SendUpdateToPlayer(player);
}
}
}
_shipsStarted = true;
}
public override void OnPlayerJoined(Player player, bool inBattleground)
{
base.OnPlayerJoined(player, inBattleground);
SendTransportInit(player);
if (!inBattleground)
TeleportToEntrancePosition(player);
}
void TeleportPlayers()
{
foreach (var (playerGuid, _) in battleground.GetPlayers())
{
Player player = Global.ObjAccessor.FindPlayer(playerGuid);
if (player != null)
{
// should remove spirit of redemption
if (player.HasAuraType(AuraType.SpiritOfRedemption))
player.RemoveAurasByType(AuraType.ModShapeshift);
if (!player.IsAlive())
{
player.ResurrectPlayer(1.0f);
player.SpawnCorpseBones();
}
player.ResetAllPowers();
player.CombatStopWithPets(true);
player.CastSpell(player, BattlegroundConst.SpellPreparation, true);
TeleportToEntrancePosition(player);
}
}
}
// This function teleports player to entrance position, but it's not implemented correctly
// It is also used on round swap; which should be handled by the following spells: 52365, 52528, 53464, 53465 (Split Teleport (FACTION) (Boat X))
// This spell however cannot work with current system because of grid limitations.
// On battleground start, this function should work fine, except that it is called to late and we need a NearTeleport to solve this.
void TeleportToEntrancePosition(Player player)
{
if (Battleground.GetTeamIndexByTeamId(battleground.GetPlayerTeam(player.GetGUID())) == _attackers)
{
ObjectGuid boatGUID = _boatGUIDs[_attackers][RandomHelper.URand(0, 1)];
GameObject boat = battlegroundMap.GetGameObject(boatGUID);
if (boat != null)
{
ITransport transport = boat.ToTransportBase();
if (transport != null)
{
player.Relocate(Misc.SpawnPositionOnTransport[_attackers]);
transport.AddPassenger(player);
player.m_movementInfo.transport.pos.Relocate(Misc.SpawnPositionOnTransport[_attackers]);
Misc.SpawnPositionOnTransport[_attackers].GetPosition(out float x, out float y, out float z, out float o);
transport.CalculatePassengerPosition(ref x, ref y, ref z, ref o);
player.Relocate(x, y, z, o);
if (player.IsInWorld)
player.NearTeleportTo(x, y, z, o);
}
}
}
else
{
WorldSafeLocsEntry defenderSpawn = Global.ObjectMgr.GetWorldSafeLoc(Misc.SpawnDefenders);
if (defenderSpawn != null)
{
if (player.IsInWorld)
player.TeleportTo(defenderSpawn.Loc);
else
player.WorldRelocate(defenderSpawn.Loc);
}
}
}
public override void ProcessEvent(WorldObject obj, uint eventId, WorldObject invoker)
{
base.ProcessEvent(obj, eventId, invoker);
switch ((EventIds)eventId)
{
case EventIds.AllianceAssaultStarted:
foreach (ObjectGuid bombGuid in _staticBombGUIDs[BattleGroundTeamId.Alliance])
{
GameObject bomb = battlegroundMap.GetGameObject(bombGuid);
if (bomb != null)
bomb.RemoveFlag(GameObjectFlags.NotSelectable);
}
break;
case EventIds.HordeAssaultStarted:
foreach (ObjectGuid bombGuid in _staticBombGUIDs[BattleGroundTeamId.Horde])
{
GameObject bomb = battlegroundMap.GetGameObject(bombGuid);
if (bomb != null)
bomb.RemoveFlag(GameObjectFlags.NotSelectable);
}
break;
default:
break;
}
GameObject go = obj?.ToGameObject();
if (go != null)
{
switch (go.GetGoType())
{
case GameObjectTypes.Goober:
if (invoker != null)
if (eventId == (uint)EventIds.TitanRelicActivated)
TitanRelicActivated(invoker.ToPlayer());
break;
case GameObjectTypes.DestructibleBuilding:
{
GateInfo gate = GetGate(obj.GetEntry());
if (gate != null)
{
uint gateId = gate.GameObjectId;
// damaged
if (eventId == go.GetGoInfo().DestructibleBuilding.DamagedEvent)
{
GateState gateState = _attackers == BattleGroundTeamId.Horde ? GateState.AllianceGateDamaged : GateState.HordeGateDamaged;
Creature c = obj.FindNearestCreature((uint)CreatureIds.WorldTrigger, 500.0f);
if (c != null)
battleground.SendChatMessage(c, gate.DamagedText, invoker);
battleground.PlaySoundToAll((uint)(_attackers == BattleGroundTeamId.Alliance ? SoundIds.WallAttackedAlliance : SoundIds.WallAttackedHorde));
UpdateWorldState(gate.WorldState, (int)gateState);
}
// destroyed
else if (eventId == go.GetGoInfo().DestructibleBuilding.DestroyedEvent)
{
GateState gateState = _attackers == BattleGroundTeamId.Horde ? GateState.AllianceGateDestroyed : GateState.HordeGateDestroyed;
Creature c = obj.FindNearestCreature((uint)CreatureIds.WorldTrigger, 500.0f);
if (c != null)
battleground.SendChatMessage(c, gate.DestroyedText, invoker);
battleground.PlaySoundToAll((uint)(_attackers == BattleGroundTeamId.Alliance ? SoundIds.WallDestroyedAlliance : SoundIds.WallDestroyedHorde));
// check if other gate from same line of defense is already destroyed for honor reward
bool rewardHonor = true;
switch ((GameObjectIds)gateId)
{
case GameObjectIds.GateOfTheGreenEmerald:
if (IsGateDestroyed(GetGate((uint)GameObjectIds.GateOfTheBlueSapphire)))
rewardHonor = false;
break;
case GameObjectIds.GateOfTheBlueSapphire:
if (IsGateDestroyed(GetGate((uint)GameObjectIds.GateOfTheGreenEmerald)))
rewardHonor = false;
break;
case GameObjectIds.GateOfTheRedSun:
if (IsGateDestroyed(GetGate((uint)GameObjectIds.GateOfThePurpleAmethyst)))
rewardHonor = false;
break;
case GameObjectIds.GateOfThePurpleAmethyst:
if (IsGateDestroyed(GetGate((uint)GameObjectIds.GateOfTheRedSun)))
rewardHonor = false;
break;
default:
break;
}
if (invoker != null)
{
Unit unit = invoker.ToUnit();
if (unit != null)
{
Player player = unit.GetCharmerOrOwnerPlayerOrPlayerItself();
if (player != null)
{
battleground.UpdatePvpStat(player, (uint)PvpStats.GatesDestroyed, 1);
if (rewardHonor)
battleground.UpdatePlayerScore(player, ScoreType.BonusHonor, battleground.GetBonusHonorFromKill(1));
}
}
}
if (rewardHonor)
MakeObjectsInteractable(gate.LineOfDefense);
UpdateWorldState(gate.WorldState, (int)gateState);
battlegroundMap.UpdateSpawnGroupConditions();
}
}
break;
}
default:
break;
}
}
}
public override void OnUnitKilled(Creature victim, Unit killer)
{
if (victim.GetEntry() == (uint)CreatureIds.Demolisher)
{
Player killerPlayer = killer.GetCharmerOrOwnerPlayerOrPlayerItself();
if (killerPlayer != null)
battleground.UpdatePvpStat(killerPlayer, (byte)PvpStats.DemolishersDestroyed, 1);
int worldStateId = _attackers == BattleGroundTeamId.Horde ? (int)WorldStateIds.DestroyedHordeVehicles : (int)WorldStateIds.DestroyedAllianceVehicles;
int currentDestroyedVehicles = Global.WorldStateMgr.GetValue(worldStateId, battlegroundMap);
UpdateWorldState(worldStateId, currentDestroyedVehicles + 1);
}
}
void CaptureGraveyard(StrandOfTheAncientsGraveyard graveyard, int teamId)
{
switch (graveyard)
{
case StrandOfTheAncientsGraveyard.West:
UpdateWorldState((int)WorldStateIds.LeftGyAlliance, teamId == BattleGroundTeamId.Alliance);
UpdateWorldState((int)WorldStateIds.LeftGyHorde, teamId == BattleGroundTeamId.Horde);
break;
case StrandOfTheAncientsGraveyard.East:
UpdateWorldState((int)WorldStateIds.RightGyAlliance, teamId == BattleGroundTeamId.Alliance);
UpdateWorldState((int)WorldStateIds.RightGyHorde, teamId == BattleGroundTeamId.Horde);
break;
case StrandOfTheAncientsGraveyard.Central:
UpdateWorldState((int)WorldStateIds.CenterGyAlliance, teamId == BattleGroundTeamId.Alliance);
UpdateWorldState((int)WorldStateIds.CenterGyHorde, teamId == BattleGroundTeamId.Horde);
CaptureGraveyard(StrandOfTheAncientsGraveyard.East, teamId);
CaptureGraveyard(StrandOfTheAncientsGraveyard.West, teamId);
break;
default:
break;
}
}
void TitanRelicActivated(Player clicker)
{
if (clicker == null)
return;
int clickerTeamId = Battleground.GetTeamIndexByTeamId(battleground.GetPlayerTeam(clicker.GetGUID()));
if (clickerTeamId == _attackers)
{
if (clickerTeamId == BattleGroundTeamId.Alliance)
battleground.SendBroadcastText((uint)BroadcastTextIds.AllianceCapturedTitanPortal, ChatMsg.BgSystemAlliance);
else
battleground.SendBroadcastText((uint)BroadcastTextIds.HordeCapturedTitanPortal, ChatMsg.BgSystemHorde);
if (_status == Status.RoundOne)
{
EndRound();
// Achievement Storm the Beach (1310)
foreach (var (guid, _) in battleground.GetPlayers())
{
Player player = Global.ObjAccessor.FindPlayer(guid);
if (player != null)
if (Battleground.GetTeamIndexByTeamId(battleground.GetPlayerTeam(player.GetGUID())) == _attackers)
player.UpdateCriteria(CriteriaType.BeSpellTarget, 65246);
}
Creature c = FindKanrethad();
if (c != null)
battleground.SendChatMessage(c, (byte)TextIds.Round1Finished);
}
else if (_status == Status.RoundTwo)
{
_roundScores[1].Winner = _attackers;
_roundScores[1].Time = _totalTime;
ToggleTimer();
// Achievement Storm the Beach (1310)
foreach (var (guid, _) in battleground.GetPlayers())
{
Player player = Global.ObjAccessor.FindPlayer(guid);
if (player != null)
if (Battleground.GetTeamIndexByTeamId(battleground.GetPlayerTeam(player.GetGUID())) == _attackers && _roundScores[1].Winner == _attackers)
player.UpdateCriteria(CriteriaType.BeSpellTarget, 65246);
}
if (_roundScores[0].Time == _roundScores[1].Time)
battleground.EndBattleground(Team.Other);
else if (_roundScores[0].Time < _roundScores[1].Time)
battleground.EndBattleground(_roundScores[0].Winner == BattleGroundTeamId.Alliance ? Team.Alliance : Team.Horde);
else
battleground.EndBattleground(_roundScores[1].Winner == BattleGroundTeamId.Alliance ? Team.Alliance : Team.Horde);
}
}
}
void ToggleTimer()
{
_timerEnabled = !_timerEnabled;
UpdateWorldState((int)WorldStateIds.EnableTimer, _timerEnabled);
}
public override void OnEnd(Team winner)
{
base.OnEnd(winner);
// honor reward for winning
if (winner == Team.Alliance)
battleground.RewardHonorToTeam(battleground.GetBonusHonorFromKill(1), Team.Alliance);
else if (winner == Team.Horde)
battleground.RewardHonorToTeam(battleground.GetBonusHonorFromKill(1), Team.Horde);
// complete map_end rewards (even if no team wins)
battleground.RewardHonorToTeam(battleground.GetBonusHonorFromKill(2), Team.Alliance);
battleground.RewardHonorToTeam(battleground.GetBonusHonorFromKill(2), Team.Horde);
}
void SendTransportInit(Player player)
{
foreach (ObjectGuid boatGuid in _boatGUIDs[_attackers])
{
GameObject boat = battlegroundMap.GetGameObject(boatGuid);
if (boat != null)
boat.SendUpdateToPlayer(player);
}
}
bool IsGateDestroyed(GateInfo gateInfo)
{
if (gateInfo == null)
return false;
int value = battlegroundMap.GetWorldStateValue(gateInfo.WorldState);
return value == (int)GateState.AllianceGateDestroyed || value == (int)GateState.HordeGateDestroyed;
}
void HandleCaptureGraveyardAction(GameObject graveyardBanner, Player player)
{
if (graveyardBanner == null || player == null)
return;
int teamId = Battleground.GetTeamIndexByTeamId(battleground.GetPlayerTeam(player.GetGUID()));
// Only attackers can capture graveyard by gameobject action
if (teamId != _attackers)
return;
switch ((GameObjectIds)graveyardBanner.GetEntry())
{
case GameObjectIds.GraveyardWestA:
case GameObjectIds.GraveyardWestH:
CaptureGraveyard(StrandOfTheAncientsGraveyard.West, teamId);
break;
case GameObjectIds.GraveyardEastA:
case GameObjectIds.GraveyardEastH:
CaptureGraveyard(StrandOfTheAncientsGraveyard.East, teamId);
break;
case GameObjectIds.GraveyardCentralA:
case GameObjectIds.GraveyardCentralH:
CaptureGraveyard(StrandOfTheAncientsGraveyard.Central, teamId);
break;
default:
break;
}
}
void MakeObjectsInteractable(DefenseLine defenseLine)
{
var makeInteractable = (ObjectGuid guid) =>
{
GameObject gameObject = battlegroundMap.GetGameObject(guid);
if (gameObject != null)
gameObject.RemoveFlag(GameObjectFlags.NotSelectable);
};
switch (defenseLine)
{
case DefenseLine.First:
makeInteractable(_graveyardWest);
makeInteractable(_graveyardEast);
break;
case DefenseLine.Second:
makeInteractable(_graveyardCentral);
break;
case DefenseLine.Third:
break;
case DefenseLine.Last:
// make titan orb interactable
GameObject door = battlegroundMap.GetGameObject(_collisionDoorGUID);
if (door != null)
door.UseDoorOrButton();
makeInteractable(_titanRelicGUID);
break;
default:
break;
}
}
Creature FindKanrethad()
{
return battlegroundMap.GetCreature(_kanrethadGUID);
}
void EndRound()
{
_roundScores[0].Winner = _attackers;
_roundScores[0].Time = Math.Min(_totalTime, Misc.RoundTime);
_attackers = (_attackers == BattleGroundTeamId.Alliance) ? BattleGroundTeamId.Horde : BattleGroundTeamId.Alliance;
_status = Status.SecondWarmup;
_totalTime = 0;
ToggleTimer();
_updateWaitTimer = 5000;
_signaledRoundTwo = false;
_signaledRoundTwoHalfMin = false;
_initSecondRound = true;
ResetObjs();
battlegroundMap.UpdateAreaDependentAuras();
battleground.CastSpellOnTeam((uint)SpellIds.EndOfRound, Team.Alliance);
battleground.CastSpellOnTeam((uint)SpellIds.EndOfRound, Team.Horde);
battleground.RemoveAuraOnTeam((uint)SpellIds.CarryingSeaforiumCharge, Team.Horde);
battleground.RemoveAuraOnTeam((uint)SpellIds.CarryingSeaforiumCharge, Team.Alliance);
}
public override void OnGameObjectCreate(GameObject gameobject)
{
base.OnGameObjectCreate(gameobject);
if (gameobject.GetGoType() == GameObjectTypes.DestructibleBuilding)
_gateGUIDs.Add(gameobject.GetGUID());
switch ((GameObjectIds)gameobject.GetEntry())
{
case GameObjectIds.BoatOneA:
_boatGUIDs[BattleGroundTeamId.Alliance][0] = gameobject.GetGUID();
break;
case GameObjectIds.BoatTwoA:
_boatGUIDs[BattleGroundTeamId.Alliance][1] = gameobject.GetGUID();
break;
case GameObjectIds.BoatOneH:
_boatGUIDs[BattleGroundTeamId.Horde][0] = gameobject.GetGUID();
break;
case GameObjectIds.BoatTwoH:
_boatGUIDs[BattleGroundTeamId.Horde][1] = gameobject.GetGUID();
break;
case GameObjectIds.SeaforiumBombA:
_staticBombGUIDs[BattleGroundTeamId.Alliance].Add(gameobject.GetGUID());
if (_status != Status.SecondWarmup && _status != Status.Warmup)
gameobject.RemoveFlag(GameObjectFlags.NotSelectable);
break;
case GameObjectIds.SeaforiumBombH:
_staticBombGUIDs[BattleGroundTeamId.Horde].Add(gameobject.GetGUID());
if (_status != Status.SecondWarmup && _status != Status.Warmup)
gameobject.RemoveFlag(GameObjectFlags.NotSelectable);
break;
case GameObjectIds.SeaforiumChargeA:
case GameObjectIds.SeaforiumChargeH:
_dynamicBombGUIDs.Add(gameobject.GetGUID());
break;
case GameObjectIds.GraveyardEastA:
case GameObjectIds.GraveyardEastH:
_graveyardEast = gameobject.GetGUID();
break;
case GameObjectIds.GraveyardWestA:
case GameObjectIds.GraveyardWestH:
_graveyardWest = gameobject.GetGUID();
break;
case GameObjectIds.GraveyardCentralA:
case GameObjectIds.GraveyardCentralH:
_graveyardCentral = gameobject.GetGUID();
break;
case GameObjectIds.CollisionDoor:
_collisionDoorGUID = gameobject.GetGUID();
break;
case GameObjectIds.TitanRelicA:
case GameObjectIds.TitanRelicH:
_titanRelicGUID = gameobject.GetGUID();
break;
default:
break;
}
}
public override void DoAction(uint actionId, WorldObject source, WorldObject target)
{
base.DoAction(actionId, source, target);
switch (actionId)
{
case 0:
HandleCaptureGraveyardAction(target?.ToGameObject(), source?.ToPlayer());
break;
default:
break;
}
}
public override void OnCreatureCreate(Creature creature)
{
base.OnCreatureCreate(creature);
switch ((CreatureIds)creature.GetEntry())
{
case CreatureIds.Demolisher:
creature.SetFaction(Misc.Factions[_attackers]);
break;
case CreatureIds.AntipersonnelCannon:
creature.SetFaction(Misc.Factions[_attackers == BattleGroundTeamId.Horde ? BattleGroundTeamId.Alliance : BattleGroundTeamId.Horde]);
break;
case CreatureIds.Kanrethad:
_kanrethadGUID = creature.GetGUID();
break;
case CreatureIds.RiggerSparklight:
case CreatureIds.GorgrilRigspark:
creature.GetAI().Talk((uint)TextIds.SparklightRigsparkSpawn);
break;
default:
break;
}
}
public override uint GetData(uint dataId)
{
switch (dataId)
{
case Misc.DataAttackers:
return (uint)_attackers;
case Misc.DataStatus:
return (uint)_status;
default:
return base.GetData(dataId);
}
}
static GateInfo GetGate(uint entry)
{
foreach (GateInfo gate in Misc.Gates)
if (gate.GameObjectId == entry)
return gate;
return null;
}
}
}