aboutsummaryrefslogtreecommitdiff
path: root/src/server/scripts
diff options
context:
space:
mode:
authorCarbenium <carbenium@outlook.com>2020-06-22 16:10:34 +0200
committerShauren <shauren.trinity@gmail.com>2022-01-07 00:20:57 +0100
commit49523a74a4c28e5ae17f9a8352aa8224b765b7d8 (patch)
tree829e998508b4320f305bc9e4891ec7116c4005fd /src/server/scripts
parenta26cc135fa34e0e4aa0c244c4c4b4bec4c25d709 (diff)
Battlefields: Move BF scripts out of game
This commit introduces the usual script interface for battlefields. (cherry picked from commit f7faf20254a120a90b8ee8eb55a284a6351aabc3)
Diffstat (limited to 'src/server/scripts')
-rw-r--r--src/server/scripts/Battlefield/BattlefieldTB.cpp889
-rw-r--r--src/server/scripts/Battlefield/BattlefieldTB.h632
-rw-r--r--src/server/scripts/Battlefield/BattlefieldWG.cpp1870
-rw-r--r--src/server/scripts/Battlefield/BattlefieldWG.h575
-rw-r--r--src/server/scripts/Battlefield/battlefield_script_loader.cpp25
-rw-r--r--src/server/scripts/EasternKingdoms/zone_tol_barad.cpp2
-rw-r--r--src/server/scripts/Northrend/zone_wintergrasp.cpp6
7 files changed, 3995 insertions, 4 deletions
diff --git a/src/server/scripts/Battlefield/BattlefieldTB.cpp b/src/server/scripts/Battlefield/BattlefieldTB.cpp
new file mode 100644
index 00000000000..e147689d610
--- /dev/null
+++ b/src/server/scripts/Battlefield/BattlefieldTB.cpp
@@ -0,0 +1,889 @@
+/*
+* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// TO-DO:
+// - Implement proper support for vehicles (Player::VehicleSpellInitialize())
+// - Siege Engine Turret (45564) crashing server (Auras: Unknown Shapeshift Type: 24)
+// - Graveyard spirit phasing, ressurection, Spiritual Immunity aura for players nearby
+// - Warn and teleport players out of the Baradin Hold instance (need sniffs; spell 94964?)
+// - Not sure, but players should probably be able to ressurect from guide spirits when there's no battle
+// - Check and script achievements
+
+#include "BattlefieldTB.h"
+#include "AchievementMgr.h"
+#include "Battleground.h"
+#include "CreatureTextMgr.h"
+#include "GameObject.h"
+#include "GameTime.h"
+#include "MapManager.h"
+#include "ObjectAccessor.h"
+#include "Player.h"
+#include "Random.h"
+#include "ScriptMgr.h"
+#include "SpellAuras.h"
+#include "TemporarySummon.h"
+#include "World.h"
+#include "WorldStatePackets.h"
+
+BattlefieldTB::~BattlefieldTB() { }
+
+bool BattlefieldTB::SetupBattlefield()
+{
+ m_TypeId = BATTLEFIELD_TB; // See enum BattlefieldTypes
+ m_BattleId = BATTLEFIELD_BATTLEID_TB;
+ m_ZoneId = BATTLEFIELD_TB_ZONEID;
+ m_MapId = BATTLEFIELD_TB_MAPID;
+ m_Map = sMapMgr->CreateBaseMap(m_MapId);
+
+ InitStalker(NPC_DEBUG_ANNOUNCER, TolBaradDebugAnnouncerPos);
+
+ m_MaxPlayer = sWorld->getIntConfig(CONFIG_TOLBARAD_PLR_MAX);
+ m_IsEnabled = sWorld->getBoolConfig(CONFIG_TOLBARAD_ENABLE);
+ m_MinPlayer = sWorld->getIntConfig(CONFIG_TOLBARAD_PLR_MIN);
+ m_MinLevel = sWorld->getIntConfig(CONFIG_TOLBARAD_PLR_MIN_LVL);
+ m_BattleTime = sWorld->getIntConfig(CONFIG_TOLBARAD_BATTLETIME) * MINUTE * IN_MILLISECONDS;
+ m_BonusTime = sWorld->getIntConfig(CONFIG_TOLBARAD_BONUSTIME) * MINUTE * IN_MILLISECONDS;
+ m_NoWarBattleTime = sWorld->getIntConfig(CONFIG_TOLBARAD_NOBATTLETIME) * MINUTE * IN_MILLISECONDS;
+ m_RestartAfterCrash = sWorld->getIntConfig(CONFIG_TOLBARAD_RESTART_AFTER_CRASH) * MINUTE * IN_MILLISECONDS;
+
+ m_TimeForAcceptInvite = 20;
+ m_StartGroupingTimer = 15 * MINUTE * IN_MILLISECONDS;
+ m_StartGrouping = false;
+ m_isActive = false;
+
+ KickPosition.Relocate(-605.5f, 1181.31f, 95.96f, 6.177155f);
+ KickPosition.m_mapId = m_MapId;
+
+ RegisterZone(m_ZoneId);
+
+ m_Data32.resize(BATTLEFIELD_TB_DATA_MAX);
+
+ m_saveTimer = 5 * MINUTE * IN_MILLISECONDS;
+
+ updatedNPCAndObjects = true;
+ m_updateObjectsTimer = 0;
+
+ // Was there a battle going on or time isn't set yet? Then use m_RestartAfterCrash
+ if (sWorld->getWorldState(WS_BATTLEFIELD_TB_STATE_BATTLE) == 1 || sWorld->getWorldState(WS_BATTLEFIELD_TB_TIME_NEXT_BATTLE) == 0)
+ sWorld->setWorldState(WS_BATTLEFIELD_TB_TIME_NEXT_BATTLE, m_RestartAfterCrash);
+
+ // Set timer
+ m_Timer = sWorld->getWorldState(WS_BATTLEFIELD_TB_TIME_NEXT_BATTLE);
+
+ // Defending team isn't set yet? Choose randomly.
+ if (sWorld->getWorldState(WS_BATTLEFIELD_TB_FACTION_CONTROLLING) == 0)
+ sWorld->setWorldState(WS_BATTLEFIELD_TB_FACTION_CONTROLLING, uint32(urand(1, 2)));
+
+ // Set defender team
+ SetDefenderTeam(TeamId(sWorld->getWorldState(WS_BATTLEFIELD_TB_FACTION_CONTROLLING) - 1));
+
+ // Just to save world states
+ SendInitWorldStatesToAll();
+
+ // Create capture points
+ for (uint8 i = 0; i < TB_BASE_COUNT; i++)
+ {
+ TolBaradCapturePoint* capturePoint = new TolBaradCapturePoint(this, GetDefenderTeam());
+
+ //Spawn flag pole
+ if (GameObject* go = SpawnGameObject(TBCapturePoints[i].entryFlagPole[GetDefenderTeam()], TBCapturePoints[i].pos, QuaternionData::fromEulerAnglesZYX(TBCapturePoints[i].pos.GetOrientation(), 0.0f, 0.0f)))
+ {
+ go->SetGoArtKit(GetDefenderTeam() == TEAM_ALLIANCE ? TB_GO_ARTKIT_FLAG_ALLIANCE : TB_GO_ARTKIT_FLAG_HORDE);
+ capturePoint->SetCapturePointData(go);
+ }
+ AddCapturePoint(capturePoint);
+ }
+
+ // Spawn towers
+ for (uint8 i = 0; i < TB_TOWERS_COUNT; i++)
+ if (GameObject* go = SpawnGameObject(TBTowers[i].entry, TBTowers[i].pos, QuaternionData::fromEulerAnglesZYX(TBTowers[i].pos.GetOrientation(), 0.0f, 0.0f)))
+ Towers.insert(go->GetGUID());
+
+ // Init Graveyards
+ SetGraveyardNumber(BATTLEFIELD_TB_GRAVEYARD_MAX);
+
+ // Graveyards
+ for (uint8 i = 0; i < BATTLEFIELD_TB_GRAVEYARD_MAX; i++)
+ {
+ BfGraveyard* graveyard = new BfGraveyard(this);
+
+ // When between games, the graveyard is controlled by the defending team
+ graveyard->Initialize(GetDefenderTeam(), TBGraveyards[i].gyid);
+
+ // Spawn spirits
+ for (uint8 team = 0; team < 2; team++)
+ if (Creature* creature = SpawnCreature(TBGraveyards[i].spiritEntry[team], TBGraveyards[i].pos))
+ graveyard->SetSpirit(creature, TeamId(team));
+
+ m_GraveyardList[i] = graveyard;
+ }
+
+ // Time warning vars
+ warnedFiveMinutes = false;
+ warnedTwoMinutes = false;
+ warnedOneMinute = false;
+
+ UpdateNPCsAndGameObjects();
+
+ return true;
+}
+
+bool BattlefieldTB::Update(uint32 diff)
+{
+ bool m_return = Battlefield::Update(diff);
+
+ // Minutes till battle preparation warnings
+ if (GetState() == BATTLEFIELD_INACTIVE)
+ {
+ if (m_Timer <= 5 * MINUTE * IN_MILLISECONDS + m_StartGroupingTimer && !warnedFiveMinutes)
+ {
+ warnedFiveMinutes = true;
+ SendWarning(TB_TEXT_PREPARATIONS_IN_5_MIN);
+ }
+
+ if (m_Timer <= 2 * MINUTE * IN_MILLISECONDS + m_StartGroupingTimer && !warnedTwoMinutes)
+ {
+ warnedTwoMinutes = true;
+ SendWarning(TB_TEXT_PREPARATIONS_IN_2_MIN);
+ }
+
+ if (m_Timer <= 1 * MINUTE * IN_MILLISECONDS + m_StartGroupingTimer && !warnedOneMinute)
+ {
+ warnedOneMinute = true;
+ SendWarning(TB_TEXT_PREPARATIONS_IN_1_MIN);
+ }
+ }
+
+ if (!updatedNPCAndObjects)
+ {
+ if (m_updateObjectsTimer <= diff)
+ {
+ UpdateNPCsAndGameObjects();
+ updatedNPCAndObjects = true;
+ }
+ else
+ m_updateObjectsTimer -= diff;
+ }
+
+ if (m_saveTimer <= diff)
+ {
+ if (!IsWarTime())
+ sWorld->setWorldState(WS_BATTLEFIELD_TB_TIME_NEXT_BATTLE, m_Timer);
+ m_saveTimer = 60 * IN_MILLISECONDS;
+ }
+ else
+ m_saveTimer -= diff;
+
+ return m_return;
+}
+
+void BattlefieldTB::OnPlayerEnterZone(Player* player)
+{
+ if (!m_isActive)
+ RemoveAurasFromPlayer(player);
+
+ SendInitWorldStatesTo(player);
+}
+
+void BattlefieldTB::OnPlayerLeaveZone(Player* player)
+{
+ if (!m_isActive)
+ RemoveAurasFromPlayer(player);
+}
+
+void BattlefieldTB::OnPlayerJoinWar(Player* player)
+{
+ RemoveAurasFromPlayer(player);
+
+ player->SetPvP(true);
+
+ // Bonus damage buff for attackers
+ if (player->GetTeamId() == GetAttackerTeam() && GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED) > 0)
+ player->CastSpell(player, SPELL_TOWER_ATTACK_BONUS, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellMod(SPELLVALUE_AURA_STACK, GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED)));
+}
+
+
+void BattlefieldTB::OnPlayerLeaveWar(Player* player)
+{
+ RemoveAurasFromPlayer(player);
+}
+
+void BattlefieldTB::RemoveAurasFromPlayer(Player* player)
+{
+ player->RemoveAurasDueToSpell(SPELL_TB_SLOW_FALL);
+ player->RemoveAurasDueToSpell(SPELL_TB_VETERAN);
+ player->RemoveAurasDueToSpell(SPELL_TOWER_ATTACK_BONUS);
+ player->RemoveAurasDueToSpell(SPELL_TB_SPIRITUAL_IMMUNITY);
+}
+
+// 62 fields, [7]-[68]
+void BattlefieldTB::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
+{
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_ALLIANCE_ATTACKING_SHOW), int32(IsWarTime() && GetAttackerTeam() == TEAM_ALLIANCE ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_HORDE_ATTACKING_SHOW), int32(IsWarTime() && GetAttackerTeam() == TEAM_HORDE ? 1 : 0));
+
+ // Not sure if TB
+ //packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_9_UNKNOWN), int32(1));
+
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_SOUTH_DAMAGED_NEUTRAL), int32(0));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_SOUTH_INTACT_NEUTRAL), int32(0));
+
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_PROGRESS_SHOW), int32(0));
+
+ // Buildings/bases
+ for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
+ {
+ uint8 i = TB_BASE_COUNT;
+ switch (itr->second->GetCapturePointEntry())
+ {
+ case GO_CAPTURE_POINT_NORTH_A_DEFENDING:
+ case GO_CAPTURE_POINT_NORTH_H_DEFENDING:
+ i = TB_BASE_IRONCLAD_GARRISON;
+ break;
+ case GO_CAPTURE_POINT_EAST_A_DEFENDING:
+ case GO_CAPTURE_POINT_EAST_H_DEFENDING:
+ i = TB_BASE_SLAGWORKS;
+ break;
+ case GO_CAPTURE_POINT_WEST_A_DEFENDING:
+ case GO_CAPTURE_POINT_WEST_H_DEFENDING:
+ i = TB_BASE_WARDENS_VIGIL;
+ break;
+ default:
+ continue;
+ }
+
+ TeamId team = TEAM_NEUTRAL;
+ bool controlled = false;
+ bool capturing = false;
+
+ switch (itr->second->GetObjectiveState())
+ {
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE:
+ controlled = true;
+ team = itr->second->GetTeamId();
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE:
+ team = TEAM_ALLIANCE;
+ capturing = true;
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE:
+ team = TEAM_HORDE;
+ capturing = true;
+ break;
+ default:
+ team = TEAM_NEUTRAL;
+ break;
+ }
+
+ packet.Worldstates.emplace_back(uint32(TBCapturePoints[i].wsControlled[TEAM_ALLIANCE]), int32(team == TEAM_ALLIANCE && controlled ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBCapturePoints[i].wsCapturing[TEAM_ALLIANCE]), int32(team == TEAM_ALLIANCE && capturing ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBCapturePoints[i].wsNeutral), int32(team == TEAM_NEUTRAL ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBCapturePoints[i].wsCapturing[TEAM_HORDE]), int32(team == TEAM_HORDE && capturing ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBCapturePoints[i].wsControlled[TEAM_HORDE]), int32(team == TEAM_HORDE && controlled ? 1 : 0));
+ }
+
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_TOWERS_DESTROYED_SHOW), int32(GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED)));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_BUILDINGS_CAPTURED_SHOW), int32(IsWarTime() ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_BUILDINGS_CAPTURED), int32(GetData(BATTLEFIELD_TB_DATA_BUILDINGS_CAPTURED)));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_TOWERS_DESTROYED), int32(0));
+
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_TIME_BATTLE_END_SHOW), int32(IsWarTime() ? 1 : 0));
+
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_STATE_BATTLE), int32(IsWarTime() ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_STATE_PREPARATIONS), int32(GetState() == BATTLEFIELD_WARMUP ? 1 : 0));
+
+ // Not sure if TB
+ //packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_35_UNKNOWN), int32(0));
+ //packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_36_UNKNOWN), int32(0));
+ //packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_37_UNKNOWN), int32(0));
+
+ // Unused tower icons
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_WEST_DAMAGED_NEUTRAL), int32(0));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_WEST_INTACT_NEUTRAL), int32(0));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_EAST_DAMAGED_NEUTRAL), int32(0));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_EAST_INTACT_NEUTRAL), int32(0));
+
+ // Towers/spires
+ for (uint8 i = 0; i < TB_TOWERS_COUNT; i++)
+ {
+ // Find gameobject
+ for (ObjectGuid guid : Towers)
+ {
+ GameObject* tower = GetGameObject(guid);
+ if (!tower || tower->GetEntry() != TBTowers[i].entry)
+ continue;
+
+ TeamId team = GetDefenderTeam(); // 0-false -> alliance; 1-true -> horde
+ bool intact = tower->GetDestructibleState() == GO_DESTRUCTIBLE_INTACT;
+ bool damaged = tower->GetDestructibleState() == GO_DESTRUCTIBLE_DAMAGED;
+ bool destroyed = tower->GetDestructibleState() == GO_DESTRUCTIBLE_DESTROYED;
+
+ packet.Worldstates.emplace_back(uint32(TBTowers[i].wsIntact[TEAM_ALLIANCE]), int32(!team && intact ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBTowers[i].wsDamaged[TEAM_ALLIANCE]), int32(!team && damaged ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBTowers[i].wsDestroyed), int32(destroyed ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBTowers[i].wsDamaged[TEAM_HORDE]), int32(team && damaged ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(TBTowers[i].wsIntact[TEAM_HORDE]), int32(team && intact ? 1 : 0));
+ }
+ }
+
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_TIME_NEXT_BATTLE_SHOW), int32(!IsWarTime() ? 1 : 0));
+
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_ALLIANCE_CONTROLS_SHOW), int32(!IsWarTime() && GetDefenderTeam() == TEAM_ALLIANCE ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_HORDE_CONTROLS_SHOW), int32(!IsWarTime() && GetDefenderTeam() == TEAM_HORDE ? 1 : 0));
+
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_TIME_BATTLE_END), int32(IsWarTime() ? GameTime::GetGameTime() + (m_Timer / 1000) : 0));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_TIME_NEXT_BATTLE), int32(!IsWarTime() ? GameTime::GetGameTime() + (m_Timer / 1000) : 0));
+
+ // Not sure if TB
+ //packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_65_UNKNOWN), int32(0));
+ //packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_66_UNKNOWN), int32(0));
+
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_KEEP_ALLIANCE), int32(GetDefenderTeam() == TEAM_ALLIANCE ? 1 : 0));
+ packet.Worldstates.emplace_back(uint32(WS_BATTLEFIELD_TB_KEEP_HORDE), int32(GetDefenderTeam() == TEAM_HORDE ? 1 : 0));
+}
+
+void BattlefieldTB::SendInitWorldStatesTo(Player* player)
+{
+ WorldPackets::WorldState::InitWorldStates packet;
+ packet.AreaID = m_ZoneId;
+ packet.MapID = m_MapId;
+ packet.SubareaID = 0;
+
+ FillInitialWorldStates(packet);
+
+ player->SendDirectMessage(packet.Write());
+}
+
+void BattlefieldTB::SendInitWorldStatesToAll()
+{
+ // Save
+ sWorld->setWorldState(WS_BATTLEFIELD_TB_STATE_BATTLE, uint32(IsWarTime() ? 1 : 0));
+ sWorld->setWorldState(WS_BATTLEFIELD_TB_ALLIANCE_CONTROLS_SHOW, uint32(!IsWarTime() && GetDefenderTeam() == TEAM_ALLIANCE ? 1 : 0));
+ sWorld->setWorldState(WS_BATTLEFIELD_TB_HORDE_CONTROLS_SHOW, uint32(!IsWarTime() && GetDefenderTeam() == TEAM_HORDE ? 1 : 0));
+ sWorld->setWorldState(WS_BATTLEFIELD_TB_ALLIANCE_ATTACKING_SHOW, uint32(IsWarTime() && GetAttackerTeam() == TEAM_ALLIANCE ? 1 : 0));
+ sWorld->setWorldState(WS_BATTLEFIELD_TB_HORDE_ATTACKING_SHOW, uint32(IsWarTime() && GetAttackerTeam() == TEAM_HORDE ? 1 : 0));
+ sWorld->setWorldState(WS_BATTLEFIELD_TB_TIME_NEXT_BATTLE, uint32(!IsWarTime() ? m_Timer : 0));
+ sWorld->setWorldState(WS_BATTLEFIELD_TB_TIME_NEXT_BATTLE_SHOW, uint32(!IsWarTime() ? 1 : 0));
+
+ // Tol Barad
+ for (uint8 team = 0; team < PVP_TEAMS_COUNT; team++)
+ for (ObjectGuid const& guid : m_players[team])
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ SendInitWorldStatesTo(player);
+
+ // Tol Barad Peninsula
+ Map::PlayerList const& players = m_Map->GetPlayers();
+ for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ if (Player* player = itr->GetSource()->ToPlayer())
+ if (player->GetZoneId() == 5389) // ZONE_TOL_BARAD_PENINSULA
+ player->SendInitWorldStates(5389, player->GetAreaId());
+}
+
+void BattlefieldTB::OnStartGrouping()
+{
+ UpdateNPCsAndGameObjects();
+
+ SendUpdateWorldState(WS_BATTLEFIELD_TB_STATE_PREPARATIONS, uint32(1));
+
+ // Teleport players out of questing area
+ for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
+ for (ObjectGuid const& guid : m_players[team])
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ if (player->GetAreaId() == TBQuestAreas[m_iCellblockRandom].entry)
+ player->CastSpell(player, TBQuestAreas[m_iCellblockRandom].teleportSpell, true);
+
+ // Should we also teleport players out of Baradin Hold underground area?
+};
+
+void BattlefieldTB::OnBattleStart()
+{
+ SetData(BATTLEFIELD_TB_DATA_BUILDINGS_CAPTURED, uint32(0));
+ SetData(BATTLEFIELD_TB_DATA_TOWERS_INTACT, uint32(3));
+ SetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED, uint32(0));
+
+ UpdateNPCsAndGameObjects();
+
+ SendInitWorldStatesToAll();
+};
+
+void BattlefieldTB::OnBattleEnd(bool endByTimer)
+{
+ if (!endByTimer) // Attackers win (but now they are defenders already)
+ SendWarning(GetDefenderTeam() == TEAM_ALLIANCE ? TB_TEXT_FORTRESS_CAPTURE_ALLIANCE : TB_TEXT_FORTRESS_CAPTURE_HORDE);
+ else // Defenders win
+ SendWarning(GetDefenderTeam() == TEAM_ALLIANCE ? TB_TEXT_FORTRESS_DEFEND_ALLIANCE : TB_TEXT_FORTRESS_DEFEND_HORDE);
+
+ // UpdateNPCsAndGameObjects() must be called 1 minute after battle ends
+ m_updateObjectsTimer = 1 * MINUTE * IN_MILLISECONDS;
+ updatedNPCAndObjects = false;
+
+ // Complete quest
+ TeamCastSpell(GetDefenderTeam(), GetDefenderTeam() == TEAM_ALLIANCE ? SPELL_VICTORY_ALLIANCE : SPELL_VICTORY_HORDE);
+
+ // Rewards
+ TeamCastSpell(GetDefenderTeam(), GetDefenderTeam() == TEAM_ALLIANCE ? SPELL_REWARD_VICTORY_ALLIANCE : SPELL_REWARD_VICTORY_HORDE);
+ for (uint32 i = 0; i < GetData(BATTLEFIELD_TB_DATA_TOWERS_INTACT); i++) // Unsure, for each intact tower or only once for having any tower intact?
+ TeamCastSpell(GetDefenderTeam(), SPELL_REWARD_TOWER_INTACT);
+ TeamCastSpell(GetAttackerTeam(), SPELL_REWARD_DEFEAT);
+
+ for (uint8 team = 0; team < 2; ++team)
+ {
+ for (ObjectGuid const& guid : m_PlayersInWar[team])
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ RemoveAurasFromPlayer(player);
+
+ m_PlayersInWar[team].clear();
+ }
+
+ // Reset time warning vars
+ warnedFiveMinutes = false;
+ warnedTwoMinutes = false;
+ warnedOneMinute = false;
+};
+
+void BattlefieldTB::UpdateNPCsAndGameObjects()
+{
+ for (ObjectGuid guid : BattleInactiveNPCs)
+ if (Creature* creature = GetCreature(guid))
+ HideNpc(creature);
+
+ for (ObjectGuid guid : BattleInactiveGOs)
+ if (GameObject* gameobject = GetGameObject(guid))
+ gameobject->SetRespawnTime(RESPAWN_ONE_DAY);
+
+ for (ObjectGuid guid : TemporaryNPCs)
+ if (Creature* creature = GetCreature(guid))
+ creature->RemoveFromWorld();
+ TemporaryNPCs.clear();
+
+ for (ObjectGuid guid : TemporaryGOs)
+ if (GameObject* gameobject = GetGameObject(guid))
+ gameobject->Delete();
+ TemporaryGOs.clear();
+
+ // Tol Barad gates - closed during warmup
+ if (GameObject* gates = GetGameObject(TBGatesGUID))
+ gates->SetGoState(GetState() == BATTLEFIELD_WARMUP ? GO_STATE_READY : GO_STATE_ACTIVE);
+
+ // Baradin Hold door - open when inactive
+ if (GameObject* door = GetGameObject(TBDoorGUID))
+ door->SetGoState(GetState() == BATTLEFIELD_INACTIVE ? GO_STATE_ACTIVE : GO_STATE_READY);
+
+ // Decide which cellblock and questgiver will be active.
+ m_iCellblockRandom = GetState() == BATTLEFIELD_INACTIVE ? urand(CELLBLOCK_THE_HOLE, CELLBLOCK_CURSED_DEPTHS) : uint8(CELLBLOCK_NONE);
+
+ // To The Hole gate
+ if (GameObject* door = GetGameObject(m_gateToTheHoleGUID))
+ door->SetGoState(m_iCellblockRandom == CELLBLOCK_THE_HOLE ? GO_STATE_ACTIVE : GO_STATE_READY);
+
+ // D-Block gate
+ if (GameObject* door = GetGameObject(m_gateDBlockGUID))
+ door->SetGoState(m_iCellblockRandom == CELLBLOCK_D_BLOCK ? GO_STATE_ACTIVE : GO_STATE_READY);
+
+ // Cursed Depths gate
+ if (GameObject* door = GetGameObject(m_gateCursedDepthsGUID))
+ door->SetGoState(m_iCellblockRandom == CELLBLOCK_CURSED_DEPTHS ? GO_STATE_ACTIVE : GO_STATE_READY);
+
+ if (GetState() == BATTLEFIELD_INACTIVE)
+ {
+ // Delete capture points
+ for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
+ itr->second->DelCapturePoint();
+ m_capturePoints.clear();
+
+ // Create capture points
+ for (uint8 i = 0; i < TB_BASE_COUNT; i++)
+ {
+ TolBaradCapturePoint* capturePoint = new TolBaradCapturePoint(this, GetDefenderTeam());
+
+ //Spawn flag pole
+ if (GameObject* go = SpawnGameObject(TBCapturePoints[i].entryFlagPole[GetDefenderTeam()], TBCapturePoints[i].pos, QuaternionData::fromEulerAnglesZYX(TBCapturePoints[i].pos.GetOrientation(), 0.0f, 0.0f)))
+ {
+ go->SetGoArtKit(GetDefenderTeam() == TEAM_ALLIANCE ? TB_GO_ARTKIT_FLAG_ALLIANCE : TB_GO_ARTKIT_FLAG_HORDE);
+ capturePoint->SetCapturePointData(go);
+ }
+
+ AddCapturePoint(capturePoint);
+ }
+
+ for (ObjectGuid guid : BattleInactiveNPCs)
+ if (Creature* creature = GetCreature(guid))
+ ShowNpc(creature, true);
+
+ for (ObjectGuid guid : BattleInactiveGOs)
+ if (GameObject* gameobject = GetGameObject(guid))
+ gameobject->SetRespawnTime(RESPAWN_IMMEDIATELY);
+
+ for (uint8 i = 0; i < TB_QUEST_INFANTRY_MAX; i++)
+ {
+ uint32 entry = TB_QUEST_INFANTRY[GetDefenderTeam()][urand(0,3)];
+ if (Creature* creature = SpawnCreature(entry, TBQuestInfantrySpawnData[i]))
+ TemporaryNPCs.insert(creature->GetGUID());
+ }
+
+ for (uint8 i = 0; i < TB_GUARDS_MAX; i++)
+ if (Creature* creature = SpawnCreature(GetDefenderTeam() == TEAM_ALLIANCE ? NPC_BARADIN_GUARD : NPC_HELLSCREAMS_SENTRY, GuardNPCSpawns[i]))
+ TemporaryNPCs.insert(creature->GetGUID());
+
+ for (uint8 i = 0; i < TB_FACTION_NPC_MAX; i++)
+ if (Creature* creature = SpawnCreature(GetDefenderTeam() == TEAM_ALLIANCE ? FactionNPCSpawns[i].entryAlliance : FactionNPCSpawns[i].entryHorde, FactionNPCSpawns[i].pos))
+ TemporaryNPCs.insert(creature->GetGUID());
+
+ if (Creature* creature = SpawnCreature(RandomQuestgivers[GetDefenderTeam()][m_iCellblockRandom], RandomQuestgiverPos))
+ TemporaryNPCs.insert(creature->GetGUID());
+
+ // Spawn portals
+ for (uint8 i = 0; i < TB_PORTAL_MAX; i++)
+ if (GameObject* go = SpawnGameObject(TBPortalEntry[GetDefenderTeam()], TBPortals[i], QuaternionData::fromEulerAnglesZYX(TBPortals[i].GetOrientation(), 0.0f, 0.0f)))
+ TemporaryGOs.insert(go->GetGUID());
+
+ // Update towers
+ for (ObjectGuid guid : Towers)
+ if (GameObject* go = GetGameObject(guid))
+ go->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING);
+ }
+ else if (GetState() == BATTLEFIELD_IN_PROGRESS)
+ {
+ for (uint8 i = 0; i < TB_ABANDONED_SIEGE_ENGINE_COUNT; i++)
+ if (Creature* creature = SpawnCreature(NPC_ABANDONED_SIEGE_ENGINE, TBAbandonedSiegeEngineSpawnData[i]))
+ TemporaryNPCs.insert(creature->GetGUID());
+
+ for (ObjectGuid guid : Towers)
+ {
+ if (GameObject* go = GetGameObject(guid))
+ {
+ go->SetDestructibleState(GO_DESTRUCTIBLE_INTACT);
+ go->ModifyHealth(go->GetGOValue()->Building.MaxHealth);
+ }
+ }
+ }
+
+ // Spawn banners
+ for (uint8 i = 0; i < TB_BANNER_MAX; i++)
+ if (GameObject* go = SpawnGameObject(TBBannerEntry[GetDefenderTeam()], TBBanners[i], QuaternionData::fromEulerAnglesZYX(TBBanners[i].GetOrientation(), 0.0f, 0.0f)))
+ TemporaryGOs.insert(go->GetGUID());
+
+ // Set graveyard controls
+ for (uint8 i = 0; i < BATTLEFIELD_TB_GRAVEYARD_MAX; i++)
+ if (BfGraveyard* graveyard = GetGraveyardById(i))
+ graveyard->GiveControlTo(!IsWarTime() || TBGraveyards[i].defenderControls ? GetDefenderTeam() : GetAttackerTeam());
+};
+
+void BattlefieldTB::OnCreatureCreate(Creature* creature)
+{
+ switch (creature->GetEntry())
+ {
+ // Store NPCs that need visibility toggling
+ case NPC_TOLBARAD_CAPTIVE_SPIRIT:
+ case NPC_TOLBARAD_CELLBLOCK_OOZE:
+ case NPC_TOLBARAD_ARCHMAGE_GALUS:
+ case NPC_TOLBARAD_GHASTLY_CONVICT:
+ case NPC_TOLBARAD_SHIVARRA_DESTROYER:
+ case NPC_TOLBARAD_CELL_WATCHER:
+ case NPC_TOLBARAD_SVARNOS:
+ case NPC_TOLBARAD_JAILED_WRATHGUARD:
+ case NPC_TOLBARAD_IMPRISONED_IMP:
+ case NPC_TOLBARAD_WARDEN_SILVA:
+ case NPC_TOLBARAD_WARDEN_GUARD:
+ case NPC_TOLBARAD_IMPRISONED_WORKER:
+ case NPC_TOLBARAD_EXILED_MAGE:
+ case NPC_CROCOLISK:
+ case NPC_PROBLIM:
+ BattleInactiveNPCs.insert(creature->GetGUID());
+ if (GetState() == BATTLEFIELD_WARMUP) // If battle is about to start, we must hide these.
+ HideNpc(creature);
+ break;
+ case NPC_ABANDONED_SIEGE_ENGINE:
+ creature->SetFaction(TBFactions[GetDefenderTeam()]);
+ creature->CastSpell(creature, SPELL_THICK_LAYER_OF_RUST, true);
+ break;
+ case NPC_SIEGE_ENGINE_TURRET:
+ if (Unit* vehiclebase = creature->GetCharmerOrOwner()->GetVehicleBase())
+ creature->EnterVehicle(vehiclebase);
+ break;
+ case NPC_TOWER_RANGE_FINDER:
+ creature->CastSpell(creature, SPELL_TOWER_RANGE_FINDER_PERIODIC, true);
+ break;
+ case NPC_TB_GY_SPIRIT_BARADIN_HOLD_A:
+ case NPC_TB_GY_SPIRIT_BARADIN_HOLD_H:
+ case NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_A:
+ case NPC_TB_GY_SPIRIT_WARDENS_VIGIL_A:
+ case NPC_TB_GY_SPIRIT_EAST_SPIRE_A:
+ case NPC_TB_GY_SPIRIT_SOUTH_SPIRE_A:
+ case NPC_TB_GY_SPIRIT_WEST_SPIRE_A:
+ case NPC_TB_GY_SPIRIT_SLAGWORKS_A:
+ case NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_H:
+ case NPC_TB_GY_SPIRIT_WARDENS_VIGIL_H:
+ case NPC_TB_GY_SPIRIT_SLAGWORKS_H:
+ case NPC_TB_GY_SPIRIT_WEST_SPIRE_H:
+ case NPC_TB_GY_SPIRIT_EAST_SPIRE_H:
+ case NPC_TB_GY_SPIRIT_SOUTH_SPIRE_H:
+ creature->CastSpell(creature, SPELL_TB_SPIRITUAL_IMMUNITY, true);
+ creature->CastSpell(creature, SPELL_TB_SPIRIT_HEAL_CHANNEL, true);
+ break;
+ default:
+ break;
+ }
+};
+
+void BattlefieldTB::OnGameObjectCreate(GameObject* go)
+{
+ switch (go->GetEntry())
+ {
+ case GO_TOLBARAD_GATES:
+ TBGatesGUID = go->GetGUID();
+ go->SetGoState(GetState() == BATTLEFIELD_WARMUP ? GO_STATE_READY : GO_STATE_ACTIVE);
+ break;
+ case GO_TOLBARAD_DOOR:
+ TBDoorGUID = go->GetGUID();
+ go->SetGoState(GetState() == BATTLEFIELD_INACTIVE ? GO_STATE_ACTIVE : GO_STATE_READY);
+ break;
+ case GO_GATE_TO_THE_HOLE:
+ m_gateToTheHoleGUID = go->GetGUID();
+ go->SetGoState(m_iCellblockRandom == CELLBLOCK_THE_HOLE ? GO_STATE_ACTIVE : GO_STATE_READY);
+ break;
+ case GO_GATE_D_BLOCK:
+ m_gateDBlockGUID = go->GetGUID();
+ go->SetGoState(m_iCellblockRandom == CELLBLOCK_D_BLOCK ? GO_STATE_ACTIVE : GO_STATE_READY);
+ break;
+ case GO_CURSED_DEPTHS_GATE:
+ m_gateCursedDepthsGUID = go->GetGUID();
+ go->SetGoState(m_iCellblockRandom == CELLBLOCK_CURSED_DEPTHS ? GO_STATE_ACTIVE : GO_STATE_READY);
+ break;
+ case GO_CRATE_OF_CELLBLOCK_RATIONS:
+ case GO_CURSED_SHACKLES:
+ case GO_DUSTY_PRISON_JOURNAL:
+ case GO_TB_MEETING_STONE:
+ case GO_TB_INSTANCE_VISUAL_1:
+ case GO_TB_INSTANCE_VISUAL_2:
+ case GO_TB_INSTANCE_VISUAL_3:
+ case GO_TB_INSTANCE_VISUAL_4:
+ BattleInactiveGOs.insert(go->GetGUID());
+ if (GetState() == BATTLEFIELD_WARMUP) // If battle is about to start, we must hide these.
+ go->SetRespawnTime(RESPAWN_ONE_DAY);
+ break;
+ default:
+ break;
+ }
+};
+
+void BattlefieldTB::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* /*invoker*/)
+{
+ if (!IsWarTime())
+ return;
+
+ if (eventId == EVENT_COUNT_CAPTURED_BASE)
+ {
+ UpdateCapturedBaseCount();
+ return;
+ }
+
+ if (!obj)
+ return;
+
+ GameObject* go = obj->ToGameObject();
+ if (!go)
+ return;
+
+ TBTowerId towerId;
+ switch (go->GetEntry())
+ {
+ case GO_WEST_SPIRE:
+ towerId = TB_TOWER_WEST_SPIRE;
+ break;
+ case GO_EAST_SPIRE:
+ towerId = TB_TOWER_EAST_SPIRE;
+ break;
+ case GO_SOUTH_SPIRE:
+ towerId = TB_TOWER_SOUTH_SPIRE;
+ break;
+ default:
+ return;
+ }
+
+ if (go->GetDestructibleState() == GO_DESTRUCTIBLE_DAMAGED)
+ TowerDamaged(towerId);
+ else if (go->GetDestructibleState() == GO_DESTRUCTIBLE_DESTROYED)
+ TowerDestroyed(towerId);
+}
+
+void BattlefieldTB::TowerDamaged(TBTowerId tbTowerId)
+{
+ if (!IsWarTime())
+ return;
+
+ SendWarning(TBTowers[tbTowerId].textDamaged);
+
+ SetData(BATTLEFIELD_TB_DATA_TOWERS_INTACT, GetData(BATTLEFIELD_TB_DATA_TOWERS_INTACT) - 1);
+
+ SendUpdateWorldState(uint32(TBTowers[tbTowerId].wsIntact[GetDefenderTeam()]), int32(0));
+ SendUpdateWorldState(uint32(TBTowers[tbTowerId].wsDamaged[GetDefenderTeam()]), int32(1));
+
+ TeamCastSpell(GetAttackerTeam(), SPELL_REWARD_TOWER_DAMAGED);
+}
+
+void BattlefieldTB::TowerDestroyed(TBTowerId tbTowerId)
+{
+ if (!IsWarTime())
+ return;
+
+ // Add 5 minute bonus time
+ m_Timer += m_BonusTime;
+
+ SendUpdateWorldState(WS_BATTLEFIELD_TB_TIME_BATTLE_END, uint32(GameTime::GetGameTime() + (m_Timer / 1000)));
+
+ SendWarning(TBTowers[tbTowerId].textDamaged);
+
+ SetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED, GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED) + 1);
+ SendUpdateWorldState(uint32(WS_BATTLEFIELD_TB_TOWERS_DESTROYED), int32(GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED)));
+
+ SendUpdateWorldState(uint32(TBTowers[tbTowerId].wsDamaged[GetDefenderTeam()]), int32(0));
+ SendUpdateWorldState(uint32(TBTowers[tbTowerId].wsDestroyed), int32(1));
+
+ // Attack bonus buff
+ for (ObjectGuid const& guid : m_PlayersInWar[GetAttackerTeam()])
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ player->CastSpell(player, SPELL_TOWER_ATTACK_BONUS, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellMod(SPELLVALUE_AURA_STACK, GetData(BATTLEFIELD_TB_DATA_TOWERS_DESTROYED)));
+
+ // Honor reward
+ TeamCastSpell(GetAttackerTeam(), SPELL_REWARD_TOWER_DESTROYED);
+}
+
+void BattlefieldTB::UpdateCapturedBaseCount()
+{
+ uint32 numCapturedBases = 0; // How many bases attacker has captured
+
+ for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
+ if (itr->second->GetTeamId() == GetAttackerTeam())
+ numCapturedBases += 1;
+
+ SetData(BATTLEFIELD_TB_DATA_BUILDINGS_CAPTURED, numCapturedBases);
+ SendUpdateWorldState(WS_BATTLEFIELD_TB_BUILDINGS_CAPTURED, uint32(numCapturedBases));
+
+ // Check if attackers won
+ if (numCapturedBases == TB_BASE_COUNT)
+ EndBattle(false);
+}
+
+// Called when player kill a unit in wg zone
+void BattlefieldTB::HandleKill(Player* killer, Unit* victim)
+{
+ if (killer == victim || victim->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ TeamId killerTeam = killer->GetTeamId();
+ for (ObjectGuid const& guid : m_PlayersInWar[killerTeam])
+ if (Player* player = ObjectAccessor::FindPlayer(guid))
+ if (player->GetDistance2d(killer) < 40.0f)
+ PromotePlayer(player);
+}
+
+void BattlefieldTB::PromotePlayer(Player* killer)
+{
+ if (!m_isActive || killer->HasAura(SPELL_TB_VETERAN))
+ return;
+
+ killer->CastSpell(killer, SPELL_TB_VETERAN, true);
+}
+
+TolBaradCapturePoint::TolBaradCapturePoint(BattlefieldTB* battlefield, TeamId teamInControl) : BfCapturePoint(battlefield)
+{
+ m_Bf = battlefield;
+ m_team = teamInControl;
+ m_value = teamInControl == TEAM_ALLIANCE ? m_maxValue : -m_maxValue;
+ m_State = teamInControl == TEAM_ALLIANCE ? BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE : BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE;
+}
+
+void TolBaradCapturePoint::ChangeTeam(TeamId /*oldTeam*/)
+{
+ // Find out index
+ uint8 iBase = TB_BASE_COUNT;
+ for (uint8 i = 0; i < TB_BASE_COUNT; i++)
+ if (GetCapturePointEntry() == TBCapturePoints[i].entryFlagPole[m_Bf->GetDefenderTeam()])
+ iBase = i;
+
+ if (iBase == TB_BASE_COUNT)
+ return;
+
+ // Turn off previous world state icon
+ switch (m_OldState)
+ {
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE:
+ SendUpdateWorldState(TBCapturePoints[iBase].wsControlled[GetTeamId()], uint32(0));
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE:
+ SendUpdateWorldState(TBCapturePoints[iBase].wsCapturing[TEAM_ALLIANCE], uint32(0));
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE:
+ SendUpdateWorldState(TBCapturePoints[iBase].wsCapturing[TEAM_HORDE], uint32(0));
+ break;
+ default:
+ break;
+ }
+
+ // Turn on new world state icon and send warning
+ switch (m_State)
+ {
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE:
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE:
+ m_Bf->SendWarning(TBCapturePoints[iBase].textGained[GetTeamId()]);
+ SendUpdateWorldState(TBCapturePoints[iBase].wsControlled[GetTeamId()], uint32(1));
+ GetCapturePointGo()->SetGoArtKit(GetTeamId() == TEAM_ALLIANCE ? TB_GO_ARTKIT_FLAG_ALLIANCE : TB_GO_ARTKIT_FLAG_HORDE);
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE:
+ m_Bf->SendWarning(TBCapturePoints[iBase].textLost[TEAM_HORDE]);
+ /* fallthrough */
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE:
+ SendUpdateWorldState(TBCapturePoints[iBase].wsCapturing[TEAM_ALLIANCE], uint32(1));
+ GetCapturePointGo()->SetGoArtKit(TB_GO_ARTKIT_FLAG_NONE);
+ break;
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE:
+ m_Bf->SendWarning(TBCapturePoints[iBase].textLost[TEAM_ALLIANCE]);
+ /* fallthrough */
+ case BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE:
+ SendUpdateWorldState(TBCapturePoints[iBase].wsCapturing[TEAM_HORDE], uint32(1));
+ GetCapturePointGo()->SetGoArtKit(TB_GO_ARTKIT_FLAG_NONE);
+ break;
+ default:
+ break;
+ }
+
+ // Update counter
+ m_Bf->ProcessEvent(nullptr, EVENT_COUNT_CAPTURED_BASE, nullptr);
+}
+
+class Battlefield_tol_barad : public BattlefieldScript
+{
+public:
+ Battlefield_tol_barad() : BattlefieldScript("battlefield_tb") { }
+
+ Battlefield* GetBattlefield() const override
+ {
+ return new BattlefieldTB();
+ }
+};
+
+void AddSC_BF_tol_barad()
+{
+ new Battlefield_tol_barad();
+}
diff --git a/src/server/scripts/Battlefield/BattlefieldTB.h b/src/server/scripts/Battlefield/BattlefieldTB.h
new file mode 100644
index 00000000000..e8250d2bb36
--- /dev/null
+++ b/src/server/scripts/Battlefield/BattlefieldTB.h
@@ -0,0 +1,632 @@
+/*
+* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BATTLEFIELD_TB_
+#define BATTLEFIELD_TB_
+
+#include "Battlefield.h"
+
+class BattlefieldTB;
+class TolBaradCapturePoint;
+
+enum TolBaradInfo
+{
+ BATTLEFIELD_TB_MAPID = 732, // Tol Barad
+ BATTLEFIELD_TB_ZONEID = 5095, // Tol Barad
+};
+
+enum TolBaradData
+{
+ BATTLEFIELD_TB_DATA_BUILDINGS_CAPTURED,
+ BATTLEFIELD_TB_DATA_TOWERS_INTACT,
+ BATTLEFIELD_TB_DATA_TOWERS_DESTROYED,
+ BATTLEFIELD_TB_DATA_MAX,
+};
+
+enum TolBaradSpells
+{
+ // Quest completion
+ SPELL_VICTORY_ALLIANCE = 94665,
+ SPELL_VICTORY_HORDE = 94763,
+
+ // Rewards
+ SPELL_REWARD_VICTORY_ALLIANCE = 89789,
+ SPELL_REWARD_VICTORY_HORDE = 89791,
+ SPELL_REWARD_DEFEAT = 89793,
+
+ SPELL_REWARD_TOWER_INTACT = 89794,
+ SPELL_REWARD_TOWER_DAMAGED = 89795,
+ SPELL_REWARD_TOWER_DESTROYED = 89796,
+
+ // Player buffs
+ SPELL_TB_SLOW_FALL = 88473,
+ SPELL_TB_VETERAN = 84655,
+ SPELL_TOWER_ATTACK_BONUS = 82629,
+ SPELL_TB_SPIRIT_HEAL_CHANNEL = 22011, // this spell replaces m_LastResurrectTimer in Battlefield.cpp?
+ SPELL_TB_SPIRITUAL_IMMUNITY = 95332,
+
+ // Vehicle
+ SPELL_THICK_LAYER_OF_RUST = 95330,
+ SPELL_RIDE_TOL_BARAD_VEHICLE = 84754,
+ SPELL_DEPLOY_SIEGE_MODE = 84974,
+ SPELL_SIEGE_CANNON_AURA = 85167, // aura, periodically triggers spell 85122
+// SPELL_SIEGE_CANNON_EFFECT = 85122, // targets random
+// SPELL_SIEGE_CANNON_DAMAGE = 85125,
+ SPELL_LEAVE_SIEGE_MODE = 85078,
+
+ SPELL_TOWER_RANGE_FINDER_PERIODIC = 85671,
+ SPELL_TOWER_RANGE_FINDER = 84979,
+
+ // Teleportation spells
+ SPELL_TB_THE_HOLE_TELEPORT = 89035,
+ SPELL_TB_D_BLOCK_TELEPORT = 89037,
+ SPELL_TB_CURSED_DEPTHS_TELEPORT = 89038,
+};
+
+enum TolBaradNpcs
+{
+ // Cursed Depths area
+ NPC_TOLBARAD_CAPTIVE_SPIRIT = 47531,
+ NPC_TOLBARAD_CELLBLOCK_OOZE = 47534,
+ NPC_TOLBARAD_ARCHMAGE_GALUS = 47537,
+ NPC_TOLBARAD_GHASTLY_CONVICT = 47590,
+
+ // D-Block area
+ NPC_TOLBARAD_SHIVARRA_DESTROYER = 47540,
+ NPC_TOLBARAD_CELL_WATCHER = 47542,
+ NPC_TOLBARAD_SVARNOS = 47544,
+ NPC_TOLBARAD_JAILED_WRATHGUARD = 47548,
+ NPC_TOLBARAD_IMPRISONED_IMP = 47549,
+
+ // The Hole area
+ NPC_TOLBARAD_WARDEN_SILVA = 48036,
+ NPC_TOLBARAD_WARDEN_GUARD = 47561,
+ NPC_TOLBARAD_IMPRISONED_WORKER = 47550,
+ NPC_TOLBARAD_EXILED_MAGE = 47552,
+
+ // Other
+ NPC_CROCOLISK = 47591,
+ NPC_PROBLIM = 47593,
+
+ // Graveyard spirits
+ NPC_TB_GY_SPIRIT_BARADIN_HOLD_A = 45066,
+ NPC_TB_GY_SPIRIT_BARADIN_HOLD_H = 45067,
+ NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_A = 45068,
+ NPC_TB_GY_SPIRIT_WARDENS_VIGIL_A = 45069,
+ NPC_TB_GY_SPIRIT_EAST_SPIRE_A = 45070,
+ NPC_TB_GY_SPIRIT_SOUTH_SPIRE_A = 45071,
+ NPC_TB_GY_SPIRIT_WEST_SPIRE_A = 45072,
+ NPC_TB_GY_SPIRIT_SLAGWORKS_A = 45073,
+ NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_H = 45074,
+ NPC_TB_GY_SPIRIT_WARDENS_VIGIL_H = 45075,
+ NPC_TB_GY_SPIRIT_SLAGWORKS_H = 45076,
+ NPC_TB_GY_SPIRIT_WEST_SPIRE_H = 45077,
+ NPC_TB_GY_SPIRIT_EAST_SPIRE_H = 45078,
+ NPC_TB_GY_SPIRIT_SOUTH_SPIRE_H = 45079,
+
+ // Stalker, dummies
+ NPC_DEBUG_ANNOUNCER = 43679,
+ NPC_TOWER_RANGE_FINDER = 45492,
+ NPC_TOWER_CANNON_TARGET = 45561,
+ NPC_SIEGE_ENGINE_TURRET = 45564,
+};
+
+enum TolBaradGOs
+{
+ // Towers
+ GO_WEST_SPIRE = 204588,
+ GO_EAST_SPIRE = 204589,
+ GO_SOUTH_SPIRE = 204590,
+
+ GO_CAPTURE_POINT_NORTH_A_DEFENDING = 205068,
+ GO_CAPTURE_POINT_NORTH_H_DEFENDING = 205096,
+ GO_CAPTURE_POINT_EAST_A_DEFENDING = 205138,
+ GO_CAPTURE_POINT_EAST_H_DEFENDING = 205139,
+ GO_CAPTURE_POINT_WEST_A_DEFENDING = 205101,
+ GO_CAPTURE_POINT_WEST_H_DEFENDING = 205103,
+
+ // Entrance gates and instance door
+ GO_TOLBARAD_GATES = 206598,
+ GO_TOLBARAD_DOOR = 206576,
+
+ // Other
+ GO_TB_MEETING_STONE = 206668,
+
+ GO_TB_INSTANCE_VISUAL_1 = 207746,
+ GO_TB_INSTANCE_VISUAL_2 = 207747,
+ GO_TB_INSTANCE_VISUAL_3 = 210114,
+ GO_TB_INSTANCE_VISUAL_4 = 210115,
+};
+
+enum TolBaradGOArtKit
+{
+ TB_GO_ARTKIT_FLAG_NONE = 0,
+ TB_GO_ARTKIT_FLAG_HORDE = 1,
+ TB_GO_ARTKIT_FLAG_ALLIANCE = 2,
+};
+
+enum TolBaradText
+{
+ // DEBUG Announcer
+ TB_TEXT_EAST_SPIRE_DAMAGED = 1,
+ TB_TEXT_EAST_SPIRE_DESTROYED = 2,
+ TB_TEXT_WEST_SPIRE_DAMAGED = 3,
+ TB_TEXT_WEST_SPIRE_DESTROYED = 4,
+ TB_TEXT_SOUTH_SPIRE_DAMAGED = 5,
+ TB_TEXT_SOUTH_SPIRE_DESTROYED = 6,
+ TB_TEXT_GARRISON_ALLIANCE_GAINED = 7,
+ TB_TEXT_GARRISON_ALLIANCE_LOST = 8,
+ TB_TEXT_GARRISON_HORDE_GAINED = 9,
+ TB_TEXT_GARRISON_HORDE_LOST = 10,
+ TB_TEXT_VIGIL_ALLIANCE_GAINED = 11,
+ TB_TEXT_VIGIL_ALLIANCE_LOST = 12,
+ TB_TEXT_VIGIL_HORDE_GAINED = 13,
+ TB_TEXT_VIGIL_HORDE_LOST = 14,
+ TB_TEXT_SLAGWORKS_ALLIANCE_GAINED = 15,
+ TB_TEXT_SLAGWORKS_ALLIANCE_LOST = 16,
+ TB_TEXT_SLAGWORKS_HORDE_GAINED = 17,
+ TB_TEXT_SLAGWORKS_HORDE_LOST = 18,
+ TB_TEXT_FORTRESS_DEFEND_ALLIANCE = 19,
+ TB_TEXT_FORTRESS_DEFEND_HORDE = 20,
+ TB_TEXT_FORTRESS_CAPTURE_ALLIANCE = 21,
+ TB_TEXT_FORTRESS_CAPTURE_HORDE = 22,
+ TB_TEXT_VEHICLE_OUTSIDE_WARNING = 23,
+ TB_TEXT_PREPARATIONS_IN_5_MIN = 24,
+ TB_TEXT_PREPARATIONS_IN_2_MIN = 25,
+ TB_TEXT_PREPARATIONS_IN_1_MIN = 26,
+};
+
+enum TolBaradEvent
+{
+ EVENT_COUNT_CAPTURED_BASE = 1,
+};
+
+const uint32 TBFactions[PVP_TEAMS_COUNT] = { 1610, 1732 };
+
+// Stalker
+Position const TolBaradDebugAnnouncerPos = { -1234.25f, 961.903f, 159.4913f, 0.0f };
+
+// Quest Infantry NPCs
+enum TBQuestInfantryEntry
+{
+ NPC_ALLIANCE_WARRIOR_INFANTRY = 47599,
+ NPC_ALLIANCE_PALADIN_INFANTRY = 47600,
+ NPC_ALLIANCE_HUNTER_INFANTRY = 47595,
+ NPC_ALLIANCE_MAGE_INFANTRY = 47598,
+
+ NPC_HORDE_DRUID_INFANTRY = 47607,
+ NPC_HORDE_MAGE_INFANTRY = 47608,
+ NPC_HORDE_ROGUE_INFANTRY = 47609,
+ NPC_HORDE_SHAMAN_INFANTRY = 47610,
+};
+
+uint32 const TB_QUEST_INFANTRY[PVP_TEAMS_COUNT][4] =
+{
+ { NPC_HORDE_DRUID_INFANTRY, NPC_HORDE_MAGE_INFANTRY, NPC_HORDE_ROGUE_INFANTRY, NPC_HORDE_SHAMAN_INFANTRY },
+ { NPC_ALLIANCE_WARRIOR_INFANTRY, NPC_ALLIANCE_PALADIN_INFANTRY, NPC_ALLIANCE_HUNTER_INFANTRY, NPC_ALLIANCE_MAGE_INFANTRY },
+};
+
+uint8 const TB_QUEST_INFANTRY_MAX = 37;
+Position const TBQuestInfantrySpawnData[TB_QUEST_INFANTRY_MAX] =
+{
+ { -930.4685f, 1020.178f, 121.5658f, 0.1537642f },
+ { -831.5157f, 975.816f, 121.5255f, 5.022717f },
+ { -837.0773f, 943.9008f, 121.5055f, 5.461119f },
+ { -839.1646f, 1024.046f, 121.5505f, 4.782219f },
+ { -881.283f, 1033.25f, 121.5243f, 0.0f },
+ { -883.038f, 924.955f, 121.5243f, 0.0f },
+ { -883.913f, 978.059f, 121.5243f, 3.388291f },
+ { -883.6224f, 950.8459f, 121.5122f, 0.8307042f },
+ { -895.181f, 1015.2f, 121.5505f, 2.652318f },
+ { -943.4023f, 961.7462f, 121.5658f, 5.258394f },
+ { -958.649f, 926.877f, 121.5243f, 0.0f },
+ { -959.743f, 1029.09f, 121.5243f, 0.0f },
+ { -964.6652f, 978.5373f, 121.5257f, 0.02025719f },
+ { -1407.14f, 721.42f, 123.5033f, 0.0f },
+ { -1414.46f, 671.66f, 123.5043f, 0.0f },
+ { -1431.7f, 623.073f, 123.5043f, 0.0f },
+ { -1434.162f, 655.8566f, 123.5051f, 4.84886f },
+ { -1445.19f, 739.729f, 123.5457f, 5.767949f },
+ { -1460.954f, 718.418f, 123.6453f, 5.178094f },
+ { -1462.48f, 694.378f, 123.5463f, 0.3441857f },
+ { -1372.23f, 683.707f, 123.5043f, 0.0f },
+ { -1479.46f, 635.799f, 123.5043f, 0.0f },
+ { -1491.259f, 734.5692f, 123.4525f, 1.529741f },
+ { -1509.024f, 688.8625f, 123.5463f, 6.243045f },
+ { -1419.311f, 1310.25f, 133.8389f, 0.0f },
+ { -1444.24f, 1266.439f, 133.8229f, 0.0f },
+ { -1450.569f, 1337.351f, 133.914f, 0.0f },
+ { -1479.819f, 1331.34f, 153.2f, 0.0f },
+ { -1497.62f, 1276.429f, 133.6676f, 3.147845f },
+ { -1498.37f, 1379.689f, 133.827f, 0.0f },
+ { -1499.97f, 1232.87f, 133.8239f, 0.0f },
+ { -1505.7f, 1261.99f, 133.7089f, 0.6167698f },
+ { -1531.84f, 1316.569f, 153.2f, 0.0f },
+ { -1533.141f, 1267.66f, 133.836f, 0.0f },
+ { -1547.59f, 1300.21f, 133.7094f, 1.908187f },
+ { -1563.3f, 1325.79f, 133.6673f, 0.0f },
+};
+
+// Guard NPCs
+enum TBGuardEntry
+{
+ NPC_BARADIN_GUARD = 51165,
+ NPC_HELLSCREAMS_SENTRY = 51166,
+};
+
+uint8 const TB_GUARDS_MAX = 8;
+Position const GuardNPCSpawns[TB_GUARDS_MAX] =
+{
+// { -837.3768f, 1196.082f, 114.2994f, 3.036873f },
+// { -762.118f, 1195.259f, 107.2007f, 3.036873f },
+// { -837.809f, 1179.842f, 114.1356f, 3.159046f },
+// { -762.5504f, 1179.019f, 107.2137f, 3.159046f },
+ { -1272.951f, 964.8854f, 119.5782f, 3.193953f },
+ { -1274.394f, 997.6511f, 119.5743f, 3.193953f },
+ { -1248.226f, 1018.476f, 119.8113f, 1.605703f },
+ { -1218.948f, 943.5695f, 119.5994f, 4.625123f },
+ { -1195.417f, 965.5364f, 119.8113f, 0.0f },
+ { -1220.832f, 1018.497f, 119.8113f, 1.605703f },
+ { -1196.151f, 999.5121f, 119.5966f, 0.0f },
+ { -1249.304f, 942.9063f, 119.5782f, 4.625123f },
+};
+
+enum TBFactionNPCEntry
+{
+ // Guards
+ NPC_BARADIN_GUARD_1 = 47324,
+ NPC_BARADIN_GUARD_2 = 47325,
+ NPC_BARADIN_GRUNT_1 = 47335,
+ NPC_BARADIN_GRUNT_2 = 47336,
+
+ // Questgivers
+ NPC_SERGEANT_PARKER = 48066, // Everytime
+ NPC_COMMANDER_STEVENS = 48039, // One of these three
+ NPC_2ND_LIEUTENANT_WANSWORTH = 48061,
+ NPC_MARSHAL_FALLOWS = 48074,
+
+ NPC_COMMANDER_ZANOTH = 48069, // Everytime!
+ NPC_STAFF_SERGEANT_LAZGAR = 48062, // One of these three
+ NPC_DRILLMASTER_RAZGOTH = 48070,
+ NPC_PRIVATE_GARNOTH = 48071,
+
+ // Portal summoners
+ NPC_MAVEN_ZARA = 50173,
+ NPC_RHAGHA = 50167,
+};
+
+struct TBFactionNPCInfo
+{
+ Position pos;
+ uint32 entryAlliance;
+ uint32 entryHorde;
+};
+
+uint8 const TB_FACTION_NPC_MAX = 4;
+TBFactionNPCInfo const FactionNPCSpawns[TB_FACTION_NPC_MAX] =
+{
+ { { -1259.356f, 1057.108f, 107.0786f, 4.956735f }, NPC_BARADIN_GUARD_1, NPC_BARADIN_GRUNT_1 },
+ { { -1254.174f, 1061.094f, 107.0772f, 5.445427f }, NPC_BARADIN_GUARD_2, NPC_BARADIN_GRUNT_2 },
+ { { -1256.365f, 1058.47f, 107.0776f, 2.216568f }, NPC_MAVEN_ZARA, NPC_RHAGHA },
+ { { -1231.38f, 985.681f, 121.2403f, 0.6108652f }, NPC_SERGEANT_PARKER, NPC_COMMANDER_ZANOTH },
+};
+
+// Questing
+enum TBQuesting
+{
+ CELLBLOCK_THE_HOLE = 0, // The Hole area
+ CELLBLOCK_D_BLOCK = 1, // D-Block area
+ CELLBLOCK_CURSED_DEPTHS = 2, // Cursed Depths area
+ CELLBLOCK_MAX = 3,
+ CELLBLOCK_NONE,
+
+ AREA_THE_HOLE = 5659,
+ AREA_D_BLOCK = 5657,
+ AREA_CURSED_DEPTHS = 5658,
+
+ GO_GATE_TO_THE_HOLE = 206845,
+ GO_GATE_D_BLOCK = 206844,
+ GO_CURSED_DEPTHS_GATE = 206843,
+
+ GO_CRATE_OF_CELLBLOCK_RATIONS = 206996,
+ GO_CURSED_SHACKLES = 206905,
+ GO_DUSTY_PRISON_JOURNAL = 206890,
+};
+
+Position const RandomQuestgiverPos = { -1228.93f, 975.038f, 121.7153f, 5.969026f };
+
+struct TBQuestAreaInfo
+{
+ uint32 entry;
+ uint32 teleportSpell;
+};
+TBQuestAreaInfo const TBQuestAreas[CELLBLOCK_MAX] =
+{
+ { AREA_THE_HOLE, SPELL_TB_THE_HOLE_TELEPORT },
+ { AREA_D_BLOCK, SPELL_TB_D_BLOCK_TELEPORT },
+ { AREA_CURSED_DEPTHS, SPELL_TB_CURSED_DEPTHS_TELEPORT },
+};
+uint32 const RandomQuestgivers[PVP_TEAMS_COUNT][CELLBLOCK_MAX] =
+{
+ { NPC_MARSHAL_FALLOWS, NPC_2ND_LIEUTENANT_WANSWORTH, NPC_COMMANDER_STEVENS },
+ { NPC_DRILLMASTER_RAZGOTH, NPC_STAFF_SERGEANT_LAZGAR, NPC_PRIVATE_GARNOTH },
+};
+
+// Capture Points
+enum TBCapturePointId
+{
+ TB_BASE_IRONCLAD_GARRISON = 0,
+ TB_BASE_WARDENS_VIGIL = 1,
+ TB_BASE_SLAGWORKS = 2,
+ TB_BASE_COUNT = 3,
+};
+
+struct TBCapturePointSpawnData
+{
+ Position pos;
+ TBCapturePointId id;
+ uint32 entryFlagPole[2];
+ uint32 wsControlled[2];
+ uint32 wsCapturing[2];
+ uint32 wsNeutral;
+ uint32 textGained[2];
+ uint32 textLost[2];
+};
+
+TBCapturePointSpawnData const TBCapturePoints[TB_BASE_COUNT] =
+{
+ { { -896.96f, 979.497f, 121.441f, 3.124123f }, TB_BASE_IRONCLAD_GARRISON, { GO_CAPTURE_POINT_NORTH_A_DEFENDING, GO_CAPTURE_POINT_NORTH_H_DEFENDING }, { WS_BATTLEFIELD_TB_GARRISON_ALLIANCE_CONTROLLED, WS_BATTLEFIELD_TB_GARRISON_HORDE_CONTROLLED }, { WS_BATTLEFIELD_TB_GARRISON_ALLIANCE_CAPTURING, WS_BATTLEFIELD_TB_GARRISON_HORDE_CAPTURING }, WS_BATTLEFIELD_TB_GARRISON_NEUTRAL, { TB_TEXT_GARRISON_ALLIANCE_GAINED, TB_TEXT_GARRISON_HORDE_GAINED }, { TB_TEXT_GARRISON_ALLIANCE_LOST, TB_TEXT_GARRISON_HORDE_LOST } },
+ { { -1492.34f, 1309.87f, 152.961f, 5.462882f }, TB_BASE_WARDENS_VIGIL, { GO_CAPTURE_POINT_WEST_A_DEFENDING, GO_CAPTURE_POINT_WEST_H_DEFENDING }, { WS_BATTLEFIELD_TB_VIGIL_ALLIANCE_CONTROLLED, WS_BATTLEFIELD_TB_VIGIL_HORDE_CONTROLLED }, { WS_BATTLEFIELD_TB_VIGIL_ALLIANCE_CAPTURING, WS_BATTLEFIELD_TB_VIGIL_HORDE_CAPTURING }, WS_BATTLEFIELD_TB_VIGIL_NEUTRAL, { TB_TEXT_VIGIL_ALLIANCE_GAINED, TB_TEXT_VIGIL_HORDE_GAINED }, { TB_TEXT_VIGIL_ALLIANCE_LOST, TB_TEXT_VIGIL_HORDE_LOST } },
+ { { -1437.f, 685.556f, 123.421f, 0.802851f }, TB_BASE_SLAGWORKS, { GO_CAPTURE_POINT_EAST_A_DEFENDING, GO_CAPTURE_POINT_EAST_H_DEFENDING }, { WS_BATTLEFIELD_TB_SLAGWORKS_ALLIANCE_CONTROLLED, WS_BATTLEFIELD_TB_SLAGWORKS_HORDE_CONTROLLED }, { WS_BATTLEFIELD_TB_SLAGWORKS_ALLIANCE_CAPTURING, WS_BATTLEFIELD_TB_SLAGWORKS_HORDE_CAPTURING }, WS_BATTLEFIELD_TB_SLAGWORKS_NEUTRAL, { TB_TEXT_SLAGWORKS_ALLIANCE_GAINED, TB_TEXT_SLAGWORKS_HORDE_GAINED }, { TB_TEXT_SLAGWORKS_ALLIANCE_LOST, TB_TEXT_SLAGWORKS_HORDE_LOST } },
+};
+
+// Towers
+enum TBTowerId
+{
+ TB_TOWER_EAST_SPIRE = 0,
+ TB_TOWER_SOUTH_SPIRE = 1,
+ TB_TOWER_WEST_SPIRE = 2,
+ TB_TOWERS_COUNT = 3,
+};
+
+struct TBTowerInfo
+{
+ Position pos;
+ uint32 entry;
+ uint32 textDamaged;
+ uint32 textDestroyed;
+ uint32 wsIntact[PVP_TEAMS_COUNT];
+ uint32 wsDamaged[PVP_TEAMS_COUNT];
+ uint32 wsDestroyed;
+};
+
+TBTowerInfo const TBTowers[TB_TOWERS_COUNT] =
+{
+ { { -1013.279f, 529.5382f, 146.427f, 1.97222f }, GO_EAST_SPIRE, TB_TEXT_EAST_SPIRE_DAMAGED, TB_TEXT_EAST_SPIRE_DESTROYED, { WS_BATTLEFIELD_TB_EAST_INTACT_ALLIANCE, WS_BATTLEFIELD_TB_EAST_INTACT_HORDE }, { WS_BATTLEFIELD_TB_EAST_DAMAGED_ALLIANCE, WS_BATTLEFIELD_TB_EAST_DAMAGED_HORDE }, WS_BATTLEFIELD_TB_EAST_DESTROYED_NEUTRAL },
+ { { -1618.91f, 954.5417f, 168.601f, 0.06981169f }, GO_SOUTH_SPIRE, TB_TEXT_SOUTH_SPIRE_DAMAGED, TB_TEXT_SOUTH_SPIRE_DESTROYED, { WS_BATTLEFIELD_TB_SOUTH_INTACT_ALLIANCE, WS_BATTLEFIELD_TB_SOUTH_INTACT_HORDE }, { WS_BATTLEFIELD_TB_SOUTH_DAMAGED_ALLIANCE, WS_BATTLEFIELD_TB_SOUTH_DAMAGED_HORDE }, WS_BATTLEFIELD_TB_SOUTH_DESTROYED_NEUTRAL },
+ { { -950.4097f, 1469.101f, 176.596f, 4.180066f }, GO_WEST_SPIRE, TB_TEXT_WEST_SPIRE_DAMAGED, TB_TEXT_WEST_SPIRE_DESTROYED, { WS_BATTLEFIELD_TB_WEST_INTACT_ALLIANCE, WS_BATTLEFIELD_TB_WEST_INTACT_HORDE }, { WS_BATTLEFIELD_TB_WEST_DAMAGED_ALLIANCE, WS_BATTLEFIELD_TB_WEST_DAMAGED_HORDE }, WS_BATTLEFIELD_TB_WEST_DESTROYED_NEUTRAL },
+};
+
+// Vehicles
+enum TBVehicles
+{
+ NPC_ABANDONED_SIEGE_ENGINE = 45344,
+};
+
+int8 const TB_ABANDONED_SIEGE_ENGINE_COUNT = 6;
+Position const TBAbandonedSiegeEngineSpawnData[TB_ABANDONED_SIEGE_ENGINE_COUNT] =
+{
+ { -1106.57f, 1196.34f, 121.8023f, 0.4014257f },
+ { -1108.52f, 1111.33f, 121.2783f, 1.37881f },
+ { -1213.01f, 782.236f, 121.4473f, 1.675516f },
+ { -1258.26f, 780.497f, 122.4413f, 1.48353f },
+ { -1438.3f, 1095.24f, 121.1363f, 5.288348f },
+ { -1442.3f, 1141.07f, 123.6323f, 4.24115f },
+};
+
+// Banners
+enum TBFactionBannerEntry
+{
+ GO_BARADINS_WARDEN_BANNER = 207391, // Alliance banner
+ GO_HELLSCREAM_REACH_BANNER = 207400, // Horde banner
+};
+
+uint32 const TBBannerEntry[PVP_TEAMS_COUNT] = { GO_BARADINS_WARDEN_BANNER, GO_HELLSCREAM_REACH_BANNER };
+
+uint8 const TB_BANNER_MAX = 23;
+Position const TBBanners[TB_BANNER_MAX] =
+{
+ { -987.6129f, 963.9861f, 121.4506f, 2.617989f },
+ { -988.118f, 993.0087f, 121.6746f, 3.612838f },
+ { -1195.941f, 964.342f, 119.728f, 0.8901166f },
+ { -1196.892f, 1000.957f, 119.8211f, 5.445428f },
+ { -1198.236f, 1081.898f, 120.2007f, 1.06465f },
+ { -1089.337f, 1157.161f, 120.2749f, 3.036838f },
+ { -1090.033f, 1143.476f, 120.2656f, 3.036838f },
+ { -1217.495f, 944.0261f, 119.4949f, 1.989672f },
+ { -1219.226f, 1018.168f, 119.728f, 2.251473f },
+ { -1210.319f, 1081.885f, 120.2396f, 2.007128f },
+ { -1226.903f, 786.7656f, 119.4592f, 1.553341f },
+ { -1228.464f, 979.7379f, 119.3814f, 0.03490625f },
+ { -1239.668f, 786.7899f, 119.4271f, 1.553341f },
+ { -1250.262f, 1017.887f, 119.728f, 0.8377575f },
+ { -1250.693f, 943.4496f, 119.4949f, 5.305802f },
+ { -1272.29f, 963.5208f, 119.4949f, 2.617989f },
+ { -1273.997f, 998.7934f, 119.4884f, 3.665196f },
+ { -1378.363f, 725.0087f, 124.2978f, 1.326448f },
+ { -1401.97f, 747.0972f, 123.2302f, 0.2443456f },
+ { -1421.953f, 1263.559f, 133.6141f, 5.009095f },
+ { -1446.497f, 1238.964f, 133.7601f, 5.969027f },
+ { -1488.908f, 1118.747f, 124.9255f, 6.248279f },
+ { -1488.533f, 1131.608f, 124.6363f, 6.248279f },
+};
+
+// Portals
+enum TBPortalEntry
+{
+ TB_PORTAL_ALLIANCE = 208227, // Portal to Stormwind
+ TB_PORTAL_HORDE = 208226, // Portal to Orgrimmar
+};
+
+uint32 const TBPortalEntry[PVP_TEAMS_COUNT] = { TB_PORTAL_ALLIANCE, TB_PORTAL_HORDE };
+
+uint8 const TB_PORTAL_MAX = 2;
+Position const TBPortals[TB_PORTAL_MAX] =
+{
+ { -598.7656f, 1377.974f, 21.91898f, 0.0f },
+ { -1257.729f, 1060.365f, 106.9938f, 5.462882f },
+};
+
+/* ################### *
+ * Tol Barad graveyard *
+ * ################### */
+
+enum TBGraveyardAreaId
+{
+ // Tol Barad
+ TB_GY_BARADIN_HOLD = 1789,
+ TB_GY_IRONCLAD_GARRISON = 1783,
+ TB_GY_WARDENS_VIGIL = 1785,
+ TB_GY_SLAGWORKS = 1787,
+ TB_GY_WEST_SPIRE = 1784,
+ TB_GY_SOUTH_SPIRE = 1786,
+ TB_GY_EAST_SPIRE = 1788,
+ BATTLEFIELD_TB_GRAVEYARD_MAX = 7,
+
+ // Tol Barad Peninsula
+ TBP_GY_ALLIANCE_DAILY = 1808,
+ TBP_GY_HORDE_DAILY = 1807,
+};
+
+struct TBGraveyardInfo
+{
+ Position pos;
+ uint32 phaseId;
+ uint32 gyid;
+ uint32 spiritEntry[PVP_TEAMS_COUNT];
+ bool defenderControls;
+};
+
+TBGraveyardInfo const TBGraveyards[BATTLEFIELD_TB_GRAVEYARD_MAX] =
+{
+ { { -1247.42f, 981.25f, 155.35f, 6.28f }, 128, TB_GY_BARADIN_HOLD, { NPC_TB_GY_SPIRIT_BARADIN_HOLD_A, NPC_TB_GY_SPIRIT_BARADIN_HOLD_H }, true },
+ { { -974.28f, 1089.47f, 132.99f, 5.90f }, 64, TB_GY_IRONCLAD_GARRISON, { NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_A, NPC_TB_GY_SPIRIT_IRONCLAD_GARRISON_H }, false },
+ { { -1570.44f, 1167.57f, 159.50f, 2.20f }, 64, TB_GY_WARDENS_VIGIL, { NPC_TB_GY_SPIRIT_WARDENS_VIGIL_A, NPC_TB_GY_SPIRIT_WARDENS_VIGIL_H }, false },
+ { { -1343.32f, 565.24f, 139.04f, 1.66f }, 64, TB_GY_SLAGWORKS, { NPC_TB_GY_SPIRIT_SLAGWORKS_A, NPC_TB_GY_SPIRIT_SLAGWORKS_H }, false },
+ { { -1052.02f, 1494.05f, 191.41f, 4.13f }, 64, TB_GY_WEST_SPIRE, { NPC_TB_GY_SPIRIT_WEST_SPIRE_A, NPC_TB_GY_SPIRIT_WEST_SPIRE_H }, false },
+ { { -1603.34f, 874.29f, 193.69f, 5.27f }, 64, TB_GY_SOUTH_SPIRE, { NPC_TB_GY_SPIRIT_SOUTH_SPIRE_A, NPC_TB_GY_SPIRIT_SOUTH_SPIRE_H }, false },
+ { { -943.66f, 572.36f, 157.54f, 1.74f }, 64, TB_GY_EAST_SPIRE, { NPC_TB_GY_SPIRIT_EAST_SPIRE_A, NPC_TB_GY_SPIRIT_EAST_SPIRE_H }, false },
+};
+
+/* ####################### *
+ * Tol Barad capture point *
+ * ####################### */
+
+class TolBaradCapturePoint : public BfCapturePoint
+{
+ public:
+ TolBaradCapturePoint(BattlefieldTB* battlefield, TeamId teamInControl);
+
+ void ChangeTeam(TeamId /*oldteam*/) override;
+};
+
+/* ##################### *
+ * Tol Barad battlefield *
+ * ##################### */
+
+class BattlefieldTB : public Battlefield
+{
+ public:
+ ~BattlefieldTB();
+
+ void OnStartGrouping() override;
+ void OnBattleStart() override;
+ void OnBattleEnd(bool endByTimer) override;
+
+ void OnPlayerEnterZone(Player* player) override;
+ void OnPlayerLeaveZone(Player* player) override;
+
+ void OnPlayerJoinWar(Player* player) override;
+ void OnPlayerLeaveWar(Player* player) override;
+
+ bool Update(uint32 diff) override;
+
+ void OnCreatureCreate(Creature* creature) override;
+ //void OnCreatureRemove(Creature* creature) override;
+
+ void OnGameObjectCreate(GameObject* go) override;
+
+ void UpdateCapturedBaseCount();
+ //void UpdatedDestroyedTowerCount(TeamId team);
+
+ //void DoCompleteOrIncrementAchievement(uint32 achievement, Player* player, uint8 incrementNumber = 1) override;
+
+ bool SetupBattlefield() override;
+
+ void SendInitWorldStatesTo(Player* player);
+ void SendInitWorldStatesToAll() override;
+ void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
+ void UpdateWorldStates();
+
+ void HandleKill(Player* killer, Unit* victim) override;
+ //void OnUnitDeath(Unit* unit) override;
+ void PromotePlayer(Player* killer);
+ void RemoveAurasFromPlayer(Player* player);
+
+ void ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker) override;
+
+ void TowerDamaged(TBTowerId tbTowerId);
+ void TowerDestroyed(TBTowerId tbTowerId);
+
+ // returns the graveyardId in the specified area.
+ //uint8 GetSpiritGraveyardId(uint32 areaId) const;
+
+ void UpdateNPCsAndGameObjects();
+ void CreateCapturePoints();
+
+ protected:
+ // Minutes till battle preparation warnings
+ bool warnedFiveMinutes;
+ bool warnedTwoMinutes;
+ bool warnedOneMinute;
+
+ uint32 m_saveTimer;
+
+ bool updatedNPCAndObjects;
+ uint32 m_updateObjectsTimer;
+
+ uint32 m_BonusTime;
+
+ GuidSet BattleInactiveNPCs;
+ GuidSet BattleInactiveGOs;
+
+ GuidSet TemporaryNPCs;
+ GuidSet TemporaryGOs;
+
+ GuidSet Towers;
+
+ uint8 m_iCellblockRandom;
+
+ ObjectGuid TBGatesGUID;
+ ObjectGuid TBDoorGUID;
+
+ ObjectGuid m_gateToTheHoleGUID;
+ ObjectGuid m_gateDBlockGUID;
+ ObjectGuid m_gateCursedDepthsGUID;
+};
+
+#endif
diff --git a/src/server/scripts/Battlefield/BattlefieldWG.cpp b/src/server/scripts/Battlefield/BattlefieldWG.cpp
new file mode 100644
index 00000000000..a8f3d135ebd
--- /dev/null
+++ b/src/server/scripts/Battlefield/BattlefieldWG.cpp
@@ -0,0 +1,1870 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/// @todo Implement proper support for vehicle+player teleportation
+/// @todo Use spell victory/defeat in wg instead of RewardMarkOfHonor() && RewardHonor
+/// @todo Add proper implement of achievement
+
+#include "BattlefieldWG.h"
+#include "AchievementMgr.h"
+#include "Battleground.h"
+#include "CreatureTextMgr.h"
+#include "GameObject.h"
+#include "GameTime.h"
+#include "DB2Stores.h"
+#include "Log.h"
+#include "MapManager.h"
+#include "ObjectAccessor.h"
+#include "Player.h"
+#include "Random.h"
+#include "ScriptMgr.h"
+#include "SpellAuras.h"
+#include "TemporarySummon.h"
+#include "World.h"
+#include "WorldSession.h"
+#include "WorldStatePackets.h"
+
+struct BfWGCoordGY
+{
+ Position Pos;
+ uint32 GraveyardID;
+ uint32 TextID; // for gossip menu
+ TeamId StartControl;
+};
+
+// 7 in sql, 7 in header
+BfWGCoordGY const WGGraveyard[BATTLEFIELD_WG_GRAVEYARD_MAX] =
+{
+ { { 5104.750f, 2300.940f, 368.579f, 0.733038f }, 1329, BATTLEFIELD_WG_GOSSIPTEXT_GY_NE, TEAM_NEUTRAL },
+ { { 5099.120f, 3466.036f, 368.484f, 5.317802f }, 1330, BATTLEFIELD_WG_GOSSIPTEXT_GY_NW, TEAM_NEUTRAL },
+ { { 4314.648f, 2408.522f, 392.642f, 6.268125f }, 1333, BATTLEFIELD_WG_GOSSIPTEXT_GY_SE, TEAM_NEUTRAL },
+ { { 4331.716f, 3235.695f, 390.251f, 0.008500f }, 1334, BATTLEFIELD_WG_GOSSIPTEXT_GY_SW, TEAM_NEUTRAL },
+ { { 5537.986f, 2897.493f, 517.057f, 4.819249f }, 1285, BATTLEFIELD_WG_GOSSIPTEXT_GY_KEEP, TEAM_NEUTRAL },
+ { { 5032.454f, 3711.382f, 372.468f, 3.971623f }, 1331, BATTLEFIELD_WG_GOSSIPTEXT_GY_HORDE, TEAM_HORDE },
+ { { 5140.790f, 2179.120f, 390.950f, 1.972220f }, 1332, BATTLEFIELD_WG_GOSSIPTEXT_GY_ALLIANCE, TEAM_ALLIANCE },
+};
+
+uint32 const ClockWorldState[] = { WS_BATTLEFIELD_WG_TIME_BATTLE_END, WS_BATTLEFIELD_WG_TIME_NEXT_BATTLE };
+uint32 const WintergraspFaction[] = { FACTION_ALLIANCE_GENERIC_WG, FACTION_HORDE_GENERIC_WG, FACTION_FRIENDLY };
+
+Position const WintergraspStalkerPos = { 4948.985f, 2937.789f, 550.5172f, 1.815142f };
+
+Position const WintergraspRelicPos = { 5440.379f, 2840.493f, 430.2816f, -1.832595f };
+QuaternionData const WintergraspRelicRot = { 0.f, 0.f, -0.7933531f, 0.6087617f };
+
+uint8 const WG_MAX_OBJ = 32;
+uint8 const WG_MAX_TURRET = 15;
+uint8 const WG_MAX_TELEPORTER = 12;
+uint8 const WG_MAX_WORKSHOP = 6;
+uint8 const WG_MAX_TOWER = 7;
+
+// *****************************************************
+// ************ Destructible (Wall, Tower..) ***********
+// *****************************************************
+
+struct WintergraspBuildingSpawnData
+{
+ uint32 entry;
+ uint32 WorldState;
+ Position pos;
+ QuaternionData rot;
+ WintergraspGameObjectBuildingType type;
+};
+
+WintergraspBuildingSpawnData const WGGameObjectBuilding[WG_MAX_OBJ] =
+{
+ // Wall (Not spawned in db)
+ // Entry WS X Y Z O rX rY rZ rW Type
+ { 190219, 3749, { 5371.457f, 3047.472f, 407.5710f, 3.14159300f }, { 0.f, 0.f, -1.000000000f, 0.00000000f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 190220, 3750, { 5331.264f, 3047.105f, 407.9228f, 0.05235888f }, { 0.f, 0.f, 0.026176450f, 0.99965730f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191795, 3764, { 5385.841f, 2909.490f, 409.7127f, 0.00872424f }, { 0.f, 0.f, 0.004362106f, 0.99999050f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191796, 3772, { 5384.452f, 2771.835f, 410.2704f, 3.14159300f }, { 0.f, 0.f, -1.000000000f, 0.00000000f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191799, 3762, { 5371.436f, 2630.610f, 408.8163f, 3.13285800f }, { 0.f, 0.f, 0.999990500f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191800, 3766, { 5301.838f, 2909.089f, 409.8661f, 0.00872424f }, { 0.f, 0.f, 0.004362106f, 0.99999050f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191801, 3770, { 5301.063f, 2771.411f, 409.9014f, 3.14159300f }, { 0.f, 0.f, -1.000000000f, 0.00000000f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191802, 3751, { 5280.197f, 2995.583f, 408.8249f, 1.61442800f }, { 0.f, 0.f, 0.722363500f, 0.69151360f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191803, 3752, { 5279.136f, 2956.023f, 408.6041f, 1.57079600f }, { 0.f, 0.f, 0.707106600f, 0.70710690f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191804, 3767, { 5278.685f, 2882.513f, 409.5388f, 1.57079600f }, { 0.f, 0.f, 0.707106600f, 0.70710690f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191806, 3769, { 5279.502f, 2798.945f, 409.9983f, 1.57079600f }, { 0.f, 0.f, 0.707106600f, 0.70710690f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191807, 3759, { 5279.937f, 2724.766f, 409.9452f, 1.56207000f }, { 0.f, 0.f, 0.704014800f, 0.71018530f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191808, 3760, { 5279.601f, 2683.786f, 409.8488f, 1.55334100f }, { 0.f, 0.f, 0.700908700f, 0.71325110f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191809, 3761, { 5330.955f, 2630.777f, 409.2826f, 3.13285800f }, { 0.f, 0.f, 0.999990500f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 190369, 3753, { 5256.085f, 2933.963f, 409.3571f, 3.13285800f }, { 0.f, 0.f, 0.999990500f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 190370, 3758, { 5257.463f, 2747.327f, 409.7427f, -3.13285800f }, { 0.f, 0.f, -0.999990500f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 190371, 3754, { 5214.960f, 2934.089f, 409.1905f, -0.00872424f }, { 0.f, 0.f, -0.004362106f, 0.99999050f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 190372, 3757, { 5215.821f, 2747.566f, 409.1884f, -3.13285800f }, { 0.f, 0.f, -0.999990500f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 190374, 3755, { 5162.273f, 2883.043f, 410.2556f, 1.57952200f }, { 0.f, 0.f, 0.710185100f, 0.70401500f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 190376, 3756, { 5163.724f, 2799.838f, 409.2270f, 1.57952200f }, { 0.f, 0.f, 0.710185100f, 0.70401500f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+
+ // Tower of keep (Not spawned in db)
+ { 190221, 3711, { 5281.154f, 3044.588f, 407.8434f, 3.115388f }, { 0.f, 0.f, 0.9999142f, 0.013101960f }, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // NW
+ { 190373, 3713, { 5163.757f, 2932.228f, 409.1904f, 3.124123f }, { 0.f, 0.f, 0.9999619f, 0.008734641f }, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // SW
+ { 190377, 3714, { 5166.397f, 2748.368f, 409.1884f, -1.570796f }, { 0.f, 0.f, -0.7071066f, 0.707106900f }, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // SE
+ { 190378, 3712, { 5281.192f, 2632.479f, 409.0985f, -1.588246f }, { 0.f, 0.f, -0.7132492f, 0.700910500f }, BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER }, // NE
+
+ // Wall (with passage) (Not spawned in db)
+ { 191797, 3765, { 5343.290f, 2908.860f, 409.5757f, 0.00872424f }, { 0.f, 0.f, 0.004362106f, 0.9999905f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191798, 3771, { 5342.719f, 2771.386f, 409.6249f, 3.14159300f }, { 0.f, 0.f, -1.000000000f, 0.0000000f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+ { 191805, 3768, { 5279.126f, 2840.797f, 409.7826f, 1.57952200f }, { 0.f, 0.f, 0.710185100f, 0.7040150f }, BATTLEFIELD_WG_OBJECTTYPE_WALL },
+
+ // South tower (Not spawned in db)
+ { 190356, 3704, { 4557.173f, 3623.943f, 395.8828f, 1.675516f }, { 0.f, 0.f, 0.7431450f, 0.669130400f }, BATTLEFIELD_WG_OBJECTTYPE_TOWER }, // W
+ { 190357, 3705, { 4398.172f, 2822.497f, 405.6270f, -3.124123f }, { 0.f, 0.f, -0.9999619f, 0.008734641f }, BATTLEFIELD_WG_OBJECTTYPE_TOWER }, // S
+ { 190358, 3706, { 4459.105f, 1944.326f, 434.9912f, -2.002762f }, { 0.f, 0.f, -0.8422165f, 0.539139500f }, BATTLEFIELD_WG_OBJECTTYPE_TOWER }, // E
+
+ // Door of forteress (Not spawned in db)
+ { GO_WINTERGRASP_FORTRESS_GATE, 3763, { 5162.991f, 2841.232f, 410.1892f, -3.132858f }, { 0.f, 0.f, -0.9999905f, 0.00436732f }, BATTLEFIELD_WG_OBJECTTYPE_DOOR },
+
+ // Last door (Not spawned in db)
+ { GO_WINTERGRASP_VAULT_GATE, 3773, { 5397.108f, 2841.54f, 425.9014f, 3.141593f }, { 0.f, 0.f, -1.f, 0.f }, BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST },
+};
+
+struct StaticWintergraspTowerInfo
+{
+ uint8 TowerId;
+
+ struct
+ {
+ uint8 Damaged;
+ uint8 Destroyed;
+ } TextIds;
+};
+
+StaticWintergraspTowerInfo const TowerData[WG_MAX_TOWER] =
+{
+ { BATTLEFIELD_WG_TOWER_FORTRESS_NW, { BATTLEFIELD_WG_TEXT_NW_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_NW_KEEPTOWER_DESTROY } },
+ { BATTLEFIELD_WG_TOWER_FORTRESS_SW, { BATTLEFIELD_WG_TEXT_SW_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_SW_KEEPTOWER_DESTROY } },
+ { BATTLEFIELD_WG_TOWER_FORTRESS_SE, { BATTLEFIELD_WG_TEXT_SE_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_SE_KEEPTOWER_DESTROY } },
+ { BATTLEFIELD_WG_TOWER_FORTRESS_NE, { BATTLEFIELD_WG_TEXT_NE_KEEPTOWER_DAMAGE, BATTLEFIELD_WG_TEXT_NE_KEEPTOWER_DESTROY } },
+ { BATTLEFIELD_WG_TOWER_SHADOWSIGHT, { BATTLEFIELD_WG_TEXT_WESTERN_TOWER_DAMAGE, BATTLEFIELD_WG_TEXT_WESTERN_TOWER_DESTROY } },
+ { BATTLEFIELD_WG_TOWER_WINTER_S_EDGE, { BATTLEFIELD_WG_TEXT_SOUTHERN_TOWER_DAMAGE, BATTLEFIELD_WG_TEXT_SOUTHERN_TOWER_DESTROY } },
+ { BATTLEFIELD_WG_TOWER_FLAMEWATCH, { BATTLEFIELD_WG_TEXT_EASTERN_TOWER_DAMAGE, BATTLEFIELD_WG_TEXT_EASTERN_TOWER_DESTROY } }
+};
+
+Position const WGTurret[WG_MAX_TURRET] =
+{
+ { 5391.19f, 3060.8f, 419.616f, 1.69557f },
+ { 5266.75f, 2976.5f, 421.067f, 3.20354f },
+ { 5234.86f, 2948.8f, 420.88f, 1.61311f },
+ { 5323.05f, 2923.7f, 421.645f, 1.5817f },
+ { 5363.82f, 2923.87f, 421.709f, 1.60527f },
+ { 5264.04f, 2861.34f, 421.587f, 3.21142f },
+ { 5264.68f, 2819.78f, 421.656f, 3.15645f },
+ { 5322.16f, 2756.69f, 421.646f, 4.69978f },
+ { 5363.78f, 2756.77f, 421.629f, 4.78226f },
+ { 5236.2f, 2732.68f, 421.649f, 4.72336f },
+ { 5265.02f, 2704.63f, 421.7f, 3.12507f },
+ { 5350.87f, 2616.03f, 421.243f, 4.72729f },
+ { 5390.95f, 2615.5f, 421.126f, 4.6409f },
+ { 5148.8f, 2820.24f, 421.621f, 3.16043f },
+ { 5147.98f, 2861.93f, 421.63f, 3.18792f },
+};
+
+struct WintergraspObjectPositionData
+{
+ Position Pos;
+ uint32 HordeEntry;
+ uint32 AllianceEntry;
+};
+
+struct WintergraspGameObjectData
+{
+ Position Pos;
+ QuaternionData Rot;
+ uint32 HordeEntry;
+ uint32 AllianceEntry;
+};
+
+WintergraspGameObjectData const WGPortalDefenderData[WG_MAX_TELEPORTER] =
+{
+ // Player teleporter
+ { { 5153.408f, 2901.349f, 409.1913f, -0.06981169f }, { 0.f, 0.f, -0.03489876f, 0.9993908f }, 190763, 191575 },
+ { { 5268.698f, 2666.421f, 409.0985f, -0.71558490f }, { 0.f, 0.f, -0.35020730f, 0.9366722f }, 190763, 191575 },
+ { { 5197.050f, 2944.814f, 409.1913f, 2.33874000f }, { 0.f, 0.f, 0.92050460f, 0.3907318f }, 190763, 191575 },
+ { { 5196.671f, 2737.345f, 409.1892f, -2.93213900f }, { 0.f, 0.f, -0.99452110f, 0.1045355f }, 190763, 191575 },
+ { { 5314.580f, 3055.852f, 408.8620f, 0.54105060f }, { 0.f, 0.f, 0.26723770f, 0.9636307f }, 190763, 191575 },
+ { { 5391.277f, 2828.094f, 418.6752f, -2.16420600f }, { 0.f, 0.f, -0.88294700f, 0.4694727f }, 190763, 191575 },
+ { { 5153.931f, 2781.671f, 409.2455f, 1.65806200f }, { 0.f, 0.f, 0.73727700f, 0.6755905f }, 190763, 191575 },
+ { { 5311.445f, 2618.931f, 409.0916f, -2.37364400f }, { 0.f, 0.f, -0.92718320f, 0.3746083f }, 190763, 191575 },
+ { { 5269.208f, 3013.838f, 408.8276f, -1.76278200f }, { 0.f, 0.f, -0.77162460f, 0.6360782f }, 190763, 191575 },
+
+ { { 5401.634f, 2853.667f, 418.6748f, 2.63544400f }, { 0.f, 0.f, 0.96814730f, 0.2503814f }, 192819, 192819 }, // return portal inside fortress, neutral
+ // Vehicle teleporter
+ { { 5314.515f, 2703.687f, 408.5502f, -0.89011660f }, { 0.f, 0.f, -0.43051050f, 0.9025856f }, 192951, 192951 },
+ { { 5316.252f, 2977.042f, 408.5385f, -0.82030330f }, { 0.f, 0.f, -0.39874840f, 0.9170604f }, 192951, 192951 }
+};
+
+// *********************************************************
+// **********Tower Element(GameObject, Creature)************
+// *********************************************************
+
+struct WintergraspTowerData
+{
+ uint32 towerEntry; // Gameobject id of tower
+ std::vector<WintergraspGameObjectData> GameObject; // Gameobject position and entry (Horde/Alliance)
+
+ // Creature: Turrets and Guard /// @todo: Killed on Tower destruction ? Tower damage ? Requires confirming
+ std::vector<WintergraspObjectPositionData> CreatureBottom;
+};
+
+uint8 const WG_MAX_ATTACKTOWERS = 3;
+// 192414 : 0 in sql, 1 in header
+// 192278 : 0 in sql, 3 in header
+WintergraspTowerData const AttackTowers[WG_MAX_ATTACKTOWERS] =
+{
+ // West tower
+ {
+ 190356,
+ {
+ { { 4559.113f, 3606.216f, 419.9992f, 4.799657f }, { 0.f, 0.f, -0.67558960f, 0.73727790f }, 192488, 192501 }, // Flag on tower
+ { { 4539.420f, 3622.490f, 420.0342f, 3.211419f }, { 0.f, 0.f, -0.99939060f, 0.03490613f }, 192488, 192501 }, // Flag on tower
+ { { 4555.258f, 3641.648f, 419.9740f, 1.675514f }, { 0.f, 0.f, 0.74314400f, 0.66913150f }, 192488, 192501 }, // Flag on tower
+ { { 4574.872f, 3625.911f, 420.0792f, 0.087266f }, { 0.f, 0.f, 0.04361916f, 0.99904820f }, 192488, 192501 }, // Flag on tower
+ { { 4433.899f, 3534.142f, 360.2750f, 4.433136f }, { 0.f, 0.f, -0.79863550f, 0.60181500f }, 192269, 192278 }, // Flag near workshop
+ { { 4572.933f, 3475.519f, 363.0090f, 1.422443f }, { 0.f, 0.f, 0.65275960f, 0.75756520f }, 192269, 192277 } // Flag near bridge
+ },
+ {
+ { { 4418.688477f, 3506.251709f, 358.975494f, 4.293305f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A } // Roaming Guard
+ }
+ },
+ // South Tower
+ {
+ 190357,
+ {
+ { { 4416.004f, 2822.666f, 429.8512f, 6.2657330f }, { 0.f, 0.f, -0.00872612f, 0.99996190f }, 192488, 192501 }, // Flag on tower
+ { { 4398.819f, 2804.698f, 429.7920f, 4.6949370f }, { 0.f, 0.f, -0.71325020f, 0.70090960f }, 192488, 192501 }, // Flag on tower
+ { { 4387.622f, 2719.566f, 389.9351f, 4.7385700f }, { 0.f, 0.f, -0.69779010f, 0.71630230f }, 192366, 192414 }, // Flag near tower
+ { { 4464.124f, 2855.453f, 406.1106f, 0.8290324f }, { 0.f, 0.f, 0.40274720f, 0.91531130f }, 192366, 192429 }, // Flag near tower
+ { { 4526.457f, 2810.181f, 391.1997f, 3.2899610f }, { 0.f, 0.f, -0.99724960f, 0.07411628f }, 192269, 192278 } // Flag near bridge
+ },
+ {
+ { { 4452.859863f, 2808.870117f, 402.604004f, 6.056290f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
+ { { 4455.899902f, 2835.958008f, 401.122559f, 0.034907f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
+ { { 4412.649414f, 2953.792236f, 374.799957f, 0.980838f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Roaming Guard
+ { { 4362.089844f, 2811.510010f, 407.337006f, 3.193950f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
+ { { 4412.290039f, 2753.790039f, 401.015015f, 5.829400f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
+ { { 4421.939941f, 2773.189941f, 400.894989f, 5.707230f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A } // Standing Guard
+ }
+ },
+ // East Tower
+ {
+ 190358,
+ {
+ { { 4466.793f, 1960.418f, 459.1437f, 1.151916f }, { 0.f, 0.f, 0.5446386f, 0.8386708f }, 192488, 192501 }, // Flag on tower
+ { { 4475.351f, 1937.031f, 459.0702f, 5.846854f }, { 0.f, 0.f, -0.2164392f, 0.9762961f }, 192488, 192501 }, // Flag on tower
+ { { 4451.758f, 1928.104f, 459.0759f, 4.276057f }, { 0.f, 0.f, -0.8433914f, 0.5372996f }, 192488, 192501 }, // Flag on tower
+ { { 4442.987f, 1951.898f, 459.0930f, 2.740162f }, { 0.f, 0.f, 0.9799242f, 0.1993704f }, 192488, 192501 } // Flag on tower
+ },
+ {
+ { { 4501.060059f, 1990.280029f, 431.157013f, 1.029740f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
+ { { 4463.830078f, 2015.180054f, 430.299988f, 1.431170f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
+ { { 4494.580078f, 1943.760010f, 435.627014f, 6.195920f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
+ { { 4450.149902f, 1897.579956f, 435.045013f, 4.398230f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A }, // Standing Guard
+ { { 4428.870117f, 1906.869995f, 432.648010f, 3.996800f }, BATTLEFIELD_WG_NPC_GUARD_H, BATTLEFIELD_WG_NPC_GUARD_A } // Standing Guard
+ }
+ }
+};
+
+struct WintergraspTowerCannonData
+{
+ uint32 towerEntry;
+ std::vector<Position> TowerCannonBottom;
+ std::vector<Position> TurretTop;
+};
+
+uint8 const WG_MAX_TOWER_CANNON = 7;
+
+WintergraspTowerCannonData const TowerCannon[WG_MAX_TOWER_CANNON] =
+{
+ {
+ 190221,
+ {
+ // no cannons at bottom
+ },
+ {
+ { 5255.88f, 3047.63f, 438.499f, 3.13677f },
+ { 5280.90f, 3071.32f, 438.499f, 1.62879f }
+ }
+ },
+ {
+ 190373,
+ {
+ // no cannons at bottom
+ },
+ {
+ { 5138.59f, 2935.16f, 439.845f, 3.11723f },
+ { 5163.06f, 2959.52f, 439.846f, 1.47258f }
+ }
+ },
+ {
+ 190377,
+ {
+ // no cannons at bottom
+ },
+ {
+ { 5163.84f, 2723.74f, 439.844f, 1.39940f },
+ { 5139.69f, 2747.40f, 439.844f, 3.17221f }
+ }
+ },
+ {
+ 190378,
+ {
+ // no cannons at bottom
+ },
+ {
+ { 5278.21f, 2607.23f, 439.755f, 4.71944f },
+ { 5255.01f, 2631.98f, 439.755f, 3.15257f }
+ }
+ },
+ {
+ 190356,
+ {
+ { 4537.380371f, 3599.531738f, 402.886993f, 3.998462f },
+ { 4581.497559f, 3604.087158f, 402.886963f, 5.651723f }
+ },
+ {
+ { 4469.448242f, 1966.623779f, 465.647217f, 1.153573f },
+ { 4581.895996f, 3626.438477f, 426.539062f, 0.117806f }
+ }
+ },
+ {
+ 190357,
+ {
+ { 4421.640137f, 2799.935791f, 412.630920f, 5.459298f },
+ { 4420.263184f, 2845.340332f, 412.630951f, 0.742197f }
+ },
+ {
+ { 4423.430664f, 2822.762939f, 436.283142f, 6.223487f },
+ { 4397.825684f, 2847.629639f, 436.283325f, 1.579430f },
+ { 4398.814941f, 2797.266357f, 436.283051f, 4.703747f }
+ }
+ },
+ {
+ 190358,
+ {
+ { 4448.138184f, 1974.998779f, 441.995911f, 1.967238f },
+ { 4448.713379f, 1955.148682f, 441.995178f, 0.380733f }
+ },
+ {
+ { 4469.448242f, 1966.623779f, 465.647217f, 1.153573f },
+ { 4481.996582f, 1933.658325f, 465.647186f, 5.873029f }
+ }
+ }
+};
+
+// *********************************************************
+// *****************WorkShop Data & Element*****************
+// *********************************************************
+
+struct StaticWintergraspWorkshopInfo
+{
+ uint8 WorkshopId;
+ uint32 WorldStateId;
+
+ struct
+ {
+ uint8 AllianceCapture;
+ uint8 AllianceAttack;
+ uint8 HordeCapture;
+ uint8 HordeAttack;
+ } TextIds;
+};
+
+StaticWintergraspWorkshopInfo const WorkshopData[WG_MAX_WORKSHOP] =
+{
+ { BATTLEFIELD_WG_WORKSHOP_NE, WS_BATTLEFIELD_WG_WORKSHOP_NE, { BATTLEFIELD_WG_TEXT_SUNKEN_RING_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_SUNKEN_RING_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_SUNKEN_RING_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_SUNKEN_RING_ATTACK_HORDE } },
+ { BATTLEFIELD_WG_WORKSHOP_NW, WS_BATTLEFIELD_WG_WORKSHOP_NW, { BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_ATTACK_HORDE } },
+ { BATTLEFIELD_WG_WORKSHOP_SE, WS_BATTLEFIELD_WG_WORKSHOP_SE, { BATTLEFIELD_WG_TEXT_EASTSPARK_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_EASTSPARK_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_EASTSPARK_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_EASTSPARK_ATTACK_HORDE } },
+ { BATTLEFIELD_WG_WORKSHOP_SW, WS_BATTLEFIELD_WG_WORKSHOP_SW, { BATTLEFIELD_WG_TEXT_WESTSPARK_CAPTURE_ALLIANCE, BATTLEFIELD_WG_TEXT_WESTSPARK_ATTACK_ALLIANCE, BATTLEFIELD_WG_TEXT_WESTSPARK_CAPTURE_HORDE, BATTLEFIELD_WG_TEXT_WESTSPARK_ATTACK_HORDE } },
+ // KEEP WORKSHOPS - It can't be taken, so it doesn't have a textids
+ { BATTLEFIELD_WG_WORKSHOP_KEEP_WEST, WS_BATTLEFIELD_WG_WORKSHOP_K_W, { 0, 0, 0, 0 } },
+ { BATTLEFIELD_WG_WORKSHOP_KEEP_EAST, WS_BATTLEFIELD_WG_WORKSHOP_K_E, { 0, 0, 0, 0 } }
+};
+
+BattlefieldWG::~BattlefieldWG()
+{
+ for (WintergraspWorkshop* workshop : Workshops)
+ delete workshop;
+
+ for (BfWGGameObjectBuilding* building : BuildingsInZone)
+ delete building;
+}
+
+bool BattlefieldWG::SetupBattlefield()
+{
+ m_TypeId = BATTLEFIELD_WG; // See enum BattlefieldTypes
+ m_BattleId = BATTLEFIELD_BATTLEID_WG;
+ m_ZoneId = AREA_WINTERGRASP;
+ m_MapId = BATTLEFIELD_WG_MAPID;
+ m_Map = sMapMgr->CreateBaseMap(m_MapId);
+
+ InitStalker(BATTLEFIELD_WG_NPC_STALKER, WintergraspStalkerPos);
+
+ m_MaxPlayer = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MAX);
+ m_IsEnabled = sWorld->getBoolConfig(CONFIG_WINTERGRASP_ENABLE);
+ m_MinPlayer = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MIN);
+ m_MinLevel = sWorld->getIntConfig(CONFIG_WINTERGRASP_PLR_MIN_LVL);
+ m_BattleTime = sWorld->getIntConfig(CONFIG_WINTERGRASP_BATTLETIME) * MINUTE * IN_MILLISECONDS;
+ m_NoWarBattleTime = sWorld->getIntConfig(CONFIG_WINTERGRASP_NOBATTLETIME) * MINUTE * IN_MILLISECONDS;
+ m_RestartAfterCrash = sWorld->getIntConfig(CONFIG_WINTERGRASP_RESTART_AFTER_CRASH) * MINUTE * IN_MILLISECONDS;
+
+ m_TimeForAcceptInvite = 20;
+ m_StartGroupingTimer = 15 * MINUTE * IN_MILLISECONDS;
+ m_StartGrouping = false;
+
+ m_tenacityTeam = TEAM_NEUTRAL;
+ m_tenacityStack = 0;
+
+ KickPosition.Relocate(5728.117f, 2714.346f, 697.733f, 0);
+ KickPosition.m_mapId = m_MapId;
+
+ RegisterZone(m_ZoneId);
+
+ m_Data32.resize(BATTLEFIELD_WG_DATA_MAX);
+
+ m_saveTimer = 60000;
+
+ // Init Graveyards
+ SetGraveyardNumber(BATTLEFIELD_WG_GRAVEYARD_MAX);
+
+ // Load from db
+ if ((sWorld->getWorldState(WS_BATTLEFIELD_WG_ACTIVE) == 0) && (sWorld->getWorldState(WS_BATTLEFIELD_WG_DEFENDER) == 0)
+ && (sWorld->getWorldState(ClockWorldState[0]) == 0))
+ {
+ sWorld->setWorldState(WS_BATTLEFIELD_WG_ACTIVE, uint64(false));
+ sWorld->setWorldState(WS_BATTLEFIELD_WG_DEFENDER, uint64(urand(0, 1)));
+ sWorld->setWorldState(ClockWorldState[0], uint64(m_NoWarBattleTime));
+ }
+
+ m_isActive = sWorld->getWorldState(WS_BATTLEFIELD_WG_ACTIVE) != 0;
+ m_DefenderTeam = TeamId(sWorld->getWorldState(WS_BATTLEFIELD_WG_DEFENDER));
+
+ m_Timer = sWorld->getWorldState(ClockWorldState[0]);
+ if (m_isActive)
+ {
+ m_isActive = false;
+ m_Timer = m_RestartAfterCrash;
+ }
+
+ SetData(BATTLEFIELD_WG_DATA_WON_A, uint32(sWorld->getWorldState(WS_BATTLEFIELD_WG_ATTACKED_A)));
+ SetData(BATTLEFIELD_WG_DATA_DEF_A, uint32(sWorld->getWorldState(WS_BATTLEFIELD_WG_DEFENDED_A)));
+ SetData(BATTLEFIELD_WG_DATA_WON_H, uint32(sWorld->getWorldState(WS_BATTLEFIELD_WG_ATTACKED_H)));
+ SetData(BATTLEFIELD_WG_DATA_DEF_H, uint32(sWorld->getWorldState(WS_BATTLEFIELD_WG_DEFENDED_H)));
+
+ for (uint8 i = 0; i < BATTLEFIELD_WG_GRAVEYARD_MAX; i++)
+ {
+ BfGraveyardWG* graveyard = new BfGraveyardWG(this);
+
+ // When between games, the graveyard is controlled by the defending team
+ if (WGGraveyard[i].StartControl == TEAM_NEUTRAL)
+ graveyard->Initialize(m_DefenderTeam, WGGraveyard[i].GraveyardID);
+ else
+ graveyard->Initialize(WGGraveyard[i].StartControl, WGGraveyard[i].GraveyardID);
+
+ graveyard->SetTextId(WGGraveyard[i].TextID);
+ m_GraveyardList[i] = graveyard;
+ }
+
+
+ Workshops.resize(WG_MAX_WORKSHOP);
+ // Spawn workshop creatures and gameobjects
+ for (uint8 i = 0; i < WG_MAX_WORKSHOP; i++)
+ {
+ WintergraspWorkshop* workshop = new WintergraspWorkshop(this, i);
+ if (i < BATTLEFIELD_WG_WORKSHOP_NE)
+ workshop->GiveControlTo(GetAttackerTeam(), true);
+ else
+ workshop->GiveControlTo(GetDefenderTeam(), true);
+
+ // Note: Capture point is added once the gameobject is created.
+ Workshops[i] = workshop;
+ }
+
+ // Spawn turrets and hide them per default
+ for (uint8 i = 0; i < WG_MAX_TURRET; i++)
+ {
+ Position towerCannonPos = WGTurret[i].GetPosition();
+ if (Creature* creature = SpawnCreature(NPC_WINTERGRASP_TOWER_CANNON, towerCannonPos))
+ {
+ CanonList.push_back(creature->GetGUID());
+ HideNpc(creature);
+ }
+ }
+
+ BuildingsInZone.resize(WG_MAX_OBJ);
+ // Spawn all gameobjects
+ for (uint8 i = 0; i < WG_MAX_OBJ; i++)
+ {
+ if (GameObject* go = SpawnGameObject(WGGameObjectBuilding[i].entry, WGGameObjectBuilding[i].pos, WGGameObjectBuilding[i].rot))
+ {
+ BfWGGameObjectBuilding* b = new BfWGGameObjectBuilding(this, WGGameObjectBuilding[i].type, WGGameObjectBuilding[i].WorldState);
+ b->Init(go);
+ if (!IsEnabled() && go->GetEntry() == GO_WINTERGRASP_VAULT_GATE)
+ go->SetDestructibleState(GO_DESTRUCTIBLE_DESTROYED);
+
+ BuildingsInZone[i] = b;
+ }
+ }
+
+ // Spawning portal defender
+ for (uint8 i = 0; i < WG_MAX_TELEPORTER; ++i)
+ {
+ WintergraspGameObjectData const& teleporter = WGPortalDefenderData[i];
+ if (GameObject* go = SpawnGameObject(teleporter.AllianceEntry, teleporter.Pos, teleporter.Rot))
+ {
+ DefenderPortalList[TEAM_ALLIANCE].push_back(go->GetGUID());
+ go->SetRespawnTime(GetDefenderTeam() == TEAM_ALLIANCE ? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY);
+ }
+
+ if (GameObject* go = SpawnGameObject(teleporter.HordeEntry, teleporter.Pos, teleporter.Rot))
+ {
+ DefenderPortalList[TEAM_HORDE].push_back(go->GetGUID());
+ go->SetRespawnTime(GetDefenderTeam() == TEAM_HORDE ? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY);
+ }
+ }
+
+ UpdateCounterVehicle(true);
+ return true;
+}
+
+bool BattlefieldWG::Update(uint32 diff)
+{
+ bool m_return = Battlefield::Update(diff);
+ if (m_saveTimer <= diff)
+ {
+ sWorld->setWorldState(WS_BATTLEFIELD_WG_ACTIVE, m_isActive);
+ sWorld->setWorldState(WS_BATTLEFIELD_WG_DEFENDER, m_DefenderTeam);
+ sWorld->setWorldState(ClockWorldState[0], m_Timer);
+ sWorld->setWorldState(WS_BATTLEFIELD_WG_ATTACKED_A, GetData(BATTLEFIELD_WG_DATA_WON_A));
+ sWorld->setWorldState(WS_BATTLEFIELD_WG_DEFENDED_A, GetData(BATTLEFIELD_WG_DATA_DEF_A));
+ sWorld->setWorldState(WS_BATTLEFIELD_WG_ATTACKED_H, GetData(BATTLEFIELD_WG_DATA_WON_H));
+ sWorld->setWorldState(WS_BATTLEFIELD_WG_DEFENDED_H, GetData(BATTLEFIELD_WG_DATA_DEF_H));
+ m_saveTimer = 60 * IN_MILLISECONDS;
+ }
+ else
+ m_saveTimer -= diff;
+
+ return m_return;
+}
+
+void BattlefieldWG::OnBattleStart()
+{
+ // Spawn titan relic
+ if (GameObject* relic = SpawnGameObject(GO_WINTERGRASP_TITAN_S_RELIC, WintergraspRelicPos, WintergraspRelicRot))
+ {
+ // Update faction of relic, only attacker can click on
+ relic->SetFaction(WintergraspFaction[GetAttackerTeam()]);
+ // Set in use (not allow to click on before last door is broken)
+ relic->AddFlag(GameObjectFlags(GO_FLAG_IN_USE | GO_FLAG_NOT_SELECTABLE));
+ m_titansRelicGUID = relic->GetGUID();
+ }
+ else
+ TC_LOG_ERROR("bg.battlefield", "WG: Failed to spawn titan relic.");
+
+
+ // Update tower visibility and update faction
+ for (auto itr = CanonList.begin(); itr != CanonList.end(); ++itr)
+ {
+ if (Creature* creature = GetCreature(*itr))
+ {
+ ShowNpc(creature, true);
+ creature->SetFaction(WintergraspFaction[GetDefenderTeam()]);
+ }
+ }
+
+ // Rebuild all wall
+ for (BfWGGameObjectBuilding* building : BuildingsInZone)
+ {
+ building->Rebuild();
+ building->UpdateTurretAttack(false);
+ }
+
+ SetData(BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT, 0);
+ SetData(BATTLEFIELD_WG_DATA_BROKEN_TOWER_DEF, 0);
+ SetData(BATTLEFIELD_WG_DATA_DAMAGED_TOWER_ATT, 0);
+ SetData(BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF, 0);
+
+ // Update graveyard (in no war time all graveyard is to deffender, in war time, depend of base)
+ for (WintergraspWorkshop* workshop : Workshops)
+ workshop->UpdateGraveyardAndWorkshop();
+
+ for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
+ {
+ for (auto itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
+ {
+ // Kick player in orb room, TODO: offline player ?
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ {
+ float x, y, z;
+ player->GetPosition(x, y, z);
+ if (5500 > x && x > 5392 && y < 2880 && y > 2800 && z < 480)
+ player->TeleportTo(571, 5349.8686f, 2838.481f, 409.240f, 0.046328f);
+ SendInitWorldStatesTo(player);
+ }
+ }
+ }
+
+ // Initialize vehicle counter
+ UpdateCounterVehicle(true);
+ // Send start warning to all players
+ SendWarning(BATTLEFIELD_WG_TEXT_START_BATTLE);
+}
+
+void BattlefieldWG::UpdateCounterVehicle(bool init)
+{
+ if (init)
+ {
+ SetData(BATTLEFIELD_WG_DATA_VEHICLE_H, 0);
+ SetData(BATTLEFIELD_WG_DATA_VEHICLE_A, 0);
+ }
+ SetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H, 0);
+ SetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A, 0);
+
+ for (WintergraspWorkshop* workshop : Workshops)
+ {
+ if (workshop->GetTeamControl() == TEAM_ALLIANCE)
+ UpdateData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A, 4);
+ else if (workshop->GetTeamControl() == TEAM_HORDE)
+ UpdateData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H, 4);
+ }
+
+ UpdateVehicleCountWG();
+}
+
+void BattlefieldWG::OnBattleEnd(bool endByTimer)
+{
+ // Remove relic
+ if (!m_titansRelicGUID.IsEmpty())
+ if (GameObject* relic = GetGameObject(m_titansRelicGUID))
+ relic->RemoveFromWorld();
+ m_titansRelicGUID.Clear();
+
+ // change collision wall state closed
+ for (BfWGGameObjectBuilding* building : BuildingsInZone)
+ {
+ building->RebuildGate();
+ }
+
+ // successful defense
+ if (endByTimer)
+ UpdateData(GetDefenderTeam() == TEAM_HORDE ? BATTLEFIELD_WG_DATA_DEF_H : BATTLEFIELD_WG_DATA_DEF_A, 1);
+ // successful attack (note that teams have already been swapped, so defender team is the one who won)
+ else
+ UpdateData(GetDefenderTeam() == TEAM_HORDE ? BATTLEFIELD_WG_DATA_WON_H : BATTLEFIELD_WG_DATA_WON_A, 1);
+
+ // Remove turret
+ for (auto itr = CanonList.begin(); itr != CanonList.end(); ++itr)
+ {
+ if (Creature* creature = GetCreature(*itr))
+ {
+ if (!endByTimer)
+ creature->SetFaction(WintergraspFaction[GetDefenderTeam()]);
+ HideNpc(creature);
+ }
+ }
+
+ // Update all graveyard, control is to defender when no wartime
+ for (uint8 i = 0; i < BATTLEFIELD_WG_GY_HORDE; i++)
+ if (BfGraveyard* graveyard = GetGraveyardById(i))
+ graveyard->GiveControlTo(GetDefenderTeam());
+
+ // Update portals
+ for (auto itr = DefenderPortalList[GetDefenderTeam()].begin(); itr != DefenderPortalList[GetDefenderTeam()].end(); ++itr)
+ if (GameObject* portal = GetGameObject(*itr))
+ portal->SetRespawnTime(RESPAWN_IMMEDIATELY);
+
+ for (auto itr = DefenderPortalList[GetAttackerTeam()].begin(); itr != DefenderPortalList[GetAttackerTeam()].end(); ++itr)
+ if (GameObject* portal = GetGameObject(*itr))
+ portal->SetRespawnTime(RESPAWN_ONE_DAY);
+
+ // Saving data
+ for (BfWGGameObjectBuilding* building : BuildingsInZone)
+ building->Save();
+
+ for (WintergraspWorkshop* workshop : Workshops)
+ workshop->Save();
+
+ for (auto itr = m_PlayersInWar[GetDefenderTeam()].begin(); itr != m_PlayersInWar[GetDefenderTeam()].end(); ++itr)
+ {
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ {
+ player->CastSpell(player, SPELL_ESSENCE_OF_WINTERGRASP, true);
+ player->CastSpell(player, SPELL_VICTORY_REWARD, true);
+ // Complete victory quests
+ player->AreaExploredOrEventHappens(QUEST_VICTORY_WINTERGRASP_A);
+ player->AreaExploredOrEventHappens(QUEST_VICTORY_WINTERGRASP_H);
+ // Send Wintergrasp victory achievement
+ DoCompleteOrIncrementAchievement(ACHIEVEMENTS_WIN_WG, player);
+ // Award achievement for succeeding in Wintergrasp in 10 minutes or less
+ if (!endByTimer && GetTimer() <= 10000)
+ DoCompleteOrIncrementAchievement(ACHIEVEMENTS_WIN_WG_TIMER_10, player);
+ }
+ }
+
+ for (auto itr = m_PlayersInWar[GetAttackerTeam()].begin(); itr != m_PlayersInWar[GetAttackerTeam()].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ player->CastSpell(player, SPELL_DEFEAT_REWARD, true);
+
+ for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
+ {
+ for (auto itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ RemoveAurasFromPlayer(player);
+
+ m_PlayersInWar[team].clear();
+
+ for (auto itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr)
+ if (Creature* creature = GetCreature(*itr))
+ if (creature->IsVehicle())
+ creature->DespawnOrUnsummon();
+
+ m_vehicles[team].clear();
+ }
+
+ if (!endByTimer)
+ {
+ for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
+ {
+ for (auto itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
+ {
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ {
+ player->RemoveAurasDueToSpell(m_DefenderTeam == TEAM_ALLIANCE ? SPELL_HORDE_CONTROL_PHASE_SHIFT : SPELL_ALLIANCE_CONTROL_PHASE_SHIFT, player->GetGUID());
+ player->AddAura(m_DefenderTeam == TEAM_HORDE ? SPELL_HORDE_CONTROL_PHASE_SHIFT : SPELL_ALLIANCE_CONTROL_PHASE_SHIFT, player);
+ }
+ }
+ }
+ }
+
+ if (!endByTimer) // win alli/horde
+ SendWarning(GetDefenderTeam() == TEAM_ALLIANCE ? BATTLEFIELD_WG_TEXT_FORTRESS_CAPTURE_ALLIANCE : BATTLEFIELD_WG_TEXT_FORTRESS_CAPTURE_HORDE);
+ else // defend alli/horde
+ SendWarning(GetDefenderTeam() == TEAM_ALLIANCE ? BATTLEFIELD_WG_TEXT_FORTRESS_DEFEND_ALLIANCE : BATTLEFIELD_WG_TEXT_FORTRESS_DEFEND_HORDE);
+}
+
+// *******************************************************
+// ******************* Reward System *********************
+// *******************************************************
+void BattlefieldWG::DoCompleteOrIncrementAchievement(uint32 achievement, Player* player, uint8 /*incrementNumber*/)
+{
+ AchievementEntry const* achievementEntry = sAchievementStore.LookupEntry(achievement);
+
+ if (!achievementEntry)
+ return;
+
+ switch (achievement)
+ {
+ case ACHIEVEMENTS_WIN_WG_100:
+ {
+ // player->UpdateCriteria();
+ }
+ default:
+ {
+ if (player)
+ player->CompletedAchievement(achievementEntry);
+ break;
+ }
+ }
+
+}
+
+void BattlefieldWG::OnStartGrouping()
+{
+ SendWarning(BATTLEFIELD_WG_TEXT_START_GROUPING);
+}
+
+uint8 BattlefieldWG::GetSpiritGraveyardId(uint32 areaId) const
+{
+ switch (areaId)
+ {
+ case AREA_WINTERGRASP_FORTRESS:
+ return BATTLEFIELD_WG_GY_KEEP;
+ case AREA_THE_SUNKEN_RING:
+ return BATTLEFIELD_WG_GY_WORKSHOP_NE;
+ case AREA_THE_BROKEN_TEMPLATE:
+ return BATTLEFIELD_WG_GY_WORKSHOP_NW;
+ case AREA_WESTPARK_WORKSHOP:
+ return BATTLEFIELD_WG_GY_WORKSHOP_SW;
+ case AREA_EASTPARK_WORKSHOP:
+ return BATTLEFIELD_WG_GY_WORKSHOP_SE;
+ case AREA_WINTERGRASP:
+ return BATTLEFIELD_WG_GY_ALLIANCE;
+ case AREA_THE_CHILLED_QUAGMIRE:
+ return BATTLEFIELD_WG_GY_HORDE;
+ default:
+ TC_LOG_ERROR("bg.battlefield", "BattlefieldWG::GetSpiritGraveyardId: Unexpected Area Id %u", areaId);
+ break;
+ }
+
+ return 0;
+}
+
+void BattlefieldWG::OnCreatureCreate(Creature* creature)
+{
+ // Accessing to db spawned creatures
+ switch (creature->GetEntry())
+ {
+ case NPC_DWARVEN_SPIRIT_GUIDE:
+ case NPC_TAUNKA_SPIRIT_GUIDE:
+ {
+ TeamId teamId = (creature->GetEntry() == NPC_DWARVEN_SPIRIT_GUIDE ? TEAM_ALLIANCE : TEAM_HORDE);
+ uint8 graveyardId = GetSpiritGraveyardId(creature->GetAreaId());
+ if (m_GraveyardList[graveyardId])
+ m_GraveyardList[graveyardId]->SetSpirit(creature, teamId);
+ break;
+ }
+ }
+
+ // untested code - not sure if it is valid.
+ if (IsWarTime())
+ {
+ switch (creature->GetEntry())
+ {
+ case NPC_WINTERGRASP_SIEGE_ENGINE_ALLIANCE:
+ case NPC_WINTERGRASP_SIEGE_ENGINE_HORDE:
+ case NPC_WINTERGRASP_CATAPULT:
+ case NPC_WINTERGRASP_DEMOLISHER:
+ {
+ if (!creature->ToTempSummon() || !creature->ToTempSummon()->GetSummonerGUID() || !ObjectAccessor::FindPlayer(creature->ToTempSummon()->GetSummonerGUID()))
+ {
+ creature->DespawnOrUnsummon();
+ return;
+ }
+
+ Player* creator = ObjectAccessor::FindPlayer(creature->ToTempSummon()->GetSummonerGUID());
+ TeamId team = creator->GetTeamId();
+
+ if (team == TEAM_HORDE)
+ {
+ if (GetData(BATTLEFIELD_WG_DATA_VEHICLE_H) < GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H))
+ {
+ UpdateData(BATTLEFIELD_WG_DATA_VEHICLE_H, 1);
+ creature->AddAura(SPELL_HORDE_FLAG, creature);
+ m_vehicles[team].insert(creature->GetGUID());
+ UpdateVehicleCountWG();
+ }
+ else
+ {
+ creature->DespawnOrUnsummon();
+ return;
+ }
+ }
+ else
+ {
+ if (GetData(BATTLEFIELD_WG_DATA_VEHICLE_A) < GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A))
+ {
+ UpdateData(BATTLEFIELD_WG_DATA_VEHICLE_A, 1);
+ creature->AddAura(SPELL_ALLIANCE_FLAG, creature);
+ m_vehicles[team].insert(creature->GetGUID());
+ UpdateVehicleCountWG();
+ }
+ else
+ {
+ creature->DespawnOrUnsummon();
+ return;
+ }
+ }
+
+ creature->CastSpell(creator, SPELL_GRAB_PASSENGER, true);
+ break;
+ }
+ }
+ }
+}
+
+void BattlefieldWG::OnCreatureRemove(Creature* /*creature*/)
+{
+/* possibly can be used later
+ if (IsWarTime())
+ {
+ switch (creature->GetEntry())
+ {
+ case NPC_WINTERGRASP_SIEGE_ENGINE_ALLIANCE:
+ case NPC_WINTERGRASP_SIEGE_ENGINE_HORDE:
+ case NPC_WINTERGRASP_CATAPULT:
+ case NPC_WINTERGRASP_DEMOLISHER:
+ {
+ uint8 team;
+ if (creature->GetFaction() == WintergraspFaction[TEAM_ALLIANCE])
+ team = TEAM_ALLIANCE;
+ else if (creature->GetFaction() == WintergraspFaction[TEAM_HORDE])
+ team = TEAM_HORDE;
+ else
+ return;
+
+ m_vehicles[team].erase(creature->GetGUID());
+ if (team == TEAM_HORDE)
+ UpdateData(BATTLEFIELD_WG_DATA_VEHICLE_H, -1);
+ else
+ UpdateData(BATTLEFIELD_WG_DATA_VEHICLE_A, -1);
+ UpdateVehicleCountWG();
+
+ break;
+ }
+ }
+ }*/
+}
+
+void BattlefieldWG::OnGameObjectCreate(GameObject* go)
+{
+ uint8 workshopId = 0;
+
+ switch (go->GetEntry())
+ {
+ case GO_WINTERGRASP_FACTORY_BANNER_NE:
+ workshopId = BATTLEFIELD_WG_WORKSHOP_NE;
+ break;
+ case GO_WINTERGRASP_FACTORY_BANNER_NW:
+ workshopId = BATTLEFIELD_WG_WORKSHOP_NW;
+ break;
+ case GO_WINTERGRASP_FACTORY_BANNER_SE:
+ workshopId = BATTLEFIELD_WG_WORKSHOP_SE;
+ break;
+ case GO_WINTERGRASP_FACTORY_BANNER_SW:
+ workshopId = BATTLEFIELD_WG_WORKSHOP_SW;
+ break;
+ default:
+ return;
+ }
+
+ for (WintergraspWorkshop* workshop : Workshops)
+ {
+ if (workshop->GetId() == workshopId)
+ {
+ WintergraspCapturePoint* capturePoint = new WintergraspCapturePoint(this, GetAttackerTeam());
+
+ capturePoint->SetCapturePointData(go);
+ capturePoint->LinkToWorkshop(workshop);
+ AddCapturePoint(capturePoint);
+ break;
+ }
+ }
+}
+
+// Called when player kill a unit in wg zone
+void BattlefieldWG::HandleKill(Player* killer, Unit* victim)
+{
+ if (killer == victim)
+ return;
+
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ {
+ HandlePromotion(killer, victim);
+
+ // Allow to Skin non-released corpse
+ victim->AddUnitFlag(UNIT_FLAG_SKINNABLE);
+ }
+
+ /// @todoRecent PvP activity worldstate
+}
+
+bool BattlefieldWG::FindAndRemoveVehicleFromList(Unit* vehicle)
+{
+ for (uint32 team = 0; team < PVP_TEAMS_COUNT; ++team)
+ {
+ auto itr = m_vehicles[team].find(vehicle->GetGUID());
+ if (itr != m_vehicles[team].end())
+ {
+ m_vehicles[team].erase(itr);
+
+ if (team == TEAM_HORDE)
+ UpdateData(BATTLEFIELD_WG_DATA_VEHICLE_H, -1);
+ else
+ UpdateData(BATTLEFIELD_WG_DATA_VEHICLE_A, -1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void BattlefieldWG::OnUnitDeath(Unit* unit)
+{
+ if (IsWarTime())
+ if (unit->IsVehicle())
+ if (FindAndRemoveVehicleFromList(unit))
+ UpdateVehicleCountWG();
+}
+
+void BattlefieldWG::HandlePromotion(Player* playerKiller, Unit* unitKilled)
+{
+ uint32 teamId = playerKiller->GetTeamId();
+
+ for (auto iter = m_PlayersInWar[teamId].begin(); iter != m_PlayersInWar[teamId].end(); ++iter)
+ if (Player* player = ObjectAccessor::FindPlayer(*iter))
+ if (player->GetDistance2d(unitKilled) < 40.0f)
+ PromotePlayer(player);
+}
+
+// Update rank for player
+void BattlefieldWG::PromotePlayer(Player* killer)
+{
+ if (!m_isActive)
+ return;
+ // Updating rank of player
+ if (Aura* auraRecruit = killer->GetAura(SPELL_RECRUIT))
+ {
+ if (auraRecruit->GetStackAmount() >= 5)
+ {
+ killer->RemoveAura(SPELL_RECRUIT);
+ killer->CastSpell(killer, SPELL_CORPORAL, true);
+ if (Creature* stalker = GetCreature(StalkerGuid))
+ sCreatureTextMgr->SendChat(stalker, BATTLEFIELD_WG_TEXT_RANK_CORPORAL, killer, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, SoundKitPlayType::Normal, TEAM_OTHER, false, killer);
+ }
+ else
+ killer->CastSpell(killer, SPELL_RECRUIT, true);
+ }
+ else if (Aura* auraCorporal = killer->GetAura(SPELL_CORPORAL))
+ {
+ if (auraCorporal->GetStackAmount() >= 5)
+ {
+ killer->RemoveAura(SPELL_CORPORAL);
+ killer->CastSpell(killer, SPELL_LIEUTENANT, true);
+ if (Creature* stalker = GetCreature(StalkerGuid))
+ sCreatureTextMgr->SendChat(stalker, BATTLEFIELD_WG_TEXT_RANK_FIRST_LIEUTENANT, killer, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, SoundKitPlayType::Normal, TEAM_OTHER, false, killer);
+ }
+ else
+ killer->CastSpell(killer, SPELL_CORPORAL, true);
+ }
+}
+
+void BattlefieldWG::RemoveAurasFromPlayer(Player* player)
+{
+ player->RemoveAurasDueToSpell(SPELL_RECRUIT);
+ player->RemoveAurasDueToSpell(SPELL_CORPORAL);
+ player->RemoveAurasDueToSpell(SPELL_LIEUTENANT);
+ player->RemoveAurasDueToSpell(SPELL_TOWER_CONTROL);
+ player->RemoveAurasDueToSpell(SPELL_SPIRITUAL_IMMUNITY);
+ player->RemoveAurasDueToSpell(SPELL_TENACITY);
+ player->RemoveAurasDueToSpell(SPELL_ESSENCE_OF_WINTERGRASP);
+ player->RemoveAurasDueToSpell(SPELL_WINTERGRASP_RESTRICTED_FLIGHT_AREA);
+}
+
+void BattlefieldWG::OnPlayerJoinWar(Player* player)
+{
+ RemoveAurasFromPlayer(player);
+
+ player->CastSpell(player, SPELL_RECRUIT, true);
+
+ if (player->GetZoneId() != m_ZoneId)
+ {
+ if (player->GetTeamId() == GetDefenderTeam())
+ player->TeleportTo(571, 5345, 2842, 410, 3.14f);
+ else
+ {
+ if (player->GetTeamId() == TEAM_HORDE)
+ player->TeleportTo(571, 5025.857422f, 3674.628906f, 362.737122f, 4.135169f);
+ else
+ player->TeleportTo(571, 5101.284f, 2186.564f, 373.549f, 3.812f);
+ }
+ }
+
+ UpdateTenacity();
+
+ if (player->GetTeamId() == GetAttackerTeam())
+ {
+ if (GetData(BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT) < 3)
+ player->SetAuraStack(SPELL_TOWER_CONTROL, player, 3 - GetData(BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT));
+ }
+ else
+ {
+ if (GetData(BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT) > 0)
+ player->SetAuraStack(SPELL_TOWER_CONTROL, player, GetData(BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT));
+ }
+ SendInitWorldStatesTo(player);
+}
+
+void BattlefieldWG::OnPlayerLeaveWar(Player* player)
+{
+ // Remove all aura from WG /// @todo false we can go out of this zone on retail and keep Rank buff, remove on end of WG
+ if (!player->GetSession()->PlayerLogout())
+ {
+ if (Creature* vehicle = player->GetVehicleCreatureBase()) // Remove vehicle of player if he go out.
+ vehicle->DespawnOrUnsummon();
+
+ RemoveAurasFromPlayer(player);
+ }
+
+ player->RemoveAurasDueToSpell(SPELL_HORDE_CONTROLS_FACTORY_PHASE_SHIFT);
+ player->RemoveAurasDueToSpell(SPELL_ALLIANCE_CONTROLS_FACTORY_PHASE_SHIFT);
+ player->RemoveAurasDueToSpell(SPELL_HORDE_CONTROL_PHASE_SHIFT);
+ player->RemoveAurasDueToSpell(SPELL_ALLIANCE_CONTROL_PHASE_SHIFT);
+ UpdateTenacity();
+}
+
+void BattlefieldWG::OnPlayerLeaveZone(Player* player)
+{
+ if (!m_isActive)
+ RemoveAurasFromPlayer(player);
+
+ player->RemoveAurasDueToSpell(SPELL_HORDE_CONTROLS_FACTORY_PHASE_SHIFT);
+ player->RemoveAurasDueToSpell(SPELL_ALLIANCE_CONTROLS_FACTORY_PHASE_SHIFT);
+ player->RemoveAurasDueToSpell(SPELL_HORDE_CONTROL_PHASE_SHIFT);
+ player->RemoveAurasDueToSpell(SPELL_ALLIANCE_CONTROL_PHASE_SHIFT);
+}
+
+void BattlefieldWG::OnPlayerEnterZone(Player* player)
+{
+ if (!m_isActive)
+ RemoveAurasFromPlayer(player);
+
+ player->AddAura(m_DefenderTeam == TEAM_HORDE ? SPELL_HORDE_CONTROL_PHASE_SHIFT : SPELL_ALLIANCE_CONTROL_PHASE_SHIFT, player);
+ // Send worldstate to player
+ SendInitWorldStatesTo(player);
+}
+
+uint32 BattlefieldWG::GetData(uint32 data) const
+{
+ switch (data)
+ {
+ // Used to determine when the phasing spells must be cast
+ // See: SpellArea::IsFitToRequirements
+ case AREA_THE_SUNKEN_RING:
+ case AREA_THE_BROKEN_TEMPLATE:
+ case AREA_WESTPARK_WORKSHOP:
+ case AREA_EASTPARK_WORKSHOP:
+ // Graveyards and Workshops are controlled by the same team.
+ if (BfGraveyard const* graveyard = GetGraveyardById(GetSpiritGraveyardId(data)))
+ return graveyard->GetControlTeamId();
+ break;
+ default:
+ break;
+ }
+
+ return Battlefield::GetData(data);
+}
+
+
+void BattlefieldWG::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
+{
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_DEFENDED_A, GetData(BATTLEFIELD_WG_DATA_DEF_A));
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_DEFENDED_H, GetData(BATTLEFIELD_WG_DATA_DEF_H));
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_ATTACKED_A, GetData(BATTLEFIELD_WG_DATA_WON_A));
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_ATTACKED_H, GetData(BATTLEFIELD_WG_DATA_WON_H));
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_ATTACKER, GetAttackerTeam());
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_DEFENDER, GetDefenderTeam());
+
+ // Note: cleanup these two, their names look awkward
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_ACTIVE, IsWarTime() ? 0 : 1);
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_SHOW_WORLDSTATE, IsWarTime() ? 1 : 0);
+
+ for (uint32 itr = 0; itr < 2; ++itr)
+ packet.Worldstates.emplace_back(ClockWorldState[itr], int32(GameTime::GetGameTime()) + int32(m_Timer) / int32(1000));
+
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_VEHICLE_H, GetData(BATTLEFIELD_WG_DATA_VEHICLE_H));
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_MAX_VEHICLE_H, GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H));
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_VEHICLE_A, GetData(BATTLEFIELD_WG_DATA_VEHICLE_A));
+ packet.Worldstates.emplace_back(WS_BATTLEFIELD_WG_MAX_VEHICLE_A, GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A));
+
+ for (BfWGGameObjectBuilding* building : BuildingsInZone)
+ building->FillInitialWorldStates(packet);
+
+ for (WintergraspWorkshop* workshop : Workshops)
+ workshop->FillInitialWorldStates(packet);
+}
+
+void BattlefieldWG::SendInitWorldStatesTo(Player* player)
+{
+ WorldPackets::WorldState::InitWorldStates packet;
+ packet.MapID = m_MapId;
+ packet.AreaID = m_ZoneId;
+ packet.SubareaID = player->GetAreaId();
+ FillInitialWorldStates(packet);
+
+ player->SendDirectMessage(packet.Write());
+}
+
+void BattlefieldWG::SendInitWorldStatesToAll()
+{
+ for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
+ for (auto itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ SendInitWorldStatesTo(player);
+}
+
+void BattlefieldWG::BrokenWallOrTower(TeamId team, BfWGGameObjectBuilding* building)
+{
+ if (team == GetDefenderTeam())
+ {
+ for (auto itr = m_PlayersInWar[GetAttackerTeam()].begin(); itr != m_PlayersInWar[GetAttackerTeam()].end(); ++itr)
+ {
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ if (player->GetDistance2d(ASSERT_NOTNULL(GetGameObject(building->GetGUID()))) < 50.0f)
+ player->KilledMonsterCredit(QUEST_CREDIT_DEFEND_SIEGE);
+ }
+ }
+}
+
+// Called when a tower is broke
+void BattlefieldWG::UpdatedDestroyedTowerCount(TeamId team)
+{
+ // Southern tower
+ if (team == GetAttackerTeam())
+ {
+ // Update counter
+ UpdateData(BATTLEFIELD_WG_DATA_DAMAGED_TOWER_ATT, -1);
+ UpdateData(BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT, 1);
+
+ // Remove buff stack on attackers
+ for (auto itr = m_PlayersInWar[GetAttackerTeam()].begin(); itr != m_PlayersInWar[GetAttackerTeam()].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ player->RemoveAuraFromStack(SPELL_TOWER_CONTROL);
+
+ // Add buff stack to defenders and give achievement/quest credit
+ for (auto itr = m_PlayersInWar[GetDefenderTeam()].begin(); itr != m_PlayersInWar[GetDefenderTeam()].end(); ++itr)
+ {
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ {
+ player->CastSpell(player, SPELL_TOWER_CONTROL, true);
+ player->KilledMonsterCredit(QUEST_CREDIT_TOWERS_DESTROYED);
+ DoCompleteOrIncrementAchievement(ACHIEVEMENTS_WG_TOWER_DESTROY, player);
+ }
+ }
+
+ // If all three south towers are destroyed (ie. all attack towers), remove ten minutes from battle time
+ if (GetData(BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT) == 3)
+ {
+ if (int32(m_Timer - 600000) < 0)
+ m_Timer = 0;
+ else
+ m_Timer -= 600000;
+ SendInitWorldStatesToAll();
+ }
+ }
+ else // Keep tower
+ {
+ UpdateData(BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF, -1);
+ UpdateData(BATTLEFIELD_WG_DATA_BROKEN_TOWER_DEF, 1);
+ }
+}
+
+void BattlefieldWG::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* /*invoker*/)
+{
+ if (!obj || !IsWarTime())
+ return;
+
+ // We handle only gameobjects here
+ GameObject* go = obj->ToGameObject();
+ if (!go)
+ return;
+
+ // On click on titan relic
+ if (go->GetEntry() == GO_WINTERGRASP_TITAN_S_RELIC)
+ {
+ if (CanInteractWithRelic())
+ EndBattle(false);
+ else if (GameObject* relic = GetRelic())
+ relic->SetRespawnTime(RESPAWN_IMMEDIATELY);
+ }
+
+ // if destroy or damage event, search the wall/tower and update worldstate/send warning message
+ for (BfWGGameObjectBuilding* building : BuildingsInZone)
+ {
+ if (go->GetGUID() == building->GetGUID())
+ {
+ if (GameObject* buildingGo = GetGameObject(building->GetGUID()))
+ {
+ if (buildingGo->GetGOInfo()->destructibleBuilding.DamagedEvent == eventId)
+ building->Damaged();
+ else if (buildingGo->GetGOInfo()->destructibleBuilding.DestroyedEvent == eventId)
+ building->Destroyed();
+ break;
+ }
+ }
+ }
+}
+
+// Called when a tower is damaged, used for honor reward calcul
+void BattlefieldWG::UpdateDamagedTowerCount(TeamId team)
+{
+ if (team == GetAttackerTeam())
+ UpdateData(BATTLEFIELD_WG_DATA_DAMAGED_TOWER_ATT, 1);
+ else
+ UpdateData(BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF, 1);
+}
+
+// Update vehicle count WorldState to player
+void BattlefieldWG::UpdateVehicleCountWG()
+{
+ SendUpdateWorldState(WS_BATTLEFIELD_WG_VEHICLE_H, GetData(BATTLEFIELD_WG_DATA_VEHICLE_H));
+ SendUpdateWorldState(WS_BATTLEFIELD_WG_MAX_VEHICLE_H, GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_H));
+ SendUpdateWorldState(WS_BATTLEFIELD_WG_VEHICLE_A, GetData(BATTLEFIELD_WG_DATA_VEHICLE_A));
+ SendUpdateWorldState(WS_BATTLEFIELD_WG_MAX_VEHICLE_A, GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A));
+}
+
+void BattlefieldWG::UpdateTenacity()
+{
+ uint32 alliancePlayers = m_PlayersInWar[TEAM_ALLIANCE].size();
+ uint32 hordePlayers = m_PlayersInWar[TEAM_HORDE].size();
+ int32 newStack = 0;
+
+ if (alliancePlayers && hordePlayers)
+ {
+ if (alliancePlayers < hordePlayers)
+ newStack = int32((float(hordePlayers / alliancePlayers) - 1) * 4); // positive, should cast on alliance
+ else if (alliancePlayers > hordePlayers)
+ newStack = int32((1 - float(alliancePlayers / hordePlayers)) * 4); // negative, should cast on horde
+ }
+
+ if (newStack == int32(m_tenacityStack))
+ return;
+
+ m_tenacityStack = newStack;
+ // Remove old buff
+ if (m_tenacityTeam != TEAM_NEUTRAL)
+ {
+ for (auto itr = m_players[m_tenacityTeam].begin(); itr != m_players[m_tenacityTeam].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ if (player->GetLevel() >= m_MinLevel)
+ player->RemoveAurasDueToSpell(SPELL_TENACITY);
+
+ for (auto itr = m_vehicles[m_tenacityTeam].begin(); itr != m_vehicles[m_tenacityTeam].end(); ++itr)
+ if (Creature* creature = GetCreature(*itr))
+ creature->RemoveAurasDueToSpell(SPELL_TENACITY_VEHICLE);
+ }
+
+ // Apply new buff
+ if (newStack)
+ {
+ m_tenacityTeam = newStack > 0 ? TEAM_ALLIANCE : TEAM_HORDE;
+
+ if (newStack < 0)
+ newStack = -newStack;
+ if (newStack > 20)
+ newStack = 20;
+
+ uint32 buff_honor = SPELL_GREATEST_HONOR;
+ if (newStack < 15)
+ buff_honor = SPELL_GREATER_HONOR;
+ if (newStack < 10)
+ buff_honor = SPELL_GREAT_HONOR;
+ if (newStack < 5)
+ buff_honor = 0;
+
+ for (auto itr = m_PlayersInWar[m_tenacityTeam].begin(); itr != m_PlayersInWar[m_tenacityTeam].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ player->SetAuraStack(SPELL_TENACITY, player, newStack);
+
+ for (auto itr = m_vehicles[m_tenacityTeam].begin(); itr != m_vehicles[m_tenacityTeam].end(); ++itr)
+ if (Creature* creature = GetCreature(*itr))
+ creature->SetAuraStack(SPELL_TENACITY_VEHICLE, creature, newStack);
+
+ if (buff_honor != 0)
+ {
+ for (auto itr = m_PlayersInWar[m_tenacityTeam].begin(); itr != m_PlayersInWar[m_tenacityTeam].end(); ++itr)
+ if (Player* player = ObjectAccessor::FindPlayer(*itr))
+ player->CastSpell(player, buff_honor, true);
+
+ for (auto itr = m_vehicles[m_tenacityTeam].begin(); itr != m_vehicles[m_tenacityTeam].end(); ++itr)
+ if (Creature* creature = GetCreature(*itr))
+ creature->CastSpell(creature, buff_honor, true);
+ }
+ }
+ else
+ m_tenacityTeam = TEAM_NEUTRAL;
+}
+
+WintergraspCapturePoint::WintergraspCapturePoint(BattlefieldWG* battlefield, TeamId teamInControl) : BfCapturePoint(battlefield)
+{
+ m_Bf = battlefield;
+ m_team = teamInControl;
+ m_Workshop = nullptr;
+}
+
+void WintergraspCapturePoint::ChangeTeam(TeamId /*oldTeam*/)
+{
+ ASSERT(m_Workshop);
+ m_Workshop->GiveControlTo(m_team);
+}
+
+BfGraveyardWG::BfGraveyardWG(BattlefieldWG* battlefield) : BfGraveyard(battlefield)
+{
+ m_Bf = battlefield;
+ m_GossipTextId = 0;
+}
+
+BfWGGameObjectBuilding::BfWGGameObjectBuilding(BattlefieldWG* wg, WintergraspGameObjectBuildingType type, uint32 worldState)
+{
+ ASSERT(wg);
+
+ _wg = wg;
+ _teamControl = TEAM_NEUTRAL;
+ _type = type;
+ _worldState = worldState;
+ _state = BATTLEFIELD_WG_OBJECTSTATE_NONE;
+ _staticTowerInfo = nullptr;
+}
+
+void BfWGGameObjectBuilding::Rebuild()
+{
+ switch (_type)
+ {
+ case BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER:
+ case BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST:
+ case BATTLEFIELD_WG_OBJECTTYPE_DOOR:
+ case BATTLEFIELD_WG_OBJECTTYPE_WALL:
+ _teamControl = _wg->GetDefenderTeam(); // Objects that are part of the keep should be the defender's
+ break;
+ case BATTLEFIELD_WG_OBJECTTYPE_TOWER:
+ _teamControl = _wg->GetAttackerTeam(); // The towers in the south should be the attacker's
+ break;
+ default:
+ _teamControl = TEAM_NEUTRAL;
+ break;
+ }
+
+ if (GameObject* build = _wg->GetGameObject(_buildGUID))
+ {
+ // Rebuild gameobject
+ if (build->IsDestructibleBuilding())
+ {
+ build->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING, nullptr, true);
+ if (build->GetEntry() == GO_WINTERGRASP_VAULT_GATE)
+ if (GameObject* go = build->FindNearestGameObject(GO_WINTERGRASP_KEEP_COLLISION_WALL, 50.0f))
+ go->SetGoState(GO_STATE_ACTIVE);
+
+ // Update worldstate
+ _state = WintergraspGameObjectState(BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_INTACT - (_teamControl * 3));
+ _wg->SendUpdateWorldState(_worldState, _state);
+ }
+ UpdateCreatureAndGo();
+ build->SetFaction(WintergraspFaction[_teamControl]);
+ }
+}
+
+void BfWGGameObjectBuilding::RebuildGate()
+{
+ if (GameObject* build = _wg->GetGameObject(_buildGUID))
+ {
+ if (build->IsDestructibleBuilding() && build->GetEntry() == GO_WINTERGRASP_VAULT_GATE)
+ {
+ if (GameObject* go = build->FindNearestGameObject(GO_WINTERGRASP_KEEP_COLLISION_WALL, 50.0f))
+ go->SetGoState(GO_STATE_READY); //not GO_STATE_ACTIVE
+ }
+ }
+}
+
+void BfWGGameObjectBuilding::Damaged()
+{
+ // Update worldstate
+ _state = WintergraspGameObjectState(BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DAMAGE - (_teamControl * 3));
+ _wg->SendUpdateWorldState(_worldState, _state);
+
+ // Send warning message
+ if (_staticTowerInfo)
+ _wg->SendWarning(_staticTowerInfo->TextIds.Damaged);
+
+ for (ObjectGuid guid : m_CreatureTopList[_wg->GetAttackerTeam()])
+ if (Creature* creature = _wg->GetCreature(guid))
+ _wg->HideNpc(creature);
+
+ for (ObjectGuid guid : m_TurretTopList)
+ if (Creature* creature = _wg->GetCreature(guid))
+ _wg->HideNpc(creature);
+
+ if (_type == BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER)
+ _wg->UpdateDamagedTowerCount(_wg->GetDefenderTeam());
+ else if (_type == BATTLEFIELD_WG_OBJECTTYPE_TOWER)
+ _wg->UpdateDamagedTowerCount(_wg->GetAttackerTeam());
+}
+
+void BfWGGameObjectBuilding::Destroyed()
+{
+ // Update worldstate
+ _state = WintergraspGameObjectState(BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DESTROY - (_teamControl * 3));
+ _wg->SendUpdateWorldState(_worldState, _state);
+
+ // Warn players
+ if (_staticTowerInfo)
+ _wg->SendWarning(_staticTowerInfo->TextIds.Destroyed);
+
+ switch (_type)
+ {
+ // Inform the global wintergrasp script of the destruction of this object
+ case BATTLEFIELD_WG_OBJECTTYPE_TOWER:
+ case BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER:
+ _wg->UpdatedDestroyedTowerCount(_teamControl);
+ break;
+ case BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST:
+ if (GameObject* build = _wg->GetGameObject(_buildGUID))
+ if (GameObject* go = build->FindNearestGameObject(GO_WINTERGRASP_KEEP_COLLISION_WALL, 50.0f))
+ go->SetGoState(GO_STATE_ACTIVE);
+ _wg->SetRelicInteractible(true);
+ if (_wg->GetRelic())
+ _wg->GetRelic()->RemoveFlag(GameObjectFlags(GO_FLAG_IN_USE | GO_FLAG_NOT_SELECTABLE));
+ else
+ TC_LOG_ERROR("bg.battlefield.wg", "Titan Relic not found.");
+ break;
+ default:
+ break;
+ }
+
+ _wg->BrokenWallOrTower(_teamControl, this);
+}
+
+void BfWGGameObjectBuilding::Init(GameObject* go)
+{
+ if (!go)
+ return;
+
+ // GameObject associated to object
+ _buildGUID = go->GetGUID();
+
+ switch (_type)
+ {
+ case BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER:
+ case BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST:
+ case BATTLEFIELD_WG_OBJECTTYPE_DOOR:
+ case BATTLEFIELD_WG_OBJECTTYPE_WALL:
+ _teamControl = _wg->GetDefenderTeam(); // Objects that are part of the keep should be the defender's
+ break;
+ case BATTLEFIELD_WG_OBJECTTYPE_TOWER:
+ _teamControl = _wg->GetAttackerTeam(); // The towers in the south should be the attacker's
+ break;
+ default:
+ _teamControl = TEAM_NEUTRAL;
+ break;
+ }
+
+ _state = WintergraspGameObjectState(sWorld->getWorldState(_worldState));
+ switch (_state)
+ {
+ case BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_INTACT:
+ case BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_INTACT:
+ case BATTLEFIELD_WG_OBJECTSTATE_HORDE_INTACT:
+ go->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING, nullptr, true);
+ break;
+ case BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_DESTROY:
+ case BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DESTROY:
+ case BATTLEFIELD_WG_OBJECTSTATE_HORDE_DESTROY:
+ go->SetDestructibleState(GO_DESTRUCTIBLE_DESTROYED);
+ break;
+ case BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_DAMAGE:
+ case BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DAMAGE:
+ case BATTLEFIELD_WG_OBJECTSTATE_HORDE_DAMAGE:
+ go->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED);
+ break;
+ default:
+ break;
+ }
+
+ int32 towerId = -1;
+ switch (go->GetEntry())
+ {
+ case GO_WINTERGRASP_FORTRESS_TOWER_1:
+ towerId = BATTLEFIELD_WG_TOWER_FORTRESS_NW;
+ break;
+ case GO_WINTERGRASP_FORTRESS_TOWER_2:
+ towerId = BATTLEFIELD_WG_TOWER_FORTRESS_SW;
+ break;
+ case GO_WINTERGRASP_FORTRESS_TOWER_3:
+ towerId = BATTLEFIELD_WG_TOWER_FORTRESS_SE;
+ break;
+ case GO_WINTERGRASP_FORTRESS_TOWER_4:
+ towerId = BATTLEFIELD_WG_TOWER_FORTRESS_NE;
+ break;
+ case GO_WINTERGRASP_SHADOWSIGHT_TOWER:
+ towerId = BATTLEFIELD_WG_TOWER_SHADOWSIGHT;
+ break;
+ case GO_WINTERGRASP_WINTER_S_EDGE_TOWER:
+ towerId = BATTLEFIELD_WG_TOWER_WINTER_S_EDGE;
+ break;
+ case GO_WINTERGRASP_FLAMEWATCH_TOWER:
+ towerId = BATTLEFIELD_WG_TOWER_FLAMEWATCH;
+ break;
+ }
+
+ if (towerId >= BATTLEFIELD_WG_TOWER_SHADOWSIGHT) // Attacker towers
+ {
+ // Spawn associate gameobjects
+ for (WintergraspGameObjectData const& gobData : AttackTowers[towerId - 4].GameObject)
+ {
+ if (GameObject* goHorde = _wg->SpawnGameObject(gobData.HordeEntry, gobData.Pos, gobData.Rot))
+ m_GameObjectList[TEAM_HORDE].push_back(goHorde->GetGUID());
+
+ if (GameObject* goAlliance = _wg->SpawnGameObject(gobData.AllianceEntry, gobData.Pos, gobData.Rot))
+ m_GameObjectList[TEAM_ALLIANCE].push_back(goAlliance->GetGUID());
+ }
+
+ // Spawn associate npc bottom
+ for (WintergraspObjectPositionData const& creatureData : AttackTowers[towerId - 4].CreatureBottom)
+ {
+ if (Creature* creature = _wg->SpawnCreature(creatureData.HordeEntry, creatureData.Pos))
+ m_CreatureBottomList[TEAM_HORDE].push_back(creature->GetGUID());
+
+ if (Creature* creature = _wg->SpawnCreature(creatureData.AllianceEntry, creatureData.Pos))
+ m_CreatureBottomList[TEAM_ALLIANCE].push_back(creature->GetGUID());
+ }
+ }
+
+ if (towerId >= 0)
+ {
+ ASSERT(towerId < WG_MAX_TOWER);
+ _staticTowerInfo = &TowerData[towerId];
+
+ // Spawn Turret bottom
+ for (Position const& turretPos : TowerCannon[towerId].TowerCannonBottom)
+ {
+ if (Creature* turret = _wg->SpawnCreature(NPC_WINTERGRASP_TOWER_CANNON, turretPos))
+ {
+ m_TowerCannonBottomList.push_back(turret->GetGUID());
+ switch (go->GetEntry())
+ {
+ case GO_WINTERGRASP_FORTRESS_TOWER_1:
+ case GO_WINTERGRASP_FORTRESS_TOWER_2:
+ case GO_WINTERGRASP_FORTRESS_TOWER_3:
+ case GO_WINTERGRASP_FORTRESS_TOWER_4:
+ turret->SetFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
+ break;
+ case GO_WINTERGRASP_SHADOWSIGHT_TOWER:
+ case GO_WINTERGRASP_WINTER_S_EDGE_TOWER:
+ case GO_WINTERGRASP_FLAMEWATCH_TOWER:
+ turret->SetFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
+ break;
+ }
+
+ _wg->HideNpc(turret);
+ }
+ }
+
+ // Spawn Turret top
+ for (Position const& towerCannonPos : TowerCannon[towerId].TurretTop)
+ {
+ if (Creature* turret = _wg->SpawnCreature(NPC_WINTERGRASP_TOWER_CANNON, towerCannonPos))
+ {
+ m_TurretTopList.push_back(turret->GetGUID());
+ switch (go->GetEntry())
+ {
+ case GO_WINTERGRASP_FORTRESS_TOWER_1:
+ case GO_WINTERGRASP_FORTRESS_TOWER_2:
+ case GO_WINTERGRASP_FORTRESS_TOWER_3:
+ case GO_WINTERGRASP_FORTRESS_TOWER_4:
+ turret->SetFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
+ break;
+ case GO_WINTERGRASP_SHADOWSIGHT_TOWER:
+ case GO_WINTERGRASP_WINTER_S_EDGE_TOWER:
+ case GO_WINTERGRASP_FLAMEWATCH_TOWER:
+ turret->SetFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
+ break;
+ }
+ _wg->HideNpc(turret);
+ }
+ }
+ UpdateCreatureAndGo();
+ }
+}
+
+void BfWGGameObjectBuilding::UpdateCreatureAndGo()
+{
+ for (ObjectGuid guid : m_CreatureTopList[_wg->GetDefenderTeam()])
+ if (Creature* creature = _wg->GetCreature(guid))
+ _wg->HideNpc(creature);
+
+ for (ObjectGuid guid : m_CreatureTopList[_wg->GetAttackerTeam()])
+ if (Creature* creature = _wg->GetCreature(guid))
+ _wg->ShowNpc(creature, true);
+
+ for (ObjectGuid guid : m_CreatureBottomList[_wg->GetDefenderTeam()])
+ if (Creature* creature = _wg->GetCreature(guid))
+ _wg->HideNpc(creature);
+
+ for (ObjectGuid guid : m_CreatureBottomList[_wg->GetAttackerTeam()])
+ if (Creature* creature = _wg->GetCreature(guid))
+ _wg->ShowNpc(creature, true);
+
+ for (ObjectGuid guid : m_GameObjectList[_wg->GetDefenderTeam()])
+ if (GameObject* go = _wg->GetGameObject(guid))
+ go->SetRespawnTime(RESPAWN_ONE_DAY);
+
+ for (ObjectGuid guid : m_GameObjectList[_wg->GetAttackerTeam()])
+ if (GameObject* go = _wg->GetGameObject(guid))
+ go->SetRespawnTime(RESPAWN_IMMEDIATELY);
+}
+
+void BfWGGameObjectBuilding::UpdateTurretAttack(bool disable)
+{
+ for (ObjectGuid guid : m_TowerCannonBottomList)
+ {
+ if (Creature* creature = _wg->GetCreature(guid))
+ {
+ if (disable)
+ _wg->HideNpc(creature);
+ else
+ _wg->ShowNpc(creature, true);
+
+ switch (_buildGUID.GetEntry())
+ {
+ case GO_WINTERGRASP_FORTRESS_TOWER_1:
+ case GO_WINTERGRASP_FORTRESS_TOWER_2:
+ case GO_WINTERGRASP_FORTRESS_TOWER_3:
+ case GO_WINTERGRASP_FORTRESS_TOWER_4:
+ {
+ creature->SetFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
+ break;
+ }
+ case GO_WINTERGRASP_SHADOWSIGHT_TOWER:
+ case GO_WINTERGRASP_WINTER_S_EDGE_TOWER:
+ case GO_WINTERGRASP_FLAMEWATCH_TOWER:
+ {
+ creature->SetFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
+ break;
+ }
+ }
+ }
+ }
+
+ for (ObjectGuid guid : m_TurretTopList)
+ {
+ if (Creature* creature = _wg->GetCreature(guid))
+ {
+ if (disable)
+ _wg->HideNpc(creature);
+ else
+ _wg->ShowNpc(creature, true);
+
+ switch (_buildGUID.GetEntry())
+ {
+ case GO_WINTERGRASP_FORTRESS_TOWER_1:
+ case GO_WINTERGRASP_FORTRESS_TOWER_2:
+ case GO_WINTERGRASP_FORTRESS_TOWER_3:
+ case GO_WINTERGRASP_FORTRESS_TOWER_4:
+ {
+ creature->SetFaction(WintergraspFaction[_wg->GetDefenderTeam()]);
+ break;
+ }
+ case GO_WINTERGRASP_SHADOWSIGHT_TOWER:
+ case GO_WINTERGRASP_WINTER_S_EDGE_TOWER:
+ case GO_WINTERGRASP_FLAMEWATCH_TOWER:
+ {
+ creature->SetFaction(WintergraspFaction[_wg->GetAttackerTeam()]);
+ break;
+ }
+ }
+ }
+ }
+}
+
+void BfWGGameObjectBuilding::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
+{
+ packet.Worldstates.emplace_back(_worldState, _state);
+}
+
+void BfWGGameObjectBuilding::Save()
+{
+ sWorld->setWorldState(_worldState, _state);
+}
+
+WintergraspWorkshop::WintergraspWorkshop(BattlefieldWG* wg, uint8 type)
+{
+ ASSERT(wg && type < WG_MAX_WORKSHOP);
+
+ _wg = wg;
+ _state = BATTLEFIELD_WG_OBJECTSTATE_NONE;
+ _teamControl = TEAM_NEUTRAL;
+ _staticInfo = &WorkshopData[type];
+}
+
+uint8 WintergraspWorkshop::GetId() const
+{
+ return _staticInfo->WorkshopId;
+}
+
+void WintergraspWorkshop::GiveControlTo(TeamId teamId, bool init /*= false*/)
+{
+ switch (teamId)
+ {
+ case TEAM_NEUTRAL:
+ {
+ // Send warning message to all player for inform a faction attack a workshop
+ // alliance / horde attacking workshop
+ _wg->SendWarning(_teamControl == TEAM_ALLIANCE ? _staticInfo->TextIds.HordeAttack : _staticInfo->TextIds.AllianceAttack);
+ break;
+ }
+ case TEAM_ALLIANCE:
+ {
+ // Updating worldstate
+ _state = BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_INTACT;
+ _wg->SendUpdateWorldState(_staticInfo->WorldStateId, _state);
+
+ // Warning message
+ if (!init)
+ _wg->SendWarning(_staticInfo->TextIds.AllianceCapture); // workshop taken - alliance
+
+ // Found associate graveyard and update it
+ if (_staticInfo->WorkshopId < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST)
+ if (BfGraveyard* gy = _wg->GetGraveyardById(_staticInfo->WorkshopId))
+ gy->GiveControlTo(TEAM_ALLIANCE);
+
+ _teamControl = teamId;
+ break;
+ }
+ case TEAM_HORDE:
+ {
+ // Update worldstate
+ _state = BATTLEFIELD_WG_OBJECTSTATE_HORDE_INTACT;
+ _wg->SendUpdateWorldState(_staticInfo->WorldStateId, _state);
+
+ // Warning message
+ if (!init)
+ _wg->SendWarning(_staticInfo->TextIds.HordeCapture); // workshop taken - horde
+
+ // Update graveyard control
+ if (_staticInfo->WorkshopId < BATTLEFIELD_WG_WORKSHOP_KEEP_WEST)
+ if (BfGraveyard* gy = _wg->GetGraveyardById(_staticInfo->WorkshopId))
+ gy->GiveControlTo(TEAM_HORDE);
+
+ _teamControl = teamId;
+ break;
+ }
+ }
+ if (!init)
+ _wg->UpdateCounterVehicle(false);
+}
+
+void WintergraspWorkshop::UpdateGraveyardAndWorkshop()
+{
+ if (_staticInfo->WorkshopId < BATTLEFIELD_WG_WORKSHOP_NE)
+ GiveControlTo(_wg->GetAttackerTeam(), true);
+ else
+ GiveControlTo(_wg->GetDefenderTeam(), true);
+}
+
+void WintergraspWorkshop::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet)
+{
+ packet.Worldstates.emplace_back(_staticInfo->WorldStateId, _state);
+}
+
+void WintergraspWorkshop::Save()
+{
+ sWorld->setWorldState(_staticInfo->WorldStateId, _state);
+}
+
+class Battlefield_wintergrasp : public BattlefieldScript
+{
+public:
+ Battlefield_wintergrasp() : BattlefieldScript("battlefield_wg") { }
+
+ Battlefield* GetBattlefield() const override
+ {
+ return new BattlefieldWG();
+ }
+};
+
+void AddSC_BF_wintergrasp()
+{
+ new Battlefield_wintergrasp();
+}
diff --git a/src/server/scripts/Battlefield/BattlefieldWG.h b/src/server/scripts/Battlefield/BattlefieldWG.h
new file mode 100644
index 00000000000..fc3806427d9
--- /dev/null
+++ b/src/server/scripts/Battlefield/BattlefieldWG.h
@@ -0,0 +1,575 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef BATTLEFIELD_WG_
+#define BATTLEFIELD_WG_
+
+#include "Battlefield.h"
+
+class Group;
+class BattlefieldWG;
+class WintergraspCapturePoint;
+
+struct BfWGGameObjectBuilding;
+struct WintergraspWorkshop;
+struct StaticWintergraspTowerInfo;
+struct StaticWintergraspWorkshopInfo;
+struct WintergraspObjectPositionData;
+
+typedef std::vector<BfWGGameObjectBuilding*> GameObjectBuildingVect;
+typedef std::vector<WintergraspWorkshop*> WorkshopVect;
+
+enum WintergraspSpells
+{
+ // Wartime auras
+ SPELL_RECRUIT = 37795,
+ SPELL_CORPORAL = 33280,
+ SPELL_LIEUTENANT = 55629,
+ SPELL_TENACITY = 58549,
+ SPELL_TENACITY_VEHICLE = 59911,
+ SPELL_TOWER_CONTROL = 62064,
+ SPELL_SPIRITUAL_IMMUNITY = 58729,
+ SPELL_GREAT_HONOR = 58555,
+ SPELL_GREATER_HONOR = 58556,
+ SPELL_GREATEST_HONOR = 58557,
+ SPELL_ALLIANCE_FLAG = 14268,
+ SPELL_HORDE_FLAG = 14267,
+ SPELL_GRAB_PASSENGER = 61178,
+
+ // Reward spells
+ SPELL_VICTORY_REWARD = 56902,
+ SPELL_DEFEAT_REWARD = 58494,
+ SPELL_DAMAGED_TOWER = 59135,
+ SPELL_DESTROYED_TOWER = 59136,
+ SPELL_DAMAGED_BUILDING = 59201,
+ SPELL_INTACT_BUILDING = 59203,
+
+ SPELL_TELEPORT_BRIDGE = 59096,
+ SPELL_TELEPORT_FORTRESS = 60035,
+
+ SPELL_TELEPORT_DALARAN = 53360,
+ SPELL_VICTORY_AURA = 60044,
+
+ // Other spells
+ SPELL_WINTERGRASP_WATER = 36444,
+ SPELL_ESSENCE_OF_WINTERGRASP = 58045,
+ SPELL_WINTERGRASP_RESTRICTED_FLIGHT_AREA = 91604,
+
+ // Phasing spells
+ SPELL_HORDE_CONTROLS_FACTORY_PHASE_SHIFT = 56618, // ADDS PHASE 16
+ SPELL_ALLIANCE_CONTROLS_FACTORY_PHASE_SHIFT = 56617, // ADDS PHASE 32
+
+ SPELL_HORDE_CONTROL_PHASE_SHIFT = 55773, // ADDS PHASE 64
+ SPELL_ALLIANCE_CONTROL_PHASE_SHIFT = 55774 // ADDS PHASE 128
+};
+
+enum WintergraspData
+{
+ BATTLEFIELD_WG_DATA_DAMAGED_TOWER_DEF,
+ BATTLEFIELD_WG_DATA_BROKEN_TOWER_DEF,
+ BATTLEFIELD_WG_DATA_DAMAGED_TOWER_ATT,
+ BATTLEFIELD_WG_DATA_BROKEN_TOWER_ATT,
+ BATTLEFIELD_WG_DATA_MAX_VEHICLE_A,
+ BATTLEFIELD_WG_DATA_MAX_VEHICLE_H,
+ BATTLEFIELD_WG_DATA_VEHICLE_A,
+ BATTLEFIELD_WG_DATA_VEHICLE_H,
+ BATTLEFIELD_WG_DATA_WON_A,
+ BATTLEFIELD_WG_DATA_DEF_A,
+ BATTLEFIELD_WG_DATA_WON_H,
+ BATTLEFIELD_WG_DATA_DEF_H,
+ BATTLEFIELD_WG_DATA_MAX,
+
+ BATTLEFIELD_WG_MAPID = 571 // Northrend
+};
+
+enum WintergraspAchievements
+{
+ ACHIEVEMENTS_WIN_WG = 1717,
+ ACHIEVEMENTS_WIN_WG_100 = 1718, /// @todo: Has to be implemented
+ ACHIEVEMENTS_WG_GNOMESLAUGHTER = 1723, /// @todo: Has to be implemented
+ ACHIEVEMENTS_WG_TOWER_DESTROY = 1727,
+ ACHIEVEMENTS_DESTRUCTION_DERBY_A = 1737, /// @todo: Has to be implemented
+ ACHIEVEMENTS_WG_TOWER_CANNON_KILL = 1751, /// @todo: Has to be implemented
+ ACHIEVEMENTS_WG_MASTER_A = 1752, /// @todo: Has to be implemented
+ ACHIEVEMENTS_WIN_WG_TIMER_10 = 1755,
+ ACHIEVEMENTS_STONE_KEEPER_50 = 2085, /// @todo: Has to be implemented
+ ACHIEVEMENTS_STONE_KEEPER_100 = 2086, /// @todo: Has to be implemented
+ ACHIEVEMENTS_STONE_KEEPER_250 = 2087, /// @todo: Has to be implemented
+ ACHIEVEMENTS_STONE_KEEPER_500 = 2088, /// @todo: Has to be implemented
+ ACHIEVEMENTS_STONE_KEEPER_1000 = 2089, /// @todo: Has to be implemented
+ ACHIEVEMENTS_WG_RANGER = 2199, /// @todo: Has to be implemented
+ ACHIEVEMENTS_DESTRUCTION_DERBY_H = 2476, /// @todo: Has to be implemented
+ ACHIEVEMENTS_WG_MASTER_H = 2776 /// @todo: Has to be implemented
+};
+
+enum WintergraspQuests
+{
+ QUEST_VICTORY_WINTERGRASP_A = 13181,
+ QUEST_VICTORY_WINTERGRASP_H = 13183,
+ QUEST_CREDIT_TOWERS_DESTROYED = 35074,
+ QUEST_CREDIT_DEFEND_SIEGE = 31284
+};
+
+/*#########################
+ *####### Graveyards ######
+ *#########################*/
+
+class BfGraveyardWG : public BfGraveyard
+{
+ public:
+ BfGraveyardWG(BattlefieldWG* Bf);
+
+ void SetTextId(uint32 textId) { m_GossipTextId = textId; }
+ uint32 GetTextId() const { return m_GossipTextId; }
+
+ protected:
+ uint32 m_GossipTextId;
+};
+
+enum WGGraveyardId
+{
+ BATTLEFIELD_WG_GY_WORKSHOP_NE,
+ BATTLEFIELD_WG_GY_WORKSHOP_NW,
+ BATTLEFIELD_WG_GY_WORKSHOP_SE,
+ BATTLEFIELD_WG_GY_WORKSHOP_SW,
+ BATTLEFIELD_WG_GY_KEEP,
+ BATTLEFIELD_WG_GY_HORDE,
+ BATTLEFIELD_WG_GY_ALLIANCE,
+ BATTLEFIELD_WG_GRAVEYARD_MAX
+};
+
+enum WGGossipText
+{
+ BATTLEFIELD_WG_GOSSIPTEXT_GY_NE = 20071,
+ BATTLEFIELD_WG_GOSSIPTEXT_GY_NW = 20072,
+ BATTLEFIELD_WG_GOSSIPTEXT_GY_SE = 20074,
+ BATTLEFIELD_WG_GOSSIPTEXT_GY_SW = 20073,
+ BATTLEFIELD_WG_GOSSIPTEXT_GY_KEEP = 20070,
+ BATTLEFIELD_WG_GOSSIPTEXT_GY_HORDE = 20075,
+ BATTLEFIELD_WG_GOSSIPTEXT_GY_ALLIANCE = 20076
+};
+
+enum WintergraspNpcs
+{
+ BATTLEFIELD_WG_NPC_GUARD_H = 30739,
+ BATTLEFIELD_WG_NPC_GUARD_A = 30740,
+ BATTLEFIELD_WG_NPC_STALKER = 15214,
+
+ NPC_TAUNKA_SPIRIT_GUIDE = 31841, // Horde spirit guide for Wintergrasp
+ NPC_DWARVEN_SPIRIT_GUIDE = 31842, // Alliance spirit guide for Wintergrasp
+
+ NPC_WINTERGRASP_SIEGE_ENGINE_ALLIANCE = 28312,
+ NPC_WINTERGRASP_SIEGE_ENGINE_HORDE = 32627,
+ NPC_WINTERGRASP_CATAPULT = 27881,
+ NPC_WINTERGRASP_DEMOLISHER = 28094,
+ NPC_WINTERGRASP_TOWER_CANNON = 28366
+};
+
+/* ######################### *
+ * WintergraspCapturePoint *
+ * ######################### */
+
+class WintergraspCapturePoint : public BfCapturePoint
+{
+ public:
+ WintergraspCapturePoint(BattlefieldWG* battlefield, TeamId teamInControl);
+
+ void LinkToWorkshop(WintergraspWorkshop* workshop) { m_Workshop = workshop; }
+
+ void ChangeTeam(TeamId oldteam) override;
+ TeamId GetTeam() const { return m_team; }
+
+ protected:
+ WintergraspWorkshop* m_Workshop;
+};
+
+/* ######################### *
+ * WinterGrasp Battlefield *
+ * ######################### */
+
+class BattlefieldWG : public Battlefield
+{
+ public:
+ ~BattlefieldWG();
+ /**
+ * \brief Called when the battle start
+ * - Spawn relic and turret
+ * - Rebuild tower and wall
+ * - Invite player to war
+ */
+ void OnBattleStart() override;
+
+ /**
+ * \brief Called when battle end
+ * - Remove relic and turret
+ * - Change banner/npc in keep if it needed
+ * - Saving battlestate
+ * - Reward honor/mark to player
+ * - Remove vehicle
+ * \param endByTimer : true if battle ended when timer is at 00:00, false if battle ended by clicking on relic
+ */
+ void OnBattleEnd(bool endByTimer) override;
+
+ /**
+ * \brief Called when grouping starts (15 minutes before battlestart)
+ * - Invite all player in zone to join queue
+ */
+ void OnStartGrouping() override;
+
+ /**
+ * \brief Called when player accept invite to join battle
+ * - Update aura
+ * - Teleport if it needed
+ * - Update worldstate
+ * - Update tenacity
+ * \param player: Player who accepted invite
+ */
+ void OnPlayerJoinWar(Player* player) override;
+
+ /**
+ * \brief Called when player left the battle
+ * - Update player aura
+ * \param player : Player who left the battle
+ */
+ void OnPlayerLeaveWar(Player* player) override;
+
+ /**
+ * \brief Called when player left the WG zone
+ * \param player : Player who left the zone
+ */
+ void OnPlayerLeaveZone(Player* player) override;
+
+ /**
+ * \brief Called when player enters in WG zone
+ * - Update aura
+ * - Update worldstate
+ * \param player : Player who enters the zone
+ */
+ void OnPlayerEnterZone(Player* player) override;
+
+ /**
+ * \brief Called for update battlefield data
+ * - Save battle timer in database every minutes
+ * - Update imunity aura from graveyard
+ * \param diff : time elapsed since the last call (in ms)
+ */
+ bool Update(uint32 diff) override;
+
+ /**
+ * \brief Called when a creature is created
+ * - Update vehicle count
+ */
+ void OnCreatureCreate(Creature* creature) override;
+
+ /**
+ * \brief Called when a creature is removed
+ * - Update vehicle count
+ */
+ void OnCreatureRemove(Creature* creature) override;
+
+ /**
+ * \brief Called when a gameobject is created
+ */
+ void OnGameObjectCreate(GameObject* go) override;
+
+ /**
+ * \brief Called when a wall/tower is broken
+ * - Update quest
+ */
+ void BrokenWallOrTower(TeamId team, BfWGGameObjectBuilding* building);
+
+ /**
+ * \brief Called when a tower is damaged
+ * - Update tower count (for reward calcul)
+ */
+ void UpdateDamagedTowerCount(TeamId team);
+
+ /**
+ * \brief Called when tower is broken
+ * - Update tower buff
+ * - check if three south tower is down for remove 10 minutes to wg
+ */
+ void UpdatedDestroyedTowerCount(TeamId team);
+
+ void DoCompleteOrIncrementAchievement(uint32 achievement, Player* player, uint8 incrementNumber = 1) override;
+
+ void RemoveAurasFromPlayer(Player* player);
+
+ /**
+ * \brief Called when battlefield is setup, at server start
+ */
+ bool SetupBattlefield() override;
+
+ /// Return pointer to relic object
+ GameObject* GetRelic() { return GetGameObject(m_titansRelicGUID); }
+
+ /// Define relic object
+ void SetRelic(ObjectGuid relicGUID) { m_titansRelicGUID = relicGUID; }
+
+ /// Check if players can interact with the relic (Only if the last door has been broken)
+ bool CanInteractWithRelic() { return m_isRelicInteractible; }
+
+ /// Define if player can interact with the relic
+ void SetRelicInteractible(bool allow) { m_isRelicInteractible = allow; }
+
+ void UpdateVehicleCountWG();
+ void UpdateCounterVehicle(bool init);
+
+ void SendInitWorldStatesTo(Player* player);
+ void SendInitWorldStatesToAll() override;
+ void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override;
+
+ void HandleKill(Player* killer, Unit* victim) override;
+ void OnUnitDeath(Unit* unit) override;
+ void HandlePromotion(Player* killer, Unit* killed);
+ void PromotePlayer(Player* killer);
+
+ void UpdateTenacity();
+ void ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker) override;
+
+ bool FindAndRemoveVehicleFromList(Unit* vehicle);
+
+ // returns the graveyardId in the specified area.
+ uint8 GetSpiritGraveyardId(uint32 areaId) const;
+
+ uint32 GetData(uint32 data) const override;
+
+ protected:
+ bool m_isRelicInteractible;
+
+ WorkshopVect Workshops;
+
+ GuidVector DefenderPortalList[PVP_TEAMS_COUNT];
+ GameObjectBuildingVect BuildingsInZone;
+
+ GuidUnorderedSet m_vehicles[PVP_TEAMS_COUNT];
+ GuidVector CanonList;
+
+ TeamId m_tenacityTeam;
+ uint32 m_tenacityStack;
+ uint32 m_saveTimer;
+
+ ObjectGuid m_titansRelicGUID;
+};
+
+enum WintergraspGameObjectBuildingType
+{
+ BATTLEFIELD_WG_OBJECTTYPE_DOOR,
+ BATTLEFIELD_WG_OBJECTTYPE_TITANRELIC,
+ BATTLEFIELD_WG_OBJECTTYPE_WALL,
+ BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST,
+ BATTLEFIELD_WG_OBJECTTYPE_KEEP_TOWER,
+ BATTLEFIELD_WG_OBJECTTYPE_TOWER
+};
+
+enum WintergraspGameObjectState
+{
+ BATTLEFIELD_WG_OBJECTSTATE_NONE,
+ BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_INTACT,
+ BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_DAMAGE,
+ BATTLEFIELD_WG_OBJECTSTATE_NEUTRAL_DESTROY,
+ BATTLEFIELD_WG_OBJECTSTATE_HORDE_INTACT,
+ BATTLEFIELD_WG_OBJECTSTATE_HORDE_DAMAGE,
+ BATTLEFIELD_WG_OBJECTSTATE_HORDE_DESTROY,
+ BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_INTACT,
+ BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DAMAGE,
+ BATTLEFIELD_WG_OBJECTSTATE_ALLIANCE_DESTROY
+};
+
+enum WintergraspTowerIds
+{
+ BATTLEFIELD_WG_TOWER_FORTRESS_NW,
+ BATTLEFIELD_WG_TOWER_FORTRESS_SW,
+ BATTLEFIELD_WG_TOWER_FORTRESS_SE,
+ BATTLEFIELD_WG_TOWER_FORTRESS_NE,
+ BATTLEFIELD_WG_TOWER_SHADOWSIGHT,
+ BATTLEFIELD_WG_TOWER_WINTER_S_EDGE,
+ BATTLEFIELD_WG_TOWER_FLAMEWATCH
+};
+
+enum WintergraspWorkshopIds
+{
+ BATTLEFIELD_WG_WORKSHOP_SE,
+ BATTLEFIELD_WG_WORKSHOP_SW,
+ BATTLEFIELD_WG_WORKSHOP_NE,
+ BATTLEFIELD_WG_WORKSHOP_NW,
+ BATTLEFIELD_WG_WORKSHOP_KEEP_WEST,
+ BATTLEFIELD_WG_WORKSHOP_KEEP_EAST
+};
+
+enum WintergraspTeamControl
+{
+ BATTLEFIELD_WG_TEAM_ALLIANCE,
+ BATTLEFIELD_WG_TEAM_HORDE,
+ BATTLEFIELD_WG_TEAM_NEUTRAL
+};
+
+enum WintergraspText
+{
+ // Invisible Stalker
+ BATTLEFIELD_WG_TEXT_SOUTHERN_TOWER_DAMAGE = 1,
+ BATTLEFIELD_WG_TEXT_SOUTHERN_TOWER_DESTROY = 2,
+ BATTLEFIELD_WG_TEXT_EASTERN_TOWER_DAMAGE = 3,
+ BATTLEFIELD_WG_TEXT_EASTERN_TOWER_DESTROY = 4,
+ BATTLEFIELD_WG_TEXT_WESTERN_TOWER_DAMAGE = 5,
+ BATTLEFIELD_WG_TEXT_WESTERN_TOWER_DESTROY = 6,
+ BATTLEFIELD_WG_TEXT_NW_KEEPTOWER_DAMAGE = 7,
+ BATTLEFIELD_WG_TEXT_NW_KEEPTOWER_DESTROY = 8,
+ BATTLEFIELD_WG_TEXT_SE_KEEPTOWER_DAMAGE = 9,
+ BATTLEFIELD_WG_TEXT_SE_KEEPTOWER_DESTROY = 10,
+ BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_ATTACK_ALLIANCE = 11,
+ BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_CAPTURE_ALLIANCE = 12,
+ BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_ATTACK_HORDE = 13,
+ BATTLEFIELD_WG_TEXT_BROKEN_TEMPLE_CAPTURE_HORDE = 14,
+ BATTLEFIELD_WG_TEXT_EASTSPARK_ATTACK_ALLIANCE = 15,
+ BATTLEFIELD_WG_TEXT_EASTSPARK_CAPTURE_ALLIANCE = 16,
+ BATTLEFIELD_WG_TEXT_EASTSPARK_ATTACK_HORDE = 17,
+ BATTLEFIELD_WG_TEXT_EASTSPARK_CAPTURE_HORDE = 18,
+ BATTLEFIELD_WG_TEXT_SUNKEN_RING_ATTACK_ALLIANCE = 19,
+ BATTLEFIELD_WG_TEXT_SUNKEN_RING_CAPTURE_ALLIANCE = 20,
+ BATTLEFIELD_WG_TEXT_SUNKEN_RING_ATTACK_HORDE = 21,
+ BATTLEFIELD_WG_TEXT_SUNKEN_RING_CAPTURE_HORDE = 22,
+ BATTLEFIELD_WG_TEXT_WESTSPARK_ATTACK_ALLIANCE = 23,
+ BATTLEFIELD_WG_TEXT_WESTSPARK_CAPTURE_ALLIANCE = 24,
+ BATTLEFIELD_WG_TEXT_WESTSPARK_ATTACK_HORDE = 25,
+ BATTLEFIELD_WG_TEXT_WESTSPARK_CAPTURE_HORDE = 26,
+
+ BATTLEFIELD_WG_TEXT_START_GROUPING = 27,
+ BATTLEFIELD_WG_TEXT_START_BATTLE = 28,
+ BATTLEFIELD_WG_TEXT_FORTRESS_DEFEND_ALLIANCE = 29,
+ BATTLEFIELD_WG_TEXT_FORTRESS_CAPTURE_ALLIANCE = 30,
+ BATTLEFIELD_WG_TEXT_FORTRESS_DEFEND_HORDE = 31,
+ BATTLEFIELD_WG_TEXT_FORTRESS_CAPTURE_HORDE = 32,
+
+ BATTLEFIELD_WG_TEXT_NE_KEEPTOWER_DAMAGE = 33,
+ BATTLEFIELD_WG_TEXT_NE_KEEPTOWER_DESTROY = 34,
+ BATTLEFIELD_WG_TEXT_SW_KEEPTOWER_DAMAGE = 35,
+ BATTLEFIELD_WG_TEXT_SW_KEEPTOWER_DESTROY = 36,
+
+ BATTLEFIELD_WG_TEXT_RANK_CORPORAL = 37,
+ BATTLEFIELD_WG_TEXT_RANK_FIRST_LIEUTENANT = 38
+};
+
+enum WintergraspGameObject
+{
+ GO_WINTERGRASP_FACTORY_BANNER_NE = 190475,
+ GO_WINTERGRASP_FACTORY_BANNER_NW = 190487,
+ GO_WINTERGRASP_FACTORY_BANNER_SE = 194959,
+ GO_WINTERGRASP_FACTORY_BANNER_SW = 194962,
+
+ GO_WINTERGRASP_TITAN_S_RELIC = 192829,
+
+ GO_WINTERGRASP_FORTRESS_TOWER_1 = 190221,
+ GO_WINTERGRASP_FORTRESS_TOWER_2 = 190373,
+ GO_WINTERGRASP_FORTRESS_TOWER_3 = 190377,
+ GO_WINTERGRASP_FORTRESS_TOWER_4 = 190378,
+
+ GO_WINTERGRASP_SHADOWSIGHT_TOWER = 190356,
+ GO_WINTERGRASP_WINTER_S_EDGE_TOWER = 190357,
+ GO_WINTERGRASP_FLAMEWATCH_TOWER = 190358,
+
+ GO_WINTERGRASP_FORTRESS_GATE = 190375,
+ GO_WINTERGRASP_VAULT_GATE = 191810,
+
+ GO_WINTERGRASP_KEEP_COLLISION_WALL = 194323
+};
+
+// ********************************************************************
+// * Structs using for Building, Graveyard, Workshop *
+// ********************************************************************
+
+// Structure for different buildings that can be destroyed during battle
+struct BfWGGameObjectBuilding
+{
+private:
+ // WG object
+ BattlefieldWG* _wg;
+
+ // Linked gameobject
+ ObjectGuid _buildGUID;
+
+ // the team that controls this point
+ TeamId _teamControl;
+
+ WintergraspGameObjectBuildingType _type;
+ uint32 _worldState;
+
+ WintergraspGameObjectState _state;
+
+ StaticWintergraspTowerInfo const* _staticTowerInfo;
+
+ // GameObject associations
+ GuidVector m_GameObjectList[PVP_TEAMS_COUNT];
+
+ // Creature associations
+ GuidVector m_CreatureBottomList[PVP_TEAMS_COUNT];
+ GuidVector m_CreatureTopList[PVP_TEAMS_COUNT];
+ GuidVector m_TowerCannonBottomList;
+ GuidVector m_TurretTopList;
+
+public:
+ BfWGGameObjectBuilding(BattlefieldWG* wg, WintergraspGameObjectBuildingType type, uint32 worldState);
+ void Init(GameObject* go);
+
+ ObjectGuid const& GetGUID() const { return _buildGUID; }
+
+ void Rebuild();
+ void RebuildGate();
+
+ // Called when associated gameobject is damaged
+ void Damaged();
+
+ // Called when associated gameobject is destroyed
+ void Destroyed();
+
+ void UpdateCreatureAndGo();
+
+ void UpdateTurretAttack(bool disable);
+
+ void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet);
+
+ void Save();
+};
+
+// Structure for the 6 workshop
+struct WintergraspWorkshop
+{
+private:
+ BattlefieldWG* _wg; // Pointer to wintergrasp
+ ObjectGuid _buildGUID;
+ WintergraspGameObjectState _state; // For worldstate
+ TeamId _teamControl; // Team witch control the workshop
+
+ StaticWintergraspWorkshopInfo const* _staticInfo;
+
+public:
+ WintergraspWorkshop(BattlefieldWG* wg, uint8 type);
+
+ uint8 GetId() const;
+ TeamId GetTeamControl() const { return _teamControl; }
+
+ // Called on change faction in CapturePoint class
+ void GiveControlTo(TeamId teamId, bool init = false);
+
+ void UpdateGraveyardAndWorkshop();
+
+ void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet);
+
+ void Save();
+};
+
+#endif
diff --git a/src/server/scripts/Battlefield/battlefield_script_loader.cpp b/src/server/scripts/Battlefield/battlefield_script_loader.cpp
new file mode 100644
index 00000000000..fcfa06e9449
--- /dev/null
+++ b/src/server/scripts/Battlefield/battlefield_script_loader.cpp
@@ -0,0 +1,25 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+void AddSC_BF_wintergrasp();
+void AddSC_BF_tol_barad();
+
+void AddBattlefieldScripts()
+{
+ AddSC_BF_wintergrasp();
+ AddSC_BF_tol_barad();
+}
diff --git a/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp b/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp
index a30fb95d026..b8fe8a65f3f 100644
--- a/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp
+++ b/src/server/scripts/EasternKingdoms/zone_tol_barad.cpp
@@ -18,7 +18,7 @@
#include "ScriptMgr.h"
#include "Battlefield.h"
#include "BattlefieldMgr.h"
-#include "BattlefieldTB.h"
+#include "Battlefield/BattlefieldTB.h"
#include "DB2Stores.h"
#include "ObjectMgr.h"
#include "Player.h"
diff --git a/src/server/scripts/Northrend/zone_wintergrasp.cpp b/src/server/scripts/Northrend/zone_wintergrasp.cpp
index 5d2390b1ab7..d38c8c43aab 100644
--- a/src/server/scripts/Northrend/zone_wintergrasp.cpp
+++ b/src/server/scripts/Northrend/zone_wintergrasp.cpp
@@ -18,7 +18,7 @@
#include "ScriptMgr.h"
#include "Battlefield.h"
#include "BattlefieldMgr.h"
-#include "BattlefieldWG.h"
+#include "Battlefield/BattlefieldWG.h"
#include "DB2Stores.h"
#include "GameObject.h"
#include "GameObjectAI.h"
@@ -360,8 +360,8 @@ class go_wg_vehicle_teleporter : public GameObjectScript
bool IsFriendly(Unit* passenger)
{
- return ((me->GetFaction() == WintergraspFaction[TEAM_HORDE] && passenger->GetFaction() == HORDE) ||
- (me->GetFaction() == WintergraspFaction[TEAM_ALLIANCE] && passenger->GetFaction() == ALLIANCE));
+ return ((me->GetFaction() == FACTION_HORDE_GENERIC_WG && passenger->GetFaction() == HORDE) ||
+ (me->GetFaction() == FACTION_ALLIANCE_GENERIC_WG && passenger->GetFaction() == ALLIANCE));
}
Creature* GetValidVehicle(Creature* cVeh)