Core/Battlegrounds: Move to scripts And a lot of misc commits i couldn't recover.

Port From (https://github.com/TrinityCore/TrinityCore/commit/d0d5d309bb5877dc2fcb27f6cb123707a31ec1e8)
This commit is contained in:
Hondacrx
2024-08-04 15:18:22 -04:00
parent bca02a24b0
commit e9b21a91be
139 changed files with 8322 additions and 8700 deletions
+26 -338
View File
@@ -40,15 +40,8 @@ namespace Game.BattleGrounds
public virtual void Dispose()
{
// remove objects and creatures
// (this is done automatically in mapmanager update, when the instance is reset after the reset time)
for (uint i = 0; i < BgCreatures.Length; ++i)
DelCreature(i);
for (var i = 0; i < BgObjects.Length; ++i)
DelObject(i);
Global.BattlegroundMgr.RemoveBattleground(GetTypeID(), GetInstanceID());
// unload map
if (m_Map != null)
{
@@ -207,7 +200,7 @@ namespace Game.BattleGrounds
}
}
public virtual Team GetPrematureWinner()
public Team GetPrematureWinner()
{
Team winner = Team.Other;
if (GetPlayersCountByTeam(Team.Alliance) >= GetMinPlayersPerTeam())
@@ -286,19 +279,12 @@ namespace Game.BattleGrounds
return;
}
// Setup here, only when at least one player has ported to the map
if (!SetupBattleground())
{
EndNow();
return;
}
_preparationStartTime = GameTime.GetGameTime();
foreach (Group group in m_BgRaids)
if (group != null)
group.StartCountdown(CountdownTimerType.Pvp, TimeSpan.FromSeconds((int)StartDelayTimes[BattlegroundConst.EventIdFirst] / 1000), _preparationStartTime);
StartingEventCloseDoors();
GetBgMap().GetBattlegroundScript().OnPrepareStage1();
SetStartDelayTime(StartDelayTimes[BattlegroundConst.EventIdFirst]);
// First start warning - 2 or 1 Minute
if (StartMessageIds[BattlegroundConst.EventIdFirst] != 0)
@@ -308,6 +294,7 @@ namespace Game.BattleGrounds
else if (GetStartDelayTime() <= (int)StartDelayTimes[BattlegroundConst.EventIdSecond] && !m_Events.HasAnyFlag(BattlegroundEventFlags.Event2))
{
m_Events |= BattlegroundEventFlags.Event2;
GetBgMap().GetBattlegroundScript().OnPrepareStage2();
if (StartMessageIds[BattlegroundConst.EventIdSecond] != 0)
SendBroadcastText(StartMessageIds[BattlegroundConst.EventIdSecond], ChatMsg.BgSystemNeutral);
}
@@ -315,6 +302,7 @@ namespace Game.BattleGrounds
else if (GetStartDelayTime() <= (int)StartDelayTimes[BattlegroundConst.EventIdThird] && !m_Events.HasAnyFlag(BattlegroundEventFlags.Event3))
{
m_Events |= BattlegroundEventFlags.Event3;
GetBgMap().GetBattlegroundScript().OnPrepareStage3();
if (StartMessageIds[BattlegroundConst.EventIdThird] != 0)
SendBroadcastText(StartMessageIds[BattlegroundConst.EventIdThird], ChatMsg.BgSystemNeutral);
}
@@ -323,7 +311,7 @@ namespace Game.BattleGrounds
{
m_Events |= BattlegroundEventFlags.Event4;
StartingEventOpenDoors();
GetBgMap().GetBattlegroundScript().OnStart();
if (StartMessageIds[BattlegroundConst.EventIdFourth] != 0)
SendBroadcastText(StartMessageIds[BattlegroundConst.EventIdFourth], ChatMsg.RaidBossEmote);
@@ -740,6 +728,8 @@ namespace Game.BattleGrounds
player.SendPacket(pvpMatchComplete);
player.UpdateCriteria(CriteriaType.ParticipateInBattleground, player.GetMapId());
GetBgMap().GetBattlegroundScript().OnEnd(winner);
}
}
@@ -1027,6 +1017,8 @@ namespace Game.BattleGrounds
// setup BG group membership
PlayerAddedToBGCheckIfBGIsRunning(player);
AddOrSetPlayerToCorrectBgGroup(player, team);
GetBgMap().GetBattlegroundScript().OnPlayerJoined(player, isInBattleground);
}
// this method adds player to his team's bg group, or sets his correct group if player is already in bg group
@@ -1104,8 +1096,8 @@ namespace Game.BattleGrounds
// 1 player is logging out, if it is the last alive, then end arena!
if (IsArena() && player.IsAlive())
if (GetAlivePlayersCountByTeam(player.GetBGTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player.GetBGTeam())) != 0)
EndBattleground(GetOtherTeam(player.GetBGTeam()));
if (GetAlivePlayersCountByTeam(player.GetBGTeam()) <= 1 && GetPlayersCountByTeam(SharedConst.GetOtherTeam(player.GetBGTeam())) != 0)
EndBattleground(SharedConst.GetOtherTeam(player.GetBGTeam()));
}
}
@@ -1241,7 +1233,7 @@ namespace Game.BattleGrounds
return PlayerScores.LookupByKey(player.GetGUID());
}
public virtual bool UpdatePlayerScore(Player player, ScoreType type, uint value, bool doAddHonor = true)
public bool UpdatePlayerScore(Player player, ScoreType type, uint value, bool doAddHonor = true)
{
var bgScore = PlayerScores.LookupByKey(player.GetGUID());
if (bgScore == null) // player not found...
@@ -1262,99 +1254,6 @@ namespace Game.BattleGrounds
score.UpdatePvpStat(pvpStatId, value);
}
public bool AddObject(int type, uint entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint respawnTime = 0, GameObjectState goState = GameObjectState.Ready)
{
Map map = FindBgMap();
if (map == null)
return false;
Quaternion rotation = new(rotation0, rotation1, rotation2, rotation3);
// Temporally add safety check for bad spawns and send log (object rotations need to be rechecked in sniff)
if (rotation0 == 0 && rotation1 == 0 && rotation2 == 0 && rotation3 == 0)
{
Log.outDebug(LogFilter.Battleground, $"Battleground.AddObject: gameoobject [entry: {entry}, object type: {type}] for BG (map: {GetMapId()}) has zeroed rotation fields, " +
"orientation used temporally, but please fix the spawn");
rotation = Quaternion.CreateFromRotationMatrix(Extensions.fromEulerAnglesZYX(o, 0.0f, 0.0f));
}
// Must be created this way, adding to godatamap would add it to the base map of the instance
// and when loading it (in go.LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
// So we must create it specific for this instance
GameObject go = GameObject.CreateGameObject(entry, GetBgMap(), new Position(x, y, z, o), rotation, 255, goState);
if (go == null)
{
Log.outError(LogFilter.Battleground, $"Battleground.AddObject: cannot create gameobject (entry: {entry}) for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
return false;
}
// Add to world, so it can be later looked up from HashMapHolder
if (!map.AddToMap(go))
return false;
BgObjects[type] = go.GetGUID();
return true;
}
public bool AddObject(int type, uint entry, Position pos, float rotation0, float rotation1, float rotation2, float rotation3, uint respawnTime = 0, GameObjectState goState = GameObjectState.Ready)
{
return AddObject(type, entry, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), rotation0, rotation1, rotation2, rotation3, respawnTime, goState);
}
// Some doors aren't despawned so we cannot handle their closing in gameobject.update()
// It would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
public void DoorClose(int type)
{
GameObject obj = GetBgMap().GetGameObject(BgObjects[type]);
if (obj != null)
{
// If doors are open, close it
if (obj.GetLootState() == LootState.Activated && obj.GetGoState() != GameObjectState.Ready)
{
obj.SetLootState(LootState.Ready);
obj.SetGoState(GameObjectState.Ready);
}
}
else
Log.outError(LogFilter.Battleground, $"Battleground.DoorClose: door gameobject (type: {type}, {BgObjects[type]}) not found for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
}
public void DoorOpen(int type)
{
GameObject obj = GetBgMap().GetGameObject(BgObjects[type]);
if (obj != null)
{
obj.SetLootState(LootState.Activated);
obj.SetGoState(GameObjectState.Active);
}
else
Log.outError(LogFilter.Battleground, $"Battleground.DoorOpen: door gameobject (type: {type}, {BgObjects[type]}) not found for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
}
public GameObject GetBGObject(int type)
{
if (BgObjects[type].IsEmpty())
return null;
GameObject obj = GetBgMap().GetGameObject(BgObjects[type]);
if (obj == null)
Log.outError(LogFilter.Battleground, $"Battleground.GetBGObject: gameobject (type: {type}, {BgObjects[type]}) not found for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
return obj;
}
public Creature GetBGCreature(uint type)
{
if (BgCreatures[type].IsEmpty())
return null;
Creature creature = GetBgMap().GetCreature(BgCreatures[type]);
if (creature == null)
Log.outError(LogFilter.Battleground, $"Battleground.GetBGCreature: creature (type: {type}, {BgCreatures[type]}) not found for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
return creature;
}
public uint GetMapId()
{
return (uint)_battlegroundTemplate.BattlemasterEntry.MapId[0];
@@ -1364,168 +1263,11 @@ namespace Game.BattleGrounds
{
m_Map = map;
if (map != null)
{
_pvpStatIds = Global.DB2Mgr.GetPVPStatIDsForMap(map.GetId());
OnMapSet(map);
}
else
_pvpStatIds = null;
}
public void SpawnBGObject(int type, uint respawntime)
{
Map map = FindBgMap();
if (map != null)
{
GameObject obj = map.GetGameObject(BgObjects[type]);
if (obj != null)
{
if (respawntime != 0)
{
obj.SetLootState(LootState.JustDeactivated);
{
GameObjectOverride goOverride = obj.GetGameObjectOverride();
if (goOverride != null)
if (goOverride.Flags.HasFlag(GameObjectFlags.NoDespawn))
{
// This function should be called in GameObject::Update() but in case of
// GO_FLAG_NODESPAWN flag the function is never called, so we call it here
obj.SendGameObjectDespawn();
}
}
}
else if (obj.GetLootState() == LootState.JustDeactivated)
{
// Change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
obj.SetLootState(LootState.Ready);
}
obj.SetRespawnTime((int)respawntime);
map.AddToMap(obj);
}
}
}
public virtual Creature AddCreature(uint entry, uint type, float x, float y, float z, float o, int teamIndex = BattleGroundTeamId.Neutral, uint respawntime = 0, Transport transport = null)
{
Map map = FindBgMap();
if (map == null)
return null;
if (Global.ObjectMgr.GetCreatureTemplate(entry) == null)
{
Log.outError(LogFilter.Battleground, $"Battleground.AddCreature: creature template (entry: {entry}) does not exist for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
return null;
}
if (transport != null)
{
Creature transCreature = transport.SummonPassenger(entry, new Position(x, y, z, o), TempSummonType.ManualDespawn);
if (transCreature != null)
{
BgCreatures[type] = transCreature.GetGUID();
return transCreature;
}
return null;
}
Position pos = new(x, y, z, o);
Creature creature = Creature.CreateCreature(entry, map, pos);
if (creature == null)
{
Log.outError(LogFilter.Battleground, $"Battleground.AddCreature: cannot create creature (entry: {entry}) for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
return null;
}
creature.SetHomePosition(pos);
if (!map.AddToMap(creature))
return null;
BgCreatures[type] = creature.GetGUID();
if (respawntime != 0)
creature.SetRespawnDelay(respawntime);
return creature;
}
public Creature AddCreature(uint entry, uint type, Position pos, int teamIndex = BattleGroundTeamId.Neutral, uint respawntime = 0, Transport transport = null)
{
return AddCreature(entry, type, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teamIndex, respawntime, transport);
}
public bool DelCreature(uint type)
{
if (BgCreatures[type].IsEmpty())
return true;
Creature creature = GetBgMap().GetCreature(BgCreatures[type]);
if (creature != null)
{
creature.AddObjectToRemoveList();
BgCreatures[type].Clear();
return true;
}
Log.outError(LogFilter.Battleground, $"Battleground.DelCreature: creature (type: {type}, {BgCreatures[type]}) not found for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
BgCreatures[type].Clear();
return false;
}
public bool DelObject(int type)
{
if (BgObjects[type].IsEmpty())
return true;
GameObject obj = GetBgMap().GetGameObject(BgObjects[type]);
if (obj != null)
{
obj.SetRespawnTime(0); // not save respawn time
obj.Delete();
BgObjects[type].Clear();
return true;
}
Log.outError(LogFilter.Battleground, $"Battleground.DelObject: gameobject (type: {type}, {BgObjects[type]}) not found for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
BgObjects[type].Clear();
return false;
}
bool RemoveObjectFromWorld(uint type)
{
if (BgObjects[type].IsEmpty())
return true;
GameObject obj = GetBgMap().GetGameObject(BgObjects[type]);
if (obj != null)
{
obj.RemoveFromWorld();
BgObjects[type].Clear();
return true;
}
Log.outInfo(LogFilter.Battleground, $"Battleground::RemoveObjectFromWorld: gameobject (type: {type}, {BgObjects[type]}) not found for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
return false;
}
public bool AddSpiritGuide(uint type, float x, float y, float z, float o, int teamIndex)
{
uint entry = (uint)(teamIndex == BattleGroundTeamId.Alliance ? BattlegroundCreatures.A_SpiritGuide : BattlegroundCreatures.H_SpiritGuide);
if (AddCreature(entry, type, x, y, z, o) != null)
return true;
Log.outError(LogFilter.Battleground, $"Battleground.AddSpiritGuide: cannot create spirit guide (type: {type}, entry: {entry}) for BG (map: {GetMapId()}, instance id: {m_InstanceID})!");
EndNow();
return false;
}
public bool AddSpiritGuide(uint type, Position pos, int teamIndex = BattleGroundTeamId.Neutral)
{
return AddSpiritGuide(type, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teamIndex);
}
public void SendMessageToAll(CypherStrings entry, ChatMsg msgType, Player source = null)
{
if (entry == 0)
@@ -1598,9 +1340,18 @@ namespace Game.BattleGrounds
victim.SetUnitFlag(UnitFlags.Skinnable);
RewardXPAtKill(killer, victim);
}
BattlegroundScript script = GetBgMap().GetBattlegroundScript();
if (script != null)
script.OnPlayerKilled(victim, killer);
}
public virtual void HandleKillUnit(Creature creature, Unit killer) { }
public virtual void HandleKillUnit(Creature victim, Unit killer)
{
BattlegroundScript script = GetBgMap().GetBattlegroundScript();
if (script != null)
script.OnUnitKilled(victim, killer);
}
// Return the player's team based on Battlegroundplayer info
// Used in same faction arena matches mainly
@@ -1612,11 +1363,6 @@ namespace Game.BattleGrounds
return Team.Other;
}
public Team GetOtherTeam(Team team)
{
return team != 0 ? ((team == Team.Alliance) ? Team.Horde : Team.Alliance) : Team.Other;
}
public bool IsPlayerInBattleground(ObjectGuid guid)
{
return m_Players.ContainsKey(guid);
@@ -1658,15 +1404,6 @@ namespace Game.BattleGrounds
return count;
}
public int GetObjectType(ObjectGuid guid)
{
for (int i = 0; i < BgObjects.Length; ++i)
if (BgObjects[i] == guid)
return i;
Log.outError(LogFilter.Battleground, $"Battleground.GetObjectType: player used gameobject ({guid}) which is not in internal data for BG (map: {GetMapId()}, instance id: {m_InstanceID}), cheating?");
return -1;
}
public void SetBgRaid(Team team, Group bg_raid)
{
Group old_raid = m_BgRaids[GetTeamIndexByTeamId(team)];
@@ -1677,23 +1414,6 @@ namespace Game.BattleGrounds
m_BgRaids[GetTeamIndexByTeamId(team)] = bg_raid;
}
public virtual WorldSafeLocsEntry GetClosestGraveyard(Player player)
{
return Global.ObjectMgr.GetClosestGraveyard(player, GetPlayerTeam(player.GetGUID()), player);
}
public override void TriggerGameEvent(uint gameEventId, WorldObject source = null, WorldObject target = null)
{
ProcessEvent(target, gameEventId, source);
GameEvents.TriggerForMap(gameEventId, GetBgMap(), source, target);
foreach (var guid in GetPlayers().Keys)
{
Player player = Global.ObjAccessor.FindPlayer(guid);
if (player != null)
GameEvents.TriggerForPlayer(gameEventId, player);
}
}
public void SetBracket(PvpDifficultyRecord bracketEntry)
{
_pvpDifficultyEntry = bracketEntry;
@@ -1714,17 +1434,6 @@ namespace Game.BattleGrounds
return 0;
}
public virtual void HandleAreaTrigger(Player player, uint trigger, bool entered)
{
Log.outDebug(LogFilter.Battleground, "Unhandled AreaTrigger {0} in Battleground {1}. Player coords (x: {2}, y: {3}, z: {4})",
trigger, player.GetMapId(), player.GetPositionX(), player.GetPositionY(), player.GetPositionZ());
}
public virtual bool SetupBattleground()
{
return true;
}
public string GetName()
{
return _battlegroundTemplate.BattlemasterEntry.Name[Global.WorldMgr.GetDefaultDbcLocale()];
@@ -1801,13 +1510,9 @@ namespace Game.BattleGrounds
return m_Players.LookupByKey(playerGuid);
}
// Called when valid BattlegroundMap is assigned to the battleground
public virtual void OnMapSet(BattlegroundMap map) { }
public virtual void StartingEventCloseDoors() { }
public virtual void StartingEventOpenDoors() { }
public virtual void DestroyGate(Player player, GameObject go) { }
public void AddPoint(Team team, uint points = 1) { m_TeamScores[GetTeamIndexByTeamId(team)] += points; }
public void SetTeamPoint(Team team, uint points = 0) { m_TeamScores[GetTeamIndexByTeamId(team)] = points; }
void RemovePoint(Team team, uint points = 1) { m_TeamScores[GetTeamIndexByTeamId(team)] -= points; }
public uint GetInstanceID() { return m_InstanceID; }
public BattlegroundStatus GetStatus() { return m_Status; }
@@ -1878,14 +1583,6 @@ namespace Game.BattleGrounds
public void SetArenaMatchmakerRating(Team team, uint MMR) { m_ArenaTeamMMR[GetTeamIndexByTeamId(team)] = MMR; }
public uint GetArenaMatchmakerRating(Team team) { return m_ArenaTeamMMR[GetTeamIndexByTeamId(team)]; }
// Battleground events
public virtual void EventPlayerDroppedFlag(Player player) { }
public virtual void EventPlayerClickedOnFlag(Player player, GameObject target_obj) { }
public override void ProcessEvent(WorldObject obj, uint eventId, WorldObject invoker = null) { }
public virtual void HandlePlayerResurrect(Player player) { }
public virtual WorldSafeLocsEntry GetExploitTeleportLocation(Team team) { return null; }
public virtual bool HandlePlayerUnderMap(Player player) { return false; }
@@ -1895,12 +1592,6 @@ namespace Game.BattleGrounds
bool CanAwardArenaPoints() { return GetMinLevel() >= 71; }
public virtual ObjectGuid GetFlagPickerGUID(int teamIndex = -1) { return ObjectGuid.Empty; }
public virtual void SetDroppedFlagGUID(ObjectGuid guid, int teamIndex = -1) { }
public virtual void HandleQuestComplete(uint questid, Player player) { }
public virtual bool CanActivateGO(int entry, uint team) { return true; }
public virtual bool IsSpellAllowed(uint spellId, Player player) { return true; }
public virtual void RemovePlayer(Player player, ObjectGuid guid, Team team) { }
public virtual bool PreUpdateImpl(uint diff) { return true; }
@@ -1930,9 +1621,6 @@ namespace Game.BattleGrounds
public uint[] m_TeamScores = new uint[SharedConst.PvpTeamsCount];
protected ObjectGuid[] BgObjects;// = new Dictionary<int, ObjectGuid>();
protected ObjectGuid[] BgCreatures;// = new Dictionary<int, ObjectGuid>();
public uint[] Buff_Entries = { BattlegroundConst.SpeedBuff, BattlegroundConst.RegenBuff, BattlegroundConst.BerserkerBuff };
// Battleground
@@ -3,13 +3,7 @@
using Framework.Constants;
using Framework.Database;
using Game.BattleGrounds.Zones;
using Game.BattleGrounds.Zones.AlteracValley;
using Game.BattleGrounds.Zones.ArathisBasin;
using Game.BattleGrounds.Zones.EyeofStorm;
using Game.BattleGrounds.Zones.IsleOfConquest;
using Game.BattleGrounds.Zones.StrandOfAncients;
using Game.BattleGrounds.Zones.WarsongGluch;
using Game.Arenas;
using Game.DataStorage;
using Game.Entities;
using Game.Networking.Packets;
@@ -201,6 +195,60 @@ namespace Game.BattleGrounds
return null;
}
public void LoadBattlegroundScriptTemplate()
{
uint oldMSTime = Time.GetMSTime();
// 0 1 2
SQLResult result = DB.World.Query("SELECT MapId, BattlemasterListId, ScriptName FROM battleground_scripts");
if (result.IsEmpty())
{
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 battleground scripts. DB table `battleground_scripts` is empty!");
return;
}
uint count = 0;
do
{
uint mapID = result.Read<uint>(0);
var mapEntry = CliDB.MapStorage.LookupByKey(mapID);
if (mapEntry == null || !mapEntry.IsBattlegroundOrArena())
{
Log.outError(LogFilter.Sql, $"BattlegroundMgr::LoadBattlegroundScriptTemplate: bad mapid {mapID}! Map doesn't exist or is not a battleground/arena!");
continue;
}
BattlegroundTypeId bgTypeId = (BattlegroundTypeId)result.Read<uint>(1);
if (bgTypeId != BattlegroundTypeId.None && !_battlegroundTemplates.ContainsKey(bgTypeId))
{
Log.outError(LogFilter.Sql, $"BattlegroundMgr::LoadBattlegroundScriptTemplate: bad battlemasterlist id {bgTypeId}! Battleground doesn't exist or is not supported in battleground_template!");
continue;
}
BattlegroundScriptTemplate scriptTemplate = new();
scriptTemplate.MapId = mapID;
scriptTemplate.Id = bgTypeId;
scriptTemplate.ScriptId = Global.ObjectMgr.GetScriptId(result.Read<string>(2));
_battlegroundScriptTemplates[(mapID, bgTypeId)] = scriptTemplate;
++count;
} while (result.NextRow());
Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} battleground scripts in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
}
public BattlegroundScriptTemplate FindBattlegroundScriptTemplate(uint mapId, BattlegroundTypeId bgTypeId)
{
BattlegroundScriptTemplate scriptTemplate = _battlegroundScriptTemplates.LookupByKey((mapId, bgTypeId));
if (scriptTemplate != null)
return scriptTemplate;
// fall back to 0 for no specific battleground type id
return _battlegroundScriptTemplates.LookupByKey((mapId, BattlegroundTypeId.None));
}
uint CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
{
if (IsArenaType(bgTypeId))
@@ -250,56 +298,10 @@ namespace Game.BattleGrounds
}
Battleground bg = null;
// create a copy of the BG template
switch (bgTypeId)
{
case BattlegroundTypeId.AV:
bg = new BgAlteracValley(bg_template);
break;
case BattlegroundTypeId.WS:
case BattlegroundTypeId.WgCtf:
bg = new BgWarsongGluch(bg_template);
break;
case BattlegroundTypeId.AB:
case BattlegroundTypeId.DomAb:
bg = new BgArathiBasin(bg_template);
break;
case BattlegroundTypeId.NA:
bg = new BgNagrandArena(bg_template);
break;
case BattlegroundTypeId.BE:
bg = new BgBladesEdgeArena(bg_template);
break;
case BattlegroundTypeId.EY:
bg = new BgEyeofStorm(bg_template);
break;
case BattlegroundTypeId.RL:
bg = new BgRuinsOfLordaernon(bg_template);
break;
case BattlegroundTypeId.SA:
bg = new BgStrandOfAncients(bg_template);
break;
case BattlegroundTypeId.DS:
bg = new BgDalaranSewers(bg_template);
break;
case BattlegroundTypeId.RV:
bg = new BgTheRingOfValor(bg_template);
break;
case BattlegroundTypeId.IC:
bg = new BgIsleofConquest(bg_template);
break;
case BattlegroundTypeId.TP:
bg = new BgTwinPeaks(bg_template);
break;
case BattlegroundTypeId.BFG:
bg = new BgBattleforGilneas(bg_template);
break;
case BattlegroundTypeId.RB:
case BattlegroundTypeId.AA:
case BattlegroundTypeId.RandomEpic:
default:
return null;
}
if (bg_template.IsArena())
bg = new Arena(bg_template);
else
bg = new Battleground(bg_template);
bg.SetBracket(bracketEntry);
bg.SetInstanceID(Global.MapMgr.GenerateInstanceId());
@@ -723,6 +725,7 @@ namespace Game.BattleGrounds
Dictionary<uint, BattlegroundTypeId> mBattleMastersMap = new();
Dictionary<BattlegroundTypeId, BattlegroundTemplate> _battlegroundTemplates = new();
Dictionary<uint, BattlegroundTemplate> _battlegroundMapTemplates = new();
Dictionary<(uint, BattlegroundTypeId), BattlegroundScriptTemplate> _battlegroundScriptTemplates = new();
struct ScheduledQueueUpdate
{
@@ -808,4 +811,11 @@ namespace Game.BattleGrounds
return BattlemasterEntry.MaxLevel;
}
}
public class BattlegroundScriptTemplate
{
public uint MapId;
public BattlegroundTypeId Id;
public uint ScriptId;
}
}
@@ -0,0 +1,136 @@
// 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 Game.Maps;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Framework.Constants;
using Game.Entities;
using System.Numerics;
namespace Game.BattleGrounds
{
public class BattlegroundScript : ZoneScript
{
protected BattlegroundMap battlegroundMap;
protected Battleground battleground;
public BattlegroundScript(BattlegroundMap map)
{
battlegroundMap = map;
battleground = map.GetBG();
}
public virtual Team GetPrematureWinner()
{
Team winner = Team.Other;
if (battleground.GetPlayersCountByTeam(Team.Alliance) >= battleground.GetMinPlayersPerTeam())
winner = Team.Alliance;
else if (battleground.GetPlayersCountByTeam(Team.Horde) >= battleground.GetMinPlayersPerTeam())
winner = Team.Horde;
return winner;
}
public override void TriggerGameEvent(uint gameEventId, WorldObject source = null, WorldObject target = null)
{
ProcessEvent(target, gameEventId, source);
GameEvents.TriggerForMap(gameEventId, battlegroundMap, source, target);
foreach (var (playerGuid, _) in battleground.GetPlayers())
{
Player player = Global.ObjAccessor.FindPlayer(playerGuid);
if (player != null)
GameEvents.TriggerForPlayer(gameEventId, player);
}
}
public void UpdateWorldState(int worldStateId, int value, bool hidden = false)
{
Global.WorldStateMgr.SetValue(worldStateId, value, hidden, battlegroundMap);
}
public void UpdateWorldState(int worldStateId, bool value, bool hidden = false)
{
Global.WorldStateMgr.SetValue(worldStateId, value ? 1 : 0, hidden, battlegroundMap);
}
public virtual void OnInit() { }
public virtual void OnUpdate(uint diff) { }
public virtual void OnPrepareStage1() { }
public virtual void OnPrepareStage2() { }
public virtual void OnPrepareStage3() { }
public virtual void OnStart() { }
public virtual void OnEnd(Team winner) { }
public virtual void OnPlayerJoined(Player player, bool inBattleground) { }
public virtual void OnPlayerLeft(Player player) { }
public virtual void OnPlayerKilled(Player victim, Player killer) { }
public virtual void OnUnitKilled(Creature victim, Unit killer) { }
}
public class ArenaScript : BattlegroundScript
{
public ArenaScript(BattlegroundMap map) : base(map) { }
public GameObject CreateObject(uint entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, GameObjectState goState = GameObjectState.Ready)
{
Quaternion rot = new(rotation0, rotation1, rotation2, rotation3);
// Temporally add safety check for bad spawns and send log (object rotations need to be rechecked in sniff)
if (rotation0 == 0 && rotation1 == 0 && rotation2 == 0 && rotation3 == 0)
{
Log.outDebug(LogFilter.Battleground, $"Battleground::AddObject: gameoobject [entry: {entry}] for BG (map: {battlegroundMap.GetId()}) has zeroed rotation fields, " +
"orientation used temporally, but please fix the spawn");
rot = Quaternion.CreateFromRotationMatrix(Extensions.fromEulerAnglesZYX(o, 0.0f, 0.0f));
}
// Must be created this way, adding to godatamap would add it to the base map of the instance
// and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
// So we must create it specific for this instance
GameObject go = GameObject.CreateGameObject(entry, battlegroundMap, new Position(x, y, z, o), rot, 255, goState);
if (go == null)
{
Log.outError(LogFilter.Battleground, $"Battleground::AddObject: cannot create gameobject (entry: {entry}) for BG (map: {battlegroundMap.GetId()}, instance id: {battleground.GetInstanceID()})!");
return null;
}
if (!battlegroundMap.AddToMap(go))
{
go.Dispose();
return null;
}
return go;
}
public Creature CreateCreature(uint entry, float x, float y, float z, float o)
{
if (Global.ObjectMgr.GetCreatureTemplate(entry) == null)
{
Log.outError(LogFilter.Battleground, $"Battleground::AddCreature: creature template (entry: {entry}) does not exist for BG (map: {battlegroundMap.GetId()}, instance id: {battleground.GetInstanceID()})!");
return null;
}
Position pos = new(x, y, z, o);
Creature creature = Creature.CreateCreature(entry, battlegroundMap, pos);
if (creature == null)
{
Log.outError(LogFilter.Battleground, $"Battleground::AddCreature: cannot create creature (entry: {entry}) for BG (map: {battlegroundMap.GetId()}, instance id: {battleground.GetInstanceID()})!");
return null;
}
creature.SetHomePosition(pos);
if (!battlegroundMap.AddToMap(creature))
{
creature.Dispose();
return null;
}
return creature;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,658 +0,0 @@
// 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.Entities;
using Game.Maps;
using System;
using System.Collections.Generic;
namespace Game.BattleGrounds.Zones.ArathisBasin
{
class BgArathiBasin : Battleground
{
TimeTracker _pointsTimer;
uint[] m_HonorScoreTics = new uint[SharedConst.PvpTeamsCount];
uint[] m_ReputationScoreTics = new uint[SharedConst.PvpTeamsCount];
bool m_IsInformedNearVictory;
uint m_HonorTics;
uint m_ReputationTics;
List<ObjectGuid> _gameobjectsToRemoveOnMatchStart = new();
List<ObjectGuid> _creaturesToRemoveOnMatchStart = new();
List<ObjectGuid> _doors = new();
List<ObjectGuid> _capturePoints = new();
public BgArathiBasin(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate)
{
m_IsInformedNearVictory = false;
_pointsTimer = new TimeTracker(MiscConst.TickInterval);
for (byte i = 0; i < SharedConst.PvpTeamsCount; ++i)
{
m_HonorScoreTics[i] = 0;
m_ReputationScoreTics[i] = 0;
}
m_HonorTics = 0;
m_ReputationTics = 0;
}
public override void PostUpdateImpl(uint diff)
{
if (GetStatus() == BattlegroundStatus.InProgress)
{
// Accumulate points
_pointsTimer.Update(diff);
if (_pointsTimer.Passed())
{
_pointsTimer.Reset(MiscConst.TickInterval);
_CalculateTeamNodes(out var ally, out var horde);
int[] points = [ally, horde];
for (int team = 0; team < SharedConst.PvpTeamsCount; ++team)
{
if (points[team] == 0)
continue;
m_TeamScores[team] += MiscConst.TickPoints[points[team]];
m_HonorScoreTics[team] += MiscConst.TickPoints[points[team]];
m_ReputationScoreTics[team] += MiscConst.TickPoints[points[team]];
if (m_ReputationScoreTics[team] >= m_ReputationTics)
{
if (team == BattleGroundTeamId.Alliance)
RewardReputationToTeam(509, 10, Team.Alliance);
else
RewardReputationToTeam(510, 10, Team.Horde);
m_ReputationScoreTics[team] -= m_ReputationTics;
}
if (m_HonorScoreTics[team] >= m_HonorTics)
{
RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BattleGroundTeamId.Alliance) ? Team.Alliance : Team.Horde);
m_HonorScoreTics[team] -= m_HonorTics;
}
if (!m_IsInformedNearVictory && m_TeamScores[team] > MiscConst.WarningNearVictoryScore)
{
if (team == BattleGroundTeamId.Alliance)
{
SendBroadcastText((uint)ABBattlegroundBroadcastTexts.AllianceNearVictory, ChatMsg.BgSystemNeutral);
PlaySoundToAll((uint)SoundIds.NearVictoryAlliance);
}
else
{
SendBroadcastText((uint)ABBattlegroundBroadcastTexts.HordeNearVictory, ChatMsg.BgSystemNeutral);
PlaySoundToAll((uint)SoundIds.NearVictoryHorde);
}
m_IsInformedNearVictory = true;
}
if (m_TeamScores[team] > MiscConst.MaxTeamScore)
m_TeamScores[team] = MiscConst.MaxTeamScore;
if (team == BattleGroundTeamId.Alliance)
UpdateWorldState(WorldStateIds.ResourcesAlly, (int)m_TeamScores[team]);
else
UpdateWorldState(WorldStateIds.ResourcesHorde, (int)m_TeamScores[team]);
// update achievement flags
// we increased m_TeamScores[team] so we just need to check if it is 500 more than other teams resources
int otherTeam = (team + 1) % SharedConst.PvpTeamsCount;
if (m_TeamScores[team] > m_TeamScores[otherTeam] + 500)
{
if (team == BattleGroundTeamId.Alliance)
UpdateWorldState(WorldStateIds.Had500DisadvantageHorde, 1);
else
UpdateWorldState(WorldStateIds.Had500DisadvantageAlliance, 1);
}
}
UpdateWorldState(WorldStateIds.OccupiedBasesAlly, ally);
UpdateWorldState(WorldStateIds.OccupiedBasesHorde, horde);
}
// Test win condition
if (m_TeamScores[BattleGroundTeamId.Alliance] >= MiscConst.MaxTeamScore)
EndBattleground(Team.Alliance);
else if (m_TeamScores[BattleGroundTeamId.Horde] >= MiscConst.MaxTeamScore)
EndBattleground(Team.Horde);
}
}
public override void StartingEventOpenDoors()
{
// Achievement: Let's Get This Done
TriggerGameEvent((uint)ABEventIds.StartBattle);
}
void _CalculateTeamNodes(out int alliance, out int horde)
{
alliance = 0;
horde = 0;
BattlegroundMap map = FindBgMap();
if (map != null)
{
foreach (ObjectGuid guid in _capturePoints)
{
GameObject capturePoint = map.GetGameObject(guid);
if (capturePoint != null)
{
int wsValue = map.GetWorldStateValue((int)capturePoint.GetGoInfo().CapturePoint.worldState1);
switch ((BattlegroundCapturePointState)wsValue)
{
case BattlegroundCapturePointState.AllianceCaptured:
++alliance;
break;
case BattlegroundCapturePointState.HordeCaptured:
++horde;
break;
default:
break;
}
}
}
}
}
public override Team GetPrematureWinner()
{
// How many bases each team owns
_CalculateTeamNodes(out var ally, out var horde);
if (ally > horde)
return Team.Alliance;
else if (horde > ally)
return Team.Horde;
// If the values are equal, fall back to the original result (based on number of players on each team)
return base.GetPrematureWinner();
}
public override void ProcessEvent(WorldObject source, uint eventId, WorldObject invoker)
{
Player player = invoker.ToPlayer();
switch ((ABEventIds)eventId)
{
case ABEventIds.StartBattle:
{
foreach (ObjectGuid guid in _creaturesToRemoveOnMatchStart)
{
Creature creature = GetBgMap().GetCreature(guid);
if (creature != null)
creature.DespawnOrUnsummon();
}
foreach (ObjectGuid guid in _gameobjectsToRemoveOnMatchStart)
{
GameObject gameObject = GetBgMap().GetGameObject(guid);
if (gameObject != null)
gameObject.DespawnOrUnsummon();
}
foreach (ObjectGuid guid in _doors)
{
GameObject gameObject = GetBgMap().GetGameObject(guid);
if (gameObject != null)
{
gameObject.UseDoorOrButton();
gameObject.DespawnOrUnsummon(TimeSpan.FromSeconds(3));
}
}
break;
}
case ABEventIds.ContestedBlacksmithAlliance:
UpdateWorldState(WorldStateIds.BlacksmithAllianceControlState, 1);
UpdateWorldState(WorldStateIds.BlacksmithHordeControlState, 0);
PlaySoundToAll((uint)SoundIds.NodeAssaultedAlliance);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesAssaulted, 1);
break;
case ABEventIds.DefendedBlacksmithAlliance:
UpdateWorldState(WorldStateIds.BlacksmithAllianceControlState, 2);
UpdateWorldState(WorldStateIds.BlacksmithHordeControlState, 0);
PlaySoundToAll((uint)SoundIds.NodeCapturedAlliance);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesDefended, 1);
break;
case ABEventIds.CaptureBlacksmithAlliance:
UpdateWorldState(WorldStateIds.BlacksmithAllianceControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedAlliance);
break;
case ABEventIds.ContestedBlacksmithHorde:
UpdateWorldState(WorldStateIds.BlacksmithAllianceControlState, 0);
UpdateWorldState(WorldStateIds.BlacksmithHordeControlState, 1);
PlaySoundToAll((uint)SoundIds.NodeAssaultedHorde);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesAssaulted, 1);
break;
case ABEventIds.DefendedBlacksmithHorde:
UpdateWorldState(WorldStateIds.BlacksmithAllianceControlState, 0);
UpdateWorldState(WorldStateIds.BlacksmithHordeControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedHorde);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesDefended, 1);
break;
case ABEventIds.CaptureBlacksmithHorde:
UpdateWorldState(WorldStateIds.BlacksmithHordeControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedHorde);
break;
case ABEventIds.ContestedFarmAlliance:
UpdateWorldState(WorldStateIds.FarmAllianceControlState, 1);
UpdateWorldState(WorldStateIds.FarmHordeControlState, 0);
PlaySoundToAll((uint)SoundIds.NodeAssaultedAlliance);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesAssaulted, 1);
break;
case ABEventIds.DefendedFarmAlliance:
UpdateWorldState(WorldStateIds.FarmAllianceControlState, 2);
UpdateWorldState(WorldStateIds.FarmHordeControlState, 0);
PlaySoundToAll((uint)SoundIds.NodeCapturedAlliance);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesDefended, 1);
break;
case ABEventIds.CaptureFarmAlliance:
UpdateWorldState(WorldStateIds.FarmAllianceControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedAlliance);
break;
case ABEventIds.ContestedFarmHorde:
UpdateWorldState(WorldStateIds.FarmAllianceControlState, 0);
UpdateWorldState(WorldStateIds.FarmHordeControlState, 1);
PlaySoundToAll((uint)SoundIds.NodeAssaultedHorde);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesAssaulted, 1);
break;
case ABEventIds.DefendedFarmHorde:
UpdateWorldState(WorldStateIds.FarmAllianceControlState, 0);
UpdateWorldState(WorldStateIds.FarmHordeControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedHorde);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesDefended, 1);
break;
case ABEventIds.CaptureFarmHorde:
UpdateWorldState(WorldStateIds.FarmHordeControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedHorde);
break;
case ABEventIds.ContestedGoldMineAlliance:
UpdateWorldState(WorldStateIds.GoldMineAllianceControlState, 1);
UpdateWorldState(WorldStateIds.GoldMineHordeControlState, 0);
PlaySoundToAll((uint)SoundIds.NodeAssaultedAlliance);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesAssaulted, 1);
break;
case ABEventIds.DefendedGoldMineAlliance:
UpdateWorldState(WorldStateIds.GoldMineAllianceControlState, 2);
UpdateWorldState(WorldStateIds.GoldMineHordeControlState, 0);
PlaySoundToAll((uint)SoundIds.NodeCapturedAlliance);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesDefended, 1);
break;
case ABEventIds.CaptureGoldMineAlliance:
UpdateWorldState(WorldStateIds.GoldMineAllianceControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedAlliance);
break;
case ABEventIds.ContestedGoldMineHorde:
UpdateWorldState(WorldStateIds.GoldMineAllianceControlState, 0);
UpdateWorldState(WorldStateIds.GoldMineHordeControlState, 1);
PlaySoundToAll((uint)SoundIds.NodeAssaultedHorde);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesAssaulted, 1);
break;
case ABEventIds.DefendedGoldMineHorde:
UpdateWorldState(WorldStateIds.GoldMineAllianceControlState, 0);
UpdateWorldState(WorldStateIds.GoldMineHordeControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedHorde);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesDefended, 1);
break;
case ABEventIds.CaptureGoldMineHorde:
UpdateWorldState(WorldStateIds.GoldMineHordeControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedHorde);
break;
case ABEventIds.ContestedLumberMillAlliance:
UpdateWorldState(WorldStateIds.LumberMillAllianceControlState, 1);
UpdateWorldState(WorldStateIds.LumberMillHordeControlState, 0);
PlaySoundToAll((uint)SoundIds.NodeAssaultedAlliance);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesAssaulted, 1);
break;
case ABEventIds.DefendedLumberMillAlliance:
UpdateWorldState(WorldStateIds.LumberMillAllianceControlState, 2);
UpdateWorldState(WorldStateIds.LumberMillHordeControlState, 0);
PlaySoundToAll((uint)SoundIds.NodeCapturedAlliance);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesDefended, 1);
break;
case ABEventIds.CaptureLumberMillAlliance:
UpdateWorldState(WorldStateIds.LumberMillAllianceControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedAlliance);
break;
case ABEventIds.ContestedLumberMillHorde:
UpdateWorldState(WorldStateIds.LumberMillAllianceControlState, 0);
UpdateWorldState(WorldStateIds.LumberMillHordeControlState, 1);
PlaySoundToAll((uint)SoundIds.NodeAssaultedHorde);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesAssaulted, 1);
break;
case ABEventIds.DefendedLumberMillHorde:
UpdateWorldState(WorldStateIds.LumberMillAllianceControlState, 0);
UpdateWorldState(WorldStateIds.LumberMillHordeControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedHorde);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesDefended, 1);
break;
case ABEventIds.CaptureLumberMillHorde:
UpdateWorldState(WorldStateIds.LumberMillHordeControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedHorde);
break;
case ABEventIds.ContestedStablesAlliance:
UpdateWorldState(WorldStateIds.StablesAllianceControlState, 1);
UpdateWorldState(WorldStateIds.StablesHordeControlState, 0);
PlaySoundToAll((uint)SoundIds.NodeAssaultedAlliance);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesAssaulted, 1);
break;
case ABEventIds.DefendedStablesAlliance:
UpdateWorldState(WorldStateIds.StablesAllianceControlState, 2);
UpdateWorldState(WorldStateIds.StablesHordeControlState, 0);
PlaySoundToAll((uint)SoundIds.NodeCapturedAlliance);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesDefended, 1);
break;
case ABEventIds.CaptureStablesAlliance:
UpdateWorldState(WorldStateIds.StablesAllianceControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedAlliance);
break;
case ABEventIds.ContestedStablesHorde:
UpdateWorldState(WorldStateIds.StablesAllianceControlState, 0);
UpdateWorldState(WorldStateIds.StablesHordeControlState, 1);
PlaySoundToAll((uint)SoundIds.NodeAssaultedHorde);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesAssaulted, 1);
break;
case ABEventIds.DefendedStablesHorde:
UpdateWorldState(WorldStateIds.StablesAllianceControlState, 0);
UpdateWorldState(WorldStateIds.StablesHordeControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedHorde);
if (player != null)
UpdatePvpStat(player, (uint)ArathiBasinPvpStats.BasesDefended, 1);
break;
case ABEventIds.CaptureStablesHorde:
UpdateWorldState(WorldStateIds.StablesHordeControlState, 2);
PlaySoundToAll((uint)SoundIds.NodeCapturedHorde);
break;
default:
Log.outWarn(LogFilter.Battleground, $"BattlegroundAB::ProcessEvent: Unhandled event {eventId}.");
break;
}
}
public override void OnCreatureCreate(Creature creature)
{
switch ((CreatureIds)creature.GetEntry())
{
case CreatureIds.TheBlackBride:
case CreatureIds.RadulfLeder:
_creaturesToRemoveOnMatchStart.Add(creature.GetGUID());
break;
default:
break;
}
}
public override void OnGameObjectCreate(GameObject gameObject)
{
if (gameObject.GetGoInfo().type == GameObjectTypes.CapturePoint)
_capturePoints.Add(gameObject.GetGUID());
switch ((GameobjectIds)gameObject.GetEntry())
{
case GameobjectIds.GhostGate:
_gameobjectsToRemoveOnMatchStart.Add(gameObject.GetGUID());
break;
case GameobjectIds.AllianceDoor:
case GameobjectIds.HordeDoor:
_doors.Add(gameObject.GetGUID());
break;
default:
break;
}
}
public override bool SetupBattleground()
{
UpdateWorldState(WorldStateIds.ResourcesMax, MiscConst.MaxTeamScore);
UpdateWorldState(WorldStateIds.ResourcesWarning, MiscConst.WarningNearVictoryScore);
return true;
}
public override void Reset()
{
//call parent's class reset
base.Reset();
for (var i = 0; i < SharedConst.PvpTeamsCount; ++i)
{
m_TeamScores[i] = 0;
m_HonorScoreTics[i] = 0;
m_ReputationScoreTics[i] = 0;
}
_pointsTimer.Reset(MiscConst.TickInterval);
m_IsInformedNearVictory = false;
bool isBGWeekend = Global.BattlegroundMgr.IsBGWeekend(GetTypeID());
m_HonorTics = isBGWeekend ? MiscConst.ABBGWeekendHonorTicks : MiscConst.NotABBGWeekendHonorTicks;
m_ReputationTics = isBGWeekend ? MiscConst.ABBGWeekendReputationTicks : MiscConst.NotABBGWeekendReputationTicks;
_creaturesToRemoveOnMatchStart.Clear();
_gameobjectsToRemoveOnMatchStart.Clear();
_doors.Clear();
_capturePoints.Clear();
}
public override void EndBattleground(Team winner)
{
// Win reward
if (winner == Team.Alliance)
RewardHonorToTeam(GetBonusHonorFromKill(1), Team.Alliance);
if (winner == Team.Horde)
RewardHonorToTeam(GetBonusHonorFromKill(1), Team.Horde);
// Complete map_end rewards (even if no team wins)
RewardHonorToTeam(GetBonusHonorFromKill(1), Team.Horde);
RewardHonorToTeam(GetBonusHonorFromKill(1), Team.Alliance);
base.EndBattleground(winner);
}
public override WorldSafeLocsEntry GetClosestGraveyard(Player player)
{
return Global.ObjectMgr.GetClosestGraveyard(player.GetWorldLocation(), player.GetTeam(), player);
}
public override WorldSafeLocsEntry GetExploitTeleportLocation(Team team)
{
return Global.ObjectMgr.GetWorldSafeLoc(team == Team.Alliance ? MiscConst.ExploitTeleportLocationAlliance : MiscConst.ExploitTeleportLocationHorde);
}
}
#region Constants
struct MiscConst
{
public const uint NotABBGWeekendHonorTicks = 260;
public const uint ABBGWeekendHonorTicks = 160;
public const uint NotABBGWeekendReputationTicks = 160;
public const uint ABBGWeekendReputationTicks = 120;
public const int WarningNearVictoryScore = 1400;
public const int MaxTeamScore = 1500;
public const uint ExploitTeleportLocationAlliance = 3705;
public const uint ExploitTeleportLocationHorde = 3706;
// Tick intervals and given points: case 0, 1, 2, 3, 4, 5 captured nodes
public static TimeSpan TickInterval = TimeSpan.FromSeconds(2);
public static uint[] TickPoints = { 0, 10, 10, 10, 10, 30 };
}
enum ABEventIds
{
StartBattle = 9158, // Achievement: Let'S Get This Done
ContestedStablesHorde = 28523,
CaptureStablesHorde = 28527,
DefendedStablesHorde = 28525,
ContestedStablesAlliance = 28522,
CaptureStablesAlliance = 28526,
DefendedStablesAlliance = 28524,
ContestedBlacksmithHorde = 8876,
CaptureBlacksmithHorde = 8773,
DefendedBlacksmithHorde = 8770,
ContestedBlacksmithAlliance = 8874,
CaptureBlacksmithAlliance = 8769,
DefendedBlacksmithAlliance = 8774,
ContestedFarmHorde = 39398,
CaptureFarmHorde = 39399,
DefendedFarmHorde = 39400,
ContestedFarmAlliance = 39401,
CaptureFarmAlliance = 39402,
DefendedFarmAlliance = 39403,
ContestedGoldMineHorde = 39404,
CaptureGoldMineHorde = 39405,
DefendedGoldMineHorde = 39406,
ContestedGoldMineAlliance = 39407,
CaptureGoldMineAlliance = 39408,
DefendedGoldMineAlliance = 39409,
ContestedLumberMillHorde = 39387,
CaptureLumberMillHorde = 39388,
DefendedLumberMillHorde = 39389,
ContestedLumberMillAlliance = 39390,
CaptureLumberMillAlliance = 39391,
DefendedLumberMillAlliance = 39392
}
struct WorldStateIds
{
public const int OccupiedBasesHorde = 1778;
public const int OccupiedBasesAlly = 1779;
public const int ResourcesAlly = 1776;
public const int ResourcesHorde = 1777;
public const int ResourcesMax = 1780;
public const int ResourcesWarning = 1955;
public const int StableIcon = 1842; // Stable Map Icon (None)
public const int StableStateAlience = 1767; // Stable Map State (Alience)
public const int StableStateHorde = 1768; // Stable Map State (Horde)
public const int StableStateConAli = 1769; // Stable Map State (Con Alience)
public const int StableStateConHor = 1770; // Stable Map State (Con Horde)
public const int FarmIcon = 1845; // Farm Map Icon (None)
public const int FarmStateAlience = 1772; // Farm State (Alience)
public const int FarmStateHorde = 1773; // Farm State (Horde)
public const int FarmStateConAli = 1774; // Farm State (Con Alience)
public const int FarmStateConHor = 1775; // Farm State (Con Horde)
public const int BlacksmithIcon = 1846; // Blacksmith Map Icon (None)
public const int BlacksmithStateAlience = 1782; // Blacksmith Map State (Alience)
public const int BlacksmithStateHorde = 1783; // Blacksmith Map State (Horde)
public const int BlacksmithStateConAli = 1784; // Blacksmith Map State (Con Alience)
public const int BlacksmithStateConHor = 1785; // Blacksmith Map State (Con Horde)
public const int LumbermillIcon = 1844; // Lumber Mill Map Icon (None)
public const int LumbermillStateAlience = 1792; // Lumber Mill Map State (Alience)
public const int LumbermillStateHorde = 1793; // Lumber Mill Map State (Horde)
public const int LumbermillStateConAli = 1794; // Lumber Mill Map State (Con Alience)
public const int LumbermillStateConHor = 1795; // Lumber Mill Map State (Con Horde)
public const int GoldmineIcon = 1843; // Gold Mine Map Icon (None)
public const int GoldmineStateAlience = 1787; // Gold Mine Map State (Alience)
public const int GoldmineStateHorde = 1788; // Gold Mine Map State (Horde)
public const int GoldmineStateConAli = 1789; // Gold Mine Map State (Con Alience
public const int GoldmineStateConHor = 1790; // Gold Mine Map State (Con Horde)
public const int Had500DisadvantageAlliance = 3644;
public const int Had500DisadvantageHorde = 3645;
public const int FarmIconNew = 8808; // Farm Map Icon
public const int LumberMillIconNew = 8805; // Lumber Mill Map Icon
public const int BlacksmithIconNew = 8799; // Blacksmith Map Icon
public const int GoldMineIconNew = 8809; // Gold Mine Map Icon
public const int StablesIconNew = 5834; // Stable Map Icon
public const int FarmHordeControlState = 17328;
public const int FarmAllianceControlState = 17325;
public const int LumberMillHordeControlState = 17330;
public const int LumberMillAllianceControlState = 17326;
public const int BlacksmithHordeControlState = 17327;
public const int BlacksmithAllianceControlState = 17324;
public const int GoldMineHordeControlState = 17329;
public const int GoldMineAllianceControlState = 17323;
public const int StablesHordeControlState = 17331;
public const int StablesAllianceControlState = 17322;
}
// Object id templates from DB
enum GameobjectIds
{
CapturePointStables = 227420,
CapturePointBlacksmith = 227522,
CapturePointFarm = 227536,
CapturePointGoldMine = 227538,
CapturePointLumberMill = 227544,
GhostGate = 180322,
AllianceDoor = 322273,
HordeDoor = 322274
}
enum CreatureIds
{
TheBlackBride = 150501,
RadulfLeder = 150505
}
struct ABBattlegroundNodes
{
public const int NodeStables = 0;
public const int NodeBlacksmith = 1;
public const int NodeFarm = 2;
public const int NodeLumberMill = 3;
public const int NodeGoldMine = 4;
public const int DynamicNodesCount = 5; // Dynamic Nodes That Can Be Captured
public const int SpiritAliance = 5;
public const int SpiritHorde = 6;
public const int AllCount = 7; // All Nodes (Dynamic And Static)
}
enum ABBattlegroundBroadcastTexts
{
AllianceNearVictory = 10598,
HordeNearVictory = 10599
}
enum SoundIds
{
NodeClaimed = 8192,
NodeCapturedAlliance = 8173,
NodeCapturedHorde = 8213,
NodeAssaultedAlliance = 8212,
NodeAssaultedHorde = 8174,
NearVictoryAlliance = 8456,
NearVictoryHorde = 8457
}
enum ArathiBasinPvpStats
{
BasesAssaulted = 926,
BasesDefended = 927,
}
#endregion
}
@@ -1,10 +0,0 @@
// 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.
namespace Game.BattleGrounds.Zones
{
class BgBattleforGilneas : Battleground
{
public BgBattleforGilneas(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate) { }
}
}
@@ -1,10 +0,0 @@
// 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.
namespace Game.BattleGrounds.Zones
{
class BgBladesEdgeArena : Battleground
{
public BgBladesEdgeArena(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate) { }
}
}
@@ -1,10 +0,0 @@
// 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.
namespace Game.BattleGrounds.Zones
{
class BgDalaranSewers : Battleground
{
public BgDalaranSewers(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate) { }
}
}
@@ -1,10 +0,0 @@
// 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.
namespace Game.BattleGrounds.Zones
{
class BgDeepwindGorge : Battleground
{
public BgDeepwindGorge(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate) { }
}
}
@@ -1,803 +0,0 @@
// 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.Entities;
using Game.Entities.GameObjectType;
using Game.Maps;
using Game.Spells;
using System;
using System.Collections.Generic;
namespace Game.BattleGrounds.Zones.EyeofStorm
{
class BgEyeofStorm : Battleground
{
uint[] m_HonorScoreTics = new uint[SharedConst.PvpTeamsCount];
uint m_FlagCapturedBgObjectType; // type that should be despawned when flag is captured
TimeTracker _pointsTimer;
uint m_HonorTics;
Dictionary<uint, BgEyeOfStormControlZoneHandler> _controlZoneHandlers = new();
List<ObjectGuid> _doorGUIDs = new();
ObjectGuid _flagGUID;
// Focused/Brutal Assault
bool _assaultEnabled;
TimeTracker _flagAssaultTimer;
byte _assaultStackCount;
public BgEyeofStorm(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate)
{
m_HonorScoreTics = [0, 0];
m_FlagCapturedBgObjectType = 0;
m_HonorTics = 0;
_pointsTimer = new(MiscConst.PointsTickTime);
_assaultEnabled = false;
_assaultStackCount = 0;
_flagAssaultTimer = new(MiscConst.FlagAssaultTimer);
}
public override void PostUpdateImpl(uint diff)
{
if (GetStatus() == BattlegroundStatus.InProgress)
{
_pointsTimer.Update(diff);
if (_pointsTimer.Passed())
{
_pointsTimer.Reset(MiscConst.PointsTickTime);
byte baseCountAlliance = GetControlledBaseCount(BattleGroundTeamId.Alliance);
byte baseCountHorde = GetControlledBaseCount(BattleGroundTeamId.Horde);
if (baseCountAlliance > 0)
AddPoints(Team.Alliance, MiscConst.TickPoints[baseCountAlliance - 1]);
if (baseCountHorde > 0)
AddPoints(Team.Horde, MiscConst.TickPoints[baseCountHorde - 1]);
}
if (_assaultEnabled)
{
_flagAssaultTimer.Update(diff);
if (_flagAssaultTimer.Passed())
{
_flagAssaultTimer.Reset(MiscConst.FlagAssaultTimer);
_assaultStackCount++;
// update assault debuff stacks
DoForFlagKeepers(player => ApplyAssaultDebuffToPlayer(player));
}
}
}
}
public override void StartingEventOpenDoors()
{
foreach (ObjectGuid door in _doorGUIDs)
{
GameObject gameObject = GetBgMap().GetGameObject(door);
if (gameObject != null)
{
gameObject.UseDoorOrButton();
gameObject.DespawnOrUnsummon(TimeSpan.FromSeconds(3));
}
}
// Achievement: Flurry
TriggerGameEvent(MiscConst.EventStartBattle);
}
void AddPoints(Team Team, uint Points)
{
int team_index = GetTeamIndexByTeamId(Team);
m_TeamScores[team_index] += Points;
m_HonorScoreTics[team_index] += Points;
if (m_HonorScoreTics[team_index] >= m_HonorTics)
{
RewardHonorToTeam(GetBonusHonorFromKill(1), Team);
m_HonorScoreTics[team_index] -= m_HonorTics;
}
UpdateTeamScore(team_index);
}
byte GetControlledBaseCount(int teamId)
{
byte baseCount = 0;
foreach (var controlZoneHandler in _controlZoneHandlers)
{
uint point = controlZoneHandler.Value.GetPoint();
switch (teamId)
{
case BattleGroundTeamId.Alliance:
if (GetBgMap().GetWorldStateValue(MiscConst.m_PointsIconStruct[point].WorldStateAllianceControlledIndex) == 1)
baseCount++;
break;
case BattleGroundTeamId.Horde:
if (GetBgMap().GetWorldStateValue(MiscConst.m_PointsIconStruct[point].WorldStateHordeControlledIndex) == 1)
baseCount++;
break;
default:
break;
}
}
return baseCount;
}
void DoForFlagKeepers(Action<Player> action)
{
GameObject flag = GetBgMap().GetGameObject(_flagGUID);
if (flag != null)
{
Player carrier = Global.ObjAccessor.FindPlayer(flag.GetFlagCarrierGUID());
if (carrier != null)
action(carrier);
}
}
void ResetAssaultDebuff()
{
_assaultEnabled = false;
_assaultStackCount = 0;
_flagAssaultTimer.Reset(MiscConst.FlagAssaultTimer);
DoForFlagKeepers(RemoveAssaultDebuffFromPlayer);
}
void ApplyAssaultDebuffToPlayer(Player player)
{
if (_assaultStackCount == 0)
return;
uint spellId = MiscConst.SpellFocusedAssault;
if (_assaultStackCount >= MiscConst.FlagBrutalAssaultStackCount)
{
player.RemoveAurasDueToSpell(MiscConst.SpellFocusedAssault);
spellId = MiscConst.SpellBrutalAssault;
}
Aura aura = player.GetAura(spellId);
if (aura == null)
{
player.CastSpell(player, spellId, true);
aura = player.GetAura(spellId);
}
if (aura != null)
aura.SetStackAmount(_assaultStackCount);
}
void RemoveAssaultDebuffFromPlayer(Player player)
{
player.RemoveAurasDueToSpell(MiscConst.SpellFocusedAssault);
player.RemoveAurasDueToSpell(MiscConst.SpellBrutalAssault);
}
void UpdateTeamScore(int team)
{
uint score = GetTeamScore(team);
if (score >= ScoreIds.MaxTeamScore)
{
score = ScoreIds.MaxTeamScore;
if (team == BattleGroundTeamId.Alliance)
EndBattleground(Team.Alliance);
else
EndBattleground(Team.Horde);
}
if (team == BattleGroundTeamId.Alliance)
UpdateWorldState(WorldStateIds.AllianceResources, (int)score);
else
UpdateWorldState(WorldStateIds.HordeResources, (int)score);
}
public override void EndBattleground(Team winner)
{
// Win reward
if (winner == Team.Alliance)
RewardHonorToTeam(GetBonusHonorFromKill(1), Team.Alliance);
if (winner == Team.Horde)
RewardHonorToTeam(GetBonusHonorFromKill(1), Team.Horde);
// Complete map reward
RewardHonorToTeam(GetBonusHonorFromKill(1), Team.Alliance);
RewardHonorToTeam(GetBonusHonorFromKill(1), Team.Horde);
base.EndBattleground(winner);
}
void UpdatePointsCount(uint teamId)
{
if (teamId == BattleGroundTeamId.Alliance)
UpdateWorldState(WorldStateIds.AllianceBase, GetControlledBaseCount(BattleGroundTeamId.Alliance));
else
UpdateWorldState(WorldStateIds.HordeBase, GetControlledBaseCount(BattleGroundTeamId.Horde));
}
public override void OnGameObjectCreate(GameObject gameobject)
{
switch (gameobject.GetEntry())
{
case GameobjectIds.ADoorEyEntry:
case GameobjectIds.HDoorEyEntry:
_doorGUIDs.Add(gameobject.GetGUID());
break;
case GameobjectIds.Flag2EyEntry:
_flagGUID = gameobject.GetGUID();
break;
default:
break;
}
}
public override bool CanCaptureFlag(AreaTrigger areaTrigger, Player player)
{
if (areaTrigger.GetEntry() != MiscConst.AreatriggerCaptureFlag)
return false;
GameObject flag = GetBgMap().GetGameObject(_flagGUID);
if (flag != null)
{
if (flag.GetFlagCarrierGUID() != player.GetGUID())
return false;
}
GameObject controlzone = player.FindNearestGameObjectWithOptions(40.0f, new FindGameObjectOptions() { StringId = "bg_eye_of_the_storm_control_zone" });
if (controlzone != null)
{
uint point = _controlZoneHandlers[controlzone.GetEntry()].GetPoint();
switch (GetPlayerTeam(player.GetGUID()))
{
case Team.Alliance:
return GetBgMap().GetWorldStateValue(MiscConst.m_PointsIconStruct[point].WorldStateAllianceControlledIndex) == 1;
case Team.Horde:
return GetBgMap().GetWorldStateValue(MiscConst.m_PointsIconStruct[point].WorldStateHordeControlledIndex) == 1;
default:
return false;
}
}
return false;
}
public override void OnCaptureFlag(AreaTrigger areaTrigger, Player player)
{
if (areaTrigger.GetEntry() != MiscConst.AreatriggerCaptureFlag)
return;
uint baseCount = GetControlledBaseCount(GetTeamIndexByTeamId(GetPlayerTeam(player.GetGUID())));
GameObject gameObject = GetBgMap().GetGameObject(_flagGUID);
if (gameObject != null)
gameObject.HandleCustomTypeCommand(new SetNewFlagState(FlagState.Respawning, player));
Team team = GetPlayerTeam(player.GetGUID());
if (team == Team.Alliance)
{
SendBroadcastText(BroadcastTextIds.AllianceCapturedFlag, ChatMsg.BgSystemAlliance, player);
PlaySoundToAll(SoundIds.FlagCapturedAlliance);
}
else
{
SendBroadcastText(BroadcastTextIds.HordeCapturedFlag, ChatMsg.BgSystemHorde, player);
PlaySoundToAll(SoundIds.FlagCapturedHorde);
}
if (baseCount > 0)
AddPoints(team, MiscConst.FlagPoints[baseCount - 1]);
UpdateWorldState(WorldStateIds.NetherstormFlagStateHorde, (int)EYFlagState.OnBase);
UpdateWorldState(WorldStateIds.NetherstormFlagStateAlliance, (int)EYFlagState.OnBase);
UpdatePvpStat(player, MiscConst.PvpStatFlagCaptures, 1);
player.RemoveAurasDueToSpell(MiscConst.SpellNetherstormFlag);
player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.PvPActive);
}
public override void OnFlagStateChange(GameObject flagInBase, FlagState oldValue, FlagState newValue, Player player)
{
switch (newValue)
{
case FlagState.InBase:
ResetAssaultDebuff();
break;
case FlagState.Dropped:
player.CastSpell(player, BattlegroundConst.SpellRecentlyDroppedNeutralFlag, true);
RemoveAssaultDebuffFromPlayer(player);
UpdateWorldState(WorldStateIds.NetherstormFlagStateHorde, (int)EYFlagState.WaitRespawn);
UpdateWorldState(WorldStateIds.NetherstormFlagStateAlliance, (int)EYFlagState.WaitRespawn);
if (GetPlayerTeam(player.GetGUID()) == Team.Alliance)
SendBroadcastText(BroadcastTextIds.FlagDropped, ChatMsg.BgSystemAlliance);
else
SendBroadcastText(BroadcastTextIds.FlagDropped, ChatMsg.BgSystemHorde);
break;
case FlagState.Taken:
if (GetPlayerTeam(player.GetGUID()) == Team.Alliance)
{
UpdateWorldState(WorldStateIds.NetherstormFlagStateAlliance, (int)EYFlagState.OnPlayer);
PlaySoundToAll(SoundIds.FlagPickedUpAlliance);
SendBroadcastText(BroadcastTextIds.TakenFlag, ChatMsg.BgSystemAlliance, player);
}
else
{
UpdateWorldState(WorldStateIds.NetherstormFlagStateHorde, (int)EYFlagState.OnPlayer);
PlaySoundToAll(SoundIds.FlagPickedUpHorde);
SendBroadcastText(BroadcastTextIds.TakenFlag, ChatMsg.BgSystemHorde, player);
}
ApplyAssaultDebuffToPlayer(player);
_assaultEnabled = true;
player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.PvPActive);
break;
case FlagState.Respawning:
ResetAssaultDebuff();
break;
default:
break;
}
UpdateWorldState(WorldStateIds.NetherstormFlag, (int)newValue);
}
public override bool SetupBattleground()
{
UpdateWorldState(WorldStateIds.MaxResources, (int)ScoreIds.MaxTeamScore);
_controlZoneHandlers[GameobjectIds.FrTowerCapEyEntry] = new BgEyeOfStormControlZoneHandler(this, Points.FelReaver);
_controlZoneHandlers[GameobjectIds.BeTowerCapEyEntry] = new BgEyeOfStormControlZoneHandler(this, Points.BloodElf);
_controlZoneHandlers[GameobjectIds.DrTowerCapEyEntry] = new BgEyeOfStormControlZoneHandler(this, Points.DraeneiRuins);
_controlZoneHandlers[GameobjectIds.HuTowerCapEyEntry] = new BgEyeOfStormControlZoneHandler(this, Points.MageTower);
return true;
}
public override void Reset()
{
//call parent's class reset
base.Reset();
m_TeamScores[BattleGroundTeamId.Alliance] = 0;
m_TeamScores[BattleGroundTeamId.Horde] = 0;
m_HonorScoreTics = [0, 0];
m_FlagCapturedBgObjectType = 0;
bool isBGWeekend = Global.BattlegroundMgr.IsBGWeekend(GetTypeID());
m_HonorTics = isBGWeekend ? MiscConst.EYWeekendHonorTicks : MiscConst.NotEYWeekendHonorTicks;
}
public override void HandleKillPlayer(Player player, Player killer)
{
if (GetStatus() != BattlegroundStatus.InProgress)
return;
base.HandleKillPlayer(player, killer);
EventPlayerDroppedFlag(player);
}
public void EventTeamLostPoint(uint teamId, uint point, WorldObject controlZone)
{
if (teamId == BattleGroundTeamId.Alliance)
{
SendBroadcastText(MiscConst.m_LosingPointTypes[point].MessageIdAlliance, ChatMsg.BgSystemAlliance, controlZone);
UpdateWorldState(MiscConst.m_PointsIconStruct[point].WorldStateAllianceControlledIndex, 0);
}
else if (teamId == BattleGroundTeamId.Horde)
{
SendBroadcastText(MiscConst.m_LosingPointTypes[point].MessageIdHorde, ChatMsg.BgSystemHorde, controlZone);
UpdateWorldState(MiscConst.m_PointsIconStruct[point].WorldStateHordeControlledIndex, 0);
}
UpdateWorldState(MiscConst.m_PointsIconStruct[point].WorldStateControlIndex, 1);
UpdatePointsCount(teamId);
}
public void EventTeamCapturedPoint(uint teamId, uint point, WorldObject controlZone)
{
if (teamId == BattleGroundTeamId.Alliance)
{
SendBroadcastText(MiscConst.m_CapturingPointTypes[point].MessageIdAlliance, ChatMsg.BgSystemAlliance, controlZone);
UpdateWorldState(MiscConst.m_PointsIconStruct[point].WorldStateAllianceControlledIndex, 1);
}
else if (teamId == BattleGroundTeamId.Horde)
{
SendBroadcastText(MiscConst.m_CapturingPointTypes[point].MessageIdHorde, ChatMsg.BgSystemHorde, controlZone);
UpdateWorldState(MiscConst.m_PointsIconStruct[point].WorldStateHordeControlledIndex, 1);
}
UpdateWorldState(MiscConst.m_PointsIconStruct[point].WorldStateControlIndex, 0);
UpdatePointsCount(teamId);
}
public override WorldSafeLocsEntry GetExploitTeleportLocation(Team team)
{
return Global.ObjectMgr.GetWorldSafeLoc(team == Team.Alliance ? MiscConst.ExploitTeleportLocationAlliance : MiscConst.ExploitTeleportLocationHorde);
}
public override Team GetPrematureWinner()
{
if (GetTeamScore(BattleGroundTeamId.Alliance) > GetTeamScore(BattleGroundTeamId.Horde))
return Team.Alliance;
else if (GetTeamScore(BattleGroundTeamId.Horde) > GetTeamScore(BattleGroundTeamId.Alliance))
return Team.Horde;
return base.GetPrematureWinner();
}
public override void ProcessEvent(WorldObject target, uint eventId, WorldObject invoker)
{
base.ProcessEvent(target, eventId, invoker);
if (invoker != null)
{
GameObject gameobject = invoker.ToGameObject();
if (gameobject != null)
{
if (gameobject.GetGoType() == GameObjectTypes.ControlZone)
{
if (!_controlZoneHandlers.TryGetValue(gameobject.GetEntry(), out BgEyeOfStormControlZoneHandler handler))
return;
var controlzone = gameobject.GetGoInfo().ControlZone;
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 RemovePoint(Team team, uint Points = 1) { m_TeamScores[GetTeamIndexByTeamId(team)] -= Points; }
void SetTeamPoint(Team team, uint Points = 0) { m_TeamScores[GetTeamIndexByTeamId(team)] = Points; }
}
struct BgEyeOfStormPointIconsStruct
{
public BgEyeOfStormPointIconsStruct(uint worldStateControlIndex, int worldStateAllianceControlledIndex, int worldStateHordeControlledIndex, uint worldStateAllianceStatusBarIcon, uint worldStateHordeStatusBarIcon)
{
WorldStateControlIndex = worldStateControlIndex;
WorldStateAllianceControlledIndex = worldStateAllianceControlledIndex;
WorldStateHordeControlledIndex = worldStateHordeControlledIndex;
WorldStateAllianceStatusBarIcon = worldStateAllianceStatusBarIcon;
WorldStateHordeStatusBarIcon = worldStateHordeStatusBarIcon;
}
public uint WorldStateControlIndex;
public int WorldStateAllianceControlledIndex;
public int WorldStateHordeControlledIndex;
public uint WorldStateAllianceStatusBarIcon;
public uint WorldStateHordeStatusBarIcon;
}
struct BgEyeOfStormLosingPointStruct
{
public BgEyeOfStormLosingPointStruct(int _SpawnNeutralObjectType, int _DespawnObjectTypeAlliance, uint _MessageIdAlliance, int _DespawnObjectTypeHorde, uint _MessageIdHorde)
{
SpawnNeutralObjectType = _SpawnNeutralObjectType;
DespawnObjectTypeAlliance = _DespawnObjectTypeAlliance;
MessageIdAlliance = _MessageIdAlliance;
DespawnObjectTypeHorde = _DespawnObjectTypeHorde;
MessageIdHorde = _MessageIdHorde;
}
public int SpawnNeutralObjectType;
public int DespawnObjectTypeAlliance;
public uint MessageIdAlliance;
public int DespawnObjectTypeHorde;
public uint MessageIdHorde;
}
struct BgEyeOfStormCapturingPointStruct
{
public BgEyeOfStormCapturingPointStruct(int _DespawnNeutralObjectType, int _SpawnObjectTypeAlliance, uint _MessageIdAlliance, int _SpawnObjectTypeHorde, uint _MessageIdHorde, uint _GraveyardId)
{
DespawnNeutralObjectType = _DespawnNeutralObjectType;
SpawnObjectTypeAlliance = _SpawnObjectTypeAlliance;
MessageIdAlliance = _MessageIdAlliance;
SpawnObjectTypeHorde = _SpawnObjectTypeHorde;
MessageIdHorde = _MessageIdHorde;
GraveyardId = _GraveyardId;
}
public int DespawnNeutralObjectType;
public int SpawnObjectTypeAlliance;
public uint MessageIdAlliance;
public int SpawnObjectTypeHorde;
public uint MessageIdHorde;
public uint GraveyardId;
}
class BgEyeOfStormControlZoneHandler : ControlZoneHandler
{
BgEyeofStorm _battleground;
uint _point;
public BgEyeOfStormControlZoneHandler(BgEyeofStorm bg, uint point)
{
_battleground = bg;
_point = point;
}
public override void HandleProgressEventHorde(GameObject controlZone)
{
_battleground.EventTeamCapturedPoint(BattleGroundTeamId.Horde, _point, controlZone);
}
public override void HandleProgressEventAlliance(GameObject controlZone)
{
_battleground.EventTeamCapturedPoint(BattleGroundTeamId.Alliance, _point, controlZone);
}
public override void HandleNeutralEventHorde(GameObject controlZone)
{
_battleground.EventTeamLostPoint(BattleGroundTeamId.Horde, _point, controlZone);
}
public override void HandleNeutralEventAlliance(GameObject controlZone)
{
_battleground.EventTeamLostPoint(BattleGroundTeamId.Alliance, _point, controlZone);
}
public uint GetPoint() { return _point; }
}
#region Constants
struct MiscConst
{
public static TimeSpan PointsTickTime = TimeSpan.FromSeconds(2);
public static TimeSpan FlagAssaultTimer = TimeSpan.FromSeconds(30);
public static ushort FlagBrutalAssaultStackCount = 5;
public const uint EventStartBattle = 13180; // Achievement: Flurry
public const uint NotEYWeekendHonorTicks = 260;
public const uint EYWeekendHonorTicks = 160;
public const uint SpellNetherstormFlag = 34976;
// Focused/Brutal Assault
public const uint SpellFocusedAssault = 46392;
public const uint SpellBrutalAssault = 46393;
public const uint ExploitTeleportLocationAlliance = 3773;
public const uint ExploitTeleportLocationHorde = 3772;
public static byte[] TickPoints = { 1, 2, 5, 10 };
public static uint[] FlagPoints = { 75, 85, 100, 500 };
public const uint AreatriggerCaptureFlag = 33;
public const uint PvpStatFlagCaptures = 183;
public static BgEyeOfStormPointIconsStruct[] m_PointsIconStruct =
{
new BgEyeOfStormPointIconsStruct(WorldStateIds.FelReaverUncontrol, WorldStateIds.FelReaverAllianceControl, WorldStateIds.FelReaverHordeControl, WorldStateIds.FelReaverAllianceControlState, WorldStateIds.FelReaverHordeControlState),
new BgEyeOfStormPointIconsStruct(WorldStateIds.BloodElfUncontrol, WorldStateIds.BloodElfAllianceControl, WorldStateIds.BloodElfHordeControl, WorldStateIds.BloodElfAllianceControlState, WorldStateIds.BloodElfHordeControlState),
new BgEyeOfStormPointIconsStruct(WorldStateIds.DraeneiRuinsUncontrol, WorldStateIds.DraeneiRuinsAllianceControl, WorldStateIds.DraeneiRuinsHordeControl, WorldStateIds.DraeneiRuinsAllianceControlState, WorldStateIds.DraeneiRuinsHordeControlState),
new BgEyeOfStormPointIconsStruct(WorldStateIds.MageTowerUncontrol, WorldStateIds.MageTowerAllianceControl, WorldStateIds.MageTowerHordeControl, WorldStateIds.MageTowerAllianceControlState, WorldStateIds.MageTowerHordeControlState)
};
public static BgEyeOfStormLosingPointStruct[] m_LosingPointTypes =
{
new BgEyeOfStormLosingPointStruct(ObjectTypes.NBannerFelReaverCenter, ObjectTypes.ABannerFelReaverCenter, BroadcastTextIds.AllianceLostFelReaverRuins, ObjectTypes.HBannerFelReaverCenter, BroadcastTextIds.HordeLostFelReaverRuins),
new BgEyeOfStormLosingPointStruct(ObjectTypes.NBannerBloodElfCenter, ObjectTypes.ABannerBloodElfCenter, BroadcastTextIds.AllianceLostBloodElfTower, ObjectTypes.HBannerBloodElfCenter, BroadcastTextIds.HordeLostBloodElfTower),
new BgEyeOfStormLosingPointStruct(ObjectTypes.NBannerDraeneiRuinsCenter, ObjectTypes.ABannerDraeneiRuinsCenter, BroadcastTextIds.AllianceLostDraeneiRuins, ObjectTypes.HBannerDraeneiRuinsCenter, BroadcastTextIds.HordeLostDraeneiRuins),
new BgEyeOfStormLosingPointStruct(ObjectTypes.NBannerMageTowerCenter, ObjectTypes.ABannerMageTowerCenter, BroadcastTextIds.AllianceLostMageTower, ObjectTypes.HBannerMageTowerCenter, BroadcastTextIds.HordeLostMageTower)
};
public static BgEyeOfStormCapturingPointStruct[] m_CapturingPointTypes =
{
new BgEyeOfStormCapturingPointStruct(ObjectTypes.NBannerFelReaverCenter, ObjectTypes.ABannerFelReaverCenter, BroadcastTextIds.AllianceTakenFelReaverRuins, ObjectTypes.HBannerFelReaverCenter, BroadcastTextIds.HordeTakenFelReaverRuins, GaveyardIds.FelReaver),
new BgEyeOfStormCapturingPointStruct(ObjectTypes.NBannerBloodElfCenter, ObjectTypes.ABannerBloodElfCenter, BroadcastTextIds.AllianceTakenBloodElfTower, ObjectTypes.HBannerBloodElfCenter, BroadcastTextIds.HordeTakenBloodElfTower, GaveyardIds.BloodElf),
new BgEyeOfStormCapturingPointStruct(ObjectTypes.NBannerDraeneiRuinsCenter, ObjectTypes.ABannerDraeneiRuinsCenter, BroadcastTextIds.AllianceTakenDraeneiRuins, ObjectTypes.HBannerDraeneiRuinsCenter, BroadcastTextIds.HordeTakenDraeneiRuins, GaveyardIds.DraeneiRuins),
new BgEyeOfStormCapturingPointStruct(ObjectTypes.NBannerMageTowerCenter, ObjectTypes.ABannerMageTowerCenter, BroadcastTextIds.AllianceTakenMageTower, ObjectTypes.HBannerMageTowerCenter, BroadcastTextIds.HordeTakenMageTower, GaveyardIds.MageTower)
};
}
struct BroadcastTextIds
{
public const uint AllianceTakenFelReaverRuins = 17828;
public const uint HordeTakenFelReaverRuins = 17829;
public const uint AllianceLostFelReaverRuins = 17835;
public const uint HordeLostFelReaverRuins = 17836;
public const uint AllianceTakenBloodElfTower = 17819;
public const uint HordeTakenBloodElfTower = 17823;
public const uint AllianceLostBloodElfTower = 17831;
public const uint HordeLostBloodElfTower = 17832;
public const uint AllianceTakenDraeneiRuins = 17827;
public const uint HordeTakenDraeneiRuins = 17826;
public const uint AllianceLostDraeneiRuins = 17833;
public const uint HordeLostDraeneiRuins = 17834;
public const uint AllianceTakenMageTower = 17824;
public const uint HordeTakenMageTower = 17825;
public const uint AllianceLostMageTower = 17837;
public const uint HordeLostMageTower = 17838;
public const uint TakenFlag = 18359;
public const uint FlagDropped = 18361;
public const uint FlagReset = 18364;
public const uint AllianceCapturedFlag = 18375;
public const uint HordeCapturedFlag = 18384;
}
struct WorldStateIds
{
public const int AllianceResources = 1776;
public const int HordeResources = 1777;
public const int MaxResources = 1780;
public const int AllianceBase = 2752;
public const int HordeBase = 2753;
public const int DraeneiRuinsHordeControl = 2733;
public const int DraeneiRuinsAllianceControl = 2732;
public const int DraeneiRuinsUncontrol = 2731;
public const int MageTowerAllianceControl = 2730;
public const int MageTowerHordeControl = 2729;
public const int MageTowerUncontrol = 2728;
public const int FelReaverHordeControl = 2727;
public const int FelReaverAllianceControl = 2726;
public const int FelReaverUncontrol = 2725;
public const int BloodElfHordeControl = 2724;
public const int BloodElfAllianceControl = 2723;
public const int BloodElfUncontrol = 2722;
public const int ProgressBarPercentGrey = 2720; //100 = Empty (Only Grey); 0 = Blue|Red (No Grey)
public const int ProgressBarStatus = 2719; //50 Init!; 48 ... Hordak Bere .. 33 .. 0 = Full 100% Hordacky; 100 = Full Alliance
public const int ProgressBarShow = 2718; //1 Init; 0 Druhy Send - Bez Messagu; 1 = Controlled Aliance
public const int NetherstormFlag = 8863;
//Set To 2 When Flag Is Picked Up; And To 1 If It Is Dropped
public const int NetherstormFlagStateAlliance = 9808;
public const int NetherstormFlagStateHorde = 9809;
public const int DraeneiRuinsHordeControlState = 17362;
public const int DraeneiRuinsAllianceControlState = 17366;
public const int MageTowerHordeControlState = 17361;
public const int MageTowerAllianceControlState = 17368;
public const int FelReaverHordeControlState = 17364;
public const int FelReaverAllianceControlState = 17367;
public const int BloodElfHordeControlState = 17363;
public const int BloodElfAllianceControlState = 17365;
}
struct SoundIds
{
//strange ids, but sure about them
public const uint FlagPickedUpAlliance = 8212;
public const uint FlagCapturedHorde = 8213;
public const uint FlagPickedUpHorde = 8174;
public const uint FlagCapturedAlliance = 8173;
public const uint FlagReset = 8192;
}
struct GameobjectIds
{
public const uint ADoorEyEntry = 184719; //Alliance Door
public const uint HDoorEyEntry = 184720; //Horde Door
public const uint Flag1EyEntry = 184493; //Netherstorm Flag (Generic)
public const uint Flag2EyEntry = 208977; //Netherstorm Flag (Flagstand)
public const uint ABannerEyEntry = 184381; //Visual Banner (Alliance)
public const uint HBannerEyEntry = 184380; //Visual Banner (Horde)
public const uint NBannerEyEntry = 184382; //Visual Banner (Neutral)
public const uint BeTowerCapEyEntry = 184080; //Be Tower Cap Pt
public const uint FrTowerCapEyEntry = 184081; //Fel Reaver Cap Pt
public const uint HuTowerCapEyEntry = 184082; //Human Tower Cap Pt
public const uint DrTowerCapEyEntry = 184083; //Draenei Tower Cap Pt
public const uint SpeedBuffFelReaverEyEntry = 184970;
public const uint RestorationBuffFelReaverEyEntry = 184971;
public const uint BerserkBuffFelReaverEyEntry = 184972;
public const uint SpeedBuffBloodElfEyEntry = 184964;
public const uint RestorationBuffBloodElfEyEntry = 184965;
public const uint BerserkBuffBloodElfEyEntry = 184966;
public const uint SpeedBuffDraeneiRuinsEyEntry = 184976;
public const uint RestorationBuffDraeneiRuinsEyEntry = 184977;
public const uint BerserkBuffDraeneiRuinsEyEntry = 184978;
public const uint SpeedBuffMageTowerEyEntry = 184973;
public const uint RestorationBuffMageTowerEyEntry = 184974;
public const uint BerserkBuffMageTowerEyEntry = 184975;
}
struct GaveyardIds
{
public const int MainAlliance = 1103;
public const uint MainHorde = 1104;
public const uint FelReaver = 1105;
public const uint BloodElf = 1106;
public const uint DraeneiRuins = 1107;
public const uint MageTower = 1108;
}
struct Points
{
public const int FelReaver = 0;
public const int BloodElf = 1;
public const int DraeneiRuins = 2;
public const int MageTower = 3;
public const int PlayersOutOfPoints = 4;
public const int PointsMax = 4;
}
struct ObjectTypes
{
public const int DoorA = 0;
public const int DoorH = 1;
public const int ABannerFelReaverCenter = 2;
public const int ABannerFelReaverLeft = 3;
public const int ABannerFelReaverRight = 4;
public const int ABannerBloodElfCenter = 5;
public const int ABannerBloodElfLeft = 6;
public const int ABannerBloodElfRight = 7;
public const int ABannerDraeneiRuinsCenter = 8;
public const int ABannerDraeneiRuinsLeft = 9;
public const int ABannerDraeneiRuinsRight = 10;
public const int ABannerMageTowerCenter = 11;
public const int ABannerMageTowerLeft = 12;
public const int ABannerMageTowerRight = 13;
public const int HBannerFelReaverCenter = 14;
public const int HBannerFelReaverLeft = 15;
public const int HBannerFelReaverRight = 16;
public const int HBannerBloodElfCenter = 17;
public const int HBannerBloodElfLeft = 18;
public const int HBannerBloodElfRight = 19;
public const int HBannerDraeneiRuinsCenter = 20;
public const int HBannerDraeneiRuinsLeft = 21;
public const int HBannerDraeneiRuinsRight = 22;
public const int HBannerMageTowerCenter = 23;
public const int HBannerMageTowerLeft = 24;
public const int HBannerMageTowerRight = 25;
public const int NBannerFelReaverCenter = 26;
public const int NBannerFelReaverLeft = 27;
public const int NBannerFelReaverRight = 28;
public const int NBannerBloodElfCenter = 29;
public const int NBannerBloodElfLeft = 30;
public const int NBannerBloodElfRight = 31;
public const int NBannerDraeneiRuinsCenter = 32;
public const int NBannerDraeneiRuinsLeft = 33;
public const int NBannerDraeneiRuinsRight = 34;
public const int NBannerMageTowerCenter = 35;
public const int NBannerMageTowerLeft = 36;
public const int NBannerMageTowerRight = 37;
public const int TowerCapFelReaver = 38;
public const int TowerCapBloodElf = 39;
public const int TowerCapDraeneiRuins = 40;
public const int TowerCapMageTower = 41;
public const int FlagNetherstorm = 42;
public const int FlagFelReaver = 43;
public const int FlagBloodElf = 44;
public const int FlagDraeneiRuins = 45;
public const int FlagMageTower = 46;
//Buffs
public const int SpeedbuffFelReaver = 47;
public const int RegenbuffFelReaver = 48;
public const int BerserkbuffFelReaver = 49;
public const int SpeedbuffBloodElf = 50;
public const int RegenbuffBloodElf = 51;
public const int BerserkbuffBloodElf = 52;
public const int SpeedbuffDraeneiRuins = 53;
public const int RegenbuffDraeneiRuins = 54;
public const int BerserkbuffDraeneiRuins = 55;
public const int SpeedbuffMageTower = 56;
public const int RegenbuffMageTower = 57;
public const int BerserkbuffMageTower = 58;
public const int Max = 59;
}
struct ScoreIds
{
public const uint WarningNearVictoryScore = 1400;
public const uint MaxTeamScore = 1500;
}
enum EYFlagState
{
OnBase = 0,
WaitRespawn = 1,
OnPlayer = 2,
OnGround = 3
}
#endregion
}
File diff suppressed because it is too large Load Diff
@@ -1,10 +0,0 @@
// 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.
namespace Game.BattleGrounds.Zones
{
class BgNagrandArena : Battleground
{
public BgNagrandArena(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate) { }
}
}
@@ -1,10 +0,0 @@
// 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.
namespace Game.BattleGrounds.Zones
{
class BgRuinsOfLordaernon : Battleground
{
public BgRuinsOfLordaernon(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate) { }
}
}
@@ -1,10 +0,0 @@
// 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.
namespace Game.BattleGrounds.Zones
{
class BgSilvershardMines : Battleground
{
public BgSilvershardMines(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate) { }
}
}
File diff suppressed because it is too large Load Diff
@@ -1,10 +0,0 @@
// 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.
namespace Game.BattleGrounds.Zones
{
class BgTempleofKotmogu : Battleground
{
public BgTempleofKotmogu(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate) { }
}
}
@@ -1,10 +0,0 @@
// 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.
namespace Game.BattleGrounds.Zones
{
class BgTheRingOfValor : Battleground
{
public BgTheRingOfValor(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate) { }
}
}
@@ -1,10 +0,0 @@
// 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.
namespace Game.BattleGrounds.Zones
{
class BgTwinPeaks : Battleground
{
public BgTwinPeaks(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate) { }
}
}
@@ -1,648 +0,0 @@
// 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.Entities;
using Game.Entities.GameObjectType;
using Game.Spells;
using System;
using System.Collections.Generic;
namespace Game.BattleGrounds.Zones.WarsongGluch
{
class BgWarsongGluch : Battleground
{
Team _lastFlagCaptureTeam; // Winner is based on this if score is equal
uint m_ReputationCapture;
uint m_HonorWinKills;
uint m_HonorEndKills;
bool _bothFlagsKept;
List<ObjectGuid> _doors = new();
ObjectGuid[] _flags = new ObjectGuid[2];
TimeTracker _flagAssaultTimer;
byte _assaultStackCount;
ObjectGuid[] _capturePointAreaTriggers = new ObjectGuid[2];
public BgWarsongGluch(BattlegroundTemplate battlegroundTemplate) : base(battlegroundTemplate)
{
StartMessageIds[BattlegroundConst.EventIdSecond] = (uint)BroadcastTextIds.StartOneMinute;
StartMessageIds[BattlegroundConst.EventIdThird] = (uint)BroadcastTextIds.StartHalfMinute;
StartMessageIds[BattlegroundConst.EventIdFourth] = (uint)BroadcastTextIds.BattleHasBegun;
_flagAssaultTimer = new(MiscConst.FlagAssaultTimer);
}
public override void PostUpdateImpl(uint diff)
{
if (GetStatus() == BattlegroundStatus.InProgress)
{
if (GetElapsedTime() >= 17 * Time.Minute * Time.InMilliseconds)
{
if (GetTeamScore(BattleGroundTeamId.Alliance) == 0)
{
if (GetTeamScore(BattleGroundTeamId.Horde) == 0) // No one scored - result is tie
EndBattleground(Team.Other);
else // Horde has more points and thus wins
EndBattleground(Team.Horde);
}
else if (GetTeamScore(BattleGroundTeamId.Horde) == 0)
EndBattleground(Team.Alliance); // Alliance has > 0, Horde has 0, alliance wins
else if (GetTeamScore(BattleGroundTeamId.Horde) == GetTeamScore(BattleGroundTeamId.Alliance)) // Team score equal, winner is team that scored the last flag
EndBattleground((Team)_lastFlagCaptureTeam);
else if (GetTeamScore(BattleGroundTeamId.Horde) > GetTeamScore(BattleGroundTeamId.Alliance)) // Last but not least, check who has the higher score
EndBattleground(Team.Horde);
else
EndBattleground(Team.Alliance);
}
}
if (_bothFlagsKept)
{
_flagAssaultTimer.Update(diff);
if (_flagAssaultTimer.Passed())
{
_flagAssaultTimer.Reset(MiscConst.FlagAssaultTimer);
_assaultStackCount++;
// update assault debuff stacks
DoForFlagKeepers(ApplyAssaultDebuffToPlayer);
}
}
}
void DoForFlagKeepers(Action<Player> action)
{
foreach (ObjectGuid flagGUID in _flags)
{
GameObject flag = GetBgMap().GetGameObject(flagGUID);
if (flag != null)
{
Player carrier = Global.ObjAccessor.FindPlayer(flag.GetFlagCarrierGUID());
if (carrier != null)
action(carrier);
}
}
}
void ResetAssaultDebuff()
{
_bothFlagsKept = false;
_assaultStackCount = 0;
_flagAssaultTimer.Reset(MiscConst.FlagAssaultTimer);
DoForFlagKeepers(RemoveAssaultDebuffFromPlayer);
}
void ApplyAssaultDebuffToPlayer(Player player)
{
if (_assaultStackCount == 0)
return;
uint spellId = (uint)SpellIds.FocusedAssault;
if (_assaultStackCount >= MiscConst.FlagBrutalAssaultStackCount)
{
player.RemoveAurasDueToSpell((uint)SpellIds.FocusedAssault);
spellId = (uint)SpellIds.BrutalAssault;
}
Aura aura = player.GetAura(spellId);
if (aura == null)
{
player.CastSpell(player, spellId, true);
aura = player.GetAura(spellId);
}
if (aura != null)
aura.SetStackAmount(_assaultStackCount);
}
void RemoveAssaultDebuffFromPlayer(Player player)
{
player.RemoveAurasDueToSpell((uint)SpellIds.FocusedAssault);
player.RemoveAurasDueToSpell((uint)SpellIds.BrutalAssault);
}
public override void StartingEventOpenDoors()
{
foreach (ObjectGuid door in _doors)
{
GameObject gameObject = GetBgMap().GetGameObject(door);
if (gameObject != null)
{
gameObject.UseDoorOrButton();
gameObject.DespawnOrUnsummon(TimeSpan.FromSeconds(3));
}
}
UpdateWorldState((int)WorldStateIds.StateTimerActive, 1);
UpdateWorldState((int)WorldStateIds.StateTimer, (int)(GameTime.GetGameTime() + 15 * Time.Minute));
// players joining later are not eligibles
TriggerGameEvent(8563);
}
FlagState GetFlagState(int team)
{
GameObject gameObject = FindBgMap().GetGameObject(_flags[team]);
if (gameObject != null)
return gameObject.GetFlagState();
return 0;
}
ObjectGuid GetFlagCarrierGUID(int team)
{
GameObject gameObject = FindBgMap().GetGameObject(_flags[team]);
if (gameObject != null)
return gameObject.GetFlagCarrierGUID();
return ObjectGuid.Empty;
}
void HandleFlagRoomCapturePoint()
{
DoForFlagKeepers(player =>
{
int team = GetTeamIndexByTeamId(GetPlayerTeam(player.GetGUID()));
AreaTrigger trigger = GetBgMap().GetAreaTrigger(_capturePointAreaTriggers[team]);
if (trigger != null && trigger.GetInsideUnits().Contains(player.GetGUID()))
if (CanCaptureFlag(trigger, player))
OnCaptureFlag(trigger, player);
});
}
void UpdateFlagState(Team team, FlagState value)
{
int transformValueToOtherTeamControlWorldState(FlagState value)
{
switch (value)
{
case FlagState.InBase:
case FlagState.Dropped:
case FlagState.Respawning:
return 1;
case FlagState.Taken:
return 2;
default:
return 0;
}
};
if (team == Team.Horde)
{
UpdateWorldState((int)WorldStateIds.FlagStateAlliance, (int)value);
UpdateWorldState((int)WorldStateIds.FlagControlHorde, transformValueToOtherTeamControlWorldState(value));
}
else
{
UpdateWorldState((int)WorldStateIds.FlagStateHorde, (int)value);
UpdateWorldState((int)WorldStateIds.FlagControlAlliance, transformValueToOtherTeamControlWorldState(value));
}
}
void UpdateTeamScore(int team)
{
if (team == BattleGroundTeamId.Alliance)
UpdateWorldState((int)WorldStateIds.FlagCapturesAlliance, (int)GetTeamScore(team));
else
UpdateWorldState((int)WorldStateIds.FlagCapturesHorde, (int)GetTeamScore(team));
}
public override bool SetupBattleground()
{
return true;
}
public override void Reset()
{
//call parent's class reset
base.Reset();
m_TeamScores[BattleGroundTeamId.Alliance] = 0;
m_TeamScores[BattleGroundTeamId.Horde] = 0;
if (Global.BattlegroundMgr.IsBGWeekend(GetTypeID()))
{
m_ReputationCapture = 45;
m_HonorWinKills = 3;
m_HonorEndKills = 4;
}
else
{
m_ReputationCapture = 35;
m_HonorWinKills = 1;
m_HonorEndKills = 2;
}
_lastFlagCaptureTeam = Team.Other;
_bothFlagsKept = false;
_doors.Clear();
_flags.Clear();
_assaultStackCount = 0;
_flagAssaultTimer.Reset(MiscConst.FlagAssaultTimer);
_capturePointAreaTriggers.Clear();
}
public override void EndBattleground(Team winner)
{
// Win reward
if (winner == Team.Alliance)
RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), Team.Alliance);
if (winner == Team.Horde)
RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), Team.Horde);
// Complete map_end rewards (even if no team wins)
RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), Team.Alliance);
RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), Team.Horde);
base.EndBattleground(winner);
}
public override void HandleKillPlayer(Player victim, Player killer)
{
if (GetStatus() != BattlegroundStatus.InProgress)
return;
EventPlayerDroppedFlag(victim);
base.HandleKillPlayer(victim, killer);
}
public override WorldSafeLocsEntry GetClosestGraveyard(Player player)
{
return Global.ObjectMgr.GetClosestGraveyard(player, player.GetBGTeam(), player);
}
public override WorldSafeLocsEntry GetExploitTeleportLocation(Team team)
{
return Global.ObjectMgr.GetWorldSafeLoc(team == Team.Alliance ? MiscConst.ExploitTeleportLocationAlliance : MiscConst.ExploitTeleportLocationHorde);
}
public override Team GetPrematureWinner()
{
if (GetTeamScore(BattleGroundTeamId.Alliance) > GetTeamScore(BattleGroundTeamId.Horde))
return Team.Alliance;
else if (GetTeamScore(BattleGroundTeamId.Horde) > GetTeamScore(BattleGroundTeamId.Alliance))
return Team.Horde;
return base.GetPrematureWinner();
}
public override void OnGameObjectCreate(GameObject gameObject)
{
switch ((GameobjectIds)gameObject.GetEntry())
{
case GameobjectIds.AllianceDoor:
case GameobjectIds.Portcullis009:
case GameobjectIds.Portcullis002:
case GameobjectIds.CollisionPcSize:
case GameobjectIds.HordeGate1:
case GameobjectIds.HordeGate2:
_doors.Add(gameObject.GetGUID());
break;
case GameobjectIds.AllianceFlagInBase:
_flags[BattleGroundTeamId.Alliance] = gameObject.GetGUID();
break;
case GameobjectIds.HordeFlagInBase:
_flags[BattleGroundTeamId.Horde] = gameObject.GetGUID();
break;
default:
break;
}
}
public override void OnAreaTriggerCreate(AreaTrigger areaTrigger)
{
if (!areaTrigger.IsStaticSpawn())
return;
switch (areaTrigger.GetEntry())
{
case MiscConst.AtCapturePointAlliance:
_capturePointAreaTriggers[BattleGroundTeamId.Alliance] = areaTrigger.GetGUID();
break;
case MiscConst.AtCapturePointHorde:
_capturePointAreaTriggers[BattleGroundTeamId.Horde] = areaTrigger.GetGUID();
break;
default:
break;
}
}
public override void OnFlagStateChange(GameObject flagInBase, FlagState oldValue, FlagState newValue, Player player)
{
Team team = flagInBase.GetEntry() == (uint)GameobjectIds.HordeFlagInBase ? Team.Horde : Team.Alliance;
int otherTeamId = GetTeamIndexByTeamId(GetOtherTeam(team));
UpdateFlagState(team, newValue);
switch (newValue)
{
case FlagState.InBase:
{
if (GetStatus() == BattlegroundStatus.InProgress)
{
ResetAssaultDebuff();
if (player != null)
{
// flag got returned to base by player interaction
UpdatePvpStat(player, MiscConst.PvpStatFlagReturns, 1); // +1 flag returns
if (team == Team.Alliance)
{
SendBroadcastText((uint)BroadcastTextIds.AllianceFlagReturned, ChatMsg.BgSystemAlliance, player);
PlaySoundToAll((uint)SoundIds.FlagReturned);
}
else
{
SendBroadcastText((uint)BroadcastTextIds.HordeFlagReturned, ChatMsg.BgSystemHorde, player);
PlaySoundToAll((uint)SoundIds.FlagReturned);
}
}
// Flag respawned due to timeout/capture
else if (GetFlagState(otherTeamId) != FlagState.Respawning)
{
// if other flag is respawning, we will let that one handle the message and sound to prevent double message/sound.
SendBroadcastText((uint)BroadcastTextIds.FlagsPlaced, ChatMsg.BgSystemNeutral);
PlaySoundToAll((uint)SoundIds.FlagsRespawned);
}
HandleFlagRoomCapturePoint();
}
break;
}
case FlagState.Dropped:
{
player.RemoveAurasDueToSpell((uint)SpellIds.QuickCapTimer);
RemoveAssaultDebuffFromPlayer(player);
uint recentlyDroppedSpellId = BattlegroundConst.SpellRecentlyDroppedHordeFlag;
if (team == Team.Alliance)
{
recentlyDroppedSpellId = BattlegroundConst.SpellRecentlyDroppedAllianceFlag;
SendBroadcastText((uint)BroadcastTextIds.AllianceFlagDropped, ChatMsg.BgSystemAlliance, player);
}
else
SendBroadcastText((uint)BroadcastTextIds.HordeFlagDropped, ChatMsg.BgSystemHorde, player);
player.CastSpell(player, recentlyDroppedSpellId, true);
break;
}
case FlagState.Taken:
{
if (team == Team.Horde)
{
SendBroadcastText((uint)BroadcastTextIds.HordeFlagPickedUp, ChatMsg.BgSystemHorde, player);
PlaySoundToAll((uint)SoundIds.HordeFlagPickedUp);
}
else
{
SendBroadcastText((uint)BroadcastTextIds.AllianceFlagPickedUp, ChatMsg.BgSystemAlliance, player);
PlaySoundToAll((uint)SoundIds.AllianceFlagPickedUp);
}
if (GetFlagState(otherTeamId) == FlagState.Taken)
_bothFlagsKept = true;
ApplyAssaultDebuffToPlayer(player);
flagInBase.CastSpell(player, (uint)SpellIds.QuickCapTimer, true);
player.StartCriteria(CriteriaStartEvent.BeSpellTarget, (uint)SpellIds.QuickCapTimer, TimeSpan.FromSeconds(GameTime.GetGameTime() - flagInBase.GetFlagTakenFromBaseTime()));
break;
}
case FlagState.Respawning:
ResetAssaultDebuff();
break;
default:
break;
}
}
public override bool CanCaptureFlag(AreaTrigger areaTrigger, Player player)
{
if (GetStatus() != BattlegroundStatus.InProgress)
return false;
Team team = GetPlayerTeam(player.GetGUID());
int teamId = GetTeamIndexByTeamId(team);
int otherTeamId = GetTeamIndexByTeamId(GetOtherTeam(team));
if (areaTrigger.GetGUID() != _capturePointAreaTriggers[teamId])
return false;
// check if enemy flag's carrier is this player
if (GetFlagCarrierGUID(otherTeamId) != player.GetGUID())
return false;
// check that team's flag is in base
return GetFlagState(teamId) == FlagState.InBase;
}
public override void OnCaptureFlag(AreaTrigger areaTrigger, Player player)
{
Team winner = Team.Other;
Team team = GetPlayerTeam(player.GetGUID());
int teamId = GetTeamIndexByTeamId(team);
int otherTeamId = GetTeamIndexByTeamId(GetOtherTeam(team));
/*
1. Update flag states & score world states
2. udpate points
3. chat message & sound
4. update criterias & achievements
5. remove all related auras
?. Reward honor & reputation
*/
// 1. update the flag states
for (byte i = 0; i < _flags.Length; i++)
{
GameObject gameObject1 = GetBgMap().GetGameObject(_flags[i]);
if (gameObject1 != null)
gameObject1.HandleCustomTypeCommand(new SetNewFlagState(FlagState.Respawning, player));
}
// 2. update points
if (GetTeamScore(teamId) < MiscConst.MaxTeamScore)
AddPoint(team, 1);
UpdateTeamScore(teamId);
// 3. chat message & sound
if (team == Team.Alliance)
{
SendBroadcastText((uint)BroadcastTextIds.CapturedHordeFlag, ChatMsg.BgSystemHorde, player);
PlaySoundToAll((uint)SoundIds.FlagCapturedAlliance);
RewardReputationToTeam(890, m_ReputationCapture, Team.Alliance);
player.CastSpell(player, (uint)SpellIds.CapturedAllianceCosmeticFx);
}
else
{
SendBroadcastText((uint)BroadcastTextIds.CapturedAllianceFlag, ChatMsg.BgSystemAlliance, player);
PlaySoundToAll((uint)SoundIds.FlagCapturedHorde);
RewardReputationToTeam(889, m_ReputationCapture, Team.Horde);
player.CastSpell(player, (uint)SpellIds.CapturedHordeCosmeticFx);
}
// 4. update criteria's for achievement, player score etc.
UpdatePvpStat(player, MiscConst.PvpStatFlagCaptures, 1); // +1 flag captures
// 5. Remove all related auras
RemoveAssaultDebuffFromPlayer(player);
GameObject gameObject = GetBgMap().GetGameObject(_flags[otherTeamId]);
if (gameObject != null)
player.RemoveAurasDueToSpell(gameObject.GetGoInfo().NewFlag.pickupSpell, gameObject.GetGUID());
player.RemoveAurasDueToSpell((uint)SpellIds.QuickCapTimer);
player.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.PvPActive);
RewardHonorToTeam(GetBonusHonorFromKill(2), team);
// update last flag capture to be used if teamscore is equal
SetLastFlagCapture(team);
if (GetTeamScore(teamId) == MiscConst.MaxTeamScore)
winner = team;
if (winner != Team.Other)
{
UpdateWorldState((int)WorldStateIds.FlagStateAlliance, 1);
UpdateWorldState((int)WorldStateIds.FlagStateHorde, 1);
UpdateWorldState((int)WorldStateIds.StateTimerActive, 0);
RewardHonorToTeam(MiscConst.Honor[Global.BattlegroundMgr.IsBGWeekend(GetTypeID()) ? 1 : 0][(int)Rewards.Win], winner);
EndBattleground(winner);
}
}
void SetLastFlagCapture(Team team) { _lastFlagCaptureTeam = team; }
void AddPoint(Team team, uint Points = 1) { m_TeamScores[GetTeamIndexByTeamId(team)] += Points; }
void SetTeamPoint(Team team, uint Points = 0) { m_TeamScores[GetTeamIndexByTeamId(team)] = Points; }
void RemovePoint(Team team, uint Points = 1) { m_TeamScores[GetTeamIndexByTeamId(team)] -= Points; }
}
#region Constants
struct MiscConst
{
public const uint MaxTeamScore = 3;
public const uint FlagRespawnTime = 23000;
public const uint FlagDropTime = 10000;
public const uint SpellForceTime = 600000;
public const uint SpellBrutalTime = 900000;
public const uint ExploitTeleportLocationAlliance = 7051;
public const uint ExploitTeleportLocationHorde = 7050;
public const uint AtCapturePointAlliance = 30;
public const uint AtCapturePointHorde = 31;
public const uint WsEventStartBattle = 35912;
public static TimeSpan FlagAssaultTimer = TimeSpan.FromSeconds(30);
public const ushort FlagBrutalAssaultStackCount = 5;
public static uint[][] Honor =
{
[20, 40, 40], // Normal Honor
[60, 40, 80] // Holiday
};
public const uint PvpStatFlagCaptures = 928;
public const uint PvpStatFlagReturns = 929;
}
enum BroadcastTextIds
{
StartOneMinute = 10015,
StartHalfMinute = 10016,
BattleHasBegun = 10014,
CapturedHordeFlag = 9801,
CapturedAllianceFlag = 9802,
FlagsPlaced = 9803,
AllianceFlagPickedUp = 9804,
AllianceFlagDropped = 9805,
HordeFlagPickedUp = 9807,
HordeFlagDropped = 9806,
AllianceFlagReturned = 9808,
HordeFlagReturned = 9809,
}
enum SoundIds
{
FlagCapturedAlliance = 8173,
FlagCapturedHorde = 8213,
FlagPlaced = 8232,
FlagReturned = 8192,
HordeFlagPickedUp = 8212,
AllianceFlagPickedUp = 8174,
FlagsRespawned = 8232
}
enum SpellIds
{
WarsongFlag = 23333,
WarsongFlagDropped = 23334,
//WarsongFlagPicked = 61266,
SilverwingFlag = 23335,
SilverwingFlagDropped = 23336,
//SilverwingFlagPicked = 61265,
FocusedAssault = 46392,
BrutalAssault = 46393,
QuickCapTimer = 183317, // Serverside
//Carrierdebuffs
CapturedAllianceCosmeticFx = 262508,
CapturedHordeCosmeticFx = 262512,
}
enum WorldStateIds
{
FlagStateAlliance = 1545,
FlagStateHorde = 1546,
FlagStateNeutral = 1547, // Unused
HordeFlagCountPickedUp = 17712, // Brawl
AllianceFlagCountPickedUp = 17713, // Brawl
FlagCapturesAlliance = 1581,
FlagCapturesHorde = 1582,
FlagCapturesMax = 1601,
FlagCapturesMaxNew = 17303,
FlagControlHorde = 2338,
FlagControlAlliance = 2339,
StateTimer = 4248,
StateTimerActive = 4247
}
enum GameobjectIds
{
// Doors
AllianceDoor = 309704,
Portcullis009 = 309705, // Doodad7neBlackrookPortcullis009
Portcullis002 = 309883, // Doodad7neBlackrookPortcullis002
CollisionPcSize = 242273,
HordeGate1 = 352709,
HordeGate2 = 352710,
// Flags
AllianceFlagInBase = 227741,
HordeFlagInBase = 227740
}
enum Rewards
{
Win = 0,
FlagCap,
MapComplete,
RewardNum
}
#endregion
}