Core/Battlegrounds: Move to scripts (#29799)

* Introduce new BattlegroundScript class for map/bg specific scripts
* Remove all sub, zone specific, battleground classes except Arena
* Move all bg zone scripts to new BattlegroundScripts class in script folder
* Remove ZoneScript from Battleground class
* Remove some unused hooks from Battleground

(cherry picked from commit be11f42a16)
This commit is contained in:
Jeremy
2024-03-28 19:29:22 +01:00
committed by funjoker
parent aefa15ece7
commit d0d5d309bb
78 changed files with 6821 additions and 7805 deletions
@@ -0,0 +1,38 @@
DROP TABLE IF EXISTS `battleground_scripts`;
CREATE TABLE `battleground_scripts` (
`MapId` int NOT NULL,
`BattlemasterListId` int NOT NULL DEFAULT '0',
`ScriptName` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
PRIMARY KEY (`MapId`,`BattlemasterListId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `battleground_scripts` (`MapId`, `BattlemasterListId`, `ScriptName`) VALUES
(30, 0, 'battleground_alterac_valley'),
(566, 0, 'battleground_eye_of_the_storm'),
(607, 0, 'battleground_strand_of_the_ancients'),
(628, 0, 'battleground_isle_of_conquest'),
(2106, 0, 'battleground_warsong_gulch'),
(2107, 0, 'battleground_arathi_basin'),
(1672, 0, 'arena_blades_edge'),
(572, 0, 'arena_ruins_of_lordaeron'),
(617, 0, 'arena_dalaran_sewers'),
(1505, 0, 'arena_nagrand'),
(618, 0, 'arena_ring_of_valor'),
(726, 0, 'battleground_twin_peaks'),
(761, 0, 'battleground_battle_for_gilneas');
DELETE FROM `quest_template_addon` WHERE `ID` IN (7223, 7224);
INSERT INTO `quest_template_addon` (`ID`, `ScriptName`) VALUES
(7223, 'quest_alterac_valley_armor_scraps'),
(7224, 'quest_alterac_valley_armor_scraps');
UPDATE `quest_template_addon` SET `ScriptName` = 'quest_alterac_valley_armor_scraps' WHERE `ID` IN (6781, 6741);
UPDATE `quest_template_addon` SET `ScriptName` = 'quest_alterac_valley_call_of_air_slidore_guse' WHERE `ID` IN (6942, 6825);
UPDATE `quest_template_addon` SET `ScriptName` = 'quest_alterac_valley_call_of_air_vipore_jeztor' WHERE `ID` IN (6941, 6826);
UPDATE `quest_template_addon` SET `ScriptName` = 'quest_alterac_valley_call_of_air_ichman_mulverick' WHERE `ID` IN (6943, 6827);
UPDATE `quest_template_addon` SET `ScriptName` = 'quest_alterac_valley_boss_5' WHERE `ID` IN (7386, 7385);
UPDATE `quest_template_addon` SET `ScriptName` = 'quest_alterac_valley_boss_1' WHERE `ID` IN (6881, 6801);
UPDATE `quest_template_addon` SET `ScriptName` = 'quest_alterac_valley_near_mine' WHERE `ID` IN (5892, 5893);
UPDATE `quest_template_addon` SET `ScriptName` = 'quest_alterac_valley_other_mine' WHERE `ID` IN (6982, 6985);
UPDATE `quest_template_addon` SET `ScriptName` = 'quest_alterac_valley_ram_harnesses' WHERE `ID` IN (7026, 7002);
UPDATE `quest_template_addon` SET `ScriptName` = 'quest_alterac_valley_empty_stables' WHERE `ID` IN (7027, 7001);
+2 -2
View File
@@ -55,9 +55,9 @@ enum ArenaWorldStates
class TC_GAME_API Arena : public Battleground
{
protected:
public:
Arena(BattlegroundTemplate const* battlegroundTemplate);
protected:
void AddPlayer(Player* player, BattlegroundQueueTypeId queueId) override;
void RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*team*/) override;
+18 -334
View File
@@ -19,6 +19,7 @@
#include "BattlegroundMgr.h"
#include "BattlegroundPackets.h"
#include "BattlegroundScore.h"
#include "BattlegroundScript.h"
#include "ChatTextBuilder.h"
#include "Creature.h"
#include "CreatureTextMgr.h"
@@ -114,16 +115,6 @@ Battleground::Battleground(Battleground const&) = default;
Battleground::~Battleground()
{
// remove objects and creatures
// (this is done automatically in mapmanager update, when the instance is reset after the reset time)
uint32 size = uint32(BgCreatures.size());
for (uint32 i = 0; i < size; ++i)
DelCreature(i);
size = uint32(BgObjects.size());
for (uint32 i = 0; i < size; ++i)
DelObject(i);
// unload map
if (m_Map)
{
@@ -355,19 +346,12 @@ inline void Battleground::_ProcessJoin(uint32 diff)
return;
}
// Setup here, only when at least one player has ported to the map
if (!SetupBattleground())
{
EndNow();
return;
}
_preparationStartTime = GameTime::GetGameTime();
for (Group* group : m_BgRaids)
if (group)
group->StartCountdown(CountdownTimerType::Pvp, Seconds(StartDelayTimes[BG_STARTING_EVENT_FIRST] / 1000), _preparationStartTime);
StartingEventCloseDoors();
GetBgMap()->GetBattlegroundScript()->OnPrepareStage1();
SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FIRST]);
// First start warning - 2 or 1 minute
if (StartMessageIds[BG_STARTING_EVENT_FIRST])
@@ -377,6 +361,7 @@ inline void Battleground::_ProcessJoin(uint32 diff)
else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2))
{
m_Events |= BG_STARTING_EVENT_2;
GetBgMap()->GetBattlegroundScript()->OnPrepareStage2();
if (StartMessageIds[BG_STARTING_EVENT_SECOND])
SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
@@ -384,6 +369,7 @@ inline void Battleground::_ProcessJoin(uint32 diff)
else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3))
{
m_Events |= BG_STARTING_EVENT_3;
GetBgMap()->GetBattlegroundScript()->OnPrepareStage3();
if (StartMessageIds[BG_STARTING_EVENT_THIRD])
SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
@@ -392,7 +378,7 @@ inline void Battleground::_ProcessJoin(uint32 diff)
{
m_Events |= BG_STARTING_EVENT_4;
StartingEventOpenDoors();
GetBgMap()->GetBattlegroundScript()->OnStart();
if (StartMessageIds[BG_STARTING_EVENT_FOURTH])
SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_FOURTH], CHAT_MSG_BG_SYSTEM_NEUTRAL);
@@ -785,6 +771,8 @@ void Battleground::EndBattleground(Team winner)
player->SendDirectMessage(pvpMatchComplete.GetRawPacket());
player->UpdateCriteria(CriteriaType::ParticipateInBattleground, player->GetMapId());
GetBgMap()->GetBattlegroundScript()->OnEnd(winner);
}
}
@@ -1081,6 +1069,8 @@ void Battleground::AddPlayer(Player* player, BattlegroundQueueTypeId queueId)
// setup BG group membership
PlayerAddedToBGCheckIfBGIsRunning(player);
AddOrSetPlayerToCorrectBgGroup(player, team);
GetBgMap()->GetBattlegroundScript()->OnPlayerJoined(player, isInBattleground);
}
// this method adds player to his team's bg group, or sets his correct group if player is already in bg group
@@ -1312,133 +1302,6 @@ void Battleground::UpdatePvpStat(Player* player, uint32 pvpStatId, uint32 value)
score->UpdatePvpStat(pvpStatId, value);
}
bool Battleground::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 /*respawnTime*/, GOState goState)
{
// If the assert is called, means that BgObjects must be resized!
ASSERT(type < BgObjects.size());
Map* map = FindBgMap();
if (!map)
return false;
QuaternionData rot(rotation0, rotation1, rotation2, rotation3);
// Temporally add safety check for bad spawns and send log (object rotations need to be rechecked in sniff)
if (!rotation0 && !rotation1 && !rotation2 && !rotation3)
{
TC_LOG_DEBUG("bg.battleground", "Battleground::AddObject: gameoobject [entry: {}, object type: {}] for BG (map: {}) has zeroed rotation fields, "
"orientation used temporally, but please fix the spawn", entry, type, GetMapId());
rot = QuaternionData::fromEulerAnglesZYX(o, 0.f, 0.f);
}
// Must be created this way, adding to godatamap would add it to the base map of the instance
// and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
// So we must create it specific for this instance
GameObject* go = GameObject::CreateGameObject(entry, GetBgMap(), Position(x, y, z, o), rot, 255, goState);
if (!go)
{
TC_LOG_ERROR("bg.battleground", "Battleground::AddObject: cannot create gameobject (entry: {}) for BG (map: {}, instance id: {})!",
entry, GetMapId(), m_InstanceID);
return false;
}
/*
uint32 guid = go->GetGUIDLow();
// without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
// iirc that was changed, so adding to go data map is no longer required if that was the only function using godata from GameObject without checking if it existed
GameObjectData& data = sObjectMgr->NewGOData(guid);
data.id = entry;
data.mapid = GetMapId();
data.posX = x;
data.posY = y;
data.posZ = z;
data.orientation = o;
data.rotation0 = rotation0;
data.rotation1 = rotation1;
data.rotation2 = rotation2;
data.rotation3 = rotation3;
data.spawntimesecs = respawnTime;
data.spawnMask = 1;
data.animprogress = 100;
data.go_state = 1;
*/
// Add to world, so it can be later looked up from HashMapHolder
if (!map->AddToMap(go))
{
delete go;
return false;
}
BgObjects[type] = go->GetGUID();
return true;
}
bool Battleground::AddObject(uint32 type, uint32 entry, Position const& pos, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime /*= 0*/, GOState goState /*= GO_STATE_READY*/)
{
return AddObject(type, entry, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), rotation0, rotation1, rotation2, rotation3, respawnTime, goState);
}
// Some doors aren't despawned so we cannot handle their closing in gameobject::update()
// It would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
void Battleground::DoorClose(uint32 type)
{
if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
{
// If doors are open, close it
if (obj->getLootState() == GO_ACTIVATED && obj->GetGoState() != GO_STATE_READY)
{
obj->SetLootState(GO_READY);
obj->SetGoState(GO_STATE_READY);
}
}
else
TC_LOG_ERROR("bg.battleground", "Battleground::DoorClose: door gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
type, BgObjects[type].ToString(), GetMapId(), m_InstanceID);
}
void Battleground::DoorOpen(uint32 type)
{
if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
{
obj->SetLootState(GO_ACTIVATED);
obj->SetGoState(GO_STATE_ACTIVE);
}
else
TC_LOG_ERROR("bg.battleground", "Battleground::DoorOpen: door gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
type, BgObjects[type].ToString(), GetMapId(), m_InstanceID);
}
GameObject* Battleground::GetBGObject(uint32 type, bool logError)
{
GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]);
if (!obj)
{
if (logError)
TC_LOG_ERROR("bg.battleground", "Battleground::GetBGObject: gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
type, BgObjects[type].ToString(), GetMapId(), m_InstanceID);
else
TC_LOG_INFO("bg.battleground", "Battleground::GetBGObject: gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
type, BgObjects[type].ToString(), GetMapId(), m_InstanceID);
}
return obj;
}
Creature* Battleground::GetBGCreature(uint32 type, bool logError)
{
Creature* creature = GetBgMap()->GetCreature(BgCreatures[type]);
if (!creature)
{
if (logError)
TC_LOG_ERROR("bg.battleground", "Battleground::GetBGCreature: creature (type: {}, {}) not found for BG (map: {}, instance id: {})!",
type, BgCreatures[type].ToString(), GetMapId(), m_InstanceID);
else
TC_LOG_INFO("bg.battleground", "Battleground::GetBGCreature: creature (type: {}, {}) not found for BG (map: {}, instance id: {})!",
type, BgCreatures[type].ToString(), GetMapId(), m_InstanceID);
}
return creature;
}
uint32 Battleground::GetMapId() const
{
return _battlegroundTemplate->BattlemasterEntry->MapID[0];
@@ -1448,169 +1311,11 @@ void Battleground::SetBgMap(BattlegroundMap* map)
{
m_Map = map;
if (map)
{
_pvpStatIds = sDB2Manager.GetPVPStatIDsForMap(map->GetId());
OnMapSet(map);
}
else
_pvpStatIds = nullptr;
}
void Battleground::SpawnBGObject(uint32 type, uint32 respawntime)
{
if (Map* map = FindBgMap())
if (GameObject* obj = map->GetGameObject(BgObjects[type]))
{
if (respawntime)
{
obj->SetLootState(GO_JUST_DEACTIVATED);
if (GameObjectOverride const* goOverride = obj->GetGameObjectOverride())
if (goOverride->Flags & GO_FLAG_NODESPAWN)
{
// This function should be called in GameObject::Update() but in case of
// GO_FLAG_NODESPAWN flag the function is never called, so we call it here
obj->SendGameObjectDespawn();
}
}
else if (obj->getLootState() == GO_JUST_DEACTIVATED)
{
// Change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
obj->SetLootState(GO_READY);
}
obj->SetRespawnTime(respawntime);
map->AddToMap(obj);
}
}
Creature* Battleground::AddCreature(uint32 entry, uint32 type, float x, float y, float z, float o, TeamId /*teamId = TEAM_NEUTRAL*/, uint32 respawntime /*= 0*/, Transport* transport)
{
// If the assert is called, means that BgCreatures must be resized!
ASSERT(type < BgCreatures.size());
Map* map = FindBgMap();
if (!map)
return nullptr;
if (!sObjectMgr->GetCreatureTemplate(entry))
{
TC_LOG_ERROR("bg.battleground", "Battleground::AddCreature: creature template (entry: {}) does not exist for BG (map: {}, instance id: {})!",
entry, GetMapId(), m_InstanceID);
return nullptr;
}
if (transport)
{
if (Creature* creature = transport->SummonPassenger(entry, { x, y, z, o }, TEMPSUMMON_MANUAL_DESPAWN))
{
BgCreatures[type] = creature->GetGUID();
return creature;
}
return nullptr;
}
Position pos = { x, y, z, o };
Creature* creature = Creature::CreateCreature(entry, map, pos);
if (!creature)
{
TC_LOG_ERROR("bg.battleground", "Battleground::AddCreature: cannot create creature (entry: {}) for BG (map: {}, instance id: {})!",
entry, GetMapId(), m_InstanceID);
return nullptr;
}
creature->SetHomePosition(pos);
if (!map->AddToMap(creature))
{
delete creature;
return nullptr;
}
BgCreatures[type] = creature->GetGUID();
if (respawntime)
creature->SetRespawnDelay(respawntime);
return creature;
}
Creature* Battleground::AddCreature(uint32 entry, uint32 type, Position const& pos, TeamId teamId /*= TEAM_NEUTRAL*/, uint32 respawntime /*= 0*/, Transport* transport)
{
return AddCreature(entry, type, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teamId, respawntime, transport);
}
bool Battleground::DelCreature(uint32 type)
{
if (!BgCreatures[type])
return true;
if (Creature* creature = GetBgMap()->GetCreature(BgCreatures[type]))
{
creature->AddObjectToRemoveList();
BgCreatures[type].Clear();
return true;
}
TC_LOG_ERROR("bg.battleground", "Battleground::DelCreature: creature (type: {}, {}) not found for BG (map: {}, instance id: {})!",
type, BgCreatures[type].ToString(), GetMapId(), m_InstanceID);
BgCreatures[type].Clear();
return false;
}
bool Battleground::DelObject(uint32 type)
{
if (!BgObjects[type])
return true;
if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
{
obj->SetRespawnTime(0); // not save respawn time
obj->Delete();
BgObjects[type].Clear();
return true;
}
TC_LOG_ERROR("bg.battleground", "Battleground::DelObject: gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
type, BgObjects[type].ToString(), GetMapId(), m_InstanceID);
BgObjects[type].Clear();
return false;
}
bool Battleground::RemoveObjectFromWorld(uint32 type)
{
if (!BgObjects[type])
return true;
if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
{
obj->RemoveFromWorld();
BgObjects[type].Clear();
return true;
}
TC_LOG_INFO("bg.battleground", "Battleground::RemoveObjectFromWorld: gameobject (type: {}, {}) not found for BG (map: {}, instance id: {})!",
type, BgObjects[type].ToString(), GetMapId(), m_InstanceID);
return false;
}
bool Battleground::AddSpiritGuide(uint32 type, float x, float y, float z, float o, TeamId teamId /*= TEAM_NEUTRAL*/)
{
uint32 entry = (teamId == TEAM_ALLIANCE) ? BG_CREATURE_ENTRY_A_SPIRITGUIDE : BG_CREATURE_ENTRY_H_SPIRITGUIDE;
if (AddCreature(entry, type, x, y, z, o, teamId))
return true;
TC_LOG_ERROR("bg.battleground", "Battleground::AddSpiritGuide: cannot create spirit guide (type: {}, entry: {}) for BG (map: {}, instance id: {})!",
type, entry, GetMapId(), m_InstanceID);
EndNow();
return false;
}
bool Battleground::AddSpiritGuide(uint32 type, Position const& pos, TeamId teamId /*= TEAM_NEUTRAL*/)
{
return AddSpiritGuide(type, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teamId);
}
void Battleground::SendMessageToAll(uint32 entry, ChatMsg msgType, Player const* source)
{
if (!entry)
@@ -1693,6 +1398,15 @@ void Battleground::HandleKillPlayer(Player* victim, Player* killer)
victim->SetUnitFlag(UNIT_FLAG_SKINNABLE);
RewardXPAtKill(killer, victim);
}
if (BattlegroundScript* script = GetBgMap()->GetBattlegroundScript())
script->OnPlayerKilled(victim, killer);
}
void Battleground::HandleKillUnit(Creature* victim, Unit* killer)
{
if (BattlegroundScript* script = GetBgMap()->GetBattlegroundScript())
script->OnUnitKilled(victim, killer);
}
// Return the player's team based on battlegroundplayer info
@@ -1748,16 +1462,6 @@ uint32 Battleground::GetAlivePlayersCountByTeam(Team team) const
return count;
}
int32 Battleground::GetObjectType(ObjectGuid guid)
{
for (uint32 i = 0; i < BgObjects.size(); ++i)
if (BgObjects[i] == guid)
return i;
TC_LOG_ERROR("bg.battleground", "Battleground::GetObjectType: player used gameobject ({}) which is not in internal data for BG (map: {}, instance id: {}), cheating?",
guid.ToString(), GetMapId(), m_InstanceID);
return -1;
}
void Battleground::SetBgRaid(Team team, Group* bg_raid)
{
Group*& old_raid = team == ALLIANCE ? m_BgRaids[TEAM_ALLIANCE] : m_BgRaids[TEAM_HORDE];
@@ -1768,20 +1472,6 @@ void Battleground::SetBgRaid(Team team, Group* bg_raid)
old_raid = bg_raid;
}
WorldSafeLocsEntry const* Battleground::GetClosestGraveyard(Player* player)
{
return sObjectMgr->GetClosestGraveyard(*player, GetPlayerTeam(player->GetGUID()), player);
}
void Battleground::TriggerGameEvent(uint32 gameEventId, WorldObject* source /*= nullptr*/, WorldObject* target /*= nullptr*/)
{
ProcessEvent(target, gameEventId, source);
GameEvents::TriggerForMap(gameEventId, GetBgMap(), source, target);
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
if (Player* player = ObjectAccessor::FindPlayer(itr->first))
GameEvents::TriggerForPlayer(gameEventId, player);
}
void Battleground::SetBracket(PVPDifficultyEntry const* bracketEntry)
{
_pvpDifficultyEntry = bracketEntry;
@@ -1805,12 +1495,6 @@ uint32 Battleground::GetTeamScore(TeamId teamId) const
return 0;
}
void Battleground::HandleAreaTrigger(Player* player, uint32 trigger, bool /*entered*/)
{
TC_LOG_DEBUG("bg.battleground", "Unhandled AreaTrigger {} in Battleground {}. Player coords (x: {}, y: {}, z: {})",
trigger, player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
}
char const* Battleground::GetName() const
{
return _battlegroundTemplate->BattlemasterEntry->Name[sWorld->GetDefaultDbcLocale()];
+8 -52
View File
@@ -252,7 +252,7 @@ This class is used to:
3. some certain cases, same for all battlegrounds
4. It has properties same for all battlegrounds
*/
class TC_GAME_API Battleground : public ZoneScript
class TC_GAME_API Battleground
{
public:
Battleground(BattlegroundTemplate const* battlegroundTemplate);
@@ -263,17 +263,7 @@ class TC_GAME_API Battleground : public ZoneScript
void Update(uint32 diff);
virtual bool SetupBattleground() // must be implemented in BG subclass
{
return true;
}
virtual void Reset(); // resets all common properties for battlegrounds, must be implemented and called in BG subclass
virtual void StartingEventCloseDoors() { }
virtual void StartingEventOpenDoors() { }
virtual void DestroyGate(Player* /*player*/, GameObject* /*go*/) { }
void TriggerGameEvent(uint32 gameEventId, WorldObject* source = nullptr, WorldObject* target = nullptr) override;
void Reset();
/* Battleground */
// Get methods:
@@ -386,7 +376,7 @@ class TC_GAME_API Battleground : public ZoneScript
BattlegroundScore const* GetBattlegroundScore(Player* player) const;
virtual bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
bool UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
void UpdatePvpStat(Player* player, uint32 pvpStatId, uint32 value);
static TeamId GetTeamIndexByTeamId(Team team) { return team == ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE; }
@@ -409,24 +399,13 @@ class TC_GAME_API Battleground : public ZoneScript
void SetArenaMatchmakerRating(Team team, uint32 MMR){ m_ArenaTeamMMR[GetTeamIndexByTeamId(team)] = MMR; }
uint32 GetArenaMatchmakerRating(Team team) const { return m_ArenaTeamMMR[GetTeamIndexByTeamId(team)]; }
// Triggers handle
// must be implemented in BG subclass
virtual void HandleAreaTrigger(Player* /*player*/, uint32 /*trigger*/, bool /*entered*/);
// must be implemented in BG subclass if need AND call base class generic code
virtual void HandleKillPlayer(Player* player, Player* killer);
virtual void HandleKillUnit(Creature* /*creature*/, Unit* /*killer*/) { }
virtual void HandleKillUnit(Creature* /*creature*/, Unit* /*killer*/);
// Battleground events
virtual void EventPlayerDroppedFlag(Player* /*player*/) { }
virtual void EventPlayerClickedOnFlag(Player* /*player*/, GameObject* /*target_obj*/) { }
void EventPlayerLoggedIn(Player* player);
void EventPlayerLoggedOut(Player* player);
void ProcessEvent(WorldObject* /*obj*/, uint32 /*eventId*/, WorldObject* /*invoker*/) override { }
virtual void HandlePlayerResurrect(Player* /*player*/) { }
// Death related
virtual WorldSafeLocsEntry const* GetClosestGraveyard(Player* player);
virtual WorldSafeLocsEntry const* GetExploitTeleportLocation(Team /*team*/) { return nullptr; }
// GetExploitTeleportLocation(TeamId) must be implemented in the battleground subclass.
@@ -437,25 +416,6 @@ class TC_GAME_API Battleground : public ZoneScript
void AddOrSetPlayerToCorrectBgGroup(Player* player, Team team);
virtual void RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool SendPacket);
// can be extended in in BG subclass
/// @todo make this protected:
GuidVector BgObjects;
GuidVector BgCreatures;
void SpawnBGObject(uint32 type, uint32 respawntime);
virtual bool AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime = 0, GOState goState = GO_STATE_READY);
bool AddObject(uint32 type, uint32 entry, Position const& pos, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime = 0, GOState goState = GO_STATE_READY);
virtual Creature* AddCreature(uint32 entry, uint32 type, float x, float y, float z, float o, TeamId teamId = TEAM_NEUTRAL, uint32 respawntime = 0, Transport* transport = nullptr);
Creature* AddCreature(uint32 entry, uint32 type, Position const& pos, TeamId teamId = TEAM_NEUTRAL, uint32 respawntime = 0, Transport* transport = nullptr);
bool DelCreature(uint32 type);
bool DelObject(uint32 type);
bool RemoveObjectFromWorld(uint32 type);
virtual bool AddSpiritGuide(uint32 type, float x, float y, float z, float o, TeamId teamId = TEAM_NEUTRAL);
bool AddSpiritGuide(uint32 type, Position const& pos, TeamId teamId = TEAM_NEUTRAL);
int32 GetObjectType(ObjectGuid guid);
void DoorOpen(uint32 type);
void DoorClose(uint32 type);
virtual bool HandlePlayerUnderMap(Player* /*player*/) { return false; }
@@ -470,14 +430,9 @@ class TC_GAME_API Battleground : public ZoneScript
void RewardXPAtKill(Player* killer, Player* victim);
bool CanAwardArenaPoints() const { return GetMinLevel() >= BG_AWARD_ARENA_POINTS_MIN_LEVEL; }
virtual ObjectGuid GetFlagPickerGUID(int32 /*team*/ = -1) const { return ObjectGuid::Empty; }
virtual void SetDroppedFlagGUID(ObjectGuid /*guid*/, int32 /*team*/ = -1) { }
virtual void HandleQuestComplete(uint32 /*questid*/, Player* /*player*/) { }
virtual bool CanActivateGO(int32 /*entry*/, uint32 /*team*/) const { return true; }
virtual bool IsSpellAllowed(uint32 /*spellId*/, Player const* /*player*/) const { return true; }
uint32 GetTeamScore(TeamId teamId) const;
virtual Team GetPrematureWinner();
Team GetPrematureWinner();
// because BattleGrounds with different types and same level range has different m_BracketId
uint8 GetUniqueBracketId() const;
@@ -494,8 +449,9 @@ class TC_GAME_API Battleground : public ZoneScript
return &itr->second;
}
// Called when valid BattlegroundMap is assigned to the battleground
virtual void OnMapSet([[maybe_unused]] BattlegroundMap* map) { }
void AddPoint(Team team, uint32 points = 1) { m_TeamScores[GetTeamIndexByTeamId(team)] += points; }
void SetTeamPoint(Team team, uint32 points = 0) { m_TeamScores[GetTeamIndexByTeamId(team)] = points; }
void RemovePoint(Team team, uint32 points = 1) { m_TeamScores[GetTeamIndexByTeamId(team)] -= points; }
Trinity::unique_weak_ptr<Battleground> GetWeakPtr() const { return m_weakRef; }
void SetWeakPtr(Trinity::unique_weak_ptr<Battleground> weakRef) { m_weakRef = std::move(weakRef); }
@@ -16,20 +16,8 @@
*/
#include "BattlegroundMgr.h"
#include "BattlegroundAB.h"
#include "BattlegroundAV.h"
#include "BattlegroundBE.h"
#include "BattlegroundBFG.h"
#include "BattlegroundDS.h"
#include "BattlegroundEY.h"
#include "BattlegroundIC.h"
#include "BattlegroundNA.h"
#include "Arena.h"
#include "BattlegroundPackets.h"
#include "BattlegroundRL.h"
#include "BattlegroundRV.h"
#include "BattlegroundSA.h"
#include "BattlegroundTP.h"
#include "BattlegroundWS.h"
#include "Containers.h"
#include "DatabaseEnv.h"
#include "DB2Stores.h"
@@ -262,6 +250,59 @@ Battleground* BattlegroundMgr::GetBattleground(uint32 instanceId, BattlegroundTy
return nullptr;
}
void BattlegroundMgr::LoadBattlegroundScriptTemplate()
{
uint32 oldMSTime = getMSTime();
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT MapId, BattlemasterListId, ScriptName FROM battleground_scripts");
if (!result)
{
TC_LOG_INFO("server.loading", ">> Loaded 0 battleground scripts. DB table `battleground_scripts` is empty!");
return;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
uint32 mapID = fields[0].GetUInt32();
MapEntry const* mapEntry = sMapStore.LookupEntry(mapID);
if (!mapEntry || !mapEntry->IsBattlegroundOrArena())
{
TC_LOG_ERROR("sql.sql", "BattlegroundMgr::LoadBattlegroundScriptTemplate: bad mapid {}! Map doesn't exist or is not a battleground/arena!", mapID);
continue;
}
BattlegroundTypeId bgTypeId = static_cast<BattlegroundTypeId>(fields[1].GetUInt32());
if (bgTypeId != BATTLEGROUND_TYPE_NONE && !Trinity::Containers::MapGetValuePtr(_battlegroundTemplates, bgTypeId))
{
TC_LOG_ERROR("sql.sql", "BattlegroundMgr::LoadBattlegroundScriptTemplate: bad battlemasterlist id {}! Battleground doesn't exist or is not supported in battleground_template!", bgTypeId);
continue;
}
BattlegroundScriptTemplate& scriptTemplate = _battlegroundScriptTemplates[{ mapID, bgTypeId }];
scriptTemplate.MapId = mapID;
scriptTemplate.Id = bgTypeId;
scriptTemplate.ScriptId = sObjectMgr->GetScriptId(fields[2].GetString());
++count;
} while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded {} battleground scripts in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
}
BattlegroundScriptTemplate const* BattlegroundMgr::FindBattlegroundScriptTemplate(uint32 mapId, BattlegroundTypeId bgTypeId) const
{
if (BattlegroundScriptTemplate const* scriptTemplate = Trinity::Containers::MapGetValuePtr(_battlegroundScriptTemplates, { mapId, bgTypeId }))
return scriptTemplate;
// fall back to 0 for no specific battleground type id
return Trinity::Containers::MapGetValuePtr(_battlegroundScriptTemplates, { mapId, BATTLEGROUND_TYPE_NONE });
}
uint32 BattlegroundMgr::CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
{
if (IsArenaType(bgTypeId))
@@ -309,56 +350,10 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundQueueTypeId que
}
Battleground* bg = nullptr;
// create a copy of the BG template
switch (bgTypeId)
{
case BATTLEGROUND_AV:
bg = new BattlegroundAV(bg_template);
break;
case BATTLEGROUND_WS:
case BATTLEGROUND_WG_CTF:
bg = new BattlegroundWS(bg_template);
break;
case BATTLEGROUND_AB:
case BATTLEGROUND_DOM_AB:
bg = new BattlegroundAB(bg_template);
break;
case BATTLEGROUND_NA:
bg = new BattlegroundNA(bg_template);
break;
case BATTLEGROUND_BE:
bg = new BattlegroundBE(bg_template);
break;
case BATTLEGROUND_EY:
bg = new BattlegroundEY(bg_template);
break;
case BATTLEGROUND_RL:
bg = new BattlegroundRL(bg_template);
break;
case BATTLEGROUND_SA:
bg = new BattlegroundSA(bg_template);
break;
case BATTLEGROUND_DS:
bg = new BattlegroundDS(bg_template);
break;
case BATTLEGROUND_RV:
bg = new BattlegroundRV(bg_template);
break;
case BATTLEGROUND_IC:
bg = new BattlegroundIC(bg_template);
break;
case BATTLEGROUND_TP:
bg = new BattlegroundTP(bg_template);
break;
case BATTLEGROUND_BFG:
bg = new BattlegroundBFG(bg_template);
break;
case BATTLEGROUND_RB:
case BATTLEGROUND_AA:
case BATTLEGROUND_RANDOM_EPIC:
default:
return nullptr;
}
if (bg_template->IsArena())
bg = new Arena(bg_template);
else
bg = new Battleground(bg_template);
bg->SetBracket(bracketEntry);
bg->SetInstanceID(sMapMgr->GenerateInstanceId());
@@ -689,6 +684,7 @@ BattlegroundTypeId BattlegroundMgr::GetRandomBG(BattlegroundTypeId bgTypeId)
ids.reserve(16);
std::vector<double> weights;
weights.reserve(16);
double totalWeight = 0.0;
for (int32 mapId : bgTemplate->BattlemasterEntry->MapID)
{
if (mapId == -1)
@@ -698,10 +694,12 @@ BattlegroundTypeId BattlegroundMgr::GetRandomBG(BattlegroundTypeId bgTypeId)
{
ids.push_back(bg->Id);
weights.push_back(bg->Weight);
totalWeight += bg->Weight;
}
}
return *Trinity::Containers::SelectRandomWeightedContainerElement(ids, std::span(weights));
if (totalWeight > 0.0)
return *Trinity::Containers::SelectRandomWeightedContainerElement(ids, std::span(weights));
}
return BATTLEGROUND_TYPE_NONE;
@@ -60,6 +60,13 @@ struct BattlegroundTemplate
uint8 GetMaxLevel() const;
};
struct BattlegroundScriptTemplate
{
int32 MapId;
BattlegroundTypeId Id;
uint32 ScriptId;
};
namespace WorldPackets
{
namespace Battleground
@@ -151,6 +158,9 @@ class TC_GAME_API BattlegroundMgr
return nullptr;
}
void LoadBattlegroundScriptTemplate();
BattlegroundScriptTemplate const* FindBattlegroundScriptTemplate(uint32 mapId, BattlegroundTypeId bgTypeId) const;
private:
uint32 CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id);
static bool IsArenaType(BattlegroundTypeId bgTypeId);
@@ -190,6 +200,8 @@ class TC_GAME_API BattlegroundMgr
typedef std::map<uint32 /*mapId*/, BattlegroundTemplate*> BattlegroundMapTemplateContainer;
BattlegroundTemplateMap _battlegroundTemplates;
BattlegroundMapTemplateContainer _battlegroundMapTemplates;
std::map<std::pair<int32, uint32>, BattlegroundScriptTemplate> _battlegroundScriptTemplates;
};
#define sBattlegroundMgr BattlegroundMgr::instance()
@@ -0,0 +1,135 @@
/*
* 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/>.
*/
#include "BattlegroundScript.h"
#include "BattlegroundMgr.h"
#include "Creature.h"
#include "GameEventSender.h"
#include "GameObject.h"
#include "Log.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "WorldStateMgr.h"
BattlegroundScript::BattlegroundScript(BattlegroundMap* map) : battlegroundMap(map), battleground(map->GetBG())
{
#ifdef TRINITY_API_USE_DYNAMIC_LINKING
BattlegroundScriptTemplate const* scriptTemplate = sBattlegroundMgr->FindBattlegroundScriptTemplate(battlegroundMap->GetId(), battlegroundMap->GetBG()->GetTypeID());
if (!scriptTemplate)
return;
auto const scriptname = sObjectMgr->GetScriptName(scriptTemplate->ScriptId);
ASSERT(!scriptname.empty());
// Acquire a strong reference from the script module
// to keep it loaded until this object is destroyed.
module_reference = sScriptMgr->AcquireModuleReferenceOfScriptName(scriptname);
#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING
}
Team BattlegroundScript::GetPrematureWinner()
{
Team winner = TEAM_OTHER;
if (battleground->GetPlayersCountByTeam(ALLIANCE) >= battleground->GetMinPlayersPerTeam())
winner = ALLIANCE;
else if (battleground->GetPlayersCountByTeam(HORDE) >= battleground->GetMinPlayersPerTeam())
winner = HORDE;
return winner;
}
void BattlegroundScript::TriggerGameEvent(uint32 gameEventId, WorldObject* source, WorldObject* target)
{
ProcessEvent(target, gameEventId, source);
GameEvents::TriggerForMap(gameEventId, battlegroundMap, source, target);
for (auto const& [playerGuid, _] : battleground->GetPlayers())
if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
GameEvents::TriggerForPlayer(gameEventId, player);
}
void BattlegroundScript::UpdateWorldState(int32 worldStateId, int32 value, bool hidden) const
{
sWorldStateMgr->SetValue(worldStateId, value, hidden, battlegroundMap);
}
ArenaScript::ArenaScript(BattlegroundMap* map) : BattlegroundScript(map)
{
}
GameObject* ArenaScript::CreateObject(uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, GOState goState) const
{
QuaternionData rot(rotation0, rotation1, rotation2, rotation3);
// Temporally add safety check for bad spawns and send log (object rotations need to be rechecked in sniff)
if (!rotation0 && !rotation1 && !rotation2 && !rotation3)
{
TC_LOG_DEBUG("bg.battleground", "Battleground::AddObject: gameoobject [entry: {}] for BG (map: {}) has zeroed rotation fields, "
"orientation used temporally, but please fix the spawn", entry, battlegroundMap->GetId());
rot = QuaternionData::fromEulerAnglesZYX(o, 0.f, 0.f);
}
// Must be created this way, adding to godatamap would add it to the base map of the instance
// and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
// So we must create it specific for this instance
GameObject* go = GameObject::CreateGameObject(entry, battlegroundMap, Position(x, y, z, o), rot, 255, goState);
if (!go)
{
TC_LOG_ERROR("bg.battleground", "Battleground::AddObject: cannot create gameobject (entry: {}) for BG (map: {}, instance id: {})!",
entry, battlegroundMap->GetId(), battleground->GetInstanceID());
return nullptr;
}
if (!battlegroundMap->AddToMap(go))
{
delete go;
return nullptr;
}
return go;
}
Creature* ArenaScript::CreateCreature(uint32 entry, float x, float y, float z, float o) const
{
if (!sObjectMgr->GetCreatureTemplate(entry))
{
TC_LOG_ERROR("bg.battleground", "Battleground::AddCreature: creature template (entry: {}) does not exist for BG (map: {}, instance id: {})!",
entry, battlegroundMap->GetId(), battleground->GetInstanceID());
return nullptr;
}
Position pos = { x, y, z, o };
Creature* creature = Creature::CreateCreature(entry, battlegroundMap, pos);
if (!creature)
{
TC_LOG_ERROR("bg.battleground", "Battleground::AddCreature: cannot create creature (entry: {}) for BG (map: {}, instance id: {})!",
entry, battlegroundMap->GetId(), battleground->GetInstanceID());
return nullptr;
}
creature->SetHomePosition(pos);
if (!battlegroundMap->AddToMap(creature))
{
delete creature;
return nullptr;
}
return creature;
}
@@ -0,0 +1,77 @@
/*
* 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 TRINITY_BATTLEGROUND_SCRIPT_H
#define TRINITY_BATTLEGROUND_SCRIPT_H
#include "SharedDefines.h"
#include "ZoneScript.h"
#ifdef TRINITY_API_USE_DYNAMIC_LINKING
#include <memory>
#endif
class Battleground;
class BattlegroundMap;
class ModuleReference;
class TC_GAME_API BattlegroundScript : public ZoneScript
{
public:
explicit BattlegroundScript(BattlegroundMap* map);
~BattlegroundScript() override = default;
virtual void OnInit() { }
virtual void OnUpdate([[maybe_unused]] uint32 diff) { }
virtual void OnPrepareStage1() { }
virtual void OnPrepareStage2() { }
virtual void OnPrepareStage3() { }
virtual void OnStart() { }
virtual void OnEnd([[maybe_unused]] Team winner) { }
virtual void OnPlayerJoined([[maybe_unused]] Player* player, [[maybe_unused]] bool inBattleground) { }
virtual void OnPlayerLeft([[maybe_unused]] Player* player) { }
virtual void OnPlayerKilled([[maybe_unused]] Player* victim, [[maybe_unused]] Player* killer) { }
virtual void OnUnitKilled([[maybe_unused]] Creature* victim, [[maybe_unused]] Unit* killer) { }
virtual Team GetPrematureWinner();
void TriggerGameEvent(uint32 gameEventId, WorldObject* source = nullptr, WorldObject* target = nullptr) override;
protected:
void UpdateWorldState(int32 worldStateId, int32 value, bool hidden = false) const;
BattlegroundMap* battlegroundMap;
Battleground* battleground;
private:
#ifdef TRINITY_API_USE_DYNAMIC_LINKING
// Strong reference to the associated script module
std::shared_ptr<ModuleReference> module_reference;
#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING
};
class TC_GAME_API ArenaScript : public BattlegroundScript
{
public:
explicit ArenaScript(BattlegroundMap* map);
~ArenaScript() override = default;
protected:
GameObject* CreateObject(uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, GOState goState = GO_STATE_READY) const;
Creature* CreateCreature(uint32 entry, float x, float y, float z, float o) const;
};
#endif // TRINITY_BATTLEGROUND_SCRIPT_H
@@ -1,480 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundAB.h"
#include "BattlegroundMgr.h"
#include "BattlegroundPackets.h"
#include "BattlegroundScore.h"
#include "Creature.h"
#include "GameObject.h"
#include "Log.h"
#include "Map.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "SpellInfo.h"
enum ArathiBasinPvpStats
{
PVP_STAT_BASES_ASSAULTED = 926,
PVP_STAT_BASES_DEFENDED = 927,
};
BattlegroundAB::BattlegroundAB(BattlegroundTemplate const* battlegroundTemplate) : Battleground(battlegroundTemplate)
{
m_IsInformedNearVictory = false;
BgObjects.resize(0);
BgCreatures.resize(0);
m_lastTick = 0;
for (uint8 i = 0; i < PVP_TEAMS_COUNT; ++i)
{
m_HonorScoreTics[i] = 0;
m_ReputationScoreTics[i] = 0;
}
m_HonorTics = 0;
m_ReputationTics = 0;
}
BattlegroundAB::~BattlegroundAB() { }
void BattlegroundAB::PostUpdateImpl(uint32 diff)
{
if (GetStatus() == STATUS_IN_PROGRESS)
{
// Accumulate points
m_lastTick += diff;
if (m_lastTick > BG_AB_TickInterval)
{
m_lastTick -= BG_AB_TickInterval;
uint8 ally = 0, horde = 0;
_CalculateTeamNodes(ally, horde);
uint8 points[PVP_TEAMS_COUNT] = { ally, horde };
for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
{
if (!points[team])
continue;
m_TeamScores[team] += BG_AB_TickPoints[points[team]];
m_HonorScoreTics[team] += BG_AB_TickPoints[points[team]];
m_ReputationScoreTics[team] += BG_AB_TickPoints[points[team]];
if (m_ReputationScoreTics[team] >= m_ReputationTics)
{
(team == TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE);
m_ReputationScoreTics[team] -= m_ReputationTics;
}
if (m_HonorScoreTics[team] >= m_HonorTics)
{
RewardHonorToTeam(GetBonusHonorFromKill(1), (team == TEAM_ALLIANCE) ? ALLIANCE : HORDE);
m_HonorScoreTics[team] -= m_HonorTics;
}
if (!m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE)
{
if (team == TEAM_ALLIANCE)
{
SendBroadcastText(BG_AB_TEXT_ALLIANCE_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY_ALLIANCE);
}
else
{
SendBroadcastText(BG_AB_TEXT_HORDE_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY_HORDE);
}
m_IsInformedNearVictory = true;
}
if (m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE)
m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE;
if (team == TEAM_ALLIANCE)
UpdateWorldState(BG_AB_WS_RESOURCES_ALLY, m_TeamScores[team]);
else
UpdateWorldState(BG_AB_WS_RESOURCES_HORDE, m_TeamScores[team]);
// update achievement flags
// we increased m_TeamScores[team] so we just need to check if it is 500 more than other teams resources
uint8 otherTeam = (team + 1) % PVP_TEAMS_COUNT;
if (m_TeamScores[team] > m_TeamScores[otherTeam] + 500)
{
if (team == TEAM_ALLIANCE)
UpdateWorldState(BG_AB_WS_HAD_500_DISADVANTAGE_HORDE, 1);
else
UpdateWorldState(BG_AB_WS_HAD_500_DISADVANTAGE_ALLIANCE, 1);
}
}
UpdateWorldState(BG_AB_WS_OCCUPIED_BASES_ALLY, ally);
UpdateWorldState(BG_AB_WS_OCCUPIED_BASES_HORDE, horde);
}
// Test win condition
if (m_TeamScores[TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE)
EndBattleground(ALLIANCE);
else if (m_TeamScores[TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE)
EndBattleground(HORDE);
}
}
void BattlegroundAB::StartingEventOpenDoors()
{
// Achievement: Let's Get This Done
TriggerGameEvent(AB_EVENT_START_BATTLE);
}
void BattlegroundAB::_CalculateTeamNodes(uint8& alliance, uint8& horde)
{
alliance = 0;
horde = 0;
if (BattlegroundMap* map = FindBgMap())
{
for (ObjectGuid const& guid : _capturePoints)
{
if (GameObject* capturePoint = map->GetGameObject(guid))
{
int32 wsValue = map->GetWorldStateValue(capturePoint->GetGOInfo()->capturePoint.worldState1);
switch (WorldPackets::Battleground::BattlegroundCapturePointState(wsValue))
{
case WorldPackets::Battleground::BattlegroundCapturePointState::AllianceCaptured:
++alliance;
break;
case WorldPackets::Battleground::BattlegroundCapturePointState::HordeCaptured:
++horde;
break;
default:
break;
}
}
}
}
}
Team BattlegroundAB::GetPrematureWinner()
{
// How many bases each team owns
uint8 ally = 0, horde = 0;
_CalculateTeamNodes(ally, horde);
if (ally > horde)
return ALLIANCE;
else if (horde > ally)
return HORDE;
// If the values are equal, fall back to the original result (based on number of players on each team)
return Battleground::GetPrematureWinner();
}
void BattlegroundAB::ProcessEvent(WorldObject* /*source*/, uint32 eventId, WorldObject* invoker)
{
switch (eventId)
{
case AB_EVENT_START_BATTLE:
{
for (ObjectGuid const& guid : _creaturesToRemoveOnMatchStart)
if (Creature* creature = GetBgMap()->GetCreature(guid))
creature->DespawnOrUnsummon();
for (ObjectGuid const& guid : _gameobjectsToRemoveOnMatchStart)
if (GameObject* gameObject = GetBgMap()->GetGameObject(guid))
gameObject->DespawnOrUnsummon();
for (ObjectGuid const& guid : _doors)
{
if (GameObject* gameObject = GetBgMap()->GetGameObject(guid))
{
gameObject->UseDoorOrButton();
gameObject->DespawnOrUnsummon(3s);
}
}
break;
}
case AB_EVENT_CONTESTED_BLACKSMITH_ALLIANCE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE, 1);
UpdateWorldState(BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE, 0);
PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_BLACKSMITH_ALLIANCE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE, 2);
UpdateWorldState(BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE, 0);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_BLACKSMITH_ALLIANCE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
break;
case AB_EVENT_CONTESTED_BLACKSMITH_HORDE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE, 1);
PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_HORDE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_BLACKSMITH_HORDE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_BLACKSMITH_HORDE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
break;
case AB_EVENT_CONTESTED_FARM_ALLIANCE:
UpdateWorldState(BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE, 1);
UpdateWorldState(BG_AB_WS_FARM_HORDE_CONTROL_STATE, 0);
PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_FARM_ALLIANCE:
UpdateWorldState(BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE, 2);
UpdateWorldState(BG_AB_WS_FARM_HORDE_CONTROL_STATE, 0);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_FARM_ALLIANCE:
UpdateWorldState(BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
break;
case AB_EVENT_CONTESTED_FARM_HORDE:
UpdateWorldState(BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_FARM_HORDE_CONTROL_STATE, 1);
PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_HORDE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_FARM_HORDE:
UpdateWorldState(BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_FARM_HORDE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_FARM_HORDE:
UpdateWorldState(BG_AB_WS_FARM_HORDE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
break;
case AB_EVENT_CONTESTED_GOLD_MINE_ALLIANCE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE, 1);
UpdateWorldState(BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE, 0);
PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_GOLD_MINE_ALLIANCE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE, 2);
UpdateWorldState(BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE, 0);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_GOLD_MINE_ALLIANCE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
break;
case AB_EVENT_CONTESTED_GOLD_MINE_HORDE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE, 1);
PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_HORDE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_GOLD_MINE_HORDE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_GOLD_MINE_HORDE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
break;
case AB_EVENT_CONTESTED_LUMBER_MILL_ALLIANCE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE, 1);
UpdateWorldState(BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE, 0);
PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_LUMBER_MILL_ALLIANCE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE, 2);
UpdateWorldState(BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE, 0);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_LUMBER_MILL_ALLIANCE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
break;
case AB_EVENT_CONTESTED_LUMBER_MILL_HORDE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE, 1);
PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_HORDE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_LUMBER_MILL_HORDE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_LUMBER_MILL_HORDE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
break;
case AB_EVENT_CONTESTED_STABLES_ALLIANCE:
UpdateWorldState(BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE, 1);
UpdateWorldState(BG_AB_WS_STABLES_HORDE_CONTROL_STATE, 0);
PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_STABLES_ALLIANCE:
UpdateWorldState(BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE, 2);
UpdateWorldState(BG_AB_WS_STABLES_HORDE_CONTROL_STATE, 0);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_STABLES_ALLIANCE:
UpdateWorldState(BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
break;
case AB_EVENT_CONTESTED_STABLES_HORDE:
UpdateWorldState(BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_STABLES_HORDE_CONTROL_STATE, 1);
PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_HORDE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_STABLES_HORDE:
UpdateWorldState(BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_STABLES_HORDE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
if (Player* player = invoker->ToPlayer())
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_STABLES_HORDE:
UpdateWorldState(BG_AB_WS_STABLES_HORDE_CONTROL_STATE, 2);
PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
break;
default:
TC_LOG_WARN("bg.events", "BattlegroundAB::ProcessEvent: Unhandled event %u.", eventId);
break;
}
}
void BattlegroundAB::OnCreatureCreate(Creature* creature)
{
switch (creature->GetEntry())
{
case BG_AB_NPC_THE_BLACK_BRIDE:
case BG_AB_NPC_RADULF_LEDER:
_creaturesToRemoveOnMatchStart.push_back(creature->GetGUID());
break;
default:
break;
}
}
void BattlegroundAB::OnGameObjectCreate(GameObject* gameObject)
{
if (gameObject->GetGOInfo()->type == GAMEOBJECT_TYPE_CAPTURE_POINT)
_capturePoints.push_back(gameObject->GetGUID());
switch (gameObject->GetEntry())
{
case BG_AB_OBJECTID_GHOST_GATE:
_gameobjectsToRemoveOnMatchStart.push_back(gameObject->GetGUID());
break;
case BG_AB_OBJECTID_ALLIANCE_DOOR:
case BG_AB_OBJECTID_HORDE_DOOR:
_doors.push_back(gameObject->GetGUID());
break;
default:
break;
}
}
bool BattlegroundAB::SetupBattleground()
{
UpdateWorldState(BG_AB_WS_RESOURCES_MAX, BG_AB_MAX_TEAM_SCORE);
UpdateWorldState(BG_AB_WS_RESOURCES_WARNING, BG_AB_WARNING_NEAR_VICTORY_SCORE);
return true;
}
void BattlegroundAB::Reset()
{
//call parent's class reset
Battleground::Reset();
m_TeamScores[TEAM_ALLIANCE] = 0;
m_TeamScores[TEAM_HORDE] = 0;
m_lastTick = 0;
m_HonorScoreTics[TEAM_ALLIANCE] = 0;
m_HonorScoreTics[TEAM_HORDE] = 0;
m_ReputationScoreTics[TEAM_ALLIANCE] = 0;
m_ReputationScoreTics[TEAM_HORDE] = 0;
m_IsInformedNearVictory = false;
bool isBGWeekend = sBattlegroundMgr->IsBGWeekend(GetTypeID());
m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks;
m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks;
_creaturesToRemoveOnMatchStart.clear();
_gameobjectsToRemoveOnMatchStart.clear();
_doors.clear();
_capturePoints.clear();
}
void BattlegroundAB::EndBattleground(Team winner)
{
// Win reward
if (winner == ALLIANCE)
RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
if (winner == HORDE)
RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
// Complete map_end rewards (even if no team wins)
RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
Battleground::EndBattleground(winner);
}
WorldSafeLocsEntry const* BattlegroundAB::GetClosestGraveyard(Player* player)
{
return sObjectMgr->GetClosestGraveyard(player->GetWorldLocation(), player->GetTeam(), player);
}
WorldSafeLocsEntry const* BattlegroundAB::GetExploitTeleportLocation(Team team)
{
return sObjectMgr->GetWorldSafeLoc(team == ALLIANCE ? AB_EXPLOIT_TELEPORT_LOCATION_ALLIANCE : AB_EXPLOIT_TELEPORT_LOCATION_HORDE);
}
@@ -1,254 +0,0 @@
/*
* 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 __BATTLEGROUNDAB_H
#define __BATTLEGROUNDAB_H
#include "Battleground.h"
#include "Object.h"
enum BG_AB_WorldStates
{
BG_AB_WS_OCCUPIED_BASES_HORDE = 1778,
BG_AB_WS_OCCUPIED_BASES_ALLY = 1779,
BG_AB_WS_RESOURCES_ALLY = 1776,
BG_AB_WS_RESOURCES_HORDE = 1777,
BG_AB_WS_RESOURCES_MAX = 1780,
BG_AB_WS_RESOURCES_WARNING = 1955,
BG_AB_WS_STABLE_ICON = 1842, // Stable map icon (NONE)
BG_AB_WS_STABLE_STATE_ALIENCE = 1767, // Stable map state (ALIENCE)
BG_AB_WS_STABLE_STATE_HORDE = 1768, // Stable map state (HORDE)
BG_AB_WS_STABLE_STATE_CON_ALI = 1769, // Stable map state (CON ALIENCE)
BG_AB_WS_STABLE_STATE_CON_HOR = 1770, // Stable map state (CON HORDE)
BG_AB_WS_FARM_ICON = 1845, // Farm map icon (NONE)
BG_AB_WS_FARM_STATE_ALIENCE = 1772, // Farm state (ALIENCE)
BG_AB_WS_FARM_STATE_HORDE = 1773, // Farm state (HORDE)
BG_AB_WS_FARM_STATE_CON_ALI = 1774, // Farm state (CON ALIENCE)
BG_AB_WS_FARM_STATE_CON_HOR = 1775, // Farm state (CON HORDE)
BG_AB_WS_BLACKSMITH_ICON = 1846, // Blacksmith map icon (NONE)
BG_AB_WS_BLACKSMITH_STATE_ALIENCE = 1782, // Blacksmith map state (ALIENCE)
BG_AB_WS_BLACKSMITH_STATE_HORDE = 1783, // Blacksmith map state (HORDE)
BG_AB_WS_BLACKSMITH_STATE_CON_ALI = 1784, // Blacksmith map state (CON ALIENCE)
BG_AB_WS_BLACKSMITH_STATE_CON_HOR = 1785, // Blacksmith map state (CON HORDE)
BG_AB_WS_LUMBERMILL_ICON = 1844, // Lumber Mill map icon (NONE)
BG_AB_WS_LUMBERMILL_STATE_ALIENCE = 1792, // Lumber Mill map state (ALIENCE)
BG_AB_WS_LUMBERMILL_STATE_HORDE = 1793, // Lumber Mill map state (HORDE)
BG_AB_WS_LUMBERMILL_STATE_CON_ALI = 1794, // Lumber Mill map state (CON ALIENCE)
BG_AB_WS_LUMBERMILL_STATE_CON_HOR = 1795, // Lumber Mill map state (CON HORDE)
BG_AB_WS_GOLDMINE_ICON = 1843, // Gold Mine map icon (NONE)
BG_AB_WS_GOLDMINE_STATE_ALIENCE = 1787, // Gold Mine map state (ALIENCE)
BG_AB_WS_GOLDMINE_STATE_HORDE = 1788, // Gold Mine map state (HORDE)
BG_AB_WS_GOLDMINE_STATE_CON_ALI = 1789, // Gold Mine map state (CON ALIENCE
BG_AB_WS_GOLDMINE_STATE_CON_HOR = 1790, // Gold Mine map state (CON HORDE)
BG_AB_WS_HAD_500_DISADVANTAGE_ALLIANCE = 3644,
BG_AB_WS_HAD_500_DISADVANTAGE_HORDE = 3645,
BG_AB_WS_FARM_ICON_NEW = 8808, // Farm map icon
BG_AB_WS_LUMBER_MILL_ICON_NEW = 8805, // Lumber Mill map icon
BG_AB_WS_BLACKSMITH_ICON_NEW = 8799, // Blacksmith map icon
BG_AB_WS_GOLD_MINE_ICON_NEW = 8809, // Gold Mine map icon
BG_AB_WS_STABLES_ICON_NEW = 5834, // Stable map icon
BG_AB_WS_FARM_HORDE_CONTROL_STATE = 17328,
BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE = 17325,
BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE = 17330,
BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE = 17326,
BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE = 17327,
BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE = 17324,
BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE = 17329,
BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE = 17323,
BG_AB_WS_STABLES_HORDE_CONTROL_STATE = 17331,
BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE = 17322,
};
/* Object id templates from DB */
enum BG_AB_ObjectTypes
{
BG_AB_OBJECTID_CAPTURE_POINT_STABLES = 227420,
BG_AB_OBJECTID_CAPTURE_POINT_BLACKSMITH = 227522,
BG_AB_OBJECTID_CAPTURE_POINT_FARM = 227536,
BG_AB_OBJECTID_CAPTURE_POINT_GOLD_MINE = 227538,
BG_AB_OBJECTID_CAPTURE_POINT_LUMBER_MILL = 227544,
BG_AB_OBJECTID_GHOST_GATE = 180322,
BG_AB_OBJECTID_ALLIANCE_DOOR = 322273,
BG_AB_OBJECTID_HORDE_DOOR = 322274
};
enum BG_AB_Creatures
{
BG_AB_NPC_THE_BLACK_BRIDE = 150501,
BG_AB_NPC_RADULF_LEDER = 150505
};
enum BG_AB_Score
{
BG_AB_WARNING_NEAR_VICTORY_SCORE = 1200,
BG_AB_MAX_TEAM_SCORE = 1500
};
/* do NOT change the order, else wrong behaviour */
enum BG_AB_BattlegroundNodes
{
BG_AB_NODE_STABLES = 0,
BG_AB_NODE_BLACKSMITH = 1,
BG_AB_NODE_FARM = 2,
BG_AB_NODE_LUMBER_MILL = 3,
BG_AB_NODE_GOLD_MINE = 4,
BG_AB_DYNAMIC_NODES_COUNT = 5, // dynamic nodes that can be captured
BG_AB_SPIRIT_ALIANCE = 5,
BG_AB_SPIRIT_HORDE = 6,
BG_AB_ALL_NODES_COUNT = 7 // all nodes (dynamic and static)
};
enum BG_AB_BroadcastTexts
{
BG_AB_TEXT_ALLIANCE_NEAR_VICTORY = 10598,
BG_AB_TEXT_HORDE_NEAR_VICTORY = 10599,
};
enum BG_AB_Sounds
{
BG_AB_SOUND_NODE_CLAIMED = 8192,
BG_AB_SOUND_NODE_CAPTURED_ALLIANCE = 8173,
BG_AB_SOUND_NODE_CAPTURED_HORDE = 8213,
BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE = 8212,
BG_AB_SOUND_NODE_ASSAULTED_HORDE = 8174,
BG_AB_SOUND_NEAR_VICTORY_ALLIANCE = 8456,
BG_AB_SOUND_NEAR_VICTORY_HORDE = 8457
};
enum BG_AB_ExploitTeleportLocations
{
AB_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 7056,
AB_EXPLOIT_TELEPORT_LOCATION_HORDE = 7055
};
#define BG_AB_NotABBGWeekendHonorTicks 260
#define BG_AB_ABBGWeekendHonorTicks 160
#define BG_AB_NotABBGWeekendReputationTicks 160
#define BG_AB_ABBGWeekendReputationTicks 120
enum BG_AB_Events
{
AB_EVENT_START_BATTLE = 9158, // Achievement: Let's Get This Done
AB_EVENT_CONTESTED_STABLES_HORDE = 28523,
AB_EVENT_CAPTURE_STABLES_HORDE = 28527,
AB_EVENT_DEFENDED_STABLES_HORDE = 28525,
AB_EVENT_CONTESTED_STABLES_ALLIANCE = 28522,
AB_EVENT_CAPTURE_STABLES_ALLIANCE = 28526,
AB_EVENT_DEFENDED_STABLES_ALLIANCE = 28524,
AB_EVENT_CONTESTED_BLACKSMITH_HORDE = 8876,
AB_EVENT_CAPTURE_BLACKSMITH_HORDE = 8773,
AB_EVENT_DEFENDED_BLACKSMITH_HORDE = 8770,
AB_EVENT_CONTESTED_BLACKSMITH_ALLIANCE = 8874,
AB_EVENT_CAPTURE_BLACKSMITH_ALLIANCE = 8769,
AB_EVENT_DEFENDED_BLACKSMITH_ALLIANCE = 8774,
AB_EVENT_CONTESTED_FARM_HORDE = 39398,
AB_EVENT_CAPTURE_FARM_HORDE = 39399,
AB_EVENT_DEFENDED_FARM_HORDE = 39400,
AB_EVENT_CONTESTED_FARM_ALLIANCE = 39401,
AB_EVENT_CAPTURE_FARM_ALLIANCE = 39402,
AB_EVENT_DEFENDED_FARM_ALLIANCE = 39403,
AB_EVENT_CONTESTED_GOLD_MINE_HORDE = 39404,
AB_EVENT_CAPTURE_GOLD_MINE_HORDE = 39405,
AB_EVENT_DEFENDED_GOLD_MINE_HORDE = 39406,
AB_EVENT_CONTESTED_GOLD_MINE_ALLIANCE = 39407,
AB_EVENT_CAPTURE_GOLD_MINE_ALLIANCE = 39408,
AB_EVENT_DEFENDED_GOLD_MINE_ALLIANCE = 39409,
AB_EVENT_CONTESTED_LUMBER_MILL_HORDE = 39387,
AB_EVENT_CAPTURE_LUMBER_MILL_HORDE = 39388,
AB_EVENT_DEFENDED_LUMBER_MILL_HORDE = 39389,
AB_EVENT_CONTESTED_LUMBER_MILL_ALLIANCE = 39390,
AB_EVENT_CAPTURE_LUMBER_MILL_ALLIANCE = 39391,
AB_EVENT_DEFENDED_LUMBER_MILL_ALLIANCE = 39392
};
// Tick intervals and given points: case 0, 1, 2, 3, 4, 5 captured nodes
const uint32 BG_AB_TickInterval = 2000;
const uint32 BG_AB_TickPoints[6] = { 0, 2, 3, 4, 7, 60 };
// WorldSafeLocs ids for 5 nodes, and for ally, and horde starting location
enum BG_AB_Graveyards
{
AB_GRAVEYARD_ALLIANCE_BASE = 7251,
AB_GRAVEYARD_STABLES = 7252,
AB_GRAVEYARD_GOLD_MINE = 7253,
AB_GRAVEYARD_LUMBER_MILL = 7254,
AB_GRAVEYARD_HORDE_BASE = 7255,
AB_GRAVEYARD_FARM = 7256,
AB_GRAVEYARD_BLACKSMITH = 7257
};
const uint32 BG_AB_GraveyardIds[BG_AB_ALL_NODES_COUNT] =
{
AB_GRAVEYARD_STABLES,
AB_GRAVEYARD_BLACKSMITH,
AB_GRAVEYARD_FARM,
AB_GRAVEYARD_LUMBER_MILL,
AB_GRAVEYARD_GOLD_MINE,
AB_GRAVEYARD_ALLIANCE_BASE,
AB_GRAVEYARD_HORDE_BASE
};
class BattlegroundAB : public Battleground
{
public:
BattlegroundAB(BattlegroundTemplate const* battlegroundTemplate);
~BattlegroundAB();
void StartingEventOpenDoors() override;
bool SetupBattleground() override;
void Reset() override;
void EndBattleground(Team winner) override;
WorldSafeLocsEntry const* GetClosestGraveyard(Player* player) override;
WorldSafeLocsEntry const* GetExploitTeleportLocation(Team team) override;
Team GetPrematureWinner() override;
void ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker = nullptr) override;
void OnCreatureCreate(Creature* creature) override;
void OnGameObjectCreate(GameObject* gameObject) override;
private:
void PostUpdateImpl(uint32 diff) override;
void _CalculateTeamNodes(uint8& alliance, uint8& horde);
uint32 m_lastTick;
uint32 m_HonorScoreTics[PVP_TEAMS_COUNT];
uint32 m_ReputationScoreTics[PVP_TEAMS_COUNT];
bool m_IsInformedNearVictory;
uint32 m_HonorTics;
uint32 m_ReputationTics;
GuidVector _gameobjectsToRemoveOnMatchStart;
GuidVector _creaturesToRemoveOnMatchStart;
GuidVector _doors;
GuidVector _capturePoints;
};
#endif
@@ -1,898 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundAV.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "DB2Stores.h"
#include "GameObject.h"
#include "Log.h"
#include "Map.h"
#include "MotionMaster.h"
#include "ObjectMgr.h"
#include "Player.h"
enum AlteracValleyPvpStats
{
PVP_STAT_TOWERS_ASSAULTED = 61,
PVP_STAT_GRAVEYARDS_ASSAULTED = 63,
PVP_STAT_TOWERS_DEFENDED = 64,
PVP_STAT_GRAVEYARDS_DEFENDED = 65,
PVP_STAT_SECONDARY_OBJECTIVES = 82
};
enum AlteracValleyMisc
{
NEAR_LOSE_POINTS = 140
};
enum AlteracValleyHonorKillBonus
{
HONOR_KILL_BONUS_BOSS = 4,
HONOR_KILL_BONUS_CAPTAIN = 3,
HONOR_KILL_BONUS_SURVIVING_TOWER = 2,
HONOR_KILL_BONUS_SURVIVING_CAPTAIN = 2,
HONOR_KILL_BONUS_DESTROY_TOWER = 3
};
enum AlteracValleyReputationGains
{
REP_GAIN_BOSS = 350,
REP_GAIN_CAPTAIN = 125,
REP_GAIN_DESTROY_TOWER = 12,
REP_GAIN_SURVIVING_TOWER = 12,
REP_GAIN_SURVIVING_CAPTAIN = 125
};
enum AlteracValleyResourceLoss
{
RESOURCE_LOSS_TOWER = -75,
RESOURCE_LOSS_CAPTAIN = -100
};
enum AlteracValleySpells
{
SPELL_COMPLETE_ALTERAC_VALLEY_QUEST = 23658,
};
enum AlteracValleyFactions
{
FACTION_FROSTWOLF_CLAN = 729,
FACTION_STORMPIKE_GUARD = 730,
};
BattlegroundAV::BattlegroundAV(BattlegroundTemplate const* battlegroundTemplate) : Battleground(battlegroundTemplate)
{
BgObjects.resize(0);
BgCreatures.resize(0);
_teamResources = { BG_AV_SCORE_INITIAL_POINTS, BG_AV_SCORE_INITIAL_POINTS };
_isInformedNearVictory = { false, false };
for (uint8 i = 0; i < 2; i++) //forloop for both teams (it just make 0 == alliance and 1 == horde also for both mines 0=north 1=south
{
for (uint8 j = 0; j < 9; j++)
m_Team_QuestStatus[i][j] = 0;
_captainBuffTimer[i].Reset(120000 + urand(0, 4) * 60); //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes @todo get the right times
}
_mineInfo[uint8(AlteracValleyMine::North)] = { TEAM_OTHER, { AV_WS_IRONDEEP_MINE_OWNER, AV_WS_IRONDEEP_MINE_ALLIANCE_CONTROLLED, AV_WS_IRONDEEP_MINE_HORDE_CONTROLLED, AV_WS_IRONDEEP_MINE_TROGG_CONTROLLED, TEXT_IRONDEEP_MINE_ALLIANCE_TAKEN, TEXT_IRONDEEP_MINE_HORDE_TAKEN } };
_mineInfo[uint8(AlteracValleyMine::South)] = { TEAM_OTHER, { AV_WS_COLDTOOTH_MINE_OWNER, AV_WS_COLDTOOTH_MINE_ALLIANCE_CONTROLLED, AV_WS_COLDTOOTH_MINE_HORDE_CONTROLLED, AV_WS_COLDTOOTH_MINE_KOBOLD_CONTROLLED, TEXT_COLDTOOTH_MINE_ALLIANCE_TAKEN, TEXT_COLDTOOTH_MINE_HORDE_TAKEN } };
for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_STONEHEART_GRAVE; ++i) //alliance graves
InitNode(i, ALLIANCE, false);
for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i) //alliance towers
InitNode(i, ALLIANCE, true);
for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_GRAVE; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) //horde graves
InitNode(i, HORDE, false);
for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) //horde towers
InitNode(i, HORDE, true);
InitNode(BG_AV_NODES_SNOWFALL_GRAVE, TEAM_OTHER, false); //give snowfall neutral owner
_mineResourceTimer.Reset(BG_AV_MINE_RESOURCE_TIMER);
StartMessageIds[BG_STARTING_EVENT_SECOND] = BG_AV_TEXT_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = BG_AV_TEXT_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = BG_AV_TEXT_BATTLE_HAS_BEGUN;
}
void BattlegroundAV::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
Battleground::HandleKillPlayer(player, killer);
UpdateScore(GetPlayerTeam(player->GetGUID()), -1);
}
void BattlegroundAV::HandleKillUnit(Creature* unit, Unit* killer)
{
TC_LOG_DEBUG("bg.battleground", "bg_av HandleKillUnit {}", unit->GetEntry());
if (GetStatus() != STATUS_IN_PROGRESS)
return;
switch (unit->GetEntry())
{
case BG_AV_CREATURE_VANNDAR:
{
UpdateWorldState(AV_WS_VANDAAR_ALIVE, 0);
CastSpellOnTeam(SPELL_COMPLETE_ALTERAC_VALLEY_QUEST, HORDE); //this is a spell which finishes a quest where a player has to kill the boss
RewardReputationToTeam(FACTION_FROSTWOLF_CLAN, REP_GAIN_BOSS, HORDE);
RewardHonorToTeam(GetBonusHonorFromKill(HONOR_KILL_BONUS_BOSS), HORDE);
EndBattleground(HORDE);
break;
}
case BG_AV_CREATURE_DREKTHAR:
{
UpdateWorldState(AV_WS_DREKTHAR_ALIVE, 0);
CastSpellOnTeam(SPELL_COMPLETE_ALTERAC_VALLEY_QUEST, ALLIANCE); //this is a spell which finishes a quest where a player has to kill the boss
RewardReputationToTeam(FACTION_STORMPIKE_GUARD, REP_GAIN_BOSS, ALLIANCE);
RewardHonorToTeam(GetBonusHonorFromKill(HONOR_KILL_BONUS_BOSS), ALLIANCE);
EndBattleground(ALLIANCE);
break;
}
case BG_AV_CREATURE_BALINDA:
{
UpdateWorldState(AV_WS_BALINDA_ALIVE, 0);
RewardReputationToTeam(FACTION_FROSTWOLF_CLAN, REP_GAIN_CAPTAIN, HORDE);
RewardHonorToTeam(GetBonusHonorFromKill(HONOR_KILL_BONUS_CAPTAIN), HORDE);
UpdateScore(ALLIANCE, RESOURCE_LOSS_CAPTAIN);
if (Creature* herald = FindHerald("bg_av_herald_horde_win"))
herald->AI()->Talk(TEXT_STORMPIKE_GENERAL_DEAD);
break;
}
case BG_AV_CREATURE_GALVANGAR:
{
UpdateWorldState(AV_WS_GALVAGAR_ALIVE, 0);
RewardReputationToTeam(FACTION_STORMPIKE_GUARD, REP_GAIN_CAPTAIN, ALLIANCE);
RewardHonorToTeam(GetBonusHonorFromKill(HONOR_KILL_BONUS_CAPTAIN), ALLIANCE);
UpdateScore(HORDE, RESOURCE_LOSS_CAPTAIN);
if (Creature* herald = FindHerald("bg_av_herald_alliance_win"))
herald->AI()->Talk(TEXT_FROSTWOLF_GENERAL_DEAD);
break;
}
case BG_AV_CREATURE_MORLOCH:
{
// if mine is not owned by morloch, then nothing happens
if (_mineInfo[uint8(AlteracValleyMine::North)].Owner != TEAM_OTHER)
break;
Team killerTeam = GetPlayerTeam(Coalesce<Unit>(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), killer)->GetGUID());
ChangeMineOwner(AlteracValleyMine::North, killerTeam);
break;
}
case BG_AV_CREATURE_TASKMASTER_SNIVVLE:
{
if (_mineInfo[uint8(AlteracValleyMine::South)].Owner != TEAM_OTHER)
break;
Team killerTeam = GetPlayerTeam(Coalesce<Unit>(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), killer)->GetGUID());
ChangeMineOwner(AlteracValleyMine::South, killerTeam);
break;
}
case BG_AV_CREATURE_UMI_THORSON:
case BG_AV_CREATURE_KEETAR:
{
Team killerTeam = GetPlayerTeam(Coalesce<Unit>(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), killer)->GetGUID());
ChangeMineOwner(AlteracValleyMine::North, killerTeam);
break;
}
case BG_AV_CREATURE_AGI_RUMBLESTOMP:
case BG_AV_CREATURE_MASHA_SWIFTCUT:
{
Team killerTeam = GetPlayerTeam(Coalesce<Unit>(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), killer)->GetGUID());
ChangeMineOwner(AlteracValleyMine::South, killerTeam);
break;
}
}
}
void BattlegroundAV::HandleQuestComplete(uint32 questid, Player* player)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;//maybe we should log this, cause this must be a cheater or a big bug
Team team = GetPlayerTeam(player->GetGUID());
TeamId teamIndex = GetTeamIndexByTeamId(team);
/// @todo add reputation, events (including quest not available anymore, next quest available, go/npc de/spawning)and maybe honor
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed", questid);
switch (questid)
{
case AV_QUEST_A_SCRAPS1:
case AV_QUEST_A_SCRAPS2:
case AV_QUEST_H_SCRAPS1:
case AV_QUEST_H_SCRAPS2:
m_Team_QuestStatus[teamIndex][0] += 20;
break;
case AV_QUEST_A_COMMANDER1:
case AV_QUEST_H_COMMANDER1:
m_Team_QuestStatus[teamIndex][1]++;
RewardReputationToTeam(teamIndex, 1, team);
if (m_Team_QuestStatus[teamIndex][1] == 30)
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
break;
case AV_QUEST_A_COMMANDER2:
case AV_QUEST_H_COMMANDER2:
m_Team_QuestStatus[teamIndex][2]++;
RewardReputationToTeam(teamIndex, 1, team);
if (m_Team_QuestStatus[teamIndex][2] == 60)
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
break;
case AV_QUEST_A_COMMANDER3:
case AV_QUEST_H_COMMANDER3:
m_Team_QuestStatus[teamIndex][3]++;
RewardReputationToTeam(teamIndex, 1, team);
if (m_Team_QuestStatus[teamIndex][3] == 120)
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
break;
case AV_QUEST_A_BOSS1:
case AV_QUEST_H_BOSS1:
m_Team_QuestStatus[teamIndex][4] += 4; //you can turn in 5 or 1 item..
[[fallthrough]];
case AV_QUEST_A_BOSS2:
case AV_QUEST_H_BOSS2:
m_Team_QuestStatus[teamIndex][4]++;
if (m_Team_QuestStatus[teamIndex][4] >= 200)
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
UpdateWorldState(teamIndex == TEAM_ALLIANCE ? AV_WS_IVUS_STORM_CRYSTAL_COUNT : AV_WS_LOKHOLAR_STORMPIKE_SOLDIERS_BLOOD_COUNT, m_Team_QuestStatus[teamIndex][4]);
break;
case AV_QUEST_A_NEAR_MINE:
case AV_QUEST_H_NEAR_MINE:
m_Team_QuestStatus[teamIndex][5]++;
if (m_Team_QuestStatus[teamIndex][5] == 28)
{
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
if (m_Team_QuestStatus[teamIndex][6] == 7)
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here - ground assault ready", questid);
}
break;
case AV_QUEST_A_OTHER_MINE:
case AV_QUEST_H_OTHER_MINE:
m_Team_QuestStatus[teamIndex][6]++;
if (m_Team_QuestStatus[teamIndex][6] == 7)
{
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
if (m_Team_QuestStatus[teamIndex][5] == 20)
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here - ground assault ready", questid);
}
break;
case AV_QUEST_A_RIDER_HIDE:
case AV_QUEST_H_RIDER_HIDE:
m_Team_QuestStatus[teamIndex][7]++;
if (m_Team_QuestStatus[teamIndex][7] == 25)
{
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
if (m_Team_QuestStatus[teamIndex][8] == 25)
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here - rider assault ready", questid);
}
break;
case AV_QUEST_A_RIDER_TAME:
case AV_QUEST_H_RIDER_TAME:
m_Team_QuestStatus[teamIndex][8]++;
if (m_Team_QuestStatus[teamIndex][8] == 25)
{
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here", questid);
if (m_Team_QuestStatus[teamIndex][7] == 25)
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed (need to implement some events here - rider assault ready", questid);
}
break;
default:
TC_LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed but is not interesting at all", questid);
break;
}
}
void BattlegroundAV::UpdateScore(Team team, int16 points)
{
ASSERT(team == ALLIANCE || team == HORDE);
TeamId teamindex = GetTeamIndexByTeamId(team);
_teamResources[teamindex] += points;
UpdateWorldState(teamindex == TEAM_HORDE ? AV_WS_HORDE_REINFORCEMENTS : AV_WS_ALLIANCE_REINFORCEMENTS, _teamResources[teamindex]);
if (points < 0)
{
if (_teamResources[teamindex] < 1)
{
_teamResources[teamindex] = 0;
EndBattleground(teamindex == TEAM_HORDE ? ALLIANCE : HORDE);
}
else if (!_isInformedNearVictory[teamindex] && _teamResources[teamindex] < NEAR_LOSE_POINTS)
{
if (teamindex == TEAM_ALLIANCE)
SendBroadcastText(BG_AV_TEXT_ALLIANCE_NEAR_LOSE, CHAT_MSG_BG_SYSTEM_ALLIANCE);
else
SendBroadcastText(BG_AV_TEXT_HORDE_NEAR_LOSE, CHAT_MSG_BG_SYSTEM_HORDE);
PlaySoundToAll(AV_SOUND_NEAR_VICTORY);
_isInformedNearVictory[teamindex] = true;
}
}
}
void BattlegroundAV::PostUpdateImpl(uint32 diff)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
_mineResourceTimer.Update(diff);
if (_mineResourceTimer.Passed())
{
for (AlteracValleyMineInfo const& info : _mineInfo)
{
if (info.Owner == TEAM_OTHER)
continue;
UpdateScore(info.Owner, 1);
}
_mineResourceTimer.Reset(BG_AV_MINE_RESOURCE_TIMER);
}
for (uint8 i = TEAM_ALLIANCE; i <= TEAM_HORDE; i++)
{
if (!IsCaptainAlive(TeamId(i)))
continue;
_captainBuffTimer[i].Update(diff);
if (_captainBuffTimer[i].Passed())
{
if (i == 0)
{
CastSpellOnTeam(AV_BUFF_A_CAPTAIN, ALLIANCE);
if (Creature* creature = GetBgMap()->GetCreature(_balindaGUID))
creature->AI()->DoAction(ACTION_BUFF_YELL);
}
else
{
CastSpellOnTeam(AV_BUFF_H_CAPTAIN, HORDE);
if (Creature* creature = GetBgMap()->GetCreature(_galvangarGUID))
creature->AI()->DoAction(ACTION_BUFF_YELL);
}
_captainBuffTimer[i].Reset(120000 + urand(0, 4) * 60000); //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes @todo get the right times
}
}
}
bool BattlegroundAV::IsCaptainAlive(TeamId teamId) const
{
if (teamId == TEAM_HORDE)
return GetBgMap()->GetWorldStateValue(AV_WS_GALVAGAR_ALIVE) == 1;
else if (teamId == TEAM_ALLIANCE)
return GetBgMap()->GetWorldStateValue(AV_WS_BALINDA_ALIVE) == 1;
return false;
}
void BattlegroundAV::StartingEventOpenDoors()
{
TC_LOG_DEBUG("bg.battleground", "BG_AV: start spawning mine stuff");
UpdateWorldState(AV_WS_SHOW_HORDE_REINFORCEMENTS, 1);
UpdateWorldState(AV_WS_SHOW_ALLIANCE_REINFORCEMENTS, 1);
// Achievement: The Alterac Blitz
TriggerGameEvent(BG_AV_EVENT_START_BATTLE);
for (ObjectGuid const& guid : _doorGUIDs)
{
if (GameObject* gameObject = GetBgMap()->GetGameObject(guid))
{
gameObject->UseDoorOrButton();
Seconds delay = gameObject->GetEntry() == BG_AV_GHOST_GATE ? 0s : 3s;
gameObject->DespawnOrUnsummon(delay);
}
}
}
void BattlegroundAV::EndBattleground(Team winner)
{
//calculate bonuskills for both teams:
//first towers:
std::array<uint8, PVP_TEAMS_COUNT> kills = { 0, 0 };
std::array<uint8, PVP_TEAMS_COUNT> rep = { 0, 0 };
for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i)
{
if (_nodes[i].State == POINT_CONTROLED)
{
if (_nodes[i].Owner == ALLIANCE)
{
rep[TEAM_ALLIANCE] += REP_GAIN_SURVIVING_TOWER;
kills[TEAM_ALLIANCE] += HONOR_KILL_BONUS_SURVIVING_TOWER;
}
else
{
rep[TEAM_HORDE] += REP_GAIN_SURVIVING_TOWER;
kills[TEAM_HORDE] += HONOR_KILL_BONUS_SURVIVING_TOWER;
}
}
}
for (uint8 i = TEAM_ALLIANCE; i <= TEAM_HORDE; ++i)
{
if (IsCaptainAlive(TeamId(i)))
{
kills[i] += HONOR_KILL_BONUS_SURVIVING_CAPTAIN;
rep[i] += REP_GAIN_SURVIVING_CAPTAIN;
}
if (rep[i] != 0)
RewardReputationToTeam(i == 0 ? FACTION_STORMPIKE_GUARD : FACTION_FROSTWOLF_CLAN, rep[i], i == 0 ? ALLIANCE : HORDE);
if (kills[i] != 0)
RewardHonorToTeam(GetBonusHonorFromKill(kills[i]), i == 0 ? ALLIANCE : HORDE);
}
/// @todo add enterevademode for all attacking creatures
Battleground::EndBattleground(winner);
}
void BattlegroundAV::RemovePlayer(Player* player, ObjectGuid /*guid*/, uint32 /*team*/)
{
if (!player)
{
TC_LOG_ERROR("bg.battleground", "bg_AV no player at remove");
return;
}
/// @todo search more buffs
player->RemoveAurasDueToSpell(AV_BUFF_ARMOR);
}
void BattlegroundAV::EventPlayerDestroyedPoint(GameObject* gameobject)
{
if (!gameobject)
return;
BG_AV_Nodes node = GetNodeThroughObject(gameobject->GetEntry());
DestroyNode(node);
UpdateNodeWorldState(node);
Team owner = _nodes[node].Owner;
if (IsTower(node))
{
UpdateScore((owner == ALLIANCE) ? HORDE : ALLIANCE, RESOURCE_LOSS_TOWER);
RewardReputationToTeam(owner == ALLIANCE ? FACTION_STORMPIKE_GUARD : FACTION_FROSTWOLF_CLAN, REP_GAIN_DESTROY_TOWER, owner);
RewardHonorToTeam(GetBonusHonorFromKill(HONOR_KILL_BONUS_DESTROY_TOWER), owner);
}
if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node))
if (Creature* herald = FindHerald(nodeInfo->StringIds.HordeOrDestroy))
herald->AI()->Talk(owner == ALLIANCE ? nodeInfo->TextIds.AllianceCapture : nodeInfo->TextIds.HordeCapture);
GetBgMap()->UpdateSpawnGroupConditions();
}
void BattlegroundAV::DoAction(uint32 actionId, WorldObject* source, WorldObject* target)
{
switch (actionId)
{
case ACTION_AV_CAPTURE_CAPTURABLE_OBJECT:
EventPlayerDestroyedPoint(source->ToGameObject());
break;
case ACTION_AV_INTERACT_CAPTURABLE_OBJECT:
if (target && source && source->IsPlayer())
HandleInteractCapturableObject(source->ToPlayer(), target->ToGameObject());
break;
default:
TC_LOG_ERROR("bg.battleground", "BattlegroundAV::DoAction: {}. Unhandled action.", actionId);
break;
}
}
void BattlegroundAV::ChangeMineOwner(AlteracValleyMine mine, Team team, bool initial)
{
if (team != ALLIANCE && team != HORDE)
team = TEAM_OTHER;
AlteracValleyMineInfo& mineInfo = _mineInfo[uint8(mine)];
if (mineInfo.Owner == team && !initial)
return;
mineInfo.Owner = team;
SendMineWorldStates(mine);
uint8 textId = team == ALLIANCE ? mineInfo.StaticInfo.TextIdAlliance : mineInfo.StaticInfo.TextIdHorde;
std::string stringId = team == ALLIANCE ? "bg_av_herald_mine_alliance" : "bg_av_herald_mine_horde";
if (Creature* herald = FindHerald(stringId))
herald->AI()->Talk(textId);
}
BG_AV_Nodes BattlegroundAV::GetNodeThroughObject(uint32 object)
{
switch (object)
{
case BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_AID_STATION_HORDE_CONTESTED:
case BG_AV_OBJECTID_AID_STATION_HORDE_CONTROLLED:
case BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTESTED:
return BG_AV_NODES_FIRSTAID_STATION;
case BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_STORMPIKE_HORDE_CONTESTED:
case BG_AV_OBJECTID_STORMPIKE_HORDE_CONTROLLED:
case BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTESTED:
return BG_AV_NODES_STORMPIKE_GRAVE;
case BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTESTED:
case BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTROLLED:
case BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTROLLED:
return BG_AV_NODES_STONEHEART_GRAVE;
case BG_AV_OBJECTID_SNOWFALL_NEUTRAL:
case BG_AV_OBJECTID_SNOWFALL_HORDE_CONTESTED:
case BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_SNOWFALL_HORDE_CONTROLLED:
case BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTROLLED:
return BG_AV_NODES_SNOWFALL_GRAVE;
case BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTROLLED:
case BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTESTED:
return BG_AV_NODES_ICEBLOOD_GRAVE;
case BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTROLLED:
case BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTESTED:
return BG_AV_NODES_FROSTWOLF_GRAVE;
case BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTROLLED:
case BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTESTED:
return BG_AV_NODES_FROSTWOLF_HUT;
case BG_AV_OBJECTID_SOUTH_BUNKER_CONTROLLED_TOWER_BANNER:
case BG_AV_OBJECTID_SOUTH_BUNKER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_SOUTH_BUNKER_CONTESTED_BANNER:
case BG_AV_OBJECTID_SOUTH_BUNKER_CONTESTED_TOWER_BANNER:
return BG_AV_NODES_DUNBALDAR_SOUTH;
case BG_AV_OBJECTID_NORTH_BUNKER_CONTROLLED_TOWER_BANNER:
case BG_AV_OBJECTID_NORTH_BUNKER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_NORTH_BUNKER_CONTESTED_BANNER:
case BG_AV_OBJECTID_NORTH_BUNKER_CONTESTED_TOWER_BANNER:
return BG_AV_NODES_DUNBALDAR_NORTH;
case BG_AV_OBJECTID_EAST_TOWER_CONTROLLED_TOWER_BANNER:
case BG_AV_OBJECTID_EAST_TOWER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_EAST_TOWER_CONTESTED_BANNER:
case BG_AV_OBJECTID_EAST_TOWER_CONTESTED_TOWER_BANNER:
return BG_AV_NODES_FROSTWOLF_ETOWER;
case BG_AV_OBJECTID_WEST_TOWER_CONTROLLED_TOWER_BANNER:
case BG_AV_OBJECTID_WEST_TOWER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_WEST_TOWER_CONTESTED_BANNER:
case BG_AV_OBJECTID_WEST_TOWER_CONTESTED_TOWER_BANNER:
return BG_AV_NODES_FROSTWOLF_WTOWER;
case BG_AV_OBJECTID_TOWER_POINT_CONTROLLED_TOWER_BANNER:
case BG_AV_OBJECTID_TOWER_POINT_CONTROLLED_BANNER:
case BG_AV_OBJECTID_TOWER_POINT_CONTESTED_BANNER:
case BG_AV_OBJECTID_TOWER_POINT_CONTESTED_TOWER_BANNER:
return BG_AV_NODES_TOWER_POINT;
case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTROLLED_TOWER_BANNER:
case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTESTED_BANNER:
case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTESTED_TOWER_BANNER:
return BG_AV_NODES_ICEBLOOD_TOWER;
case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTROLLED_TOWER_BANNER:
case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTESTED_BANNER:
case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTESTED_TOWER_BANNER:
return BG_AV_NODES_STONEHEART_BUNKER;
case BG_AV_OBJECTID_ICEWING_BUNKER_CONTROLLED_TOWER_BANNER:
case BG_AV_OBJECTID_ICEWING_BUNKER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_ICEWING_BUNKER_CONTESTED_BANNER:
case BG_AV_OBJECTID_ICEWING_BUNKER_CONTESTED_TOWER_BANNER:
return BG_AV_NODES_ICEWING_BUNKER;
default:
TC_LOG_ERROR("bg.battleground", "BattlegroundAV: ERROR! GetPlace got a wrong object :(");
ABORT();
return BG_AV_Nodes(0);
}
}
void BattlegroundAV::HandleInteractCapturableObject(Player* player, GameObject* target)
{
if (!player || !target)
return;
switch (target->GetEntry())
{
// graveyards
case BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_AID_STATION_HORDE_CONTROLLED:
case BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTROLLED:
case BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTROLLED:
case BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTROLLED:
case BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTROLLED:
case BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_STORMPIKE_HORDE_CONTROLLED:
// Snowfall
case BG_AV_OBJECTID_SNOWFALL_NEUTRAL:
case BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTROLLED:
case BG_AV_OBJECTID_SNOWFALL_HORDE_CONTROLLED:
// towers
case BG_AV_OBJECTID_EAST_TOWER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_WEST_TOWER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_TOWER_POINT_CONTROLLED_BANNER:
case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_ICEWING_BUNKER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_SOUTH_BUNKER_CONTROLLED_BANNER:
case BG_AV_OBJECTID_NORTH_BUNKER_CONTROLLED_BANNER:
EventPlayerAssaultsPoint(player, target->GetEntry());
break;
// graveyards
case BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_AID_STATION_HORDE_CONTESTED:
case BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTESTED:
case BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTESTED:
case BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTESTED:
case BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTESTED:
case BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_STORMPIKE_HORDE_CONTESTED:
// towers
case BG_AV_OBJECTID_EAST_TOWER_CONTESTED_BANNER:
case BG_AV_OBJECTID_WEST_TOWER_CONTESTED_BANNER:
case BG_AV_OBJECTID_TOWER_POINT_CONTESTED_BANNER:
case BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTESTED_BANNER:
case BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTESTED_BANNER:
case BG_AV_OBJECTID_ICEWING_BUNKER_CONTESTED_BANNER:
case BG_AV_OBJECTID_SOUTH_BUNKER_CONTESTED_BANNER:
case BG_AV_OBJECTID_NORTH_BUNKER_CONTESTED_BANNER:
EventPlayerDefendsPoint(player, target->GetEntry());
break;
// Snowfall special cases (either defend/assault)
case BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTESTED:
case BG_AV_OBJECTID_SNOWFALL_HORDE_CONTESTED:
{
BG_AV_Nodes node = GetNodeThroughObject(target->GetEntry());
if (_nodes[node].TotalOwner == TEAM_OTHER)
EventPlayerAssaultsPoint(player, target->GetEntry());
else
EventPlayerDefendsPoint(player, target->GetEntry());
break;
}
default:
break;
}
}
void BattlegroundAV::EventPlayerDefendsPoint(Player* player, uint32 object)
{
BG_AV_Nodes node = GetNodeThroughObject(object);
Team owner = _nodes[node].Owner;
Team team = GetPlayerTeam(player->GetGUID());
if (owner == team || _nodes[node].State != POINT_ASSAULTED)
return;
TC_LOG_DEBUG("bg.battleground", "player defends point object: {} node: {}", object, node);
if (_nodes[node].PrevOwner != team)
{
TC_LOG_ERROR("bg.battleground", "BG_AV: player defends point which doesn't belong to his team {}", node);
return;
}
DefendNode(node, team);
UpdateNodeWorldState(node);
if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node))
{
std::string stringId;
if (IsTower(node))
stringId = nodeInfo->StringIds.AllianceOrDefend;
else
stringId = team == ALLIANCE ? nodeInfo->StringIds.AllianceOrDefend : nodeInfo->StringIds.HordeOrDestroy;
if (Creature* herald = FindHerald(stringId))
herald->AI()->Talk(team == ALLIANCE ? nodeInfo->TextIds.AllianceCapture : nodeInfo->TextIds.HordeCapture);
}
// update the statistic for the defending player
UpdatePvpStat(player, IsTower(node) ? PVP_STAT_TOWERS_DEFENDED : PVP_STAT_GRAVEYARDS_DEFENDED, 1);
GetBgMap()->UpdateSpawnGroupConditions();
}
void BattlegroundAV::EventPlayerAssaultsPoint(Player* player, uint32 object)
{
BG_AV_Nodes node = GetNodeThroughObject(object);
Team owner = _nodes[node].Owner; //maybe name it prevowner
Team team = GetPlayerTeam(player->GetGUID());
TC_LOG_DEBUG("bg.battleground", "bg_av: player assaults point object {} node {}", object, node);
if (owner == team || team == _nodes[node].TotalOwner)
return; //surely a gm used this object
AssaultNode(node, team);
UpdateNodeWorldState(node);
if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node))
{
std::string stringId;
if (IsTower(node))
stringId = nodeInfo->StringIds.HordeOrDestroy;
else
stringId = team == ALLIANCE ? nodeInfo->StringIds.AllianceOrDefend : nodeInfo->StringIds.HordeOrDestroy;
if (Creature* herald = FindHerald(stringId))
herald->AI()->Talk(team == ALLIANCE ? nodeInfo->TextIds.AllianceAttack : nodeInfo->TextIds.HordeAttack);
}
// update the statistic for the assaulting player
UpdatePvpStat(player, (IsTower(node)) ? PVP_STAT_TOWERS_ASSAULTED : PVP_STAT_GRAVEYARDS_ASSAULTED, 1);
GetBgMap()->UpdateSpawnGroupConditions();
}
void BattlegroundAV::UpdateNodeWorldState(BG_AV_Nodes node)
{
if (StaticNodeInfo const* nodeInfo = GetStaticNodeInfo(node))
{
uint16 owner = _nodes[node].Owner;
BG_AV_States state = _nodes[node].State;
UpdateWorldState(nodeInfo->WorldStateIds.AllianceAssault, owner == ALLIANCE && state == POINT_ASSAULTED);
UpdateWorldState(nodeInfo->WorldStateIds.AllianceControl, owner == ALLIANCE && state >= POINT_DESTROYED);
UpdateWorldState(nodeInfo->WorldStateIds.HordeAssault, owner == HORDE && state == POINT_ASSAULTED);
UpdateWorldState(nodeInfo->WorldStateIds.HordeControl, owner == HORDE && state >= POINT_DESTROYED);
if (nodeInfo->WorldStateIds.Owner)
UpdateWorldState(nodeInfo->WorldStateIds.Owner, owner == HORDE ? 2 : owner == ALLIANCE ? 1 : 0);
}
if (node == BG_AV_NODES_SNOWFALL_GRAVE)
UpdateWorldState(AV_WS_SNOWFALL_GRAVEYARD_UNCONTROLLED, _nodes[node].Owner == TEAM_OTHER);
}
void BattlegroundAV::SendMineWorldStates(AlteracValleyMine mine)
{
AlteracValleyMineInfo& mineInfo = _mineInfo[uint8(mine)];
UpdateWorldState(mineInfo.StaticInfo.WorldStateHordeControlled, mineInfo.Owner == HORDE);
UpdateWorldState(mineInfo.StaticInfo.WorldStateAllianceControlled, mineInfo.Owner == ALLIANCE);
UpdateWorldState(mineInfo.StaticInfo.WorldStateNeutralControlled, mineInfo.Owner == TEAM_OTHER);
UpdateWorldState(mineInfo.StaticInfo.WorldStateOwner, mineInfo.Owner == HORDE ? 2 : mineInfo.Owner == ALLIANCE ? 1 : 0);
}
WorldSafeLocsEntry const* BattlegroundAV::GetExploitTeleportLocation(Team team)
{
return sObjectMgr->GetWorldSafeLoc(team == ALLIANCE ? AV_EXPLOIT_TELEPORT_LOCATION_ALLIANCE : AV_EXPLOIT_TELEPORT_LOCATION_HORDE);
}
bool BattlegroundAV::SetupBattleground()
{
return true;
}
void BattlegroundAV::AssaultNode(BG_AV_Nodes node, Team team)
{
_nodes[node].PrevOwner = _nodes[node].Owner;
_nodes[node].Owner = team;
_nodes[node].PrevState = _nodes[node].State;
_nodes[node].State = POINT_ASSAULTED;
}
void BattlegroundAV::DestroyNode(BG_AV_Nodes node)
{
_nodes[node].TotalOwner = _nodes[node].Owner;
_nodes[node].PrevOwner = _nodes[node].Owner;
_nodes[node].PrevState = _nodes[node].State;
_nodes[node].State = (_nodes[node].Tower)? POINT_DESTROYED : POINT_CONTROLED;
}
void BattlegroundAV::InitNode(BG_AV_Nodes node, Team team, bool tower)
{
_nodes[node].TotalOwner = team;
_nodes[node].Owner = team;
_nodes[node].PrevOwner = 0;
_nodes[node].State = POINT_CONTROLED;
_nodes[node].PrevState = _nodes[node].State;
_nodes[node].State = POINT_CONTROLED;
_nodes[node].Tower = tower;
}
void BattlegroundAV::DefendNode(BG_AV_Nodes node, Team team)
{
_nodes[node].PrevOwner = _nodes[node].Owner;
_nodes[node].Owner = team;
_nodes[node].PrevState = _nodes[node].State;
_nodes[node].State = POINT_CONTROLED;
}
Team BattlegroundAV::GetPrematureWinner()
{
uint32 allianceScore = _teamResources[GetTeamIndexByTeamId(ALLIANCE)];
uint32 hordeScore = _teamResources[GetTeamIndexByTeamId(HORDE)];
if (allianceScore > hordeScore)
return ALLIANCE;
else if (hordeScore > allianceScore)
return HORDE;
return Battleground::GetPrematureWinner();
}
void BattlegroundAV::OnGameObjectCreate(GameObject* gameObject)
{
switch (gameObject->GetEntry())
{
case BG_AV_GHOST_GATE:
case BG_AV_OBJECTID_GATE:
_doorGUIDs.insert(gameObject->GetGUID());
break;
default:
break;
}
}
void BattlegroundAV::OnCreatureCreate(Creature* creature)
{
switch (creature->GetEntry())
{
case BG_AV_CREATURE_GALVANGAR:
_galvangarGUID = creature->GetGUID();
break;
case BG_AV_CREATURE_BALINDA:
_balindaGUID = creature->GetGUID();
break;
case BG_AV_CREATURE_HERALD:
_heraldGUIDs.insert(creature->GetGUID());
break;
default:
break;
}
}
uint32 BattlegroundAV::GetData(uint32 dataId) const
{
auto getDefenderTierForTeam = [&](TeamId teamId) -> BG_AV_DefenderTier
{
if (m_Team_QuestStatus[teamId][0] < 500)
return BG_AV_DEFENDER_TIER_DEFENDER;
if (m_Team_QuestStatus[teamId][0] < 1000)
return BG_AV_DEFENDER_TIER_SEASONED;
if (m_Team_QuestStatus[teamId][0] < 1500)
return BG_AV_DEFENDER_TIER_VETERAN;
return BG_AV_DEFENDER_TIER_CHAMPION;
};
switch (dataId)
{
case DATA_DEFENDER_TIER_ALLIANCE:
return getDefenderTierForTeam(TEAM_ALLIANCE);
case DATA_DEFENDER_TIER_HORDE:
return getDefenderTierForTeam(TEAM_HORDE);
default:
return Battleground::GetData(dataId);
}
}
Creature* BattlegroundAV::FindHerald(std::string_view stringId) const
{
for (ObjectGuid const& guid : _heraldGUIDs)
if (Creature* creature = GetBgMap()->GetCreature(guid))
if (creature->HasStringId(stringId))
return creature;
return nullptr;
}
@@ -1,637 +0,0 @@
/*
* 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 __BATTLEGROUNDAV_H
#define __BATTLEGROUNDAV_H
#include "Battleground.h"
#include "BattlegroundScore.h"
#include "Object.h"
#include "QuaternionData.h"
#include "Timer.h"
constexpr uint32 BG_AV_SCORE_INITIAL_POINTS = 700;
constexpr uint32 BG_AV_EVENT_START_BATTLE = 9166; // Achievement: The Alterac Blitz
enum AlteracValleySharedActions
{
ACTION_BUFF_YELL = -30001,
ACTION_AV_INTERACT_CAPTURABLE_OBJECT = 1,
ACTION_AV_CAPTURE_CAPTURABLE_OBJECT = 2,
};
enum BG_AV_BroadcastTexts
{
BG_AV_TEXT_START_ONE_MINUTE = 10638,
BG_AV_TEXT_START_HALF_MINUTE = 10639,
BG_AV_TEXT_BATTLE_HAS_BEGUN = 10640,
BG_AV_TEXT_ALLIANCE_NEAR_LOSE = 23210,
BG_AV_TEXT_HORDE_NEAR_LOSE = 23211
};
enum BG_AV_Sounds
{ /// @todo: get out if there comes a sound when neutral team captures mine
/*
8212:
alliance grave assault
alliance tower assault
drek "mlanzenabschaum! In meiner Burg?! Toetet sie all" - nicht immer der sound
8333:
galv "sterbt fuer euch ist kein platz hier"
8332:
bal "Verschwinde, dreckiger Abschaum! Die Allianz wird im Alteractal "
8174:
horde tower assault
horde grave assault
van "es Sturmlanzenklans, euer General wird angegriffen! Ich fordere Unterst"
8173:
ally grave capture/defend
tower destroy
mine capture
ally wins
8192:
ally tower destroy(only iceblood - found a bug^^)
ally tower defend
horde tower defend
8213
horde:
grave defend/capture
tower destroy
mine capture
horde wins
*/
AV_SOUND_NEAR_VICTORY = 8456, /// @todo: Not confirmed yet
AV_SOUND_ALLIANCE_ASSAULTS = 8212, //tower, grave + enemy boss if someone tries to attack him
AV_SOUND_HORDE_ASSAULTS = 8174,
AV_SOUND_ALLIANCE_GOOD = 8173, //if something good happens for the team: wins(maybe only through killing the boss), captures mine or grave, destroys tower and defends grave
AV_SOUND_HORDE_GOOD = 8213,
AV_SOUND_BOTH_TOWER_DEFEND = 8192,
AV_SOUND_ALLIANCE_CAPTAIN = 8232, //gets called when someone attacks them and at the beginning after 5min+rand(x)*10sec (maybe buff)
AV_SOUND_HORDE_CAPTAIN = 8333
};
constexpr Seconds BG_AV_MINE_RESOURCE_TIMER = 45s;
enum class AlteracValleyMine : uint8
{
North = 0,
South
};
enum BG_AV_CreatureIds
{
BG_AV_CREATURE_VANNDAR = 11948,
BG_AV_CREATURE_DREKTHAR = 11946,
BG_AV_CREATURE_BALINDA = 11949,
BG_AV_CREATURE_GALVANGAR = 11947,
BG_AV_CREATURE_MORLOCH = 11657,
BG_AV_CREATURE_UMI_THORSON = 13078,
BG_AV_CREATURE_KEETAR = 13079,
BG_AV_CREATURE_TASKMASTER_SNIVVLE = 11677,
BG_AV_CREATURE_AGI_RUMBLESTOMP = 13086,
BG_AV_CREATURE_MASHA_SWIFTCUT = 13088,
BG_AV_CREATURE_HERALD = 14848,
BG_AV_CREATURE_STORMPIKE_DEFENDER = 12050,
BG_AV_CREATURE_FROSTWOLF_GUARDIAN = 12053,
BG_AV_CREATURE_SEASONED_DEFENDER = 13326,
BG_AV_CREATURE_SEASONED_GUARDIAN = 13328,
BG_AV_CREATURE_VETERAN_DEFENDER = 13331,
BG_AV_CREATURE_VETERAN_GUARDIAN = 13332,
BG_AV_CREATURE_CHAMPION_DEFENDER = 13422,
BG_AV_CREATURE_CHAMPION_GUARDIAN = 13421
};
enum BG_AV_ObjectIds
{
//cause the mangos-system is a bit different, we don't use the right go-ids for every node.. if we want to be 100% like another big server, we must take one object for every node
//snowfall 4flags as eyecandy 179424 (alliance neutral)
//Banners - stolen from battleground_AB.h ;-)
BG_AV_OBJECTID_BANNER_A = 178925, // can only be used by horde
BG_AV_OBJECTID_BANNER_H = 178943, // can only be used by alliance
BG_AV_OBJECTID_BANNER_CONT_A = 178940, // can only be used by horde
BG_AV_OBJECTID_BANNER_CONT_H = 179435, // can only be used by alliance
BG_AV_OBJECTID_BANNER_A_B = 178365,
BG_AV_OBJECTID_BANNER_H_B = 178364,
BG_AV_OBJECTID_BANNER_CONT_A_B = 179286,
BG_AV_OBJECTID_BANNER_CONT_H_B = 179287,
BG_AV_OBJECTID_BANNER_SNOWFALL_N = 180418,
//snowfall eyecandy banner:
BG_AV_OBJECTID_SNOWFALL_CANDY_A = 179044,
BG_AV_OBJECTID_SNOWFALL_CANDY_PA = 179424,
BG_AV_OBJECTID_SNOWFALL_CANDY_H = 179064,
BG_AV_OBJECTID_SNOWFALL_CANDY_PH = 179425,
//banners on top of towers:
BG_AV_OBJECTID_TOWER_BANNER_A = 178927, //[PH] Alliance A1 Tower Banner BIG
BG_AV_OBJECTID_TOWER_BANNER_H = 178955, //[PH] Horde H1 Tower Banner BIG
BG_AV_OBJECTID_TOWER_BANNER_PA = 179446, //[PH] Alliance H1 Tower Pre-Banner BIG
BG_AV_OBJECTID_TOWER_BANNER_PH = 179436, //[PH] Horde A1 Tower Pre-Banner BIG
//Auras
BG_AV_OBJECTID_AURA_A = 180421,
BG_AV_OBJECTID_AURA_H = 180422,
BG_AV_OBJECTID_AURA_N = 180423,
BG_AV_OBJECTID_AURA_A_S = 180100,
BG_AV_OBJECTID_AURA_H_S = 180101,
BG_AV_OBJECTID_AURA_N_S = 180102,
BG_AV_OBJECTID_GATE = 180424,
BG_AV_GHOST_GATE = 180322,
//mine supplies
BG_AV_OBJECTID_MINE_N = 178785,
BG_AV_OBJECTID_MINE_S = 178784,
BG_AV_OBJECTID_FIRE = 179065,
BG_AV_OBJECTID_SMOKE = 179066,
// Towers
BG_AV_OBJECTID_SOUTH_BUNKER_CONTROLLED_TOWER_BANNER = 178927,
BG_AV_OBJECTID_SOUTH_BUNKER_CONTROLLED_BANNER = 178925,
BG_AV_OBJECTID_SOUTH_BUNKER_CONTESTED_BANNER = 179435,
BG_AV_OBJECTID_SOUTH_BUNKER_CONTESTED_TOWER_BANNER = 179436,
BG_AV_OBJECTID_NORTH_BUNKER_CONTROLLED_TOWER_BANNER = 178932,
BG_AV_OBJECTID_NORTH_BUNKER_CONTROLLED_BANNER = 178929,
BG_AV_OBJECTID_NORTH_BUNKER_CONTESTED_BANNER = 179439,
BG_AV_OBJECTID_NORTH_BUNKER_CONTESTED_TOWER_BANNER = 179440,
BG_AV_OBJECTID_EAST_TOWER_CONTROLLED_TOWER_BANNER = 178956,
BG_AV_OBJECTID_EAST_TOWER_CONTROLLED_BANNER = 178944,
BG_AV_OBJECTID_EAST_TOWER_CONTESTED_BANNER = 179449,
BG_AV_OBJECTID_EAST_TOWER_CONTESTED_TOWER_BANNER = 179450,
BG_AV_OBJECTID_WEST_TOWER_CONTROLLED_TOWER_BANNER = 178955,
BG_AV_OBJECTID_WEST_TOWER_CONTROLLED_BANNER = 178943,
BG_AV_OBJECTID_WEST_TOWER_CONTESTED_BANNER = 179445,
BG_AV_OBJECTID_WEST_TOWER_CONTESTED_TOWER_BANNER = 179446,
BG_AV_OBJECTID_TOWER_POINT_CONTROLLED_TOWER_BANNER = 178957,
BG_AV_OBJECTID_TOWER_POINT_CONTROLLED_BANNER = 178945,
BG_AV_OBJECTID_TOWER_POINT_CONTESTED_BANNER = 179453,
BG_AV_OBJECTID_TOWER_POINT_CONTESTED_TOWER_BANNER = 179454,
BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTROLLED_TOWER_BANNER = 178958,
BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTROLLED_BANNER = 178946,
BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTESTED_BANNER = 178940,
BG_AV_OBJECTID_ICEBLOOD_TOWER_CONTESTED_TOWER_BANNER = 179458,
BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTROLLED_TOWER_BANNER = 178948,
BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTROLLED_BANNER = 178936,
BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTESTED_BANNER = 179443,
BG_AV_OBJECTID_STONEHEARTH_BUNKER_CONTESTED_TOWER_BANNER = 179444,
BG_AV_OBJECTID_ICEWING_BUNKER_CONTROLLED_TOWER_BANNER = 178947,
BG_AV_OBJECTID_ICEWING_BUNKER_CONTROLLED_BANNER = 178935,
BG_AV_OBJECTID_ICEWING_BUNKER_CONTESTED_BANNER = 179441,
BG_AV_OBJECTID_ICEWING_BUNKER_CONTESTED_TOWER_BANNER = 179442,
// Graveyards
BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTROLLED = 179465,
BG_AV_OBJECTID_AID_STATION_HORDE_CONTESTED = 179468,
BG_AV_OBJECTID_AID_STATION_HORDE_CONTROLLED = 179467,
BG_AV_OBJECTID_AID_STATION_ALLIANCE_CONTESTED = 179466,
BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTROLLED = 178389,
BG_AV_OBJECTID_STORMPIKE_HORDE_CONTESTED = 179287,
BG_AV_OBJECTID_STORMPIKE_HORDE_CONTROLLED = 178388,
BG_AV_OBJECTID_STORMPIKE_ALLIANCE_CONTESTED = 179286,
BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTESTED = 179310,
BG_AV_OBJECTID_STONEHEARTH_HORDE_CONTROLLED = 179285,
BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTESTED = 179308,
BG_AV_OBJECTID_STONEHEARTH_ALLIANCE_CONTROLLED = 179284,
BG_AV_OBJECTID_SNOWFALL_NEUTRAL = 180418,
BG_AV_OBJECTID_SNOWFALL_HORDE_CONTESTED = 180420,
BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTESTED = 180419,
BG_AV_OBJECTID_SNOWFALL_HORDE_CONTROLLED = 178364,
BG_AV_OBJECTID_SNOWFALL_ALLIANCE_CONTROLLED = 178365,
BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTROLLED = 179483,
BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTESTED = 179482,
BG_AV_OBJECTID_ICEBLOOD_ALLIANCE_CONTROLLED = 179481,
BG_AV_OBJECTID_ICEBLOOD_HORDE_CONTESTED = 179484,
BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTROLLED = 178393,
BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTESTED = 179304,
BG_AV_OBJECTID_FROSTWOLF_ALLIANCE_CONTROLLED = 178394,
BG_AV_OBJECTID_FROSTWOLF_HORDE_CONTESTED = 179305,
BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTROLLED = 179472,
BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTESTED = 179471,
BG_AV_OBJECTID_FROSTWOLF_HUT_ALLIANCE_CONTROLLED = 179470,
BG_AV_OBJECTID_FROSTWOLF_HUT_HORDE_CONTESTED = 179473
};
enum BG_AV_Nodes
{
BG_AV_NODES_FIRSTAID_STATION = 0,
BG_AV_NODES_STORMPIKE_GRAVE = 1,
BG_AV_NODES_STONEHEART_GRAVE = 2,
BG_AV_NODES_SNOWFALL_GRAVE = 3,
BG_AV_NODES_ICEBLOOD_GRAVE = 4,
BG_AV_NODES_FROSTWOLF_GRAVE = 5,
BG_AV_NODES_FROSTWOLF_HUT = 6,
BG_AV_NODES_DUNBALDAR_SOUTH = 7,
BG_AV_NODES_DUNBALDAR_NORTH = 8,
BG_AV_NODES_ICEWING_BUNKER = 9,
BG_AV_NODES_STONEHEART_BUNKER = 10,
BG_AV_NODES_ICEBLOOD_TOWER = 11,
BG_AV_NODES_TOWER_POINT = 12,
BG_AV_NODES_FROSTWOLF_ETOWER = 13,
BG_AV_NODES_FROSTWOLF_WTOWER = 14,
BG_AV_NODES_MAX = 15
};
enum BG_AV_BUFF
{ /// @todo: Add all other buffs here
AV_BUFF_ARMOR = 21163,
AV_BUFF_A_CAPTAIN = 23693, //the buff which the alliance captain does
AV_BUFF_H_CAPTAIN = 22751 //the buff which the horde captain does
};
enum BG_AV_States
{
POINT_NEUTRAL = 0,
POINT_ASSAULTED = 1,
POINT_DESTROYED = 2,
POINT_CONTROLED = 3
};
enum BG_AV_WorldStates
{
AV_WS_ALLIANCE_REINFORCEMENTS = 3127,
AV_WS_HORDE_REINFORCEMENTS = 3128,
AV_WS_SHOW_HORDE_REINFORCEMENTS = 3133,
AV_WS_SHOW_ALLIANCE_REINFORCEMENTS = 3134,
AV_WS_MAX_REINFORCEMENTS = 3136,
// Graves
// Alliance
//Stormpike first aid station
AV_WS_STORMPIKE_AID_STATION_ALLIANCE_CONTROLLED = 1325,
AV_WS_STORMPIKE_AID_STATION_IN_CONFLICT_ALLIANCE_ATTACKING = 1326,
AV_WS_STORMPIKE_AID_STATION_HORDE_CONTROLLED = 1327,
AV_WS_STORMPIKE_AID_STATION_IN_CONFLICT_HORDE_ATTACKING = 1328,
//Stormpike Graveyard
AV_WS_STORMPIKE_GRAVEYARD_ALLIANCE_CONTROLLED = 1333,
AV_WS_STORMPIKE_GRAVEYARD_IN_CONFLICT_ALLIANCE_ATTACKING = 1335,
AV_WS_STORMPIKE_GRAVEYARD_HORDE_CONTROLLED = 1334,
AV_WS_STORMPIKE_GRAVEYARD_IN_CONFLICT_HORDE_ATTACKING = 1336,
//Stoneheart Grave
AV_WS_STONEHEARTH_GRAVEYARD_ALLIANCE_CONTROLLED = 1302,
AV_WS_STONEHEARTH_GRAVEYARD_IN_CONFLICT_ALLIANCE_ATTACKING = 1304,
AV_WS_STONEHEARTH_GRAVEYARD_HORDE_CONTROLLED = 1301,
AV_WS_STONEHEARTH_GRAVEYARD_IN_CONFLICT_HORDE_ATTACKING = 1303,
//Neutral
//Snowfall Grave
AV_WS_SNOWFALL_GRAVEYARD_UNCONTROLLED = 1966,
AV_WS_SNOWFALL_GRAVEYARD_ALLIANCE_CONTROLLED = 1341,
AV_WS_SNOWFALL_GRAVEYARD_IN_CONFLICT_ALLIANCE_ATTACKING = 1343,
AV_WS_SNOWFALL_GRAVEYARD_HORDE_CONTROLLED = 1342,
AV_WS_SNOWFALL_GRAVEYARD_IN_CONFLICT_HORDE_ATTACKING = 1344,
//Horde
//Iceblood grave
AV_WS_ICEBLOOD_GRAVEYARD_ALLIANCE_CONTROLLED = 1346,
AV_WS_ICEBLOOD_GRAVEYARD_IN_CONFLICT_ALLIANCE_ATTACKING = 1348,
AV_WS_ICEBLOOD_GRAVEYARD_HORDE_CONTROLLED = 1347,
AV_WS_ICEBLOOD_GRAVEYARD_IN_CONFLICT_HORDE_ATTACKING = 1349,
//Frostwolf Grave
AV_WS_FROSTWOLF_GRAVEYARD_ALLIANCE_CONTROLLED = 1337,
AV_WS_FROSTWOLF_GRAVEYARD_IN_CONFLICT_ALLIANCE_ATTACKING = 1339,
AV_WS_FROSTWOLF_GRAVEYARD_HORDE_CONTROLLED = 1338,
AV_WS_FROSTWOLF_GRAVEYARD_IN_CONFLICT_HORDE_ATTACKING = 1340,
//Frostwolf Hut
AV_WS_FROSTWOLF_RELIEF_HUT_ALLIANCE_CONTROLLED = 1329,
AV_WS_FROSTWOLF_RELIEF_HUT_IN_CONFLICT_ALLIANCE_ATTACKING = 1331,
AV_WS_FROSTWOLF_RELIEF_HUT_HORDE_CONTROLLED = 1330,
AV_WS_FROSTWOLF_RELIEF_HUT_IN_CONFLICT_HORDE_ATTACKING = 1332,
//Towers
//Alliance
//Dunbaldar South Bunker
AV_WS_DUN_BALDAR_SOUTH_BUNKER_OWNER = 1181,
AV_WS_DUN_BALDAR_SOUTH_BUNKER_ALLIANCE_CONTROLLED = 1361,
AV_WS_DUN_BALDAR_SOUTH_BUNKER_DESTROYED = 1370,
AV_WS_DUN_BALDAR_SOUTH_BUNKER_IN_CONFLICT_HORDE_ATTACKING = 1378,
AV_WS_DUN_BALDAR_SOUTH_BUNKER_IN_CONFLICT_ALLIANCE_ATTACKING = 1374, // unused
//Dunbaldar North Bunker
AV_WS_DUN_BALDAR_NORTH_BUNKER_OWNER = 1182,
AV_WS_DUN_BALDAR_NORTH_BUNKER_ALLIANCE_CONTROLLED = 1362,
AV_WS_DUN_BALDAR_NORTH_BUNKER_DESTROYED = 1371,
AV_WS_DUN_BALDAR_NORTH_BUNKER_IN_CONFLICT_HORDE_ATTACKING = 1379,
AV_WS_DUN_BALDAR_NORTH_BUNKER_IN_CONFLICT_ALLIANCE_ATTACKING = 1375, // unused
//Icewing Bunker
AV_WS_ICEWING_BUNKER_OWNER = 1183,
AV_WS_ICEWING_BUNKER_ALLIANCE_CONTROLLED = 1363,
AV_WS_ICEWING_BUNKER_DESTROYED = 1372,
AV_WS_ICEWING_BUNKER_IN_CONFLICT_HORDE_ATTACKING = 1380,
AV_WS_ICEWING_BUNKER_IN_CONFLICT_ALLIANCE_ATTACKING = 1376, // unused
//Stoneheart Bunker
AV_WS_STONEHEARTH_BUNKER_OWNER = 1184,
AV_WS_STONEHEARTH_BUNKER_ALLIANCE_CONTROLLED = 1364,
AV_WS_STONEHEARTH_BUNKER_DESTROYED = 1373,
AV_WS_STONEHEARTH_BUNKER_IN_CONFLICT_HORDE_ATTACKING = 1381,
AV_WS_STONEHEARTH_BUNKER_IN_CONFLICT_ALLIANCE_ATTACKING = 1377, // unused
//Horde
//Iceblood Tower
AV_WS_ICEBLOOD_TOWER_OWNER = 1187,
AV_WS_ICEBLOOD_TOWER_DESTROYED = 1368,
AV_WS_ICEBLOOD_TOWER_HORDE_CONTROLLED = 1385,
AV_WS_ICEBLOOD_TOWER_IN_CONFLICT_ALLIANCE_ATTACKING = 1390,
AV_WS_ICEBLOOD_TOWER_IN_CONFLICT_HORDE_ATTACKING = 1395, // unused
//Tower Point
AV_WS_TOWER_POINT_OWNER = 1188,
AV_WS_TOWER_POINT_DESTROYED = 1367,
AV_WS_TOWER_POINT_HORDE_CONTROLLED = 1384,
AV_WS_TOWER_POINT_IN_CONFLICT_ALLIANCE_ATTACKING = 1389,
AV_WS_TOWER_POINT_IN_CONFLICT_HORDE_ATTACKING = 1394, // unused
//Frostwolf West
AV_WS_WEST_FROSTWOLF_TOWER_OWNER = 1185,
AV_WS_WEST_FROSTWOLF_TOWER_DESTROYED = 1365,
AV_WS_WEST_FROSTWOLF_TOWER_HORDE_CONTROLLED = 1382,
AV_WS_WEST_FROSTWOLF_TOWER_IN_CONFLICT_ALLIANCE_ATTACKING = 1387,
AV_WS_WEST_FROSTWOLF_TOWER_IN_CONFLICT_HORDE_ATTACKING = 1392, // unused
//Frostwolf East
AV_WS_EAST_FROSTWOLF_TOWER_OWNER = 1186,
AV_WS_EAST_FROSTWOLF_TOWER_DESTROYED = 1366,
AV_WS_EAST_FROSTWOLF_TOWER_HORDE_CONTROLLED = 1383,
AV_WS_EAST_FROSTWOLF_TOWER_IN_CONFLICT_ALLIANCE_ATTACKING = 1388,
AV_WS_EAST_FROSTWOLF_TOWER_IN_CONFLICT_HORDE_ATTACKING = 1393, // unused
//Mines
AV_WS_IRONDEEP_MINE_OWNER = 801,
AV_WS_IRONDEEP_MINE_TROGG_CONTROLLED = 1360,
AV_WS_IRONDEEP_MINE_ALLIANCE_CONTROLLED = 1358,
AV_WS_IRONDEEP_MINE_HORDE_CONTROLLED = 1359,
AV_WS_COLDTOOTH_MINE_OWNER = 804,
AV_WS_COLDTOOTH_MINE_KOBOLD_CONTROLLED = 1357,
AV_WS_COLDTOOTH_MINE_ALLIANCE_CONTROLLED = 1355,
AV_WS_COLDTOOTH_MINE_HORDE_CONTROLLED = 1356,
//Turnins
AV_WS_IVUS_STORM_CRYSTAL_COUNT = 1043,
AV_WS_IVUS_STORM_CRYSTAL_MAX = 1044,
AV_WS_LOKHOLAR_STORMPIKE_SOLDIERS_BLOOD_COUNT = 923,
AV_WS_LOKHOLAR_STORMPIKE_SOLDIERS_BLOOD_MAX = 922,
//Bosses
AV_WS_DREKTHAR_ALIVE = 601,
AV_WS_VANDAAR_ALIVE = 602,
//Captains
AV_WS_GALVAGAR_ALIVE = 1352,
AV_WS_BALINDA_ALIVE = 1351,
};
enum BG_AV_QuestIds
{
AV_QUEST_A_SCRAPS1 = 7223,
AV_QUEST_A_SCRAPS2 = 6781,
AV_QUEST_H_SCRAPS1 = 7224,
AV_QUEST_H_SCRAPS2 = 6741,
AV_QUEST_A_COMMANDER1 = 6942, //soldier
AV_QUEST_H_COMMANDER1 = 6825,
AV_QUEST_A_COMMANDER2 = 6941, //leutnant
AV_QUEST_H_COMMANDER2 = 6826,
AV_QUEST_A_COMMANDER3 = 6943, //commander
AV_QUEST_H_COMMANDER3 = 6827,
AV_QUEST_A_BOSS1 = 7386, // 5 cristal/blood
AV_QUEST_H_BOSS1 = 7385,
AV_QUEST_A_BOSS2 = 6881, // 1
AV_QUEST_H_BOSS2 = 6801,
AV_QUEST_A_NEAR_MINE = 5892, //the mine near start location of team
AV_QUEST_H_NEAR_MINE = 5893,
AV_QUEST_A_OTHER_MINE = 6982, //the other mine ;)
AV_QUEST_H_OTHER_MINE = 6985,
AV_QUEST_A_RIDER_HIDE = 7026,
AV_QUEST_H_RIDER_HIDE = 7002,
AV_QUEST_A_RIDER_TAME = 7027,
AV_QUEST_H_RIDER_TAME = 7001
};
struct StaticMineInfo
{
int32 WorldStateOwner;
int32 WorldStateAllianceControlled;
int32 WorldStateHordeControlled;
int32 WorldStateNeutralControlled;
uint8 TextIdAlliance;
uint8 TextIdHorde;
};
struct AlteracValleyMineInfo
{
Team Owner;
StaticMineInfo StaticInfo;
};
struct StaticNodeInfo
{
BG_AV_Nodes NodeId;
struct
{
uint8 AllianceCapture;
uint8 AllianceAttack;
uint8 HordeCapture;
uint8 HordeAttack;
} TextIds;
struct
{
int32 AllianceControl;
int32 AllianceAssault;
int32 HordeControl;
int32 HordeAssault;
int32 Owner;
} WorldStateIds;
struct
{
std::string AllianceOrDefend;
std::string HordeOrDestroy;
} StringIds;
};
static StaticNodeInfo const BGAVNodeInfo[] =
{
{ BG_AV_NODES_FIRSTAID_STATION, { 47, 48, 45, 46 }, { 1325, 1326, 1327, 1328, 0 }, { "bg_av_herald_stormpike_aid_station_alliance", "bg_av_herald_stormpike_aid_station_horde" } }, // Stormpike First Aid Station
{ BG_AV_NODES_STORMPIKE_GRAVE, { 1, 2, 3, 4 }, { 1333, 1335, 1334, 1336, 0 }, { "bg_av_herald_stormpike_alliance", "bg_av_herald_stormpike_horde" } }, // Stormpike Graveyard
{ BG_AV_NODES_STONEHEART_GRAVE, { 55, 56, 53, 54 }, { 1302, 1304, 1301, 1303, 0 }, { "bg_av_herald_stonehearth_alliance", "bg_av_herald_stonehearth_horde" } }, // Stoneheart Graveyard
{ BG_AV_NODES_SNOWFALL_GRAVE, { 5, 6, 7, 8 }, { 1341, 1343, 1342, 1344, 0 }, { "bg_av_herald_snowfall_alliance", "bg_av_herald_snowfall_horde" } }, // Snowfall Graveyard
{ BG_AV_NODES_ICEBLOOD_GRAVE, { 59, 60, 57, 58 }, { 1346, 1348, 1347, 1349, 0 }, { "bg_av_herald_iceblood_alliance", "bg_av_herald_iceblood_horde" } }, // Iceblood Graveyard
{ BG_AV_NODES_FROSTWOLF_GRAVE, { 9, 10, 11, 12 }, { 1337, 1339, 1338, 1340, 0 }, { "bg_av_herald_frostwolf_alliance", "bg_av_herald_frostwolf_horde" } }, // Frostwolf Graveyard
{ BG_AV_NODES_FROSTWOLF_HUT, { 51, 52, 49, 50 }, { 1329, 1331, 1330, 1332, 0 }, { "bg_av_herald_frostwolf_hut_alliance", "bg_av_herald_frostwolf_hut_horde" } }, // Frostwolf Hut
{ BG_AV_NODES_DUNBALDAR_SOUTH, { 16, 15, 14, 13 }, { 1361, 1375, 1370, 1378, 1181 }, { "bg_av_herald_south_bunker_defend", "bg_av_herald_south_bunker_attack" } }, // Dunbaldar South Bunker
{ BG_AV_NODES_DUNBALDAR_NORTH, { 20, 19, 18, 17 }, { 1362, 1374, 1371, 1379, 1182 }, { "bg_av_herald_north_bunker_defend", "bg_av_herald_south_bunker_attack" } }, // Dunbaldar North Bunker
{ BG_AV_NODES_ICEWING_BUNKER, { 24, 23, 22, 21 }, { 1363, 1376, 1372, 1380, 1183 }, { "bg_av_herald_icewing_bunker_defend", "bg_av_herald_icewing_bunker_attack" } }, // Icewing Bunker
{ BG_AV_NODES_STONEHEART_BUNKER, { 28, 27, 26, 25 }, { 1364, 1377, 1373, 1381, 1184 }, { "bg_av_herald_stonehearth_bunker_defend", "bg_av_herald_stonehearth_bunker_attack" } }, // Stoneheart Bunker
{ BG_AV_NODES_ICEBLOOD_TOWER, { 44, 43, 42, 41 }, { 1368, 1390, 1385, 1395, 1188 }, { "bg_av_herald_iceblood_tower_defend", "bg_av_herald_iceblood_tower_attack" } }, // Iceblood Tower
{ BG_AV_NODES_TOWER_POINT, { 40, 39, 38, 37 }, { 1367, 1389, 1384, 1394, 1187 }, { "bg_av_herald_tower_point_defend", "bg_av_herald_tower_point_attack" } }, // Tower Point
{ BG_AV_NODES_FROSTWOLF_ETOWER, { 36, 35, 34, 33 }, { 1366, 1388, 1383, 1393, 1186 }, { "bg_av_herald_east_tower_defend", "bg_av_herald_east_tower_attack" } }, // Frostwolf East Tower
{ BG_AV_NODES_FROSTWOLF_WTOWER, { 32, 31, 30, 29 }, { 1365, 1387, 1382, 1392, 1185 }, { "bg_av_herald_west_tower_defend", "bg_av_herald_west_tower_attack" } }, // Frostwolf West Tower
};
enum Texts
{
// Herold
// Towers/Graveyards = 1 - 60
TEXT_COLDTOOTH_MINE_ALLIANCE_TAKEN = 61,
TEXT_IRONDEEP_MINE_ALLIANCE_TAKEN = 62,
TEXT_COLDTOOTH_MINE_HORDE_TAKEN = 63,
TEXT_IRONDEEP_MINE_HORDE_TAKEN = 64,
TEXT_FROSTWOLF_GENERAL_DEAD = 65, /// @todo: sound is missing
TEXT_STORMPIKE_GENERAL_DEAD = 66, /// @todo: sound is missing
TEXT_ALLIANCE_WINS = 67, // NYI /// @todo: sound is missing
TEXT_HORDE_WINS = 68, // NYI /// @todo: sound is missing
// Taskmaster Snivvle
TEXT_SNIVVLE_RANDOM = 0
};
enum BG_AV_ExploitTeleportLocations
{
AV_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3664,
AV_EXPLOIT_TELEPORT_LOCATION_HORDE = 3665
};
struct BG_AV_NodeInfo
{
BG_AV_States State;
BG_AV_States PrevState;
uint16 TotalOwner;
Team Owner;
uint16 PrevOwner;
bool Tower;
};
inline BG_AV_Nodes &operator++(BG_AV_Nodes& i) { return i = BG_AV_Nodes(i + 1); }
enum BG_AV_Data : uint32
{
DATA_DEFENDER_TIER_HORDE = 1,
DATA_DEFENDER_TIER_ALLIANCE = 2,
};
enum BG_AV_DefenderTier : uint32
{
BG_AV_DEFENDER_TIER_DEFENDER,
BG_AV_DEFENDER_TIER_SEASONED,
BG_AV_DEFENDER_TIER_VETERAN,
BG_AV_DEFENDER_TIER_CHAMPION
};
class BattlegroundAV : public Battleground
{
public:
BattlegroundAV(BattlegroundTemplate const* battlegroundTemplate);
~BattlegroundAV() = default;
/* inherited from BattlegroundClass */
void StartingEventOpenDoors() override;
void RemovePlayer(Player* player, ObjectGuid guid, uint32 team) override;
bool SetupBattleground() override;
/*general stuff*/
void UpdateScore(Team team, int16 points);
// Handle Stuff
void HandleInteractCapturableObject(Player* player, GameObject* target);
//these are functions which get called from extern
void HandleKillPlayer(Player* player, Player* killer) override;
void HandleKillUnit(Creature* unit, Unit* killer) override;
void HandleQuestComplete(uint32 questid, Player* player) override;
void EndBattleground(Team winner) override;
WorldSafeLocsEntry const* GetExploitTeleportLocation(Team team) override;
Team GetPrematureWinner() override;
void OnGameObjectCreate(GameObject* gameObject) override;
void OnCreatureCreate(Creature* creature) override;
uint32 GetData(uint32 dataId) const override;
private:
void PostUpdateImpl(uint32 diff) override;
bool IsCaptainAlive(TeamId teamId) const;
/* Nodes occupying */
void EventPlayerAssaultsPoint(Player* player, uint32 object);
void EventPlayerDefendsPoint(Player* player, uint32 object);
void EventPlayerDestroyedPoint(GameObject* gameobject);
void DoAction([[maybe_unused]] uint32 actionId, [[maybe_unused]] WorldObject* source = nullptr, [[maybe_unused]] WorldObject* target = nullptr) override;
void AssaultNode(BG_AV_Nodes node, Team team);
void DestroyNode(BG_AV_Nodes node);
void InitNode(BG_AV_Nodes node, Team team, bool tower);
void DefendNode(BG_AV_Nodes node, Team team);
StaticNodeInfo const* GetStaticNodeInfo(BG_AV_Nodes node) const
{
for (uint8 i = 0; i < BG_AV_NODES_MAX; ++i)
if (BGAVNodeInfo[i].NodeId == node)
return &BGAVNodeInfo[i];
return nullptr;
}
BG_AV_Nodes GetNodeThroughObject(uint32 object);
bool IsTower(BG_AV_Nodes node) const { return _nodes[node].Tower; }
/*mine*/
void ChangeMineOwner(AlteracValleyMine mine, Team team, bool initial = false);
/*worldstates*/
void SendMineWorldStates(AlteracValleyMine mine);
void UpdateNodeWorldState(BG_AV_Nodes node);
Creature* FindHerald(std::string_view stringId) const;
/*variables */
std::array<int32, PVP_TEAMS_COUNT> _teamResources;
uint32 m_Team_QuestStatus[PVP_TEAMS_COUNT][9]; //[x][y] x=team y=questcounter
std::array<BG_AV_NodeInfo, BG_AV_NODES_MAX> _nodes;
TimeTracker _mineResourceTimer; //ticks for both teams
std::array<AlteracValleyMineInfo, 2> _mineInfo;
std::array<TimeTracker, PVP_TEAMS_COUNT> _captainBuffTimer;
std::array<bool, PVP_TEAMS_COUNT> _isInformedNearVictory;
GuidUnorderedSet _doorGUIDs;
ObjectGuid _balindaGUID;
ObjectGuid _galvangarGUID;
GuidUnorderedSet _heraldGUIDs;
};
#endif
@@ -1,83 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundBE.h"
#include "Log.h"
#include "Player.h"
BattlegroundBE::BattlegroundBE(BattlegroundTemplate const* battlegroundTemplate) : Arena(battlegroundTemplate)
{
BgObjects.resize(BG_BE_OBJECT_MAX);
}
void BattlegroundBE::PostUpdateImpl(uint32 diff)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case BG_BE_EVENT_REMOVE_DOORS:
for (uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_2; ++i)
DelObject(i);
break;
default:
break;
}
}
}
void BattlegroundBE::StartingEventCloseDoors()
{
for (uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_4; ++i)
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
for (uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; ++i)
SpawnBGObject(i, RESPAWN_ONE_DAY);
}
void BattlegroundBE::StartingEventOpenDoors()
{
for (uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_2; ++i)
DoorOpen(i);
_events.ScheduleEvent(BG_BE_EVENT_REMOVE_DOORS, BG_BE_REMOVE_DOORS_TIMER);
for (uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; ++i)
SpawnBGObject(i, 60);
}
bool BattlegroundBE::SetupBattleground()
{
// gates
if (!AddObject(BG_BE_OBJECT_DOOR_1, BG_BE_OBJECT_TYPE_DOOR_1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_BE_OBJECT_DOOR_2, BG_BE_OBJECT_TYPE_DOOR_2, 6189.546f, 241.7099f, 3.101481f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_BE_OBJECT_DOOR_3, BG_BE_OBJECT_TYPE_DOOR_3, 6299.116f, 296.5494f, 3.308032f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_BE_OBJECT_DOOR_4, BG_BE_OBJECT_TYPE_DOOR_4, 6177.708f, 227.3481f, 3.604374f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY)
// buffs
|| !AddObject(BG_BE_OBJECT_BUFF_1, BG_BE_OBJECT_TYPE_BUFF_1, 6249.042f, 275.3239f, 11.22033f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120)
|| !AddObject(BG_BE_OBJECT_BUFF_2, BG_BE_OBJECT_TYPE_BUFF_2, 6228.26f, 249.566f, 11.21812f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120))
{
TC_LOG_ERROR("sql.sql", "BatteGroundBE: Failed to spawn some object!");
return false;
}
return true;
}
@@ -1,68 +0,0 @@
/*
* 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 __BATTLEGROUNDBE_H
#define __BATTLEGROUNDBE_H
#include "Arena.h"
#include "EventMap.h"
enum BattlegroundBEObjectTypes
{
BG_BE_OBJECT_DOOR_1 = 0,
BG_BE_OBJECT_DOOR_2 = 1,
BG_BE_OBJECT_DOOR_3 = 2,
BG_BE_OBJECT_DOOR_4 = 3,
BG_BE_OBJECT_BUFF_1 = 4,
BG_BE_OBJECT_BUFF_2 = 5,
BG_BE_OBJECT_MAX = 6
};
enum BattlegroundBEGameObjects
{
BG_BE_OBJECT_TYPE_DOOR_1 = 183971,
BG_BE_OBJECT_TYPE_DOOR_2 = 183973,
BG_BE_OBJECT_TYPE_DOOR_3 = 183970,
BG_BE_OBJECT_TYPE_DOOR_4 = 183972,
BG_BE_OBJECT_TYPE_BUFF_1 = 184663,
BG_BE_OBJECT_TYPE_BUFF_2 = 184664
};
inline constexpr Seconds BG_BE_REMOVE_DOORS_TIMER = 5s;
enum BattlegroundBEEvents
{
BG_BE_EVENT_REMOVE_DOORS = 1
};
class BattlegroundBE : public Arena
{
public:
BattlegroundBE(BattlegroundTemplate const* battlegroundTemplate);
/* inherited from BattlegroundClass */
void StartingEventCloseDoors() override;
void StartingEventOpenDoors() override;
bool SetupBattleground() override;
private:
void PostUpdateImpl(uint32 diff) override;
EventMap _events;
};
#endif
@@ -1,159 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundDS.h"
#include "Creature.h"
#include "Log.h"
#include "Player.h"
BattlegroundDS::BattlegroundDS(BattlegroundTemplate const* battlegroundTemplate) : Arena(battlegroundTemplate)
{
BgObjects.resize(BG_DS_OBJECT_MAX);
BgCreatures.resize(BG_DS_NPC_MAX);
_pipeKnockBackTimer = 0;
_pipeKnockBackCount = 0;
}
void BattlegroundDS::PostUpdateImpl(uint32 diff)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case BG_DS_EVENT_WATERFALL_WARNING:
// Add the water
DoorClose(BG_DS_OBJECT_WATER_2);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_ON, BG_DS_WATERFALL_WARNING_DURATION);
break;
case BG_DS_EVENT_WATERFALL_ON:
// Active collision and start knockback timer
DoorClose(BG_DS_OBJECT_WATER_1);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_OFF, BG_DS_WATERFALL_DURATION);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_KNOCKBACK, BG_DS_WATERFALL_KNOCKBACK_TIMER);
break;
case BG_DS_EVENT_WATERFALL_OFF:
// Remove collision and water
DoorOpen(BG_DS_OBJECT_WATER_1);
DoorOpen(BG_DS_OBJECT_WATER_2);
_events.CancelEvent(BG_DS_EVENT_WATERFALL_KNOCKBACK);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_WARNING, BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX);
break;
case BG_DS_EVENT_WATERFALL_KNOCKBACK:
// Repeat knockback while the waterfall still active
if (Creature* waterSpout = GetBGCreature(BG_DS_NPC_WATERFALL_KNOCKBACK))
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_WATER_SPOUT, true);
_events.ScheduleEvent(eventId, BG_DS_WATERFALL_KNOCKBACK_TIMER);
break;
case BG_DS_EVENT_PIPE_KNOCKBACK:
for (uint32 i = BG_DS_NPC_PIPE_KNOCKBACK_1; i <= BG_DS_NPC_PIPE_KNOCKBACK_2; ++i)
if (Creature* waterSpout = GetBGCreature(i))
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_FLUSH, true);
break;
}
}
if (_pipeKnockBackCount < BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT)
{
if (_pipeKnockBackTimer < diff)
{
for (uint32 i = BG_DS_NPC_PIPE_KNOCKBACK_1; i <= BG_DS_NPC_PIPE_KNOCKBACK_2; ++i)
if (Creature* waterSpout = GetBGCreature(i))
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_FLUSH, true);
++_pipeKnockBackCount;
_pipeKnockBackTimer = BG_DS_PIPE_KNOCKBACK_DELAY;
}
else
_pipeKnockBackTimer -= diff;
}
}
void BattlegroundDS::StartingEventCloseDoors()
{
for (uint32 i = BG_DS_OBJECT_DOOR_1; i <= BG_DS_OBJECT_DOOR_2; ++i)
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
}
void BattlegroundDS::StartingEventOpenDoors()
{
for (uint32 i = BG_DS_OBJECT_DOOR_1; i <= BG_DS_OBJECT_DOOR_2; ++i)
DoorOpen(i);
for (uint32 i = BG_DS_OBJECT_BUFF_1; i <= BG_DS_OBJECT_BUFF_2; ++i)
SpawnBGObject(i, 60);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_WARNING, BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX);
//for (uint8 i = 0; i < BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT; ++i)
// _events.ScheduleEvent(BG_DS_EVENT_PIPE_KNOCKBACK, BG_DS_PIPE_KNOCKBACK_FIRST_DELAY + i * BG_DS_PIPE_KNOCKBACK_DELAY);
_pipeKnockBackCount = 0;
_pipeKnockBackTimer = BG_DS_PIPE_KNOCKBACK_FIRST_DELAY;
SpawnBGObject(BG_DS_OBJECT_WATER_2, RESPAWN_IMMEDIATELY);
DoorOpen(BG_DS_OBJECT_WATER_1); // Turn off collision
DoorOpen(BG_DS_OBJECT_WATER_2);
// Remove effects of Demonic Circle Summon
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
if (Player* player = _GetPlayer(itr, "BattlegroundDS::StartingEventOpenDoors"))
player->RemoveAurasDueToSpell(SPELL_WARL_DEMONIC_CIRCLE);
}
bool BattlegroundDS::SetupBattleground()
{
// gates
if (!AddObject(BG_DS_OBJECT_DOOR_1, BG_DS_OBJECT_TYPE_DOOR_1, 1350.95f, 817.2f, 20.8096f, 3.15f, 0, 0, 0.99627f, 0.0862864f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_DS_OBJECT_DOOR_2, BG_DS_OBJECT_TYPE_DOOR_2, 1232.65f, 764.913f, 20.0729f, 6.3f, 0, 0, 0.0310211f, -0.999519f, RESPAWN_IMMEDIATELY)
// water
|| !AddObject(BG_DS_OBJECT_WATER_1, BG_DS_OBJECT_TYPE_WATER_1, 1291.56f, 790.837f, 7.1f, 3.14238f, 0, 0, 0.694215f, -0.719768f, 120)
|| !AddObject(BG_DS_OBJECT_WATER_2, BG_DS_OBJECT_TYPE_WATER_2, 1291.56f, 790.837f, 7.1f, 3.14238f, 0, 0, 0.694215f, -0.719768f, 120)
// buffs
|| !AddObject(BG_DS_OBJECT_BUFF_1, BG_DS_OBJECT_TYPE_BUFF_1, 1291.7f, 813.424f, 7.11472f, 4.64562f, 0, 0, 0.730314f, -0.683111f, 120)
|| !AddObject(BG_DS_OBJECT_BUFF_2, BG_DS_OBJECT_TYPE_BUFF_2, 1291.7f, 768.911f, 7.11472f, 1.55194f, 0, 0, 0.700409f, 0.713742f, 120)
// knockback creatures
|| !AddCreature(BG_DS_NPC_TYPE_WATER_SPOUT, BG_DS_NPC_WATERFALL_KNOCKBACK, 1292.587f, 790.2205f, 7.19796f, 3.054326f, TEAM_NEUTRAL, RESPAWN_IMMEDIATELY)
|| !AddCreature(BG_DS_NPC_TYPE_WATER_SPOUT, BG_DS_NPC_PIPE_KNOCKBACK_1, 1369.977f, 817.2882f, 16.08718f, 3.106686f, TEAM_NEUTRAL, RESPAWN_IMMEDIATELY)
|| !AddCreature(BG_DS_NPC_TYPE_WATER_SPOUT, BG_DS_NPC_PIPE_KNOCKBACK_2, 1212.833f, 765.3871f, 16.09484f, 0.0f, TEAM_NEUTRAL, RESPAWN_IMMEDIATELY))
{
TC_LOG_ERROR("sql.sql", "BatteGroundDS: Failed to spawn some object!");
return false;
}
return true;
}
void BattlegroundDS::SetData(uint32 dataId, uint32 value)
{
Arena::SetData(dataId, value);
if (dataId == BG_DS_DATA_PIPE_KNOCKBACK_COUNT)
_pipeKnockBackCount = value;
}
uint32 BattlegroundDS::GetData(uint32 dataId) const
{
if (dataId == BG_DS_DATA_PIPE_KNOCKBACK_COUNT)
return _pipeKnockBackCount;
return Arena::GetData(dataId);
}
@@ -1,115 +0,0 @@
/*
* 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 __BATTLEGROUNDDS_H
#define __BATTLEGROUNDDS_H
#include "Arena.h"
#include "EventMap.h"
enum BattlegroundDSObjectTypes
{
BG_DS_OBJECT_DOOR_1 = 0,
BG_DS_OBJECT_DOOR_2 = 1,
BG_DS_OBJECT_WATER_1 = 2, // Collision
BG_DS_OBJECT_WATER_2 = 3,
BG_DS_OBJECT_BUFF_1 = 4,
BG_DS_OBJECT_BUFF_2 = 5,
BG_DS_OBJECT_MAX = 6
};
enum BattlegroundDSGameObjects
{
BG_DS_OBJECT_TYPE_DOOR_1 = 192642,
BG_DS_OBJECT_TYPE_DOOR_2 = 192643,
BG_DS_OBJECT_TYPE_WATER_1 = 194395, // Collision
BG_DS_OBJECT_TYPE_WATER_2 = 191877,
BG_DS_OBJECT_TYPE_BUFF_1 = 184663,
BG_DS_OBJECT_TYPE_BUFF_2 = 184664
};
enum BattlegroundDSCreatureTypes
{
BG_DS_NPC_WATERFALL_KNOCKBACK = 0,
BG_DS_NPC_PIPE_KNOCKBACK_1 = 1,
BG_DS_NPC_PIPE_KNOCKBACK_2 = 2,
BG_DS_NPC_MAX = 3
};
enum BattlegroundDSCreatures
{
BG_DS_NPC_TYPE_WATER_SPOUT = 28567
};
enum BattlegroundDSSpells
{
BG_DS_SPELL_FLUSH = 57405, // Visual and target selector for the starting knockback from the pipe
BG_DS_SPELL_FLUSH_KNOCKBACK = 61698, // Knockback effect for previous spell (triggered, not needed to be cast)
BG_DS_SPELL_WATER_SPOUT = 58873, // Knockback effect of the central waterfall
SPELL_WARL_DEMONIC_CIRCLE = 48018 // Demonic Circle Summon
};
enum BattlegroundDSData
{
// These values are NOT blizzlike... need the correct data!
BG_DS_PIPE_KNOCKBACK_FIRST_DELAY = 5000,
BG_DS_PIPE_KNOCKBACK_DELAY = 3000,
BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT = 2,
};
// These values are NOT blizzlike... need the correct data!
inline constexpr Seconds BG_DS_WATERFALL_TIMER_MIN = 30s;
inline constexpr Seconds BG_DS_WATERFALL_TIMER_MAX = 60s;
inline constexpr Seconds BG_DS_WATERFALL_WARNING_DURATION = 5s;
inline constexpr Seconds BG_DS_WATERFALL_DURATION = 30s;
inline constexpr Milliseconds BG_DS_WATERFALL_KNOCKBACK_TIMER = 1500ms;
inline constexpr uint32 BG_DS_DATA_PIPE_KNOCKBACK_COUNT = 1;
enum BattlegroundDSEvents
{
BG_DS_EVENT_WATERFALL_WARNING = 1, // Water starting to fall, but no LoS Blocking nor movement blocking
BG_DS_EVENT_WATERFALL_ON = 2, // LoS and Movement blocking active
BG_DS_EVENT_WATERFALL_OFF = 3,
BG_DS_EVENT_WATERFALL_KNOCKBACK = 4,
BG_DS_EVENT_PIPE_KNOCKBACK = 5
};
class BattlegroundDS : public Arena
{
public:
BattlegroundDS(BattlegroundTemplate const* battlegroundTemplate);
/* inherited from BattlegroundClass */
void StartingEventCloseDoors() override;
void StartingEventOpenDoors() override;
bool SetupBattleground() override;
void SetData(uint32 dataId, uint32 value) override;
uint32 GetData(uint32 dataId) const override;
private:
void PostUpdateImpl(uint32 diff) override;
EventMap _events;
uint32 _pipeKnockBackTimer;
uint8 _pipeKnockBackCount;
};
#endif
@@ -1,491 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundEY.h"
#include "AreaTrigger.h"
#include "BattlegroundMgr.h"
#include "BattlegroundPackets.h"
#include "Creature.h"
#include "GameObject.h"
#include "Log.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "Random.h"
#include "SpellAuras.h"
#include "SpellInfo.h"
#include "Util.h"
enum EyeOfTheStormPvpStats
{
PVP_STAT_FLAG_CAPTURES = 183
};
BattlegroundEY::BattlegroundEY(BattlegroundTemplate const* battlegroundTemplate) : Battleground(battlegroundTemplate)
{
BgObjects.resize(0);
BgCreatures.resize(0);
m_HonorScoreTics = { 0, 0 };
m_FlagCapturedBgObjectType = 0;
m_HonorTics = 0;
_pointsTimer.Reset(POINTS_TICK_TIME);
_assaultEnabled = false;
_assaultStackCount = 0;
_flagAssaultTimer.Reset(BG_EY_FLAG_ASSAULT_TIMER);
}
BattlegroundEY::~BattlegroundEY() { }
void BattlegroundEY::PostUpdateImpl(uint32 diff)
{
if (GetStatus() == STATUS_IN_PROGRESS)
{
_pointsTimer.Update(diff);
if (_pointsTimer.Passed())
{
_pointsTimer.Reset(POINTS_TICK_TIME);
uint8 baseCountAlliance = GetControlledBaseCount(TEAM_ALLIANCE);
uint8 baseCountHorde = GetControlledBaseCount(TEAM_HORDE);
if (baseCountAlliance > 0)
AddPoints(ALLIANCE, BG_EY_TickPoints[baseCountAlliance - 1]);
if (baseCountHorde > 0)
AddPoints(HORDE, BG_EY_TickPoints[baseCountHorde - 1]);
}
if (_assaultEnabled)
{
_flagAssaultTimer.Update(diff);
if (_flagAssaultTimer.Passed())
{
_flagAssaultTimer.Reset(BG_EY_FLAG_ASSAULT_TIMER);
_assaultStackCount++;
// update assault debuff stacks
DoForFlagKeepers([&](Player* player) -> void
{
ApplyAssaultDebuffToPlayer(player);
});
}
}
}
}
void BattlegroundEY::StartingEventOpenDoors()
{
for (ObjectGuid const& door : _doorGUIDs)
{
if (GameObject* gameObject = GetBgMap()->GetGameObject(door))
{
gameObject->UseDoorOrButton();
gameObject->DespawnOrUnsummon(3s);
}
}
// Achievement: Flurry
TriggerGameEvent(BG_EY_EVENT_START_BATTLE);
}
void BattlegroundEY::AddPoints(Team team, uint32 Points)
{
TeamId team_index = GetTeamIndexByTeamId(team);
m_TeamScores[team_index] += Points;
m_HonorScoreTics[team_index] += Points;
if (m_HonorScoreTics[team_index] >= m_HonorTics)
{
RewardHonorToTeam(GetBonusHonorFromKill(1), team);
m_HonorScoreTics[team_index] -= m_HonorTics;
}
UpdateTeamScore(team_index);
}
uint8 BattlegroundEY::GetControlledBaseCount(TeamId teamId) const
{
uint8 baseCount = 0;
for (auto const& controlZoneHandler : _controlZoneHandlers)
{
uint32 point = controlZoneHandler.second->GetPoint();
switch (teamId)
{
case TEAM_ALLIANCE:
if (GetBgMap()->GetWorldStateValue(m_PointsIconStruct[point].WorldStateAllianceControlledIndex) == 1)
baseCount++;
break;
case TEAM_HORDE:
if (GetBgMap()->GetWorldStateValue(m_PointsIconStruct[point].WorldStateHordeControlledIndex) == 1)
baseCount++;
break;
default:
break;
}
}
return baseCount;
}
void BattlegroundEY::DoForFlagKeepers(std::function<void(Player*)> action) const
{
if (GameObject* flag = GetBgMap()->GetGameObject(_flagGUID))
{
if (Player* carrier = ObjectAccessor::FindPlayer(flag->GetFlagCarrierGUID()))
action(carrier);
}
}
void BattlegroundEY::ResetAssaultDebuff()
{
_assaultEnabled = false;
_assaultStackCount = 0;
_flagAssaultTimer.Reset(BG_EY_FLAG_ASSAULT_TIMER);
DoForFlagKeepers([&](Player* player) -> void
{
RemoveAssaultDebuffFromPlayer(player);
});
}
void BattlegroundEY::ApplyAssaultDebuffToPlayer(Player* player)
{
if (_assaultStackCount == 0)
return;
uint32 spellId = BG_EY_FOCUSED_ASSAULT_SPELL;
if (_assaultStackCount >= BG_EY_FLAG_BRUTAL_ASSAULT_STACK_COUNT)
{
player->RemoveAurasDueToSpell(BG_EY_FOCUSED_ASSAULT_SPELL);
spellId = BG_EY_BRUTAL_ASSAULT_SPELL;
}
Aura* aura = player->GetAura(spellId);
if (!aura)
{
player->CastSpell(player, spellId, true);
aura = player->GetAura(spellId);
}
if (aura)
aura->SetStackAmount(_assaultStackCount);
}
void BattlegroundEY::RemoveAssaultDebuffFromPlayer(Player* player)
{
player->RemoveAurasDueToSpell(BG_EY_FOCUSED_ASSAULT_SPELL);
player->RemoveAurasDueToSpell(BG_EY_BRUTAL_ASSAULT_SPELL);
}
void BattlegroundEY::UpdateTeamScore(TeamId Team)
{
uint32 score = GetTeamScore(Team);
if (score >= BG_EY_MAX_TEAM_SCORE)
{
score = BG_EY_MAX_TEAM_SCORE;
if (Team == TEAM_ALLIANCE)
EndBattleground(ALLIANCE);
else
EndBattleground(HORDE);
}
if (Team == TEAM_ALLIANCE)
UpdateWorldState(EY_ALLIANCE_RESOURCES, score);
else
UpdateWorldState(EY_HORDE_RESOURCES, score);
}
void BattlegroundEY::EndBattleground(Team winner)
{
// Win reward
if (winner == ALLIANCE)
RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
if (winner == HORDE)
RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
// Complete map reward
RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
Battleground::EndBattleground(winner);
}
void BattlegroundEY::UpdatePointsCount(TeamId teamId)
{
if (teamId == TEAM_ALLIANCE)
UpdateWorldState(EY_ALLIANCE_BASE, GetControlledBaseCount(TEAM_ALLIANCE));
else
UpdateWorldState(EY_HORDE_BASE, GetControlledBaseCount(TEAM_HORDE));
}
void BattlegroundEY::OnGameObjectCreate(GameObject* gameObject)
{
switch (gameObject->GetEntry())
{
case BG_OBJECT_A_DOOR_EY_ENTRY:
case BG_OBJECT_H_DOOR_EY_ENTRY:
_doorGUIDs.insert(gameObject->GetGUID());
break;
case BG_OBJECT_FLAG2_EY_ENTRY:
_flagGUID = gameObject->GetGUID();
break;
default:
break;
}
}
bool BattlegroundEY::CanCaptureFlag(AreaTrigger* areaTrigger, Player* player)
{
if (areaTrigger->GetEntry() != AREATRIGGER_CAPTURE_FLAG)
return false;
if (GameObject* flag = GetBgMap()->GetGameObject(_flagGUID))
{
if (flag->GetFlagCarrierGUID() != player->GetGUID())
return false;
}
if (GameObject* controlzone = player->FindNearestGameObjectWithOptions(40.0f, { .StringId = "bg_eye_of_the_storm_control_zone" }))
{
uint32 point = _controlZoneHandlers[controlzone->GetEntry()]->GetPoint();
switch (GetPlayerTeam(player->GetGUID()))
{
case ALLIANCE:
return GetBgMap()->GetWorldStateValue(m_PointsIconStruct[point].WorldStateAllianceControlledIndex) == 1;
case HORDE:
return GetBgMap()->GetWorldStateValue(m_PointsIconStruct[point].WorldStateHordeControlledIndex) == 1;
default:
return false;
}
}
return false;
}
void BattlegroundEY::OnCaptureFlag(AreaTrigger* areaTrigger, Player* player)
{
if (areaTrigger->GetEntry() != AREATRIGGER_CAPTURE_FLAG)
return;
uint32 baseCount = GetControlledBaseCount(GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())));
if (GameObject* gameObject = GetBgMap()->GetGameObject(_flagGUID))
gameObject->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::Respawning, player));
Team team = Team(GetPlayerTeam(player->GetGUID()));
if (team == ALLIANCE)
{
SendBroadcastText(BG_EY_TEXT_ALLIANCE_CAPTURED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE);
}
else
{
SendBroadcastText(BG_EY_TEXT_HORDE_CAPTURED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, player);
PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE);
}
if (baseCount > 0)
AddPoints(team, BG_EY_FlagPoints[baseCount - 1]);
UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_ON_BASE);
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_ON_BASE);
UpdatePvpStat(player, PVP_STAT_FLAG_CAPTURES, 1);
player->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL);
player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive);
}
void BattlegroundEY::OnFlagStateChange(GameObject* /*flagInBase*/, FlagState /*oldValue*/, FlagState newValue, Player* player)
{
switch (newValue)
{
case FlagState::InBase:
ResetAssaultDebuff();
break;
case FlagState::Dropped:
player->CastSpell(player, SPELL_RECENTLY_DROPPED_NEUTRAL_FLAG, true);
RemoveAssaultDebuffFromPlayer(player);
UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_WAIT_RESPAWN);
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_WAIT_RESPAWN);
if (GetPlayerTeam(player->GetGUID()) == ALLIANCE)
SendBroadcastText(BG_EY_TEXT_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_ALLIANCE);
else
SendBroadcastText(BG_EY_TEXT_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_HORDE);
break;
case FlagState::Taken:
if (GetPlayerTeam(player->GetGUID()) == ALLIANCE)
{
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_ON_PLAYER);
PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE);
SendBroadcastText(BG_EY_TEXT_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
}
else
{
UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_ON_PLAYER);
PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_HORDE);
SendBroadcastText(BG_EY_TEXT_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, player);
}
ApplyAssaultDebuffToPlayer(player);
_assaultEnabled = true;
player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive);
break;
case FlagState::Respawning:
ResetAssaultDebuff();
break;
default:
break;
}
UpdateWorldState(NETHERSTORM_FLAG, AsUnderlyingType(newValue));
}
bool BattlegroundEY::SetupBattleground()
{
UpdateWorldState(EY_MAX_RESOURCES, BG_EY_MAX_TEAM_SCORE);
_controlZoneHandlers[BG_OBJECT_FR_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(this, FEL_REAVER);
_controlZoneHandlers[BG_OBJECT_BE_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(this, BLOOD_ELF);
_controlZoneHandlers[BG_OBJECT_DR_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(this, DRAENEI_RUINS);
_controlZoneHandlers[BG_OBJECT_HU_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(this, MAGE_TOWER);
return true;
}
void BattlegroundEY::Reset()
{
//call parent's class reset
Battleground::Reset();
m_TeamScores[TEAM_ALLIANCE] = 0;
m_TeamScores[TEAM_HORDE] = 0;
m_HonorScoreTics = { 0, 0 };
m_FlagCapturedBgObjectType = 0;
bool isBGWeekend = sBattlegroundMgr->IsBGWeekend(GetTypeID());
m_HonorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks;
}
void BattlegroundEY::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
Battleground::HandleKillPlayer(player, killer);
EventPlayerDroppedFlag(player);
}
void BattlegroundEY::EventTeamLostPoint(TeamId teamId, uint32 point, GameObject* controlZone)
{
if (teamId == TEAM_ALLIANCE)
{
SendBroadcastText(m_LosingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, controlZone);
UpdateWorldState(m_PointsIconStruct[point].WorldStateAllianceControlledIndex, 0);
}
else if (teamId == TEAM_HORDE)
{
SendBroadcastText(m_LosingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE, controlZone);
UpdateWorldState(m_PointsIconStruct[point].WorldStateHordeControlledIndex, 0);
}
UpdateWorldState(m_PointsIconStruct[point].WorldStateControlIndex, 1);
UpdatePointsCount(teamId);
}
void BattlegroundEY::EventTeamCapturedPoint(TeamId teamId, uint32 point, GameObject* controlZone)
{
if (teamId == TEAM_ALLIANCE)
{
SendBroadcastText(m_CapturingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, controlZone);
UpdateWorldState(m_PointsIconStruct[point].WorldStateAllianceControlledIndex, 1);
}
else if (teamId == TEAM_HORDE)
{
SendBroadcastText(m_CapturingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE, controlZone);
UpdateWorldState(m_PointsIconStruct[point].WorldStateHordeControlledIndex, 1);
}
UpdateWorldState(m_PointsIconStruct[point].WorldStateControlIndex, 0);
UpdatePointsCount(teamId);
}
WorldSafeLocsEntry const* BattlegroundEY::GetExploitTeleportLocation(Team team)
{
return sObjectMgr->GetWorldSafeLoc(team == ALLIANCE ? EY_EXPLOIT_TELEPORT_LOCATION_ALLIANCE : EY_EXPLOIT_TELEPORT_LOCATION_HORDE);
}
Team BattlegroundEY::GetPrematureWinner()
{
if (GetTeamScore(TEAM_ALLIANCE) > GetTeamScore(TEAM_HORDE))
return ALLIANCE;
else if (GetTeamScore(TEAM_HORDE) > GetTeamScore(TEAM_ALLIANCE))
return HORDE;
return Battleground::GetPrematureWinner();
}
void BattlegroundEY::ProcessEvent(WorldObject* target, uint32 eventId, WorldObject* invoker)
{
Battleground::ProcessEvent(target, eventId, invoker);
if (invoker)
{
if (GameObject* gameobject = invoker->ToGameObject())
{
if (gameobject->GetGoType() == GAMEOBJECT_TYPE_CONTROL_ZONE)
{
if (!_controlZoneHandlers.contains(gameobject->GetEntry()))
return;
auto controlzone = gameobject->GetGOInfo()->controlZone;
BattlegroundEYControlZoneHandler& handler = *_controlZoneHandlers[invoker->GetEntry()];
if (eventId == controlzone.NeutralEventAlliance)
handler.HandleNeutralEventAlliance(gameobject);
else if (eventId == controlzone.NeutralEventHorde)
handler.HandleNeutralEventHorde(gameobject);
else if (eventId == controlzone.ProgressEventAlliance)
handler.HandleProgressEventAlliance(gameobject);
else if (eventId == controlzone.ProgressEventHorde)
handler.HandleProgressEventHorde(gameobject);
}
}
}
}
BattlegroundEYControlZoneHandler::BattlegroundEYControlZoneHandler(BattlegroundEY* bg, uint32 point) : ControlZoneHandler(),
_battleground(bg), _point(point)
{
}
void BattlegroundEYControlZoneHandler::HandleProgressEventHorde(GameObject* controlZone)
{
_battleground->EventTeamCapturedPoint(TEAM_HORDE, _point, controlZone);
}
void BattlegroundEYControlZoneHandler::HandleProgressEventAlliance(GameObject* controlZone)
{
_battleground->EventTeamCapturedPoint(TEAM_ALLIANCE, _point, controlZone);
}
void BattlegroundEYControlZoneHandler::HandleNeutralEventHorde(GameObject* controlZone)
{
_battleground->EventTeamLostPoint(TEAM_HORDE, _point, controlZone);
}
void BattlegroundEYControlZoneHandler::HandleNeutralEventAlliance(GameObject* controlZone)
{
_battleground->EventTeamLostPoint(TEAM_ALLIANCE, _point, controlZone);
}
@@ -1,319 +0,0 @@
/*
* 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 __BATTLEGROUNDEY_H
#define __BATTLEGROUNDEY_H
#include "Battleground.h"
#include "BattlegroundScore.h"
#include "Object.h"
#include "Timer.h"
static constexpr Seconds POINTS_TICK_TIME = 2s;
static constexpr Seconds BG_EY_FLAG_ASSAULT_TIMER = 30s;
static constexpr uint16 BG_EY_FLAG_BRUTAL_ASSAULT_STACK_COUNT = 5;
enum BG_EY_Misc
{
BG_EY_EVENT_START_BATTLE = 13180 // Achievement: Flurry
};
enum BG_EY_WorldStates
{
EY_ALLIANCE_RESOURCES = 1776,
EY_HORDE_RESOURCES = 1777,
EY_MAX_RESOURCES = 1780,
EY_ALLIANCE_BASE = 2752,
EY_HORDE_BASE = 2753,
DRAENEI_RUINS_HORDE_CONTROL = 2733,
DRAENEI_RUINS_ALLIANCE_CONTROL = 2732,
DRAENEI_RUINS_UNCONTROL = 2731,
MAGE_TOWER_ALLIANCE_CONTROL = 2730,
MAGE_TOWER_HORDE_CONTROL = 2729,
MAGE_TOWER_UNCONTROL = 2728,
FEL_REAVER_HORDE_CONTROL = 2727,
FEL_REAVER_ALLIANCE_CONTROL = 2726,
FEL_REAVER_UNCONTROL = 2725,
BLOOD_ELF_HORDE_CONTROL = 2724,
BLOOD_ELF_ALLIANCE_CONTROL = 2723,
BLOOD_ELF_UNCONTROL = 2722,
PROGRESS_BAR_PERCENT_GREY = 2720, //100 = empty (only grey), 0 = blue|red (no grey)
PROGRESS_BAR_STATUS = 2719, //50 init!, 48 ... hordak bere .. 33 .. 0 = full 100% hordacky, 100 = full alliance
PROGRESS_BAR_SHOW = 2718, //1 init, 0 druhy send - bez messagu, 1 = controlled aliance
NETHERSTORM_FLAG = 8863,
//set to 2 when flag is picked up, and to 1 if it is dropped
NETHERSTORM_FLAG_STATE_ALLIANCE = 9808,
NETHERSTORM_FLAG_STATE_HORDE = 9809,
DRAENEI_RUINS_HORDE_CONTROL_STATE = 17362,
DRAENEI_RUINS_ALLIANCE_CONTROL_STATE = 17366,
MAGE_TOWER_HORDE_CONTROL_STATE = 17361,
MAGE_TOWER_ALLIANCE_CONTROL_STATE = 17368,
FEL_REAVER_HORDE_CONTROL_STATE = 17364,
FEL_REAVER_ALLIANCE_CONTROL_STATE = 17367,
BLOOD_ELF_HORDE_CONTROL_STATE = 17363,
BLOOD_ELF_ALLIANCE_CONTROL_STATE = 17365,
};
enum BG_EY_Sounds
{
//strange ids, but sure about them
BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212,
BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213,
BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174,
BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
BG_EY_SOUND_FLAG_RESET = 8192
};
enum BG_EY_Spells
{
BG_EY_NETHERSTORM_FLAG_SPELL = 34976,
BG_EY_PLAYER_DROPPED_FLAG_SPELL = 34991,
// Focused/Brutal Assault
BG_EY_FOCUSED_ASSAULT_SPELL = 46392,
BG_EY_BRUTAL_ASSAULT_SPELL = 46393
};
enum EYBattlegroundObjectEntry
{
BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door
BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door
BG_OBJECT_FLAG2_EY_ENTRY = 208977, //Netherstorm flag (flagstand)
BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt
BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt
BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt
BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083, //Draenei Tower Cap Pt
};
enum EYBattlegroundPointsTrigger
{
AREATRIGGER_CAPTURE_FLAG = 33
};
enum EYBattlegroundPoints
{
FEL_REAVER = 0,
BLOOD_ELF = 1,
DRAENEI_RUINS = 2,
MAGE_TOWER = 3,
EY_PLAYERS_OUT_OF_POINTS = 4,
EY_POINTS_MAX = 4
};
#define BG_EY_NotEYWeekendHonorTicks 260
#define BG_EY_EYWeekendHonorTicks 160
enum BG_EY_Score
{
BG_EY_WARNING_NEAR_VICTORY_SCORE = 1200,
BG_EY_MAX_TEAM_SCORE = 1500
};
enum BG_EY_FlagState
{
BG_EY_FLAG_STATE_ON_BASE = 0,
BG_EY_FLAG_STATE_WAIT_RESPAWN = 1,
BG_EY_FLAG_STATE_ON_PLAYER = 2,
BG_EY_FLAG_STATE_ON_GROUND = 3
};
enum EYBattlegroundPointState
{
EY_POINT_NO_OWNER = 0,
EY_POINT_STATE_UNCONTROLLED = 0,
EY_POINT_UNDER_CONTROL = 3
};
enum BG_EY_ExploitTeleportLocations
{
EY_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3773,
EY_EXPLOIT_TELEPORT_LOCATION_HORDE = 3772
};
enum BG_EY_BroadcastTexts
{
BG_EY_TEXT_ALLIANCE_TAKEN_FEL_REAVER_RUINS = 17828,
BG_EY_TEXT_HORDE_TAKEN_FEL_REAVER_RUINS = 17829,
BG_EY_TEXT_ALLIANCE_LOST_FEL_REAVER_RUINS = 91961,
BG_EY_TEXT_HORDE_LOST_FEL_REAVER_RUINS = 91962,
BG_EY_TEXT_ALLIANCE_TAKEN_BLOOD_ELF_TOWER = 17819,
BG_EY_TEXT_HORDE_TAKEN_BLOOD_ELF_TOWER = 17823,
BG_EY_TEXT_ALLIANCE_LOST_BLOOD_ELF_TOWER = 91957,
BG_EY_TEXT_HORDE_LOST_BLOOD_ELF_TOWER = 91958,
BG_EY_TEXT_ALLIANCE_TAKEN_DRAENEI_RUINS = 17827,
BG_EY_TEXT_HORDE_TAKEN_DRAENEI_RUINS = 91917,
BG_EY_TEXT_ALLIANCE_LOST_DRAENEI_RUINS = 91959,
BG_EY_TEXT_HORDE_LOST_DRAENEI_RUINS = 91960,
BG_EY_TEXT_ALLIANCE_TAKEN_MAGE_TOWER = 17824,
BG_EY_TEXT_HORDE_TAKEN_MAGE_TOWER = 17825,
BG_EY_TEXT_ALLIANCE_LOST_MAGE_TOWER = 91963,
BG_EY_TEXT_HORDE_LOST_MAGE_TOWER = 91964,
BG_EY_TEXT_TAKEN_FLAG = 18359,
BG_EY_TEXT_FLAG_DROPPED = 18361,
BG_EY_TEXT_FLAG_RESET = 18364,
BG_EY_TEXT_ALLIANCE_CAPTURED_FLAG = 18375,
BG_EY_TEXT_HORDE_CAPTURED_FLAG = 18384,
};
struct BattlegroundEYPointIconsStruct
{
BattlegroundEYPointIconsStruct(uint32 _WorldStateControlIndex, uint32 _WorldStateAllianceControlledIndex, uint32 _WorldStateHordeControlledIndex,
uint32 worldStateAllianceStatusBarIcon, uint32 worldStateHordeStatusBarIcon)
: WorldStateControlIndex(_WorldStateControlIndex), WorldStateAllianceControlledIndex(_WorldStateAllianceControlledIndex), WorldStateHordeControlledIndex(_WorldStateHordeControlledIndex),
WorldStateAllianceStatusBarIcon(worldStateAllianceStatusBarIcon), WorldStateHordeStatusBarIcon(worldStateHordeStatusBarIcon) { }
uint32 WorldStateControlIndex;
uint32 WorldStateAllianceControlledIndex;
uint32 WorldStateHordeControlledIndex;
uint32 WorldStateAllianceStatusBarIcon;
uint32 WorldStateHordeStatusBarIcon;
};
struct BattlegroundEYLosingPointStruct
{
BattlegroundEYLosingPointStruct(uint32 _MessageIdAlliance, uint32 _MessageIdHorde)
: MessageIdAlliance(_MessageIdAlliance), MessageIdHorde(_MessageIdHorde)
{ }
uint32 MessageIdAlliance;
uint32 MessageIdHorde;
};
struct BattlegroundEYCapturingPointStruct
{
BattlegroundEYCapturingPointStruct(uint32 _MessageIdAlliance, uint32 _MessageIdHorde)
: MessageIdAlliance(_MessageIdAlliance), MessageIdHorde(_MessageIdHorde)
{ }
uint32 MessageIdAlliance;
uint32 MessageIdHorde;
};
class BattlegroundEY;
class BattlegroundEYControlZoneHandler : public ControlZoneHandler
{
public:
explicit BattlegroundEYControlZoneHandler(BattlegroundEY* bg, uint32 point);
void HandleProgressEventHorde(GameObject* controlZone) override;
void HandleProgressEventAlliance(GameObject* controlZone) override;
void HandleNeutralEventHorde(GameObject* controlZone) override;
void HandleNeutralEventAlliance(GameObject* controlZone) override;
uint32 GetPoint() const { return _point; }
private:
BattlegroundEY* _battleground;
uint32 _point;
};
const std::array<uint8, EY_POINTS_MAX> BG_EY_TickPoints = { 1, 2, 5, 10 };
const std::array<uint32, EY_POINTS_MAX> BG_EY_FlagPoints = { 75, 85, 100, 500 };
//constant arrays:
const std::array<BattlegroundEYPointIconsStruct, EY_POINTS_MAX> m_PointsIconStruct =
{
BattlegroundEYPointIconsStruct(FEL_REAVER_UNCONTROL, FEL_REAVER_ALLIANCE_CONTROL, FEL_REAVER_HORDE_CONTROL, FEL_REAVER_ALLIANCE_CONTROL_STATE, FEL_REAVER_HORDE_CONTROL_STATE),
BattlegroundEYPointIconsStruct(BLOOD_ELF_UNCONTROL, BLOOD_ELF_ALLIANCE_CONTROL, BLOOD_ELF_HORDE_CONTROL, BLOOD_ELF_ALLIANCE_CONTROL_STATE, BLOOD_ELF_HORDE_CONTROL_STATE),
BattlegroundEYPointIconsStruct(DRAENEI_RUINS_UNCONTROL, DRAENEI_RUINS_ALLIANCE_CONTROL, DRAENEI_RUINS_HORDE_CONTROL, DRAENEI_RUINS_ALLIANCE_CONTROL_STATE, DRAENEI_RUINS_HORDE_CONTROL_STATE),
BattlegroundEYPointIconsStruct(MAGE_TOWER_UNCONTROL, MAGE_TOWER_ALLIANCE_CONTROL, MAGE_TOWER_HORDE_CONTROL, MAGE_TOWER_ALLIANCE_CONTROL_STATE, MAGE_TOWER_HORDE_CONTROL_STATE)
};
const std::array<BattlegroundEYLosingPointStruct, EY_POINTS_MAX> m_LosingPointTypes =
{
BattlegroundEYLosingPointStruct(BG_EY_TEXT_ALLIANCE_LOST_FEL_REAVER_RUINS, BG_EY_TEXT_HORDE_LOST_FEL_REAVER_RUINS),
BattlegroundEYLosingPointStruct(BG_EY_TEXT_ALLIANCE_LOST_BLOOD_ELF_TOWER, BG_EY_TEXT_HORDE_LOST_BLOOD_ELF_TOWER),
BattlegroundEYLosingPointStruct(BG_EY_TEXT_ALLIANCE_LOST_DRAENEI_RUINS, BG_EY_TEXT_HORDE_LOST_DRAENEI_RUINS),
BattlegroundEYLosingPointStruct(BG_EY_TEXT_ALLIANCE_LOST_MAGE_TOWER, BG_EY_TEXT_HORDE_LOST_MAGE_TOWER)
};
const std::array<BattlegroundEYCapturingPointStruct, EY_POINTS_MAX> m_CapturingPointTypes =
{
BattlegroundEYCapturingPointStruct(BG_EY_TEXT_ALLIANCE_TAKEN_FEL_REAVER_RUINS, BG_EY_TEXT_HORDE_TAKEN_FEL_REAVER_RUINS),
BattlegroundEYCapturingPointStruct(BG_EY_TEXT_ALLIANCE_TAKEN_BLOOD_ELF_TOWER, BG_EY_TEXT_HORDE_TAKEN_BLOOD_ELF_TOWER),
BattlegroundEYCapturingPointStruct(BG_EY_TEXT_ALLIANCE_TAKEN_DRAENEI_RUINS, BG_EY_TEXT_HORDE_TAKEN_DRAENEI_RUINS),
BattlegroundEYCapturingPointStruct(BG_EY_TEXT_ALLIANCE_TAKEN_MAGE_TOWER, BG_EY_TEXT_HORDE_TAKEN_MAGE_TOWER)
};
class BattlegroundEY : public Battleground
{
public:
BattlegroundEY(BattlegroundTemplate const* battlegroundTemplate);
~BattlegroundEY();
/* inherited from BattlegroundClass */
void StartingEventOpenDoors() override;
void HandleKillPlayer(Player* player, Player* killer) override;
WorldSafeLocsEntry const* GetExploitTeleportLocation(Team team) override;
bool SetupBattleground() override;
void Reset() override;
void UpdateTeamScore(TeamId Team);
void EndBattleground(Team winner) override;
Team GetPrematureWinner() override;
void ProcessEvent(WorldObject* target, uint32 eventId, WorldObject* invoker) override;
void PostUpdateImpl(uint32 diff) override;
void EventTeamCapturedPoint(TeamId teamId, uint32 point, GameObject* controlZone);
void EventTeamLostPoint(TeamId teamId, uint32 point, GameObject* controlZone);
void UpdatePointsCount(TeamId teamId);
void OnGameObjectCreate(GameObject* gameObject) override;
bool CanCaptureFlag([[maybe_unused]] AreaTrigger* areaTrigger, [[maybe_unused]] Player* player) override;
void OnCaptureFlag([[maybe_unused]] AreaTrigger* areaTrigger, [[maybe_unused]] Player* player) override;
void OnFlagStateChange(GameObject* flagInBase, FlagState oldValue, FlagState newValue, Player* player) override;
private:
/* Scorekeeping */
void AddPoints(Team team, uint32 Points);
void RemovePoint(Team team, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(team)] -= Points; }
void SetTeamPoint(Team team, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(team)] = Points; }
uint8 GetControlledBaseCount(TeamId teamId) const;
std::array<uint32, PVP_TEAMS_COUNT> m_HonorScoreTics;
uint32 m_FlagCapturedBgObjectType; // type that should be despawned when flag is captured
TimeTracker _pointsTimer;
uint32 m_HonorTics;
std::unordered_map<uint32, std::unique_ptr<BattlegroundEYControlZoneHandler>> _controlZoneHandlers;
GuidUnorderedSet _doorGUIDs;
ObjectGuid _flagGUID;
// Focused/Brutal Assault
bool _assaultEnabled;
TimeTracker _flagAssaultTimer;
uint16 _assaultStackCount;
void DoForFlagKeepers(std::function<void(Player*)> action) const;
void ResetAssaultDebuff();
void ApplyAssaultDebuffToPlayer(Player* player);
void RemoveAssaultDebuffFromPlayer(Player* player);
};
#endif
@@ -1,706 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundIC.h"
#include "Creature.h"
#include "GameObject.h"
#include "Log.h"
#include "Map.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "TemporarySummon.h"
#include "Transport.h"
#include "UnitAI.h"
#include "Vehicle.h"
enum IsleOfConquestPvpStats
{
PVP_STAT_BASES_ASSAULTED = 245,
PVP_STAT_BASES_DEFENDED = 246
};
enum IsleOfConquestGameObjects
{
GO_TELEPORTER_1 = 195314, // 195314 H-OUT 66549
GO_TELEPORTER_2 = 195313, // 195313 H-IN 66548
GO_TELEPORTER_3 = 195315, // 195315 A-OUT 66549
GO_TELEPORTER_4 = 195316, // 195316 A-IN 66548
GO_TELEPORTER_EFFECTS_A = 195701,
GO_TELEPORTER_EFFECTS_H = 195702,
GO_DOODAD_HU_PORTCULLIS01 = 195436,
GO_DOODAD_ND_HUMAN_GATE_CLOSEDFX_DOOR01 = 195703,
GO_DOODAD_PORTCULLISACTIVE02 = 195452,
GO_DOODAD_VR_PORTCULLIS01 = 195437,
GO_HORDE_GATE_1 = 195494,
GO_HORDE_GATE_2 = 195495,
GO_HORDE_GATE_3 = 195496,
GO_ALLIANCE_GATE_1 = 195699,
GO_ALLIANCE_GATE_2 = 195700,
GO_ALLIANCE_GATE_3 = 195698,
GO_DOODAD_ND_WINTERORC_WALL_GATEFX_DOOR01 = 195491,
// banners
GO_BANNER_WORKSHOP_CONTROLLED_H = 195130,
GO_BANNER_WORKSHOP_CONTROLLED_A = 195132,
GO_BANNER_WORKSHOP_CONTROLLED_N = 195133,
GO_BANNER_WORKSHOP_CONTESTED_A = 195144,
GO_BANNER_WORKSHOP_CONTESTED_H = 195145,
GO_BANNER_DOCKS_CONTROLLED_A = 195149,
GO_BANNER_DOCKS_CONTESTED_A = 195150,
GO_BANNER_DOCKS_CONTROLLED_H = 195151,
GO_BANNER_DOCKS_CONTESTED_H = 195152,
GO_BANNER_DOCKS_CONTROLLED_N = 195157,
GO_BANNER_HANGAR_CONTROLLED_A = 195153,
GO_BANNER_HANGAR_CONTESTED_A = 195154,
GO_BANNER_HANGAR_CONTROLLED_H = 195155,
GO_BANNER_HANGAR_CONTESTED_H = 195156,
GO_BANNER_HANGAR_CONTROLLED_N = 195158,
GO_BANNER_QUARRY_CONTROLLED_A = 195334,
GO_BANNER_QUARRY_CONTROLLED_H = 195336,
GO_BANNER_QUARRY_CONTESTED_A = 195335,
GO_BANNER_QUARRY_CONTESTED_H = 195337,
GO_BANNER_QUARRY_CONTROLLED_N = 195338,
GO_BANNER_REFINERY_CONTROLLED_A = 195339,
GO_BANNER_REFINERY_CONTROLLED_H = 195341,
GO_BANNER_REFINERY_CONTESTED_A = 195340,
GO_BANNER_REFINERY_CONTESTED_H = 195342,
GO_BANNER_REFINERY_CONTROLLED_N = 195343,
GO_BANNER_HORDE_KEEP_CONTROLLED_A = 195391,
GO_BANNER_HORDE_KEEP_CONTROLLED_H = 195393,
GO_BANNER_HORDE_KEEP_CONTESTED_A = 195392,
GO_BANNER_HORDE_KEEP_CONTESTED_H = 195394,
GO_BANNER_ALLIANCE_KEEP_CONTROLLED_A = 195396,
GO_BANNER_ALLIANCE_KEEP_CONTROLLED_H = 195398,
GO_BANNER_ALLIANCE_KEEP_CONTESTED_A = 195397,
GO_BANNER_ALLIANCE_KEEP_CONTESTED_H = 195399,
GO_KEEP_GATE_H = 195223,
GO_KEEP_GATE_A = 195451,
GO_KEEP_GATE_2_A = 195452,
GO_HORDE_GUNSHIP = 195276,
GO_ALLIANCE_GUNSHIP = 195121
};
static constexpr Seconds IOC_RESOURCE_TIMER = 45s;
Position const GunshipTeleportTriggerPosition[2] =
{
{ 11.69964981079101562f, 0.034145999699831008f, 20.62075996398925781f, 3.211405754089355468f },
{ 7.30560922622680664f, -0.09524600207805633f, 34.51021575927734375f, 3.159045934677124023f }
};
BattlegroundIC::BattlegroundIC(BattlegroundTemplate const* battlegroundTemplate) : Battleground(battlegroundTemplate)
{
_factionReinforcements = { MAX_REINFORCEMENTS, MAX_REINFORCEMENTS };
_gateStatus = { BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK };
_gunshipGUIDs = { };
_cannonGUIDs = { };
_nodePoints = { };
_keepGateGUIDs = { };
_keepBannerGUIDs = { };
_nodePoints[NODE_TYPE_REFINERY] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_REFINERY]);
_nodePoints[NODE_TYPE_QUARRY] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_QUARRY]);
_nodePoints[NODE_TYPE_DOCKS] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_DOCKS]);
_nodePoints[NODE_TYPE_HANGAR] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_HANGAR]);
_nodePoints[NODE_TYPE_WORKSHOP] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_WORKSHOP]);
_nodePoints[NODE_TYPE_GRAVEYARD_A] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::ControlledA, nodePointInitial[NODE_TYPE_GRAVEYARD_A]);
_nodePoints[NODE_TYPE_GRAVEYARD_H] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::ControlledH, nodePointInitial[NODE_TYPE_GRAVEYARD_H]);
_resourceTimer.Reset(IOC_RESOURCE_TIMER);
}
BattlegroundIC::~BattlegroundIC() = default;
void BattlegroundIC::PostUpdateImpl(uint32 diff)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
_scheduler.Update(diff);
_resourceTimer.Update(diff);
if (_resourceTimer.Passed())
{
for (uint8 i = 0; i < NODE_TYPE_DOCKS; ++i)
{
if (_nodePoints[i]->GetLastControlledTeam() != TEAM_NEUTRAL && !_nodePoints[i]->IsContested())
{
_factionReinforcements[_nodePoints[i]->GetLastControlledTeam()] += 1;
RewardHonorToTeam(RESOURCE_HONOR_AMOUNT, _nodePoints[i]->GetLastControlledTeam() == TEAM_ALLIANCE ? ALLIANCE : HORDE);
UpdateWorldState((_nodePoints[i]->GetLastControlledTeam() == TEAM_ALLIANCE ? BG_IC_ALLIANCE_REINFORCEMENTS : BG_IC_HORDE_REINFORCEMENTS), _factionReinforcements[_nodePoints[i]->GetLastControlledTeam()]);
}
}
_resourceTimer.Reset(IOC_RESOURCE_TIMER);
}
}
void BattlegroundIC::StartingEventOpenDoors()
{
auto gameobjectAction = [&](GuidVector const& guids, std::function<void(GameObject*)> const& action) -> void
{
for (ObjectGuid const& guid : guids)
if (GameObject* gameObject = GetBgMap()->GetGameObject(guid))
action(gameObject);
};
gameobjectAction(_mainGateDoorGUIDs, [&](GameObject* gameobject) -> void
{
gameobject->UseDoorOrButton();
gameobject->DespawnOrUnsummon(20s);
});
gameobjectAction(_portcullisGUIDs, [&](GameObject* gameobject) -> void
{
gameobject->UseDoorOrButton();
});
gameobjectAction(_teleporterGUIDs, [&](GameObject* gameobject) -> void
{
gameobject->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
});
gameobjectAction(_teleporterEffectGUIDs, [&](GameObject* gameobject) -> void
{
gameobject->SetGoState(GO_STATE_ACTIVE);
});
_scheduler.Schedule(20s, [&](TaskContext)
{
for (ObjectGuid const& guid : _wallGUIDs)
if (GameObject* gameobject = GetBgMap()->GetGameObject(guid))
gameobject->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED);
});
}
void BattlegroundIC::HandleKillUnit(Creature* unit, Unit* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
uint32 entry = unit->GetEntry();
if (entry == NPC_HIGH_COMMANDER_HALFORD_WYRMBANE)
{
RewardHonorToTeam(WINNER_HONOR_AMOUNT, HORDE);
EndBattleground(HORDE);
}
else if (entry == NPC_OVERLORD_AGMAR)
{
RewardHonorToTeam(WINNER_HONOR_AMOUNT, ALLIANCE);
EndBattleground(ALLIANCE);
}
//Achievement Mowed Down
// TO-DO: This should be done on the script of each vehicle of the BG.
if (unit->IsVehicle())
{
if (Player* killerPlayer = killer->GetCharmerOrOwnerPlayerOrPlayerItself())
killerPlayer->CastSpell(killerPlayer, SPELL_DESTROYED_VEHICLE_ACHIEVEMENT, true);
}
}
void BattlegroundIC::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
Battleground::HandleKillPlayer(player, killer);
TeamId const victimTeamId = GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID()));
_factionReinforcements[victimTeamId] -= 1;
UpdateWorldState((GetPlayerTeam(player->GetGUID()) == ALLIANCE ? BG_IC_ALLIANCE_REINFORCEMENTS : BG_IC_HORDE_REINFORCEMENTS), _factionReinforcements[victimTeamId]);
// we must end the battleground
if (_factionReinforcements[victimTeamId] < 1)
EndBattleground(GetPlayerTeam(killer->GetGUID()));
}
uint32 BattlegroundIC::GetGateIDFromEntry(uint32 id)
{
switch (id)
{
case GO_HORDE_GATE_1:
return BG_IC_H_FRONT;
case GO_HORDE_GATE_2:
return BG_IC_H_WEST;
case GO_HORDE_GATE_3:
return BG_IC_H_EAST;
case GO_ALLIANCE_GATE_3:
return BG_IC_A_FRONT;
case GO_ALLIANCE_GATE_1:
return BG_IC_A_WEST;
case GO_ALLIANCE_GATE_2:
return BG_IC_A_EAST;
default:
return 0;
}
}
int32 BattlegroundIC::GetWorldStateFromGateEntry(uint32 id, bool open)
{
int32 uws = 0;
switch (id)
{
case GO_HORDE_GATE_1:
uws = (open ? BG_IC_GATE_FRONT_H_WS_OPEN : BG_IC_GATE_FRONT_H_WS_CLOSED);
break;
case GO_HORDE_GATE_2:
uws = (open ? BG_IC_GATE_WEST_H_WS_OPEN : BG_IC_GATE_WEST_H_WS_CLOSED);
break;
case GO_HORDE_GATE_3:
uws = (open ? BG_IC_GATE_EAST_H_WS_OPEN : BG_IC_GATE_EAST_H_WS_CLOSED);
break;
case GO_ALLIANCE_GATE_3:
uws = (open ? BG_IC_GATE_FRONT_A_WS_OPEN : BG_IC_GATE_FRONT_A_WS_CLOSED);
break;
case GO_ALLIANCE_GATE_1:
uws = (open ? BG_IC_GATE_WEST_A_WS_OPEN : BG_IC_GATE_WEST_A_WS_CLOSED);
break;
case GO_ALLIANCE_GATE_2:
uws = (open ? BG_IC_GATE_EAST_A_WS_OPEN : BG_IC_GATE_EAST_A_WS_CLOSED);
break;
default:
break;
}
return uws;
}
void BattlegroundIC::UpdateNodeWorldState(ICNodePoint const& node)
{
UpdateWorldState(node.GetNodeInfo().WorldStateIds.ConflictA, node.GetState() == IsleOfConquestNodeState::ConflictA);
UpdateWorldState(node.GetNodeInfo().WorldStateIds.ConflictH, node.GetState() == IsleOfConquestNodeState::ConflictH);
UpdateWorldState(node.GetNodeInfo().WorldStateIds.ControlledA, node.GetState() == IsleOfConquestNodeState::ControlledA);
UpdateWorldState(node.GetNodeInfo().WorldStateIds.ControlledH, node.GetState() == IsleOfConquestNodeState::ControlledH);
UpdateWorldState(node.GetNodeInfo().WorldStateIds.Uncontrolled, node.GetState() == IsleOfConquestNodeState::Neutral);
}
ICNodePointType BattlegroundIC::BannerToNodeType(uint32 bannerId)
{
switch (bannerId)
{
case GO_BANNER_ALLIANCE_KEEP_CONTESTED_A:
case GO_BANNER_ALLIANCE_KEEP_CONTESTED_H:
case GO_BANNER_ALLIANCE_KEEP_CONTROLLED_A:
case GO_BANNER_ALLIANCE_KEEP_CONTROLLED_H:
return NODE_TYPE_GRAVEYARD_A;
case GO_BANNER_HORDE_KEEP_CONTESTED_A:
case GO_BANNER_HORDE_KEEP_CONTESTED_H:
case GO_BANNER_HORDE_KEEP_CONTROLLED_A:
case GO_BANNER_HORDE_KEEP_CONTROLLED_H:
return NODE_TYPE_GRAVEYARD_H;
case GO_BANNER_DOCKS_CONTESTED_A:
case GO_BANNER_DOCKS_CONTESTED_H:
case GO_BANNER_DOCKS_CONTROLLED_A:
case GO_BANNER_DOCKS_CONTROLLED_H:
case GO_BANNER_DOCKS_CONTROLLED_N:
return NODE_TYPE_DOCKS;
case GO_BANNER_HANGAR_CONTESTED_A:
case GO_BANNER_HANGAR_CONTESTED_H:
case GO_BANNER_HANGAR_CONTROLLED_A:
case GO_BANNER_HANGAR_CONTROLLED_H:
case GO_BANNER_HANGAR_CONTROLLED_N:
return NODE_TYPE_HANGAR;
case GO_BANNER_WORKSHOP_CONTESTED_A:
case GO_BANNER_WORKSHOP_CONTESTED_H:
case GO_BANNER_WORKSHOP_CONTROLLED_A:
case GO_BANNER_WORKSHOP_CONTROLLED_H:
case GO_BANNER_WORKSHOP_CONTROLLED_N:
return NODE_TYPE_WORKSHOP;
case GO_BANNER_QUARRY_CONTESTED_A:
case GO_BANNER_QUARRY_CONTESTED_H:
case GO_BANNER_QUARRY_CONTROLLED_A:
case GO_BANNER_QUARRY_CONTROLLED_H:
case GO_BANNER_QUARRY_CONTROLLED_N:
return NODE_TYPE_QUARRY;
case GO_BANNER_REFINERY_CONTESTED_A:
case GO_BANNER_REFINERY_CONTESTED_H:
case GO_BANNER_REFINERY_CONTROLLED_A:
case GO_BANNER_REFINERY_CONTROLLED_H:
case GO_BANNER_REFINERY_CONTROLLED_N:
return NODE_TYPE_REFINERY;
default:
break;
}
return MAX_NODE_TYPES;
}
void BattlegroundIC::HandleCapturedNodes(ICNodePoint& node)
{
if (node.GetLastControlledTeam() == TEAM_NEUTRAL)
return;
switch (node.GetNodeInfo().NodeType)
{
case NODE_TYPE_QUARRY:
case NODE_TYPE_REFINERY:
GetBgMap()->UpdateAreaDependentAuras();
break;
case NODE_TYPE_HANGAR:
if (Transport* transport = GetBgMap()->GetTransport(_gunshipGUIDs[node.GetLastControlledTeam()]))
{
// Can't have this in spawngroup, creature is on a transport
if (TempSummon* trigger = transport->SummonPassenger(NPC_WORLD_TRIGGER_NOT_FLOATING, GunshipTeleportTriggerPosition[node.GetLastControlledTeam()], TEMPSUMMON_MANUAL_DESPAWN))
_gunshipTeleportTarget = trigger->GetGUID();
transport->EnableMovement(true);
}
for (ObjectGuid const& guid : _cannonGUIDs[node.GetLastControlledTeam()])
if (Creature* cannon = GetBgMap()->GetCreature(guid))
cannon->SetUninteractible(false);
break;
default:
break;
}
}
WorldSafeLocsEntry const* BattlegroundIC::GetExploitTeleportLocation(Team team)
{
return sObjectMgr->GetWorldSafeLoc(team == ALLIANCE ? IC_EXPLOIT_TELEPORT_LOCATION_ALLIANCE : IC_EXPLOIT_TELEPORT_LOCATION_HORDE);
}
void BattlegroundIC::OnCreatureCreate(Creature* creature)
{
Battleground::OnCreatureCreate(creature);
if (creature->HasStringId("bg_ioc_faction_1735"))
creature->SetFaction(FACTION_HORDE_GENERIC_WG);
else if (creature->HasStringId("bg_ioc_faction_1732"))
creature->SetFaction(FACTION_ALLIANCE_GENERIC_WG);
switch (creature->GetEntry())
{
case NPC_ALLIANCE_GUNSHIP_CANNON:
_cannonGUIDs[TEAM_ALLIANCE].emplace_back(creature->GetGUID());
creature->SetUninteractible(true);
creature->SetControlled(true, UNIT_STATE_ROOT);
break;
case NPC_HORDE_GUNSHIP_CANNON:
_cannonGUIDs[TEAM_HORDE].emplace_back(creature->GetGUID());
creature->SetUninteractible(true);
creature->SetControlled(true, UNIT_STATE_ROOT);
break;
default:
break;
}
}
void BattlegroundIC::OnGameObjectCreate(GameObject* gameobject)
{
Battleground::OnGameObjectCreate(gameobject);
if (gameobject->IsDestructibleBuilding())
_wallGUIDs.emplace_back(gameobject->GetGUID());
if (gameobject->HasStringId("bg_ioc_faction_1735"))
gameobject->SetFaction(FACTION_HORDE_GENERIC_WG);
else if (gameobject->HasStringId("bg_ioc_faction_1732"))
gameobject->SetFaction(FACTION_ALLIANCE_GENERIC_WG);
switch (gameobject->GetEntry())
{
case GO_TELEPORTER_1:
case GO_TELEPORTER_2:
case GO_TELEPORTER_3:
case GO_TELEPORTER_4:
_teleporterGUIDs.emplace_back(gameobject->GetGUID());
break;
case GO_TELEPORTER_EFFECTS_A:
case GO_TELEPORTER_EFFECTS_H:
_teleporterEffectGUIDs.emplace_back(gameobject->GetGUID());
break;
case GO_DOODAD_ND_HUMAN_GATE_CLOSEDFX_DOOR01:
case GO_DOODAD_ND_WINTERORC_WALL_GATEFX_DOOR01:
_mainGateDoorGUIDs.emplace_back(gameobject->GetGUID());
break;
case GO_DOODAD_HU_PORTCULLIS01:
case GO_DOODAD_VR_PORTCULLIS01:
_portcullisGUIDs.emplace_back(gameobject->GetGUID());
break;
case GO_KEEP_GATE_H:
_keepGateGUIDs[TEAM_HORDE].emplace_back(gameobject->GetGUID());
break;
case GO_KEEP_GATE_A:
case GO_KEEP_GATE_2_A:
_keepGateGUIDs[TEAM_ALLIANCE].emplace_back(gameobject->GetGUID());
break;
case GO_BANNER_ALLIANCE_KEEP_CONTROLLED_A:
_keepBannerGUIDs[TEAM_ALLIANCE] = gameobject->GetGUID();
break;
case GO_BANNER_HORDE_KEEP_CONTROLLED_H:
_keepBannerGUIDs[TEAM_HORDE] = gameobject->GetGUID();
break;
default:
break;
}
}
void BattlegroundIC::OnMapSet(BattlegroundMap* map)
{
Battleground::OnMapSet(map);
if (Transport* transport = sTransportMgr->CreateTransport(GO_HORDE_GUNSHIP, map))
{
_gunshipGUIDs[TEAM_HORDE] = transport->GetGUID();
transport->EnableMovement(false);
}
if (Transport* transport = sTransportMgr->CreateTransport(GO_ALLIANCE_GUNSHIP, map))
{
_gunshipGUIDs[TEAM_ALLIANCE] = transport->GetGUID();
transport->EnableMovement(false);
}
}
void BattlegroundIC::DoAction(uint32 actionId, WorldObject* source, WorldObject* target)
{
switch (actionId)
{
case ACTION_IOC_INTERACT_CAPTURABLE_OBJECT:
OnPlayerInteractWithBanner(WorldObject::ToPlayer(source), WorldObject::ToGameObject(target));
break;
case ACTION_IOC_CAPTURE_CAPTURABLE_OBJECT:
HandleCaptureNodeAction(WorldObject::ToGameObject(target));
break;
default:
break;
}
}
void BattlegroundIC::OnPlayerInteractWithBanner(Player* player, GameObject* banner)
{
if (!player || !banner)
return;
Team const playerTeam = GetPlayerTeam(player->GetGUID());
TeamId const playerTeamId = GetTeamIndexByTeamId(playerTeam);
ICNodePointType const nodeType = BannerToNodeType(banner->GetEntry());
if (nodeType == MAX_NODE_TYPES)
return;
ICNodePoint& node = *_nodePoints[nodeType];
bool assault = false;
bool defend = false;
switch (node.GetState())
{
case IsleOfConquestNodeState::Neutral:
assault = true;
break;
case IsleOfConquestNodeState::ControlledH:
assault = playerTeamId != TEAM_HORDE;
break;
case IsleOfConquestNodeState::ControlledA:
assault = playerTeamId != TEAM_ALLIANCE;
break;
case IsleOfConquestNodeState::ConflictA:
defend = playerTeamId == node.GetLastControlledTeam();
assault = !defend && playerTeamId == TEAM_HORDE;
break;
case IsleOfConquestNodeState::ConflictH:
defend = playerTeamId == node.GetLastControlledTeam();
assault = !defend && playerTeamId == TEAM_ALLIANCE;
break;
}
if (assault)
OnPlayerAssaultNode(player, node);
else if (defend)
OnPlayerDefendNode(player, node);
GetBgMap()->UpdateSpawnGroupConditions();
}
void BattlegroundIC::OnPlayerAssaultNode(Player* player, ICNodePoint& node)
{
if (!player)
return;
Team const playerTeam = GetPlayerTeam(player->GetGUID());
TeamId const playerTeamId = GetTeamIndexByTeamId(playerTeam);
IsleOfConquestNodeState const newState = playerTeamId == TEAM_HORDE ? IsleOfConquestNodeState::ConflictH : IsleOfConquestNodeState::ConflictA;
node.UpdateState(newState);
UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
ChatMsg const messageType = playerTeamId == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
SendBroadcastText(node.GetNodeInfo().TextIds.Assaulted, messageType, player);
UpdateNodeWorldState(node);
// apply side effects of each node, only if it wasn't neutral before
if (node.GetLastControlledTeam() == TEAM_NEUTRAL)
return;
switch (node.GetNodeInfo().NodeType)
{
case NODE_TYPE_HANGAR:
if (Transport* transport = GetBgMap()->GetTransport(_gunshipGUIDs[node.GetLastControlledTeam()]))
transport->EnableMovement(false);
for (ObjectGuid const& guid : _cannonGUIDs[node.GetLastControlledTeam()])
{
if (Creature* cannon = GetBgMap()->GetCreature(guid))
{
cannon->GetVehicleKit()->RemoveAllPassengers();
cannon->SetUninteractible(true);
}
}
// Despawn teleport trigger target
if (Creature* creature = FindBgMap()->GetCreature(_gunshipTeleportTarget))
creature->DespawnOrUnsummon();
break;
default:
break;
}
}
void BattlegroundIC::OnPlayerDefendNode(Player* player, ICNodePoint& node)
{
if (!player)
return;
Team const playerTeam = GetPlayerTeam(player->GetGUID());
TeamId const playerTeamId = GetTeamIndexByTeamId(playerTeam);
node.UpdateState(playerTeamId == TEAM_HORDE ? IsleOfConquestNodeState::ControlledH : IsleOfConquestNodeState::ControlledA);
HandleCapturedNodes(node);
UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
ChatMsg const messageType = playerTeamId == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
SendBroadcastText(node.GetNodeInfo().TextIds.Defended, messageType, player);
UpdateNodeWorldState(node);
}
void BattlegroundIC::ProcessEvent(WorldObject* target, uint32 eventId, WorldObject* invoker)
{
Battleground::ProcessEvent(target, eventId, invoker);
if (GameObject* obj = Object::ToGameObject(target))
if (obj->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
if (obj->GetGOInfo()->destructibleBuilding.DestroyedEvent == eventId)
OnGateDestroyed(obj, invoker);
}
void BattlegroundIC::HandleCaptureNodeAction(GameObject* banner)
{
if (!banner)
return;
ICNodePointType const nodeType = BannerToNodeType(banner->GetEntry());
if (nodeType == MAX_NODE_TYPES)
return;
ICNodePoint& node = *_nodePoints[nodeType];
if (node.GetState() == IsleOfConquestNodeState::ConflictH)
node.UpdateState(IsleOfConquestNodeState::ControlledH);
else if (node.GetState() == IsleOfConquestNodeState::ConflictA)
node.UpdateState(IsleOfConquestNodeState::ControlledA);
HandleCapturedNodes(node);
ChatMsg const messageType = node.GetLastControlledTeam() == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
uint32 const textId = node.GetLastControlledTeam() == TEAM_ALLIANCE ? node.GetNodeInfo().TextIds.AllianceTaken : node.GetNodeInfo().TextIds.HordeTaken;
SendBroadcastText(textId, messageType);
UpdateNodeWorldState(node);
}
void BattlegroundIC::OnGateDestroyed(GameObject* gate, WorldObject* destroyer)
{
_gateStatus[GetGateIDFromEntry(gate->GetEntry())] = BG_IC_GATE_DESTROYED;
int32 const wsGateOpen = GetWorldStateFromGateEntry(gate->GetEntry(), true);
int32 const wsGateClosed = GetWorldStateFromGateEntry(gate->GetEntry(), false);
if (wsGateOpen)
{
UpdateWorldState(wsGateClosed, 0);
UpdateWorldState(wsGateOpen, 1);
}
TeamId teamId = TEAM_NEUTRAL;
uint32 textId;
ChatMsg msgType;
switch (gate->GetEntry())
{
case GO_HORDE_GATE_1:
textId = BG_IC_TEXT_FRONT_GATE_HORDE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
teamId = TEAM_HORDE;
break;
case GO_HORDE_GATE_2:
textId = BG_IC_TEXT_WEST_GATE_HORDE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
teamId = TEAM_HORDE;
break;
case GO_HORDE_GATE_3:
textId = BG_IC_TEXT_EAST_GATE_HORDE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
teamId = TEAM_HORDE;
break;
case GO_ALLIANCE_GATE_1:
textId = BG_IC_TEXT_WEST_GATE_ALLIANCE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_HORDE;
teamId = TEAM_ALLIANCE;
break;
case GO_ALLIANCE_GATE_2:
textId = BG_IC_TEXT_EAST_GATE_ALLIANCE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_HORDE;
teamId = TEAM_ALLIANCE;
break;
case GO_ALLIANCE_GATE_3:
textId = BG_IC_TEXT_FRONT_GATE_ALLIANCE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_HORDE;
teamId = TEAM_ALLIANCE;
break;
default:
return;
}
if (teamId != TEAM_NEUTRAL)
{
GuidVector const keepGates = _keepGateGUIDs[teamId];
ObjectGuid const bannerGuid = _keepBannerGUIDs[teamId];
for (ObjectGuid const& guid : keepGates)
if (GameObject* keepGate = GetBgMap()->GetGameObject(guid))
keepGate->UseDoorOrButton();
if (GameObject* banner = GetBgMap()->GetGameObject(bannerGuid))
banner->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
}
SendBroadcastText(textId, msgType, destroyer);
}
@@ -1,376 +0,0 @@
/*
* 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 __BATTLEGROUNDIC_H
#define __BATTLEGROUNDIC_H
#include "Battleground.h"
#include "Object.h"
#include "TaskScheduler.h"
#include "Timer.h"
const uint32 BG_IC_Factions[2] =
{
1732, // Alliance
1735 // Horde
};
enum creaturesIC
{
NPC_HIGH_COMMANDER_HALFORD_WYRMBANE = 34924, // Alliance Boss
NPC_OVERLORD_AGMAR = 34922, // Horde Boss
NPC_KOR_KRON_GUARD = 34918, // horde guard
NPC_SEVEN_TH_LEGION_INFANTRY = 34919, // alliance guard
NPC_KEEP_CANNON = 34944,
NPC_DEMOLISHER = 34775,
NPC_SIEGE_ENGINE_H = 35069,
NPC_SIEGE_ENGINE_A = 34776,
NPC_GLAIVE_THROWER_A = 34802,
NPC_GLAIVE_THROWER_H = 35273,
NPC_CATAPULT = 34793,
NPC_HORDE_GUNSHIP_CANNON = 34935,
NPC_ALLIANCE_GUNSHIP_CANNON = 34929,
NPC_HORDE_GUNSHIP_CAPTAIN = 35003,
NPC_ALLIANCE_GUNSHIP_CAPTAIN = 34960,
NPC_WORLD_TRIGGER_NOT_FLOATING = 34984,
NPC_WORLD_TRIGGER_ALLIANCE_FRIENDLY = 20213,
NPC_WORLD_TRIGGER_HORDE_FRIENDLY = 20212
};
#define MAX_REINFORCEMENTS 400
enum Actions
{
ACTION_GUNSHIP_READY = 1,
ACTION_IOC_INTERACT_CAPTURABLE_OBJECT = 2,
ACTION_IOC_CAPTURE_CAPTURABLE_OBJECT = 3
};
enum BannersTypes
{
BANNER_A_CONTROLLED,
BANNER_A_CONTESTED,
BANNER_H_CONTROLLED,
BANNER_H_CONTESTED
};
enum BG_IC_ExploitTeleportLocations
{
IC_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3986,
IC_EXPLOIT_TELEPORT_LOCATION_HORDE = 3983
};
enum Spells
{
SPELL_OIL_REFINERY = 68719,
SPELL_QUARRY = 68720,
SPELL_PARACHUTE = 66656,
SPELL_SLOW_FALL = 12438,
SPELL_DESTROYED_VEHICLE_ACHIEVEMENT = 68357,
SPELL_BACK_DOOR_JOB_ACHIEVEMENT = 68502,
SPELL_DRIVING_CREDIT_DEMOLISHER = 68365,
SPELL_DRIVING_CREDIT_GLAIVE = 68363,
SPELL_DRIVING_CREDIT_SIEGE = 68364,
SPELL_DRIVING_CREDIT_CATAPULT = 68362,
SPELL_SIMPLE_TELEPORT = 12980,
SPELL_TELEPORT_VISUAL_ONLY = 51347,
SPELL_PARACHUTE_IC = 66657,
SPELL_LAUNCH_NO_FALLING_DAMAGE = 66251
};
enum ICWorldStates
{
BG_IC_ALLIANCE_REINFORCEMENTS_SET = 4221,
BG_IC_HORDE_REINFORCEMENTS_SET = 4222,
BG_IC_ALLIANCE_REINFORCEMENTS = 4226,
BG_IC_HORDE_REINFORCEMENTS = 4227,
BG_IC_MAX_REINFORCEMENTS = 17377,
BG_IC_GATE_FRONT_H_WS_CLOSED = 4317,
BG_IC_GATE_WEST_H_WS_CLOSED = 4318,
BG_IC_GATE_EAST_H_WS_CLOSED = 4319,
BG_IC_GATE_FRONT_A_WS_CLOSED = 4328,
BG_IC_GATE_WEST_A_WS_CLOSED = 4327,
BG_IC_GATE_EAST_A_WS_CLOSED = 4326,
BG_IC_GATE_FRONT_H_WS_OPEN = 4322,
BG_IC_GATE_WEST_H_WS_OPEN = 4321,
BG_IC_GATE_EAST_H_WS_OPEN = 4320,
BG_IC_GATE_FRONT_A_WS_OPEN = 4323,
BG_IC_GATE_WEST_A_WS_OPEN = 4324,
BG_IC_GATE_EAST_A_WS_OPEN = 4325,
BG_IC_DOCKS_UNCONTROLLED = 4301,
BG_IC_DOCKS_CONFLICT_A = 4305,
BG_IC_DOCKS_CONFLICT_H = 4302,
BG_IC_DOCKS_CONTROLLED_A = 4304,
BG_IC_DOCKS_CONTROLLED_H = 4303,
BG_IC_HANGAR_UNCONTROLLED = 4296,
BG_IC_HANGAR_CONFLICT_A = 4300,
BG_IC_HANGAR_CONFLICT_H = 4297,
BG_IC_HANGAR_CONTROLLED_A = 4299,
BG_IC_HANGAR_CONTROLLED_H = 4298,
BG_IC_QUARRY_UNCONTROLLED = 4306,
BG_IC_QUARRY_CONFLICT_A = 4310,
BG_IC_QUARRY_CONFLICT_H = 4307,
BG_IC_QUARRY_CONTROLLED_A = 4309,
BG_IC_QUARRY_CONTROLLED_H = 4308,
BG_IC_REFINERY_UNCONTROLLED = 4311,
BG_IC_REFINERY_CONFLICT_A = 4315,
BG_IC_REFINERY_CONFLICT_H = 4312,
BG_IC_REFINERY_CONTROLLED_A = 4314,
BG_IC_REFINERY_CONTROLLED_H = 4313,
BG_IC_WORKSHOP_UNCONTROLLED = 4294,
BG_IC_WORKSHOP_CONFLICT_A = 4228,
BG_IC_WORKSHOP_CONFLICT_H = 4293,
BG_IC_WORKSHOP_CONTROLLED_A = 4229,
BG_IC_WORKSHOP_CONTROLLED_H = 4230,
BG_IC_ALLIANCE_KEEP_UNCONTROLLED = 4341,
BG_IC_ALLIANCE_KEEP_CONFLICT_A = 4342,
BG_IC_ALLIANCE_KEEP_CONFLICT_H = 4343,
BG_IC_ALLIANCE_KEEP_CONTROLLED_A = 4339,
BG_IC_ALLIANCE_KEEP_CONTROLLED_H = 4340,
BG_IC_HORDE_KEEP_UNCONTROLLED = 4346,
BG_IC_HORDE_KEEP_CONFLICT_A = 4347,
BG_IC_HORDE_KEEP_CONFLICT_H = 4348,
BG_IC_HORDE_KEEP_CONTROLLED_A = 4344,
BG_IC_HORDE_KEEP_CONTROLLED_H = 4345
};
enum BG_IC_GateState
{
BG_IC_GATE_OK = 1,
BG_IC_GATE_DAMAGED = 2,
BG_IC_GATE_DESTROYED = 3
};
enum ICDoorList
{
BG_IC_H_FRONT,
BG_IC_H_WEST,
BG_IC_H_EAST,
BG_IC_A_FRONT,
BG_IC_A_WEST,
BG_IC_A_EAST,
BG_IC_MAXDOOR
};
enum ICNodePointType
{
NODE_TYPE_REFINERY,
NODE_TYPE_QUARRY,
NODE_TYPE_DOCKS,
NODE_TYPE_HANGAR,
NODE_TYPE_WORKSHOP,
// Graveyards
NODE_TYPE_GRAVEYARD_A,
NODE_TYPE_GRAVEYARD_H,
MAX_NODE_TYPES
};
enum class IsleOfConquestNodeState
{
Neutral,
ConflictA,
ConflictH,
ControlledA,
ControlledH
};
Position const BG_IC_SpiritGuidePos[MAX_NODE_TYPES+2] =
{
{0.0f, 0.0f, 0.0f, 0.0f}, // no grave
{0.0f, 0.0f, 0.0f, 0.0f}, // no grave
{629.57f, -279.83f, 11.33f, 0.0f}, // dock
{780.729f, -1103.08f, 135.51f, 2.27f}, // hangar
{775.74f, -652.77f, 9.31f, 4.27f}, // workshop
{278.42f, -883.20f, 49.89f, 1.53f}, // alliance starting base
{1300.91f, -834.04f, 48.91f, 1.69f}, // horde starting base
{438.86f, -310.04f, 51.81f, 5.87f}, // last resort alliance
{1148.65f, -1250.98f, 16.60f, 1.74f}, // last resort horde
};
enum ICBroadcastTexts
{
BG_IC_TEXT_FRONT_GATE_HORDE_DESTROYED = 35409,
BG_IC_TEXT_FRONT_GATE_ALLIANCE_DESTROYED = 35410,
BG_IC_TEXT_WEST_GATE_HORDE_DESTROYED = 35411,
BG_IC_TEXT_WEST_GATE_ALLIANCE_DESTROYED = 35412,
BG_IC_TEXT_EAST_GATE_HORDE_DESTROYED = 35413,
BG_IC_TEXT_EAST_GATE_ALLIANCE_DESTROYED = 35414
};
// I.E: Hangar, Quarry, Graveyards .. etc
struct IoCStaticNodeInfo
{
ICNodePointType NodeType;
struct
{
uint32 Assaulted;
uint32 Defended;
uint32 AllianceTaken;
uint32 HordeTaken;
} TextIds;
struct
{
int32 Uncontrolled;
int32 ConflictA;
int32 ConflictH;
int32 ControlledA;
int32 ControlledH;
} WorldStateIds;
};
class ICNodePoint
{
public:
explicit ICNodePoint(IsleOfConquestNodeState state, IoCStaticNodeInfo const& nodeInfo) : _state(state), _nodeInfo(nodeInfo)
{
switch (state)
{
case IsleOfConquestNodeState::ControlledH:
_lastControlled = TEAM_HORDE;
break;
case IsleOfConquestNodeState::ControlledA:
_lastControlled = TEAM_ALLIANCE;
break;
case IsleOfConquestNodeState::ConflictA:
case IsleOfConquestNodeState::ConflictH:
case IsleOfConquestNodeState::Neutral:
_lastControlled = TEAM_NEUTRAL;
break;
}
}
IsleOfConquestNodeState GetState() const { return _state; }
bool IsContested() const
{
return _state == IsleOfConquestNodeState::ConflictA || _state == IsleOfConquestNodeState::ConflictH;
}
TeamId GetLastControlledTeam() const { return _lastControlled; }
IoCStaticNodeInfo const& GetNodeInfo() const { return _nodeInfo; }
void UpdateState(IsleOfConquestNodeState state)
{
switch (state)
{
case IsleOfConquestNodeState::ControlledA:
_lastControlled = TEAM_ALLIANCE;
break;
case IsleOfConquestNodeState::ControlledH:
_lastControlled = TEAM_HORDE;
break;
case IsleOfConquestNodeState::Neutral:
_lastControlled = TEAM_NEUTRAL;
break;
case IsleOfConquestNodeState::ConflictA:
case IsleOfConquestNodeState::ConflictH:
break;
}
_state = state;
}
private:
IsleOfConquestNodeState _state;
TeamId _lastControlled;
IoCStaticNodeInfo _nodeInfo;
};
const IoCStaticNodeInfo nodePointInitial[MAX_NODE_TYPES] =
{
{ NODE_TYPE_REFINERY, { 35377, 35378, 35379, 35380 }, { BG_IC_REFINERY_UNCONTROLLED, BG_IC_REFINERY_CONFLICT_A, BG_IC_REFINERY_CONFLICT_H, BG_IC_REFINERY_CONTROLLED_A, BG_IC_REFINERY_CONTROLLED_H } },
{ NODE_TYPE_QUARRY, { 35373, 35374, 35375, 35376 }, { BG_IC_QUARRY_UNCONTROLLED, BG_IC_QUARRY_CONFLICT_A, BG_IC_QUARRY_CONFLICT_H, BG_IC_QUARRY_CONTROLLED_A, BG_IC_QUARRY_CONTROLLED_H } },
{ NODE_TYPE_DOCKS, { 35365, 35366, 35367, 35368 }, { BG_IC_DOCKS_UNCONTROLLED, BG_IC_DOCKS_CONFLICT_A, BG_IC_DOCKS_CONFLICT_H, BG_IC_DOCKS_CONTROLLED_A, BG_IC_DOCKS_CONTROLLED_H } },
{ NODE_TYPE_HANGAR, { 35369, 35370, 35371, 35372 }, { BG_IC_HANGAR_UNCONTROLLED, BG_IC_HANGAR_CONFLICT_A, BG_IC_HANGAR_CONFLICT_H, BG_IC_HANGAR_CONTROLLED_A, BG_IC_HANGAR_CONTROLLED_H } },
{ NODE_TYPE_WORKSHOP, { 35278, 35286, 35279, 35280 }, { BG_IC_WORKSHOP_UNCONTROLLED, BG_IC_WORKSHOP_CONFLICT_A, BG_IC_WORKSHOP_CONFLICT_H, BG_IC_WORKSHOP_CONTROLLED_A, BG_IC_WORKSHOP_CONTROLLED_H } },
{ NODE_TYPE_GRAVEYARD_A, { 35461, 35459, 35463, 35466 }, { BG_IC_ALLIANCE_KEEP_UNCONTROLLED, BG_IC_ALLIANCE_KEEP_CONFLICT_A, BG_IC_ALLIANCE_KEEP_CONFLICT_H, BG_IC_ALLIANCE_KEEP_CONTROLLED_A, BG_IC_ALLIANCE_KEEP_CONTROLLED_H } },
{ NODE_TYPE_GRAVEYARD_H, { 35462, 35460, 35464, 35465 }, { BG_IC_HORDE_KEEP_UNCONTROLLED, BG_IC_HORDE_KEEP_CONFLICT_A, BG_IC_HORDE_KEEP_CONFLICT_H, BG_IC_HORDE_KEEP_CONTROLLED_A, BG_IC_HORDE_KEEP_CONTROLLED_H } }
};
enum HonorRewards
{
RESOURCE_HONOR_AMOUNT = 12,
WINNER_HONOR_AMOUNT = 500
};
class BattlegroundIC : public Battleground
{
public:
BattlegroundIC(BattlegroundTemplate const* battlegroundTemplate);
~BattlegroundIC() override;
/* inherited from BattlegroundClass */
void StartingEventOpenDoors() override;
void PostUpdateImpl(uint32 diff) override;
void HandleKillUnit(Creature* unit, Unit* killer) override;
void HandleKillPlayer(Player* player, Player* killer) override;
WorldSafeLocsEntry const* GetExploitTeleportLocation(Team team) override;
void OnCreatureCreate(Creature* creature) override;
void OnGameObjectCreate(GameObject* gameobject) override;
void OnMapSet(BattlegroundMap* map) override;
void DoAction(uint32 actionId, WorldObject* source, WorldObject* target) override;
void OnPlayerInteractWithBanner(Player* player, GameObject* banner);
void OnPlayerAssaultNode(Player* player, ICNodePoint& node);
void OnPlayerDefendNode(Player* player, ICNodePoint& node);
void ProcessEvent(WorldObject* target, uint32 eventId, WorldObject* invoker) override;
private:
std::array<uint16, PVP_TEAMS_COUNT> _factionReinforcements;
std::array<BG_IC_GateState, 6> _gateStatus;
std::array<std::unique_ptr<ICNodePoint>, 7> _nodePoints;
std::array<ObjectGuid, PVP_TEAMS_COUNT> _gunshipGUIDs;
GuidVector _teleporterGUIDs;
GuidVector _teleporterEffectGUIDs;
GuidVector _mainGateDoorGUIDs;
GuidVector _portcullisGUIDs;
GuidVector _wallGUIDs;
std::array<GuidVector, PVP_TEAMS_COUNT> _cannonGUIDs;
std::array<GuidVector, PVP_TEAMS_COUNT> _keepGateGUIDs;
std::array<ObjectGuid, PVP_TEAMS_COUNT> _keepBannerGUIDs;
ObjectGuid _gunshipTeleportTarget;
TaskScheduler _scheduler;
TimeTracker _resourceTimer;
static uint32 GetGateIDFromEntry(uint32 id);
static int32 GetWorldStateFromGateEntry(uint32 id, bool open);
void UpdateNodeWorldState(ICNodePoint const& node);
void HandleCapturedNodes(ICNodePoint& node);
void HandleCaptureNodeAction(GameObject* banner);
void OnGateDestroyed(GameObject* gate, WorldObject* destroyer);
static ICNodePointType BannerToNodeType(uint32 bannerId);
};
#endif
@@ -1,80 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundNA.h"
#include "Log.h"
#include "Player.h"
BattlegroundNA::BattlegroundNA(BattlegroundTemplate const* battlegroundTemplate) : Arena(battlegroundTemplate)
{
BgObjects.resize(BG_NA_OBJECT_MAX);
}
void BattlegroundNA::PostUpdateImpl(uint32 diff)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case BG_NA_EVENT_REMOVE_DOORS:
for (uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; ++i)
DelObject(i);
break;
default:
break;
}
}
}
void BattlegroundNA::StartingEventCloseDoors()
{
for (uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_4; ++i)
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
}
void BattlegroundNA::StartingEventOpenDoors()
{
for (uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; ++i)
DoorOpen(i);
_events.ScheduleEvent(BG_NA_EVENT_REMOVE_DOORS, BG_NA_REMOVE_DOORS_TIMER);
for (uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; ++i)
SpawnBGObject(i, 60);
}
bool BattlegroundNA::SetupBattleground()
{
// gates
if (!AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854f, 2966.833f, 12.6462f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179f, 2874.97f, 12.39171f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709f, 2981.777f, 10.70117f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064f, 2858.438f, 10.23631f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, RESPAWN_IMMEDIATELY)
// buffs
|| !AddObject(BG_NA_OBJECT_BUFF_1, BG_NA_OBJECT_TYPE_BUFF_1, 4009.189941f, 2895.250000f, 13.052700f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120)
|| !AddObject(BG_NA_OBJECT_BUFF_2, BG_NA_OBJECT_TYPE_BUFF_2, 4103.330078f, 2946.350098f, 13.051300f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120))
{
TC_LOG_ERROR("sql.sql", "BatteGroundNA: Failed to spawn some object!");
return false;
}
return true;
}
@@ -1,67 +0,0 @@
/*
* 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 __BATTLEGROUNDNA_H
#define __BATTLEGROUNDNA_H
#include "Arena.h"
#include "EventMap.h"
enum BattlegroundNAObjectTypes
{
BG_NA_OBJECT_DOOR_1 = 0,
BG_NA_OBJECT_DOOR_2 = 1,
BG_NA_OBJECT_DOOR_3 = 2,
BG_NA_OBJECT_DOOR_4 = 3,
BG_NA_OBJECT_BUFF_1 = 4,
BG_NA_OBJECT_BUFF_2 = 5,
BG_NA_OBJECT_MAX = 6
};
enum BattlegroundNAGameObjects
{
BG_NA_OBJECT_TYPE_DOOR_1 = 183978,
BG_NA_OBJECT_TYPE_DOOR_2 = 183980,
BG_NA_OBJECT_TYPE_DOOR_3 = 183977,
BG_NA_OBJECT_TYPE_DOOR_4 = 183979,
BG_NA_OBJECT_TYPE_BUFF_1 = 184663,
BG_NA_OBJECT_TYPE_BUFF_2 = 184664
};
inline constexpr Seconds BG_NA_REMOVE_DOORS_TIMER = 5s;
enum BattlegroundNAEvents
{
BG_NA_EVENT_REMOVE_DOORS = 1
};
class BattlegroundNA : public Arena
{
public:
BattlegroundNA(BattlegroundTemplate const* battlegroundTemplate);
/* inherited from BattlegroundClass */
void StartingEventCloseDoors() override;
void StartingEventOpenDoors() override;
bool SetupBattleground() override;
private:
void PostUpdateImpl(uint32 diff) override;
EventMap _events;
};
#endif
@@ -1,78 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundRL.h"
#include "Log.h"
#include "Player.h"
BattlegroundRL::BattlegroundRL(BattlegroundTemplate const* battlegroundTemplate) : Arena(battlegroundTemplate)
{
BgObjects.resize(BG_RL_OBJECT_MAX);
}
void BattlegroundRL::PostUpdateImpl(uint32 diff)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case BG_RL_EVENT_REMOVE_DOORS:
for (uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i)
DelObject(i);
break;
default:
break;
}
}
}
void BattlegroundRL::StartingEventCloseDoors()
{
for (uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i)
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
}
void BattlegroundRL::StartingEventOpenDoors()
{
for (uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i)
DoorOpen(i);
_events.ScheduleEvent(BG_RL_EVENT_REMOVE_DOORS, BG_RL_REMOVE_DOORS_TIMER);
for (uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; ++i)
SpawnBGObject(i, 60);
}
bool BattlegroundRL::SetupBattleground()
{
// gates
if (!AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561f, 1601.938f, 31.60557f, -1.457349f, 0, 0, -0.6658813f, 0.7460576f, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648f, 1730.557f, 31.60557f, 1.684245f, 0, 0, 0.7460582f, 0.6658807f, RESPAWN_IMMEDIATELY)
// buffs
|| !AddObject(BG_RL_OBJECT_BUFF_1, BG_RL_OBJECT_TYPE_BUFF_1, 1328.719971f, 1632.719971f, 36.730400f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120)
|| !AddObject(BG_RL_OBJECT_BUFF_2, BG_RL_OBJECT_TYPE_BUFF_2, 1243.300049f, 1699.170044f, 34.872601f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120))
{
TC_LOG_ERROR("sql.sql", "BatteGroundRL: Failed to spawn some object!");
return false;
}
return true;
}
@@ -1,63 +0,0 @@
/*
* 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 __BATTLEGROUNDRL_H
#define __BATTLEGROUNDRL_H
#include "Arena.h"
#include "EventMap.h"
enum BattlegroundRLObjectTypes
{
BG_RL_OBJECT_DOOR_1 = 0,
BG_RL_OBJECT_DOOR_2 = 1,
BG_RL_OBJECT_BUFF_1 = 2,
BG_RL_OBJECT_BUFF_2 = 3,
BG_RL_OBJECT_MAX = 4
};
enum BattlegroundRLGameObjects
{
BG_RL_OBJECT_TYPE_DOOR_1 = 185918,
BG_RL_OBJECT_TYPE_DOOR_2 = 185917,
BG_RL_OBJECT_TYPE_BUFF_1 = 184663,
BG_RL_OBJECT_TYPE_BUFF_2 = 184664
};
inline constexpr Seconds BG_RL_REMOVE_DOORS_TIMER = 5s;
enum BattlegroundRLEvents
{
BG_RL_EVENT_REMOVE_DOORS = 1
};
class BattlegroundRL : public Arena
{
public:
BattlegroundRL(BattlegroundTemplate const* battlegroundTemplate);
/* inherited from BattlegroundClass */
void StartingEventCloseDoors() override;
void StartingEventOpenDoors() override;
bool SetupBattleground() override;
private:
void PostUpdateImpl(uint32 diff) override;
EventMap _events;
};
#endif
@@ -1,146 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundRV.h"
#include "GameObject.h"
#include "Log.h"
#include "ObjectAccessor.h"
#include "Player.h"
BattlegroundRV::BattlegroundRV(BattlegroundTemplate const* battlegroundTemplate) : Arena(battlegroundTemplate)
{
BgObjects.resize(BG_RV_OBJECT_MAX);
_timer = 0;
_state = 0;
_pillarCollision = false;
}
void BattlegroundRV::PostUpdateImpl(uint32 diff)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
if (_timer < diff)
{
switch (_state)
{
case BG_RV_STATE_OPEN_FENCES:
// Open fire (only at game start)
for (uint8 i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i)
DoorOpen(i);
_timer = BG_RV_CLOSE_FIRE_TIMER;
_state = BG_RV_STATE_CLOSE_FIRE;
break;
case BG_RV_STATE_CLOSE_FIRE:
for (uint8 i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i)
DoorClose(i);
// Fire got closed after five seconds, leaves twenty seconds before toggling pillars
_timer = BG_RV_FIRE_TO_PILLAR_TIMER;
_state = BG_RV_STATE_SWITCH_PILLARS;
break;
case BG_RV_STATE_SWITCH_PILLARS:
TogglePillarCollision();
_timer = BG_RV_PILLAR_SWITCH_TIMER;
break;
}
}
else
_timer -= diff;
}
void BattlegroundRV::StartingEventOpenDoors()
{
// Buff respawn
SpawnBGObject(BG_RV_OBJECT_BUFF_1, 90);
SpawnBGObject(BG_RV_OBJECT_BUFF_2, 90);
// Elevators
DoorOpen(BG_RV_OBJECT_ELEVATOR_1);
DoorOpen(BG_RV_OBJECT_ELEVATOR_2);
_state = BG_RV_STATE_OPEN_FENCES;
_timer = BG_RV_FIRST_TIMER;
// Should be false at first, TogglePillarCollision will do it.
_pillarCollision = true;
TogglePillarCollision();
}
bool BattlegroundRV::SetupBattleground()
{
// elevators
if (!AddObject(BG_RV_OBJECT_ELEVATOR_1, BG_RV_OBJECT_TYPE_ELEVATOR_1, 763.536377f, -294.535767f, 0.505383f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_ELEVATOR_2, BG_RV_OBJECT_TYPE_ELEVATOR_2, 763.506348f, -273.873352f, 0.505383f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
// buffs
|| !AddObject(BG_RV_OBJECT_BUFF_1, BG_RV_OBJECT_TYPE_BUFF_1, 735.551819f, -284.794678f, 28.276682f, 0.034906f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_BUFF_2, BG_RV_OBJECT_TYPE_BUFF_2, 791.224487f, -284.794464f, 28.276682f, 2.600535f, 0, 0, 0, RESPAWN_IMMEDIATELY)
// fire
|| !AddObject(BG_RV_OBJECT_FIRE_1, BG_RV_OBJECT_TYPE_FIRE_1, 743.543457f, -283.799469f, 28.286655f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_FIRE_2, BG_RV_OBJECT_TYPE_FIRE_2, 782.971802f, -283.799469f, 28.286655f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_FIREDOOR_1, BG_RV_OBJECT_TYPE_FIREDOOR_1, 743.711060f, -284.099609f, 27.542587f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_FIREDOOR_2, BG_RV_OBJECT_TYPE_FIREDOOR_2, 783.221252f, -284.133362f, 27.535686f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
// Gear
|| !AddObject(BG_RV_OBJECT_GEAR_1, BG_RV_OBJECT_TYPE_GEAR_1, 763.664551f, -261.872986f, 26.686588f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_GEAR_2, BG_RV_OBJECT_TYPE_GEAR_2, 763.578979f, -306.146149f, 26.665222f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
// Pulley
|| !AddObject(BG_RV_OBJECT_PULLEY_1, BG_RV_OBJECT_TYPE_PULLEY_1, 700.722290f, -283.990662f, 39.517582f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_PULLEY_2, BG_RV_OBJECT_TYPE_PULLEY_2, 826.303833f, -283.996429f, 39.517582f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
// Pilars
|| !AddObject(BG_RV_OBJECT_PILAR_1, BG_RV_OBJECT_TYPE_PILAR_1, 763.632385f, -306.162384f, 25.909504f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_PILAR_2, BG_RV_OBJECT_TYPE_PILAR_2, 723.644287f, -284.493256f, 24.648525f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_PILAR_3, BG_RV_OBJECT_TYPE_PILAR_3, 763.611145f, -261.856750f, 25.909504f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_PILAR_4, BG_RV_OBJECT_TYPE_PILAR_4, 802.211609f, -284.493256f, 24.648525f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
// Pilars Collision
|| !AddObject(BG_RV_OBJECT_PILAR_COLLISION_1, BG_RV_OBJECT_TYPE_PILAR_COLLISION_1, 763.632385f, -306.162384f, 30.639660f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_PILAR_COLLISION_2, BG_RV_OBJECT_TYPE_PILAR_COLLISION_2, 723.644287f, -284.493256f, 32.382710f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_PILAR_COLLISION_3, BG_RV_OBJECT_TYPE_PILAR_COLLISION_3, 763.611145f, -261.856750f, 30.639660f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|| !AddObject(BG_RV_OBJECT_PILAR_COLLISION_4, BG_RV_OBJECT_TYPE_PILAR_COLLISION_4, 802.211609f, -284.493256f, 32.382710f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY))
{
TC_LOG_ERROR("sql.sql", "BatteGroundRV: Failed to spawn some object!");
return false;
}
return true;
}
void BattlegroundRV::TogglePillarCollision()
{
// Toggle visual pillars, pulley, gear, and collision based on previous state
for (uint8 i = BG_RV_OBJECT_PILAR_1; i <= BG_RV_OBJECT_GEAR_2; ++i)
_pillarCollision ? DoorOpen(i) : DoorClose(i);
for (uint8 i = BG_RV_OBJECT_PILAR_2; i <= BG_RV_OBJECT_PULLEY_2; ++i)
_pillarCollision ? DoorClose(i) : DoorOpen(i);
for (uint8 i = BG_RV_OBJECT_PILAR_1; i <= BG_RV_OBJECT_PILAR_COLLISION_4; ++i)
{
if (GameObject* go = GetBGObject(i))
{
if (i >= BG_RV_OBJECT_PILAR_COLLISION_1)
{
GOState state = ((go->GetGOInfo()->door.startOpen != 0) == _pillarCollision) ? GO_STATE_ACTIVE : GO_STATE_READY;
go->SetGoState(state);
}
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
if (Player* player = ObjectAccessor::FindPlayer(itr->first))
go->SendUpdateToPlayer(player);
}
}
_pillarCollision = !_pillarCollision;
}
@@ -1,109 +0,0 @@
/*
* 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 __BATTLEGROUNDRV_H
#define __BATTLEGROUNDRV_H
#include "Arena.h"
enum BattlegroundRVObjectTypes
{
BG_RV_OBJECT_BUFF_1,
BG_RV_OBJECT_BUFF_2,
BG_RV_OBJECT_FIRE_1,
BG_RV_OBJECT_FIRE_2,
BG_RV_OBJECT_FIREDOOR_1,
BG_RV_OBJECT_FIREDOOR_2,
BG_RV_OBJECT_PILAR_1,
BG_RV_OBJECT_PILAR_3,
BG_RV_OBJECT_GEAR_1,
BG_RV_OBJECT_GEAR_2,
BG_RV_OBJECT_PILAR_2,
BG_RV_OBJECT_PILAR_4,
BG_RV_OBJECT_PULLEY_1,
BG_RV_OBJECT_PULLEY_2,
BG_RV_OBJECT_PILAR_COLLISION_1,
BG_RV_OBJECT_PILAR_COLLISION_2,
BG_RV_OBJECT_PILAR_COLLISION_3,
BG_RV_OBJECT_PILAR_COLLISION_4,
BG_RV_OBJECT_ELEVATOR_1,
BG_RV_OBJECT_ELEVATOR_2,
BG_RV_OBJECT_MAX
};
enum BattlegroundRVGameObjects
{
BG_RV_OBJECT_TYPE_BUFF_1 = 184663,
BG_RV_OBJECT_TYPE_BUFF_2 = 184664,
BG_RV_OBJECT_TYPE_FIRE_1 = 192704,
BG_RV_OBJECT_TYPE_FIRE_2 = 192705,
BG_RV_OBJECT_TYPE_FIREDOOR_2 = 192387,
BG_RV_OBJECT_TYPE_FIREDOOR_1 = 192388,
BG_RV_OBJECT_TYPE_PULLEY_1 = 192389,
BG_RV_OBJECT_TYPE_PULLEY_2 = 192390,
BG_RV_OBJECT_TYPE_GEAR_1 = 192393,
BG_RV_OBJECT_TYPE_GEAR_2 = 192394,
BG_RV_OBJECT_TYPE_ELEVATOR_1 = 194582,
BG_RV_OBJECT_TYPE_ELEVATOR_2 = 194586,
BG_RV_OBJECT_TYPE_PILAR_COLLISION_1 = 194580, // axe
BG_RV_OBJECT_TYPE_PILAR_COLLISION_2 = 194579, // arena
BG_RV_OBJECT_TYPE_PILAR_COLLISION_3 = 194581, // lightning
BG_RV_OBJECT_TYPE_PILAR_COLLISION_4 = 194578, // ivory
BG_RV_OBJECT_TYPE_PILAR_1 = 194583, // axe
BG_RV_OBJECT_TYPE_PILAR_2 = 194584, // arena
BG_RV_OBJECT_TYPE_PILAR_3 = 194585, // lightning
BG_RV_OBJECT_TYPE_PILAR_4 = 194587 // ivory
};
enum BattlegroundRVData
{
BG_RV_STATE_OPEN_FENCES,
BG_RV_STATE_SWITCH_PILLARS,
BG_RV_STATE_CLOSE_FIRE,
BG_RV_PILLAR_SWITCH_TIMER = 25000,
BG_RV_FIRE_TO_PILLAR_TIMER = 20000,
BG_RV_CLOSE_FIRE_TIMER = 5000,
BG_RV_FIRST_TIMER = 20133,
};
class BattlegroundRV : public Arena
{
public:
BattlegroundRV(BattlegroundTemplate const* battlegroundTemplate);
/* inherited from BattlegroundClass */
void StartingEventOpenDoors() override;
bool SetupBattleground() override;
private:
void PostUpdateImpl(uint32 diff) override;
void TogglePillarCollision();
uint32 _timer;
uint32 _state;
bool _pillarCollision;
};
#endif
@@ -1,843 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundSA.h"
#include "BattlegroundScore.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "DB2Stores.h"
#include "GameObject.h"
#include "GameTime.h"
#include "Log.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "Random.h"
#include "UpdateData.h"
#include "WorldStateMgr.h"
enum StrandOfTheAncientsPvpStats
{
PVP_STAT_GATES_DESTROYED = 231,
PVP_STAT_DEMOLISHERS_DESTROYED = 232
};
enum StrandOfTheAncientsEvents
{
EVENT_HORDE_ASSAULT_STARTED = 21702,
EVENT_ALLIANCE_ASSAULT_STARTED = 23748,
EVENT_TITAN_RELIC_ACTIVATED = 20572
};
enum StrandOfTheAncientsCreatures
{
NPC_KANRETHAD = 29,
NPC_DEMOLISHER = 28781,
NPC_ANTIPERSONNEL_CANNON = 27894,
NPC_RIGGER_SPARKLIGHT = 29260,
NPC_GORGRIL_RIGSPARK = 29262,
NPC_WORLD_TRIGGER = 22515,
NPC_DEMOLISHER_SA = 28781
};
enum StrandOfTheAncientsSpawnPositions
{
SPAWN_DEFENDERS = 1399
};
enum StrandOfTheAncientsData
{
DATA_ATTACKERS = 1,
DATA_STATUS = 2
};
enum StrandOfTheAncientSpells
{
SPELL_TELEPORT_DEFENDER = 52364,
SPELL_TELEPORT_ATTACKERS = 60178,
SPELL_END_OF_ROUND = 52459,
SPELL_REMOVE_SEAFORIUM = 59077,
SPELL_ALLIANCE_CONTROL_PHASE_SHIFT = 60027,
SPELL_HORDE_CONTROL_PHASE_SHIFT = 60028,
SPELL_CARRYING_SEAFORIUM_CHARGE = 52415
};
Position const spawnPositionOnTransport[] =
{
{ 0.0f, 5.0f, 9.6f, 3.14f },
{ -6.0f, -3.0f, 8.6f, 0.0f }
};
BattlegroundSA::BattlegroundSA(BattlegroundTemplate const* battlegroundTemplate) : Battleground(battlegroundTemplate)
{
StartMessageIds[BG_STARTING_EVENT_FOURTH] = 0; // handle by Kanrethad
BgObjects.resize(0);
BgCreatures.resize(0);
TimerEnabled = false;
UpdateWaitTimer = 0;
SignaledRoundTwo = false;
SignaledRoundTwoHalfMin = false;
InitSecondRound = false;
Attackers = static_cast<TeamId>(urand(TEAM_ALLIANCE, TEAM_HORDE));
TotalTime = 0;
EndRoundTimer = 0;
ShipsStarted = false;
Status = BG_SA_NOT_STARTED;
for (BG_SA_RoundScore& roundScore : RoundScores)
{
roundScore.winner = TEAM_ALLIANCE;
roundScore.time = 0;
}
_boatGUIDs = { };
_staticBombGUIDs = { };
}
BattlegroundSA::~BattlegroundSA() = default;
void BattlegroundSA::Reset()
{
TotalTime = 0;
ShipsStarted = false;
Status = BG_SA_WARMUP;
}
bool BattlegroundSA::SetupBattleground()
{
return true;
}
bool BattlegroundSA::ResetObjs()
{
for (ObjectGuid const& bombGuid : _dynamicBombGUIDs)
if (GameObject* bomb = GetBgMap()->GetGameObject(bombGuid))
bomb->Delete();
_dynamicBombGUIDs.clear();
TeamId const defenders = Attackers == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE;
TotalTime = 0;
ShipsStarted = false;
UpdateWorldState(BG_SA_ALLY_ATTACKS, Attackers == TEAM_ALLIANCE);
UpdateWorldState(BG_SA_HORDE_ATTACKS, Attackers == TEAM_HORDE);
UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_ALL, Attackers == TEAM_ALLIANCE);
UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_ALL, Attackers == TEAM_ALLIANCE);
UpdateWorldState(BG_SA_RIGHT_ATT_TOKEN_HRD, Attackers == TEAM_HORDE);
UpdateWorldState(BG_SA_LEFT_ATT_TOKEN_HRD, Attackers == TEAM_HORDE);
UpdateWorldState(BG_SA_HORDE_DEFENCE_TOKEN, defenders == TEAM_HORDE);
UpdateWorldState(BG_SA_ALLIANCE_DEFENCE_TOKEN, defenders == TEAM_ALLIANCE);
CaptureGraveyard(StrandOfTheAncientsGraveyard::Central, defenders);
CaptureGraveyard(StrandOfTheAncientsGraveyard::West, defenders);
CaptureGraveyard(StrandOfTheAncientsGraveyard::East, defenders);
UpdateWorldState(BG_SA_ATTACKER_TEAM, Attackers);
for (ObjectGuid const& guid : _gateGUIDs)
if (GameObject* gate = GetBgMap()->GetGameObject(guid))
gate->SetDestructibleState(GO_DESTRUCTIBLE_INTACT, nullptr, true);
BG_SA_GateState const state = Attackers == TEAM_ALLIANCE ? BG_SA_HORDE_GATE_OK : BG_SA_ALLIANCE_GATE_OK;
UpdateWorldState(BG_SA_PURPLE_GATEWS, state);
UpdateWorldState(BG_SA_RED_GATEWS, state);
UpdateWorldState(BG_SA_BLUE_GATEWS, state);
UpdateWorldState(BG_SA_GREEN_GATEWS, state);
UpdateWorldState(BG_SA_YELLOW_GATEWS, state);
UpdateWorldState(BG_SA_ANCIENT_GATEWS, state);
GetBgMap()->UpdateSpawnGroupConditions();
if (GameObject* door = GetBgMap()->GetGameObject(_collisionDoorGUID))
door->ResetDoorOrButton();
SetStatus(STATUS_WAIT_JOIN);
GetBgMap()->DoOnPlayers([&](Player* player)
{
SendTransportInit(player);
});
TeleportPlayers();
return true;
}
void BattlegroundSA::StartShips()
{
if (ShipsStarted)
return;
for (ObjectGuid const& guid : _boatGUIDs[Attackers])
{
if (GameObject* boat = GetBgMap()->GetGameObject(guid))
{
boat->SetGoState(GO_STATE_TRANSPORT_STOPPED);
// make sure every player knows the transport exists & is moving
for (auto const& [playerGuid, _] : GetPlayers())
{
if (Player const* player = ObjectAccessor::FindPlayer(playerGuid))
{
UpdateData data(player->GetMapId());
WorldPacket pkt;
boat->BuildValuesUpdateBlockForPlayer(&data, player);
data.BuildPacket(&pkt);
player->SendDirectMessage(&pkt);
}
}
}
}
ShipsStarted = true;
}
void BattlegroundSA::PostUpdateImpl(uint32 diff)
{
if (InitSecondRound)
{
if (UpdateWaitTimer < diff)
{
if (!SignaledRoundTwo)
{
SignaledRoundTwo = true;
InitSecondRound = false;
SendBroadcastText(BG_SA_TEXT_ROUND_TWO_START_ONE_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
}
else
{
UpdateWaitTimer -= diff;
return;
}
}
TotalTime += diff;
if (Status == BG_SA_WARMUP)
{
EndRoundTimer = BG_SA_ROUNDLENGTH;
UpdateWorldState(BG_SA_TIMER, GameTime::GetGameTime() + (EndRoundTimer / 1000));
if (TotalTime >= BG_SA_WARMUPLENGTH)
{
if (Creature* c = FindKanrethad())
SendChatMessage(c, TEXT_ROUND_STARTED);
TotalTime = 0;
ToggleTimer();
Status = BG_SA_ROUND_ONE;
TriggerGameEvent((Attackers == TEAM_ALLIANCE) ? EVENT_ALLIANCE_ASSAULT_STARTED : EVENT_HORDE_ASSAULT_STARTED);
}
if (TotalTime >= BG_SA_BOAT_START)
StartShips();
return;
}
else if (Status == BG_SA_SECOND_WARMUP)
{
if (RoundScores[0].time<BG_SA_ROUNDLENGTH)
EndRoundTimer = RoundScores[0].time;
else
EndRoundTimer = BG_SA_ROUNDLENGTH;
UpdateWorldState(BG_SA_TIMER, GameTime::GetGameTime() + (EndRoundTimer / 1000));
if (TotalTime >= 60000)
{
if (Creature* c = FindKanrethad())
SendChatMessage(c, TEXT_ROUND_STARTED);
TotalTime = 0;
ToggleTimer();
Status = BG_SA_ROUND_TWO;
TriggerGameEvent((Attackers == TEAM_ALLIANCE) ? EVENT_ALLIANCE_ASSAULT_STARTED : EVENT_HORDE_ASSAULT_STARTED);
// status was set to STATUS_WAIT_JOIN manually for Preparation, set it back now
SetStatus(STATUS_IN_PROGRESS);
for (const auto& [playerGuid, bp] : GetPlayers())
if (Player* p = ObjectAccessor::FindPlayer(playerGuid))
p->RemoveAurasDueToSpell(SPELL_PREPARATION);
}
if (TotalTime >= 30000)
{
if (!SignaledRoundTwoHalfMin)
{
SignaledRoundTwoHalfMin = true;
SendBroadcastText(BG_SA_TEXT_ROUND_TWO_START_HALF_MINUTE, CHAT_MSG_BG_SYSTEM_NEUTRAL);
}
}
StartShips();
return;
}
else if (GetStatus() == STATUS_IN_PROGRESS)
{
if (Status == BG_SA_ROUND_ONE)
{
if (TotalTime >= BG_SA_ROUNDLENGTH)
{
EndRound();
return;
}
}
else if (Status == BG_SA_ROUND_TWO)
{
if (TotalTime >= EndRoundTimer)
{
CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE);
CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE);
RoundScores[1].time = BG_SA_ROUNDLENGTH;
RoundScores[1].winner = (Attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE;
if (RoundScores[0].time == RoundScores[1].time)
EndBattleground(TEAM_OTHER);
else if (RoundScores[0].time < RoundScores[1].time)
EndBattleground(RoundScores[0].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE);
else
EndBattleground(RoundScores[1].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE);
return;
}
}
}
}
void BattlegroundSA::AddPlayer(Player* player, BattlegroundQueueTypeId queueId)
{
bool const isInBattleground = IsPlayerInBattleground(player->GetGUID());
Battleground::AddPlayer(player, queueId);
SendTransportInit(player);
if (!isInBattleground)
TeleportToEntrancePosition(player);
}
void BattlegroundSA::RemovePlayer(Player* /*player*/, ObjectGuid /*guid*/, uint32 /*team*/) { }
void BattlegroundSA::TeleportPlayers() const
{
for (auto const& [playerGuid, bp] : GetPlayers())
{
if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
{
// should remove spirit of redemption
if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
if (!player->IsAlive())
{
player->ResurrectPlayer(1.0f);
player->SpawnCorpseBones();
}
player->ResetAllPowers();
player->CombatStopWithPets(true);
player->CastSpell(player, SPELL_PREPARATION, true);
TeleportToEntrancePosition(player);
}
}
}
// This function teleports player to entrance position, but it's not implemented correctly
// It is also used on round swap; which should be handled by the following spells: 52365, 52528, 53464, 53465 (Split Teleport (FACTION) (Boat X))
// This spell however cannot work with current system because of grid limitations.
// On battleground start, this function should work fine, except that it is called to late and we need a NearTeleport to solve this.
void BattlegroundSA::TeleportToEntrancePosition(Player* player) const
{
if (GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())) == Attackers)
{
ObjectGuid const boatGUID = _boatGUIDs[Attackers][urand(0, 1)];
if (GameObject* boat = GetBgMap()->GetGameObject(boatGUID))
{
if (TransportBase* transport = boat->ToTransportBase())
{
player->Relocate(spawnPositionOnTransport[Attackers]);
transport->AddPassenger(player);
player->m_movementInfo.transport.pos.Relocate(spawnPositionOnTransport[Attackers]);
float x, y, z, o;
spawnPositionOnTransport[Attackers].GetPosition(x, y, z, o);
transport->CalculatePassengerPosition(x, y, z, &o);
player->Relocate(x, y, z, o);
if (player->IsInWorld())
player->NearTeleportTo({ x, y, z, o });
}
}
}
else if (WorldSafeLocsEntry const* defenderSpawn = sObjectMgr->GetWorldSafeLoc(SPAWN_DEFENDERS))
{
if (player->IsInWorld())
player->TeleportTo(defenderSpawn->Loc);
else
player->WorldRelocate(defenderSpawn->Loc);
}
}
void BattlegroundSA::ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker /*= nullptr*/)
{
switch (eventId)
{
case EVENT_ALLIANCE_ASSAULT_STARTED:
for (ObjectGuid const& bombGuid : _staticBombGUIDs[TEAM_ALLIANCE])
if (GameObject* bomb = GetBgMap()->GetGameObject(bombGuid))
bomb->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
break;
case EVENT_HORDE_ASSAULT_STARTED:
for (ObjectGuid const& bombGuid : _staticBombGUIDs[TEAM_HORDE])
if (GameObject* bomb = GetBgMap()->GetGameObject(bombGuid))
bomb->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
break;
default:
break;
}
if (GameObject* go = Object::ToGameObject(obj))
{
switch (go->GetGoType())
{
case GAMEOBJECT_TYPE_GOOBER:
if (invoker)
if (eventId == EVENT_TITAN_RELIC_ACTIVATED)
TitanRelicActivated(invoker->ToPlayer());
break;
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
{
if (GateInfo const* gate = GetGate(obj->GetEntry()))
{
uint32 gateId = gate->GameObjectId;
// damaged
if (eventId == go->GetGOInfo()->destructibleBuilding.DamagedEvent)
{
BG_SA_GateState gateState = Attackers == TEAM_HORDE ? BG_SA_ALLIANCE_GATE_DAMAGED : BG_SA_HORDE_GATE_DAMAGED;
if (Creature* c = obj->FindNearestCreature(NPC_WORLD_TRIGGER, 500.0f))
SendChatMessage(c, gate->DamagedText, invoker);
PlaySoundToAll(Attackers == TEAM_ALLIANCE ? SOUND_WALL_ATTACKED_ALLIANCE : SOUND_WALL_ATTACKED_HORDE);
UpdateWorldState(gate->WorldState, gateState);
}
// destroyed
else if (eventId == go->GetGOInfo()->destructibleBuilding.DestroyedEvent)
{
BG_SA_GateState gateState = Attackers == TEAM_HORDE ? BG_SA_ALLIANCE_GATE_DESTROYED : BG_SA_HORDE_GATE_DESTROYED;
if (Creature* c = obj->FindNearestCreature(NPC_WORLD_TRIGGER, 500.0f))
SendChatMessage(c, gate->DestroyedText, invoker);
PlaySoundToAll(Attackers == TEAM_ALLIANCE ? SOUND_WALL_DESTROYED_ALLIANCE : SOUND_WALL_DESTROYED_HORDE);
// check if other gate from same line of defense is already destroyed for honor reward
bool rewardHonor = true;
switch (gateId)
{
case GO_GATE_OF_THE_GREEN_EMERALD:
if (IsGateDestroyed(GetGate(GO_GATE_OF_THE_BLUE_SAPPHIRE)))
rewardHonor = false;
break;
case GO_GATE_OF_THE_BLUE_SAPPHIRE:
if (IsGateDestroyed(GetGate(GO_GATE_OF_THE_GREEN_EMERALD)))
rewardHonor = false;
break;
case GO_GATE_OF_THE_RED_SUN:
if (IsGateDestroyed(GetGate(GO_GATE_OF_THE_PURPLE_AMETHYST)))
rewardHonor = false;
break;
case GO_GATE_OF_THE_PURPLE_AMETHYST:
if (IsGateDestroyed(GetGate(GO_GATE_OF_THE_RED_SUN)))
rewardHonor = false;
break;
default:
break;
}
if (invoker)
{
if (Unit* unit = invoker->ToUnit())
{
if (Player* player = unit->GetCharmerOrOwnerPlayerOrPlayerItself())
{
UpdatePvpStat(player, PVP_STAT_GATES_DESTROYED, 1);
if (rewardHonor)
UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(1));
}
}
}
if (rewardHonor)
MakeObjectsInteractable(gate->LineOfDefense);
UpdateWorldState(gate->WorldState, gateState);
GetBgMap()->UpdateSpawnGroupConditions();
}
}
break;
}
default:
break;
}
}
}
void BattlegroundSA::HandleKillUnit(Creature* creature, Unit* killer)
{
if (creature->GetEntry() == NPC_DEMOLISHER_SA)
{
if (Player* killerPlayer = killer->GetCharmerOrOwnerPlayerOrPlayerItself())
UpdatePvpStat(killerPlayer, PVP_STAT_DEMOLISHERS_DESTROYED, 1);
int32 worldStateId = Attackers == TEAM_HORDE ? BG_SA_DESTROYED_HORDE_VEHICLES : BG_SA_DESTROYED_ALLIANCE_VEHICLES;
int32 currentDestroyedVehicles = sWorldStateMgr->GetValue(worldStateId, GetBgMap());
UpdateWorldState(worldStateId, currentDestroyedVehicles + 1);
}
}
void BattlegroundSA::DestroyGate(Player* /*player*/, GameObject* /*go*/)
{
}
void BattlegroundSA::CaptureGraveyard(StrandOfTheAncientsGraveyard graveyard, TeamId teamId)
{
switch (graveyard)
{
case StrandOfTheAncientsGraveyard::West:
UpdateWorldState(BG_SA_LEFT_GY_ALLIANCE, teamId == TEAM_ALLIANCE);
UpdateWorldState(BG_SA_LEFT_GY_HORDE, teamId == TEAM_HORDE);
break;
case StrandOfTheAncientsGraveyard::East:
UpdateWorldState(BG_SA_RIGHT_GY_ALLIANCE, teamId == TEAM_ALLIANCE);
UpdateWorldState(BG_SA_RIGHT_GY_HORDE, teamId == TEAM_HORDE);
break;
case StrandOfTheAncientsGraveyard::Central:
UpdateWorldState(BG_SA_CENTER_GY_ALLIANCE, teamId == TEAM_ALLIANCE);
UpdateWorldState(BG_SA_CENTER_GY_HORDE, teamId == TEAM_HORDE);
CaptureGraveyard(StrandOfTheAncientsGraveyard::East, teamId);
CaptureGraveyard(StrandOfTheAncientsGraveyard::West, teamId);
break;
default:
break;
}
}
void BattlegroundSA::TitanRelicActivated(Player* clicker)
{
if (!clicker)
return;
TeamId clickerTeamId = GetTeamIndexByTeamId(GetPlayerTeam(clicker->GetGUID()));
if (clickerTeamId == Attackers)
{
if (clickerTeamId == TEAM_ALLIANCE)
SendBroadcastText(BG_SA_TEXT_ALLIANCE_CAPTURED_TITAN_PORTAL, CHAT_MSG_BG_SYSTEM_ALLIANCE);
else
SendBroadcastText(BG_SA_TEXT_HORDE_CAPTURED_TITAN_PORTAL, CHAT_MSG_BG_SYSTEM_HORDE);
if (Status == BG_SA_ROUND_ONE)
{
EndRound();
// Achievement Storm the Beach (1310)
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
{
if (Player* player = ObjectAccessor::FindPlayer(itr->first))
if (GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())) == Attackers)
player->UpdateCriteria(CriteriaType::BeSpellTarget, 65246);
}
if (Creature* c = FindKanrethad())
SendChatMessage(c, TEXT_ROUND_1_FINISHED);
}
else if (Status == BG_SA_ROUND_TWO)
{
RoundScores[1].winner = Attackers;
RoundScores[1].time = TotalTime;
ToggleTimer();
// Achievement Storm the Beach (1310)
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
{
if (Player* player = ObjectAccessor::FindPlayer(itr->first))
if (GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID())) == Attackers && RoundScores[1].winner == Attackers)
player->UpdateCriteria(CriteriaType::BeSpellTarget, 65246);
}
if (RoundScores[0].time == RoundScores[1].time)
EndBattleground(TEAM_OTHER);
else if (RoundScores[0].time < RoundScores[1].time)
EndBattleground(RoundScores[0].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE);
else
EndBattleground(RoundScores[1].winner == TEAM_ALLIANCE ? ALLIANCE : HORDE);
}
}
}
void BattlegroundSA::ToggleTimer()
{
TimerEnabled = !TimerEnabled;
UpdateWorldState(BG_SA_ENABLE_TIMER, TimerEnabled);
}
void BattlegroundSA::EndBattleground(Team winner)
{
// honor reward for winning
if (winner == ALLIANCE)
RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
else if (winner == HORDE)
RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
// complete map_end rewards (even if no team wins)
RewardHonorToTeam(GetBonusHonorFromKill(2), ALLIANCE);
RewardHonorToTeam(GetBonusHonorFromKill(2), HORDE);
Battleground::EndBattleground(winner);
}
void BattlegroundSA::SendTransportInit(Player* player)
{
UpdateData transData(player->GetMapId());
for (ObjectGuid const& boatGuid : _boatGUIDs[Attackers])
if (GameObject const* boat = GetBgMap()->GetGameObject(boatGuid))
boat->BuildCreateUpdateBlockForPlayer(&transData, player);
WorldPacket packet;
transData.BuildPacket(&packet);
player->SendDirectMessage(&packet);
}
void BattlegroundSA::SendTransportsRemove(Player* player)
{
UpdateData transData(player->GetMapId());
for (ObjectGuid const& boatGuid : _boatGUIDs[Attackers])
if (GameObject const* boat = GetBgMap()->GetGameObject(boatGuid))
boat->BuildOutOfRangeUpdateBlock(&transData);
WorldPacket packet;
transData.BuildPacket(&packet);
player->SendDirectMessage(&packet);
}
bool BattlegroundSA::IsGateDestroyed(GateInfo const* gateInfo) const
{
if (!gateInfo)
return false;
int32 value = GetBgMap()->GetWorldStateValue(gateInfo->WorldState);
return value == BG_SA_ALLIANCE_GATE_DESTROYED || value == BG_SA_HORDE_GATE_DESTROYED;
}
void BattlegroundSA::HandleCaptureGraveyardAction(GameObject* graveyardBanner, Player* player)
{
if (!graveyardBanner || !player)
return;
TeamId const teamId = GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID()));
// Only attackers can capture graveyard by gameobject action
if (teamId != Attackers)
return;
switch (graveyardBanner->GetEntry())
{
case GO_GRAVEYARD_WEST_A:
case GO_GRAVEYARD_WEST_H:
CaptureGraveyard(StrandOfTheAncientsGraveyard::West, teamId);
break;
case GO_GRAVEYARD_EAST_A:
case GO_GRAVEYARD_EAST_H:
CaptureGraveyard(StrandOfTheAncientsGraveyard::East, teamId);
break;
case GO_GRAVEYARD_CENTRAL_A:
case GO_GRAVEYARD_CENTRAL_H:
CaptureGraveyard(StrandOfTheAncientsGraveyard::Central, teamId);
break;
default:
break;
}
}
void BattlegroundSA::MakeObjectsInteractable(DefenseLine defenseLine)
{
auto makeInteractable = [&](ObjectGuid const& guid) -> void
{
if (GameObject* gameObject = GetBgMap()->GetGameObject(guid))
gameObject->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
};
switch (defenseLine)
{
case DefenseLine::First:
makeInteractable(_graveyardWest);
makeInteractable(_graveyardEast);
break;
case DefenseLine::Second:
makeInteractable(_graveyardCentral);
break;
case DefenseLine::Third:
break;
case DefenseLine::Last:
// make titan orb interactable
if (GameObject* door = GetBgMap()->GetGameObject(_collisionDoorGUID))
door->UseDoorOrButton();
makeInteractable(_titanRelicGUID);
break;
default:
break;
}
}
Creature* BattlegroundSA::FindKanrethad() const
{
return GetBgMap()->GetCreature(_kanrethadGUID);
}
void BattlegroundSA::EndRound()
{
RoundScores[0].winner = Attackers;
RoundScores[0].time = std::min<uint32>(TotalTime, BG_SA_ROUNDLENGTH);
Attackers = (Attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE;
Status = BG_SA_SECOND_WARMUP;
TotalTime = 0;
ToggleTimer();
UpdateWaitTimer = 5000;
SignaledRoundTwo = false;
SignaledRoundTwoHalfMin = false;
InitSecondRound = true;
ResetObjs();
GetBgMap()->UpdateAreaDependentAuras();
CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE);
CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE);
RemoveAuraOnTeam(SPELL_CARRYING_SEAFORIUM_CHARGE, HORDE);
RemoveAuraOnTeam(SPELL_CARRYING_SEAFORIUM_CHARGE, ALLIANCE);
}
void BattlegroundSA::OnGameObjectCreate(GameObject* gameobject)
{
Battleground::OnGameObjectCreate(gameobject);
if (gameobject->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
_gateGUIDs.insert(gameobject->GetGUID());
switch (gameobject->GetEntry())
{
case BG_SA_BOAT_ONE_A:
_boatGUIDs[TEAM_ALLIANCE][0] = gameobject->GetGUID();
break;
case BG_SA_BOAT_TWO_A:
_boatGUIDs[TEAM_ALLIANCE][1] = gameobject->GetGUID();
break;
case BG_SA_BOAT_ONE_H:
_boatGUIDs[TEAM_HORDE][0] = gameobject->GetGUID();
break;
case BG_SA_BOAT_TWO_H:
_boatGUIDs[TEAM_HORDE][1] = gameobject->GetGUID();
break;
case GO_SEAFORIUM_BOMB_A:
_staticBombGUIDs[TEAM_ALLIANCE].insert(gameobject->GetGUID());
if (Status != BG_SA_SECOND_WARMUP && Status != BG_SA_WARMUP)
gameobject->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
break;
case GO_SEAFORIUM_BOMB_H:
_staticBombGUIDs[TEAM_HORDE].insert(gameobject->GetGUID());
if (Status != BG_SA_SECOND_WARMUP && Status != BG_SA_WARMUP)
gameobject->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
break;
case GO_SEAFORIUM_CHARGE_A:
case GO_SEAFORIUM_CHARGE_H:
_dynamicBombGUIDs.insert(gameobject->GetGUID());
break;
case GO_GRAVEYARD_EAST_A:
case GO_GRAVEYARD_EAST_H:
_graveyardEast = gameobject->GetGUID();
break;
case GO_GRAVEYARD_WEST_A:
case GO_GRAVEYARD_WEST_H:
_graveyardWest = gameobject->GetGUID();
break;
case GO_GRAVEYARD_CENTRAL_A:
case GO_GRAVEYARD_CENTRAL_H:
_graveyardCentral = gameobject->GetGUID();
break;
case GO_COLLISION_DOOR:
_collisionDoorGUID = gameobject->GetGUID();
break;
case GO_TITAN_RELIC_A:
case GO_TITAN_RELIC_H:
_titanRelicGUID = gameobject->GetGUID();
break;
default:
break;
}
}
void BattlegroundSA::DoAction(uint32 actionId, WorldObject* source, WorldObject* target)
{
switch (actionId)
{
case ACTION_SOTA_CAPTURE_GRAVEYARD:
HandleCaptureGraveyardAction(Object::ToGameObject(target), Object::ToPlayer(source));
break;
default:
break;
}
}
void BattlegroundSA::OnCreatureCreate(Creature* creature)
{
Battleground::OnCreatureCreate(creature);
switch (creature->GetEntry())
{
case NPC_DEMOLISHER:
creature->SetFaction(BG_SA_Factions[Attackers]);
break;
case NPC_ANTIPERSONNEL_CANNON:
creature->SetFaction(BG_SA_Factions[Attackers == TEAM_HORDE ? TEAM_ALLIANCE : TEAM_HORDE]);
break;
case NPC_KANRETHAD:
_kanrethadGUID = creature->GetGUID();
break;
case NPC_RIGGER_SPARKLIGHT:
case NPC_GORGRIL_RIGSPARK:
creature->AI()->Talk(TEXT_SPARKLIGHT_RIGSPARK_SPAWN);
break;
default:
break;
}
}
void BattlegroundSA::OnMapSet(BattlegroundMap* map)
{
Battleground::OnMapSet(map);
ResetObjs();
}
uint32 BattlegroundSA::GetData(uint32 dataId) const
{
switch (dataId)
{
case DATA_ATTACKERS:
return Attackers;
case DATA_STATUS:
return Status;
default:
return Battleground::GetData(dataId);
}
}
@@ -1,365 +0,0 @@
/*
* 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 __BATTLEGROUNDSA_H
#define __BATTLEGROUNDSA_H
#include "Battleground.h"
#include "Object.h"
enum BG_SA_Status
{
BG_SA_NOT_STARTED = 0,
BG_SA_WARMUP,
BG_SA_ROUND_ONE,
BG_SA_SECOND_WARMUP,
BG_SA_ROUND_TWO,
BG_SA_BONUS_ROUND
};
enum BG_SA_GateState
{
// alliance is defender
BG_SA_ALLIANCE_GATE_OK = 1,
BG_SA_ALLIANCE_GATE_DAMAGED = 2,
BG_SA_ALLIANCE_GATE_DESTROYED = 3,
// horde is defender
BG_SA_HORDE_GATE_OK = 4,
BG_SA_HORDE_GATE_DAMAGED = 5,
BG_SA_HORDE_GATE_DESTROYED = 6,
};
enum StrandOfTheAncientsGameObjects
{
GO_SEAFORIUM_BOMB_H = 194086, // Used by horde players
GO_SEAFORIUM_BOMB_A = 190753, // Used by alliance players
GO_SEAFORIUM_CHARGE_H = 257572,
GO_SEAFORIUM_CHARGE_A = 257565,
GO_GRAVEYARD_WEST_H = 191307,
GO_GRAVEYARD_WEST_A = 191308,
GO_GRAVEYARD_EAST_H = 191305,
GO_GRAVEYARD_EAST_A = 191306,
GO_GRAVEYARD_CENTRAL_H = 191309,
GO_GRAVEYARD_CENTRAL_A = 191310,
GO_COLLISION_DOOR = 194162,
GO_TITAN_RELIC_A = 194083,
GO_TITAN_RELIC_H = 194082,
GO_GATE_OF_THE_GREEN_EMERALD = 190722,
GO_GATE_OF_THE_PURPLE_AMETHYST = 190723,
GO_GATE_OF_THE_BLUE_SAPPHIRE = 190724,
GO_GATE_OF_THE_RED_SUN = 190726,
GO_GATE_OF_THE_YELLOW_MOON = 190727,
GO_CHAMBER_OF_ANCIENT_RELICS = 192549
};
enum BG_SA_Timers
{
BG_SA_BOAT_START = 60 * IN_MILLISECONDS,
BG_SA_WARMUPLENGTH = 120 * IN_MILLISECONDS,
BG_SA_ROUNDLENGTH = 600 * IN_MILLISECONDS
};
enum SASounds
{
SOUND_GRAVEYARD_TAKEN_HORDE = 8174,
SOUND_GRAVEYARD_TAKEN_ALLIANCE = 8212,
SOUND_DEFEAT_HORDE = 15905,
SOUND_VICTORY_HORDE = 15906,
SOUND_VICTORY_ALLIANCE = 15907,
SOUND_DEFEAT_ALLIANCE = 15908,
SOUND_WALL_DESTROYED_ALLIANCE = 15909,
SOUND_WALL_DESTROYED_HORDE = 15910,
SOUND_WALL_ATTACKED_HORDE = 15911,
SOUND_WALL_ATTACKED_ALLIANCE = 15912
};
enum SATexts
{
// Kanrethad
TEXT_ROUND_STARTED = 1,
TEXT_ROUND_1_FINISHED = 2,
// Rigger Sparklight / Gorgril Rigspark
TEXT_SPARKLIGHT_RIGSPARK_SPAWN = 1,
// World Trigger
TEXT_BLUE_GATE_UNDER_ATTACK = 1,
TEXT_GREEN_GATE_UNDER_ATTACK = 2,
TEXT_RED_GATE_UNDER_ATTACK = 3,
TEXT_PURPLE_GATE_UNDER_ATTACK = 4,
TEXT_YELLOW_GATE_UNDER_ATTACK = 5,
TEXT_YELLOW_GATE_DESTROYED = 6,
TEXT_PURPLE_GATE_DESTROYED = 7,
TEXT_RED_GATE_DESTROYED = 8,
TEXT_GREEN_GATE_DESTROYED = 9,
TEXT_BLUE_GATE_DESTROYED = 10,
TEXT_EAST_GRAVEYARD_CAPTURED_A = 11,
TEXT_WEST_GRAVEYARD_CAPTURED_A = 12,
TEXT_SOUTH_GRAVEYARD_CAPTURED_A = 13,
TEXT_EAST_GRAVEYARD_CAPTURED_H = 14,
TEXT_WEST_GRAVEYARD_CAPTURED_H = 15,
TEXT_SOUTH_GRAVEYARD_CAPTURED_H = 16,
TEXT_ANCIENT_GATE_UNDER_ATTACK = 17,
TEXT_ANCIENT_GATE_DESTROYED = 18
};
enum SAWorldStates
{
BG_SA_TIMER = 3557,
BG_SA_ALLY_ATTACKS = 4352,
BG_SA_HORDE_ATTACKS = 4353,
BG_SA_PURPLE_GATEWS = 3614,
BG_SA_RED_GATEWS = 3617,
BG_SA_BLUE_GATEWS = 3620,
BG_SA_GREEN_GATEWS = 3623,
BG_SA_YELLOW_GATEWS = 3638,
BG_SA_ANCIENT_GATEWS = 3849,
BG_SA_LEFT_GY_ALLIANCE = 3635,
BG_SA_RIGHT_GY_ALLIANCE = 3636,
BG_SA_CENTER_GY_ALLIANCE = 3637,
BG_SA_RIGHT_ATT_TOKEN_ALL = 3627,
BG_SA_LEFT_ATT_TOKEN_ALL = 3626,
BG_SA_LEFT_ATT_TOKEN_HRD = 3629,
BG_SA_RIGHT_ATT_TOKEN_HRD = 3628,
BG_SA_HORDE_DEFENCE_TOKEN = 3631,
BG_SA_ALLIANCE_DEFENCE_TOKEN = 3630,
BG_SA_RIGHT_GY_HORDE = 3632,
BG_SA_LEFT_GY_HORDE = 3633,
BG_SA_CENTER_GY_HORDE = 3634,
BG_SA_BONUS_TIMER = 3571,
BG_SA_ENABLE_TIMER = 3564,
BG_SA_ATTACKER_TEAM = 3690,
BG_SA_DESTROYED_ALLIANCE_VEHICLES = 3955,
BG_SA_DESTROYED_HORDE_VEHICLES = 3956,
};
enum BG_SA_Boat
{
BG_SA_BOAT_ONE_A = 208000,
BG_SA_BOAT_TWO_H = 208001,
BG_SA_BOAT_ONE_H = 193184,
BG_SA_BOAT_TWO_A = 193185
};
uint32 const BG_SA_Factions[2] =
{
1732,
1735,
};
enum class StrandOfTheAncientsGraveyard
{
West,
East,
Central
};
enum BG_SA_BroadcastTexts
{
BG_SA_TEXT_ALLIANCE_CAPTURED_TITAN_PORTAL = 28944,
BG_SA_TEXT_HORDE_CAPTURED_TITAN_PORTAL = 28945,
BG_SA_TEXT_ROUND_TWO_START_ONE_MINUTE = 29448,
BG_SA_TEXT_ROUND_TWO_START_HALF_MINUTE = 29449
};
enum class DefenseLine
{
First,
Second,
Third,
Last
};
struct GateInfo
{
uint32 GameObjectId;
uint32 WorldState;
uint8 DamagedText;
uint8 DestroyedText;
DefenseLine LineOfDefense;
};
GateInfo const Gates[] =
{
{ GO_GATE_OF_THE_GREEN_EMERALD, BG_SA_GREEN_GATEWS, TEXT_GREEN_GATE_UNDER_ATTACK, TEXT_GREEN_GATE_DESTROYED, DefenseLine::First },
{ GO_GATE_OF_THE_YELLOW_MOON, BG_SA_YELLOW_GATEWS, TEXT_YELLOW_GATE_UNDER_ATTACK, TEXT_YELLOW_GATE_DESTROYED, DefenseLine::Third },
{ GO_GATE_OF_THE_BLUE_SAPPHIRE, BG_SA_BLUE_GATEWS, TEXT_BLUE_GATE_UNDER_ATTACK, TEXT_BLUE_GATE_DESTROYED, DefenseLine::First },
{ GO_GATE_OF_THE_RED_SUN, BG_SA_RED_GATEWS, TEXT_RED_GATE_UNDER_ATTACK, TEXT_RED_GATE_DESTROYED, DefenseLine::Second },
{ GO_GATE_OF_THE_PURPLE_AMETHYST, BG_SA_PURPLE_GATEWS, TEXT_PURPLE_GATE_UNDER_ATTACK, TEXT_PURPLE_GATE_DESTROYED, DefenseLine::Second },
{ GO_CHAMBER_OF_ANCIENT_RELICS, BG_SA_ANCIENT_GATEWS, TEXT_ANCIENT_GATE_UNDER_ATTACK, TEXT_ANCIENT_GATE_DESTROYED, DefenseLine::Last }
};
struct BG_SA_RoundScore
{
TeamId winner;
uint32 time;
};
enum StrandOfTheAncientSharedActions
{
ACTION_SOTA_CAPTURE_GRAVEYARD
};
/// Class for manage Strand of Ancient battleground
class BattlegroundSA : public Battleground
{
public:
BattlegroundSA(BattlegroundTemplate const* battlegroundTemplate);
~BattlegroundSA();
/**
* \brief Called every time for update battle data
* -Update timer
* -Round switch
*/
void PostUpdateImpl(uint32 diff) override;
/* inherited from BattlegroundClass */
/// Called when a player join battle
void AddPlayer(Player* player, BattlegroundQueueTypeId queueId) override;
/// Called for ini battleground, after that the first player be entered
bool SetupBattleground() override;
void Reset() override;
/// Called when a player kill a unit in bg
void HandleKillUnit(Creature* creature, Unit* killer) override;
/// Called when someone activates an event
void ProcessEvent(WorldObject* /*obj*/, uint32 /*eventId*/, WorldObject* /*invoker*/ = nullptr) override;
/// Called when a player clicked on relic
void TitanRelicActivated(Player* clicker);
/// Return GateInfo, relative to bg data, according to gameobject entry
GateInfo const* GetGate(uint32 entry)
{
for (GateInfo const& gate : Gates)
if (gate.GameObjectId == entry)
return &gate;
return nullptr;
}
/// Called on battleground ending
void EndBattleground(Team winner) override;
/// Called when a player leave battleground
void RemovePlayer(Player* player, ObjectGuid guid, uint32 team) override;
void OnGameObjectCreate(GameObject* gameobject) override;
void DoAction(uint32 actionId, WorldObject* source, WorldObject* target) override;
void OnCreatureCreate(Creature* creature) override;
void OnMapSet(BattlegroundMap* map) override;
uint32 GetData(uint32 dataId) const override;
private:
/**
* \brief Called on setup and between the two round
* -Delete all gameobject / creature
* -Respawn all gameobject / creature to have good faction
*/
bool ResetObjs();
/// Called for start ship movement
void StartShips();
/**
* \brief Called between the two round
* -Teleport all players to good location
*/
void TeleportPlayers() const;
void TeleportToEntrancePosition(Player* player) const;
/**
* \brief Called when a gate is destroy
* -Give honor to player witch destroy it
* -Update worldstate
* -Delete gameobject in front of door (lighting object, with different colours for each door)
*/
void DestroyGate(Player* player, GameObject* go) override;
/**
* \brief Called when a graveyard is capture
* -Update spiritguide
* -Update gameobject (flag)
* -Update Worldstate
* -Send warning for announce this
* \param i : id of graveyard
* \param Source : Player who capture gy
*/
void CaptureGraveyard(StrandOfTheAncientsGraveyard graveyard, TeamId teamId);
/// Switch on/off timer worldstate
void ToggleTimer();
/// Send packet to player for create boats (client part)
void SendTransportInit(Player* player);
/// Send packet to player for destroy boats (client part)
void SendTransportsRemove(Player* player);
bool IsGateDestroyed(GateInfo const* gateInfo) const;
void HandleCaptureGraveyardAction(GameObject* graveyardBanner, Player* player);
void MakeObjectsInteractable(DefenseLine defenseLine);
Creature* FindKanrethad() const;
void EndRound();
/// Id of attacker team
TeamId Attackers;
/// Totale elapsed time of current round
uint32 TotalTime;
/// Max time of round
uint32 EndRoundTimer;
/// For know if boats has start moving or not yet
bool ShipsStarted;
/// Statu of battle (Start or not, and what round)
BG_SA_Status Status;
/// Score of each round
BG_SA_RoundScore RoundScores[2];
/// used for know we are in timer phase or not (used for worldstate update)
bool TimerEnabled;
/// 5secs before starting the 1min countdown for second round
uint32 UpdateWaitTimer;
/// for know if warning about second round start has been sent
bool SignaledRoundTwo;
/// for know if warning about second round start has been sent
bool SignaledRoundTwoHalfMin;
/// for know if second round has been init
bool InitSecondRound;
// [team][boat_idx]
std::array<std::array<ObjectGuid, 2 /*BOAT_COUNT*/>, PVP_TEAMS_COUNT> _boatGUIDs;
std::array<GuidUnorderedSet, PVP_TEAMS_COUNT> _staticBombGUIDs; // bombs ready to be picked up
GuidUnorderedSet _dynamicBombGUIDs; // bombs thrown by players, ready to explode/disarm
ObjectGuid _graveyardWest;
ObjectGuid _graveyardEast;
ObjectGuid _graveyardCentral;
GuidUnorderedSet _gateGUIDs;
ObjectGuid _collisionDoorGUID;
ObjectGuid _kanrethadGUID;
ObjectGuid _titanRelicGUID;
};
#endif
@@ -1,559 +0,0 @@
/*
* 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/>.
*/
#include "BattlegroundWS.h"
#include "AreaTrigger.h"
#include "BattlegroundMgr.h"
#include "DB2Stores.h"
#include "GameObject.h"
#include "GameTime.h"
#include "Log.h"
#include "Map.h"
#include "Object.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "SpellAuras.h"
#include "SpellInfo.h"
// these variables aren't used outside of this file, so declare them only here
enum BG_WSG_Rewards
{
BG_WSG_WIN = 0,
BG_WSG_FLAG_CAP,
BG_WSG_MAP_COMPLETE,
BG_WSG_REWARD_NUM
};
uint32 BG_WSG_Honor[2][BG_WSG_REWARD_NUM] =
{
{20, 40, 40}, // normal honor
{60, 40, 80} // holiday
};
enum WarsongGulchPvpStats
{
PVP_STAT_FLAG_CAPTURES = 928,
PVP_STAT_FLAG_RETURNS = 929
};
BattlegroundWS::BattlegroundWS(BattlegroundTemplate const* battlegroundTemplate) : Battleground(battlegroundTemplate)
{
BgObjects.resize(0);
BgCreatures.resize(0);
StartMessageIds[BG_STARTING_EVENT_SECOND] = BG_WS_TEXT_START_ONE_MINUTE;
StartMessageIds[BG_STARTING_EVENT_THIRD] = BG_WS_TEXT_START_HALF_MINUTE;
StartMessageIds[BG_STARTING_EVENT_FOURTH] = BG_WS_TEXT_BATTLE_HAS_BEGUN;
_bothFlagsKept = false;
_lastFlagCaptureTeam = TEAM_OTHER;
m_ReputationCapture = 0;
m_HonorWinKills = 0;
m_HonorEndKills = 0;
_flags = { };
_capturePointAreaTriggers = { };
_flagAssaultTimer.Reset(FLAG_ASSAULT_TIMER);
_assaultStackCount = 0;
}
BattlegroundWS::~BattlegroundWS() { }
void BattlegroundWS::PostUpdateImpl(uint32 diff)
{
if (GetStatus() == STATUS_IN_PROGRESS)
{
if (GetElapsedTime() >= 17 * MINUTE * IN_MILLISECONDS)
{
if (GetTeamScore(TEAM_ALLIANCE) == 0)
{
if (GetTeamScore(TEAM_HORDE) == 0) // No one scored - result is tie
EndBattleground(TEAM_OTHER);
else // Horde has more points and thus wins
EndBattleground(HORDE);
}
else if (GetTeamScore(TEAM_HORDE) == 0) // Alliance has > 0, Horde has 0, alliance wins
EndBattleground(ALLIANCE);
else if (GetTeamScore(TEAM_HORDE) == GetTeamScore(TEAM_ALLIANCE)) // Team score equal, winner is team that scored the last flag
EndBattleground(_lastFlagCaptureTeam);
else if (GetTeamScore(TEAM_HORDE) > GetTeamScore(TEAM_ALLIANCE)) // Last but not least, check who has the higher score
EndBattleground(HORDE);
else
EndBattleground(ALLIANCE);
}
if (_bothFlagsKept)
{
_flagAssaultTimer.Update(diff);
if (_flagAssaultTimer.Passed())
{
_flagAssaultTimer.Reset(FLAG_ASSAULT_TIMER);
_assaultStackCount++;
// update assault debuff stacks
DoForFlagKeepers([&](Player* player) -> void
{
ApplyAssaultDebuffToPlayer(player);
});
}
}
}
}
void BattlegroundWS::DoForFlagKeepers(std::function<void(Player*)> action) const
{
for (ObjectGuid flagGUID : _flags)
{
if (GameObject* flag = GetBgMap()->GetGameObject(flagGUID))
{
if (Player* carrier = ObjectAccessor::FindPlayer(flag->GetFlagCarrierGUID()))
action(carrier);
}
}
}
void BattlegroundWS::ResetAssaultDebuff()
{
_bothFlagsKept = false;
_assaultStackCount = 0;
_flagAssaultTimer.Reset(FLAG_ASSAULT_TIMER);
DoForFlagKeepers([&](Player* player) -> void
{
RemoveAssaultDebuffFromPlayer(player);
});
}
void BattlegroundWS::ApplyAssaultDebuffToPlayer(Player* player)
{
if (_assaultStackCount == 0)
return;
uint32 spellId = WS_SPELL_FOCUSED_ASSAULT;
if (_assaultStackCount >= FLAG_BRUTAL_ASSAULT_STACK_COUNT)
{
player->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT);
spellId = WS_SPELL_BRUTAL_ASSAULT;
}
Aura* aura = player->GetAura(spellId);
if (!aura)
{
player->CastSpell(player, spellId, true);
aura = player->GetAura(spellId);
}
if (aura)
aura->SetStackAmount(_assaultStackCount);
}
void BattlegroundWS::RemoveAssaultDebuffFromPlayer(Player* player)
{
player->RemoveAurasDueToSpell(WS_SPELL_FOCUSED_ASSAULT);
player->RemoveAurasDueToSpell(WS_SPELL_BRUTAL_ASSAULT);
}
void BattlegroundWS::StartingEventOpenDoors()
{
for (ObjectGuid door : _doors)
{
if (GameObject* gameObject = GetBgMap()->GetGameObject(door))
{
gameObject->UseDoorOrButton();
gameObject->DespawnOrUnsummon(3s);
}
}
UpdateWorldState(BG_WS_STATE_TIMER_ACTIVE, 1);
UpdateWorldState(BG_WS_STATE_TIMER, GameTime::GetGameTime() + 15 * MINUTE);
// players joining later are not eligibles
TriggerGameEvent(WS_EVENT_START_BATTLE);
}
FlagState BattlegroundWS::GetFlagState(TeamId team) const
{
if (GameObject* gameObject = FindBgMap()->GetGameObject(_flags[team]))
return gameObject->GetFlagState();
return FlagState(0);
}
ObjectGuid const& BattlegroundWS::GetFlagCarrierGUID(TeamId team) const
{
if (GameObject* gameObject = FindBgMap()->GetGameObject(_flags[team]))
return gameObject->GetFlagCarrierGUID();
return ObjectGuid::Empty;
}
void BattlegroundWS::HandleFlagRoomCapturePoint()
{
DoForFlagKeepers([&](Player* player) -> void
{
TeamId team = GetTeamIndexByTeamId(GetPlayerTeam(player->GetGUID()));
if (AreaTrigger* trigger = GetBgMap()->GetAreaTrigger(_capturePointAreaTriggers[team]))
if (trigger->GetInsideUnits().contains(player->GetGUID()))
if (CanCaptureFlag(trigger, player))
OnCaptureFlag(trigger, player);
});
}
void BattlegroundWS::UpdateFlagState(uint32 team, FlagState value)
{
auto transformValueToOtherTeamControlWorldState = [](FlagState value)
{
switch (value)
{
case FlagState::InBase:
case FlagState::Dropped:
case FlagState::Respawning:
return 1;
case FlagState::Taken:
return 2;
default:
return 0;
}
};
if (team == ALLIANCE)
{
UpdateWorldState(BG_WS_FLAG_STATE_ALLIANCE, AsUnderlyingType(value));
UpdateWorldState(BG_WS_FLAG_CONTROL_HORDE, transformValueToOtherTeamControlWorldState(value));
}
else
{
UpdateWorldState(BG_WS_FLAG_STATE_HORDE, AsUnderlyingType(value));
UpdateWorldState(BG_WS_FLAG_CONTROL_ALLIANCE, transformValueToOtherTeamControlWorldState(value));
}
}
void BattlegroundWS::UpdateTeamScore(TeamId team)
{
if (team == TEAM_ALLIANCE)
UpdateWorldState(BG_WS_FLAG_CAPTURES_ALLIANCE, GetTeamScore(team));
else
UpdateWorldState(BG_WS_FLAG_CAPTURES_HORDE, GetTeamScore(team));
}
bool BattlegroundWS::SetupBattleground()
{
return true;
}
void BattlegroundWS::Reset()
{
//call parent's class reset
Battleground::Reset();
m_TeamScores[TEAM_ALLIANCE] = 0;
m_TeamScores[TEAM_HORDE] = 0;
if (sBattlegroundMgr->IsBGWeekend(GetTypeID()))
{
m_ReputationCapture = 45;
m_HonorWinKills = 3;
m_HonorEndKills = 4;
}
else
{
m_ReputationCapture = 35;
m_HonorWinKills = 1;
m_HonorEndKills = 2;
}
_lastFlagCaptureTeam = TEAM_OTHER;
_bothFlagsKept = false;
_doors.clear();
_flags = { };
_assaultStackCount = 0;
_flagAssaultTimer.Reset(FLAG_ASSAULT_TIMER);
_capturePointAreaTriggers = { };
}
void BattlegroundWS::EndBattleground(Team winner)
{
// Win reward
if (winner == ALLIANCE)
RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), ALLIANCE);
if (winner == HORDE)
RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), HORDE);
// Complete map_end rewards (even if no team wins)
RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), ALLIANCE);
RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), HORDE);
Battleground::EndBattleground(winner);
}
void BattlegroundWS::HandleKillPlayer(Player* player, Player* killer)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return;
EventPlayerDroppedFlag(player);
Battleground::HandleKillPlayer(player, killer);
}
WorldSafeLocsEntry const* BattlegroundWS::GetClosestGraveyard(Player* player)
{
return sObjectMgr->GetClosestGraveyard(*player, player->GetBGTeam(), player);
}
WorldSafeLocsEntry const* BattlegroundWS::GetExploitTeleportLocation(Team team)
{
return sObjectMgr->GetWorldSafeLoc(team == ALLIANCE ? WS_EXPLOIT_TELEPORT_LOCATION_ALLIANCE : WS_EXPLOIT_TELEPORT_LOCATION_HORDE);
}
Team BattlegroundWS::GetPrematureWinner()
{
if (GetTeamScore(TEAM_ALLIANCE) > GetTeamScore(TEAM_HORDE))
return ALLIANCE;
else if (GetTeamScore(TEAM_HORDE) > GetTeamScore(TEAM_ALLIANCE))
return HORDE;
return Battleground::GetPrematureWinner();
}
void BattlegroundWS::OnGameObjectCreate(GameObject* gameObject)
{
switch (gameObject->GetEntry())
{
case BG_WS_OBJECT_ALLIANCE_DOOR:
case BG_WS_OBJECT_PORTCULLIS_009:
case BG_WS_OBJECT_PORTCULLIS_002:
case BG_WS_OBJECT_COLLISION_PC_SIZE:
case BG_WS_OBJECT_HORDE_GATE_1:
case BG_WS_OBJECT_HORDE_GATE_2:
_doors.insert(gameObject->GetGUID());
break;
case BG_WS_OBJECT_ALLIANCE_FLAG_IN_BASE:
_flags[TEAM_ALLIANCE] = gameObject->GetGUID();
break;
case BG_WS_OBJECT_HORDE_FLAG_IN_BASE:
_flags[TEAM_HORDE] = gameObject->GetGUID();
break;
default:
break;
}
}
void BattlegroundWS::OnAreaTriggerCreate(AreaTrigger* areaTrigger)
{
if (!areaTrigger->IsStaticSpawn())
return;
switch (areaTrigger->GetEntry())
{
case AT_CAPTURE_POINT_ALLIANCE:
_capturePointAreaTriggers[TEAM_ALLIANCE] = areaTrigger->GetGUID();
break;
case AT_CAPTURE_POINT_HORDE:
_capturePointAreaTriggers[TEAM_HORDE] = areaTrigger->GetGUID();
break;
default:
break;
}
}
void BattlegroundWS::OnFlagStateChange(GameObject* flagInBase, FlagState /*oldValue*/, FlagState newValue, Player* player)
{
Team team = flagInBase->GetEntry() == BG_WS_OBJECT_HORDE_FLAG_IN_BASE ? HORDE : ALLIANCE;
TeamId otherTeamId = GetTeamIndexByTeamId(GetOtherTeam(team));
UpdateFlagState(team, newValue);
switch (newValue)
{
case FlagState::InBase:
{
if (GetStatus() == STATUS_IN_PROGRESS)
{
ResetAssaultDebuff();
if (player)
{
// flag got returned to base by player interaction
UpdatePvpStat(player, PVP_STAT_FLAG_RETURNS, 1); // +1 flag returns
if (team == ALLIANCE)
{
SendBroadcastText(BG_WS_TEXT_ALLIANCE_FLAG_RETURNED, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED);
}
else
{
SendBroadcastText(BG_WS_TEXT_HORDE_FLAG_RETURNED, CHAT_MSG_BG_SYSTEM_HORDE, player);
PlaySoundToAll(BG_WS_SOUND_FLAG_RETURNED);
}
}
// Flag respawned due to timeout/capture
else if (GetFlagState(otherTeamId) != FlagState::Respawning)
{
// if other flag is respawning, we will let that one handle the message and sound to prevent double message/sound.
SendBroadcastText(BG_WS_TEXT_FLAGS_PLACED, CHAT_MSG_BG_SYSTEM_NEUTRAL);
PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED);
}
HandleFlagRoomCapturePoint();
}
break;
}
case FlagState::Dropped:
{
player->RemoveAurasDueToSpell(BG_WS_SPELL_QUICK_CAP_TIMER);
RemoveAssaultDebuffFromPlayer(player);
uint32 recentlyDroppedSpellId = SPELL_RECENTLY_DROPPED_HORDE_FLAG;
if (team == ALLIANCE)
{
recentlyDroppedSpellId = SPELL_RECENTLY_DROPPED_ALLIANCE_FLAG;
SendBroadcastText(BG_WS_TEXT_ALLIANCE_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
}
else
SendBroadcastText(BG_WS_TEXT_HORDE_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_HORDE, player);
player->CastSpell(player, recentlyDroppedSpellId, true);
break;
}
case FlagState::Taken:
{
if (team == HORDE)
{
SendBroadcastText(BG_WS_TEXT_HORDE_FLAG_PICKED_UP, CHAT_MSG_BG_SYSTEM_HORDE, player);
PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP);
}
else
{
SendBroadcastText(BG_WS_TEXT_ALLIANCE_FLAG_PICKED_UP, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP);
}
if (GetFlagState(otherTeamId) == FlagState::Taken)
_bothFlagsKept = true;
ApplyAssaultDebuffToPlayer(player);
flagInBase->CastSpell(player, BG_WS_SPELL_QUICK_CAP_TIMER, true);
player->StartCriteria(CriteriaStartEvent::BeSpellTarget, BG_WS_SPELL_QUICK_CAP_TIMER, Seconds(GameTime::GetGameTime() - flagInBase->GetFlagTakenFromBaseTime()));
break;
}
case FlagState::Respawning:
ResetAssaultDebuff();
break;
default:
break;
}
}
bool BattlegroundWS::CanCaptureFlag(AreaTrigger* areaTrigger, Player* player)
{
if (GetStatus() != STATUS_IN_PROGRESS)
return false;
Team team = GetPlayerTeam(player->GetGUID());
TeamId teamId = GetTeamIndexByTeamId(team);
TeamId otherTeamId = GetTeamIndexByTeamId(GetOtherTeam(team));
if (areaTrigger->GetGUID() != _capturePointAreaTriggers[teamId])
return false;
// check if enemy flag's carrier is this player
if (GetFlagCarrierGUID(otherTeamId) != player->GetGUID())
return false;
// check that team's flag is in base
return GetFlagState(teamId) == FlagState::InBase;
}
void BattlegroundWS::OnCaptureFlag(AreaTrigger* /*areaTrigger*/, Player* player)
{
Team winner = TEAM_OTHER;
Team team = GetPlayerTeam(player->GetGUID());
TeamId teamId = GetTeamIndexByTeamId(team);
TeamId otherTeamId = GetTeamIndexByTeamId(GetOtherTeam(team));
/*
1. Update flag states & score world states
2. udpate points
3. chat message & sound
4. update criterias & achievements
5. remove all related auras
?. Reward honor & reputation
*/
// 1. update the flag states
for (uint8 i = 0; i < _flags.size(); i++)
if (GameObject* gameObject = GetBgMap()->GetGameObject(_flags[i]))
gameObject->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::Respawning, player));
// 2. update points
if (GetTeamScore(teamId) < BG_WS_MAX_TEAM_SCORE)
AddPoint(team, 1);
UpdateTeamScore(teamId);
// 3. chat message & sound
if (team == ALLIANCE)
{
SendBroadcastText(BG_WS_TEXT_CAPTURED_HORDE_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, player);
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE);
RewardReputationToTeam(890, m_ReputationCapture, ALLIANCE);
player->CastSpell(player, SPELL_CAPTURED_ALLIANCE_COSMETIC_FX);
}
else
{
SendBroadcastText(BG_WS_TEXT_CAPTURED_ALLIANCE_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE);
RewardReputationToTeam(889, m_ReputationCapture, HORDE);
player->CastSpell(player, SPELL_CAPTURED_HORDE_COSMETIC_FX);
}
// 4. update criteria's for achievement, player score etc.
UpdatePvpStat(player, PVP_STAT_FLAG_CAPTURES, 1); // +1 flag captures
// 5. Remove all related auras
RemoveAssaultDebuffFromPlayer(player);
if (GameObject* gameObject = GetBgMap()->GetGameObject(_flags[otherTeamId]))
player->RemoveAurasDueToSpell(gameObject->GetGOInfo()->newflag.pickupSpell, gameObject->GetGUID());
player->RemoveAurasDueToSpell(BG_WS_SPELL_QUICK_CAP_TIMER);
player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive);
RewardHonorToTeam(GetBonusHonorFromKill(2), team);
// update last flag capture to be used if teamscore is equal
SetLastFlagCapture(team);
if (GetTeamScore(teamId) == BG_WS_MAX_TEAM_SCORE)
winner = team;
if (winner)
{
UpdateWorldState(BG_WS_FLAG_STATE_ALLIANCE, 1);
UpdateWorldState(BG_WS_FLAG_STATE_HORDE, 1);
UpdateWorldState(BG_WS_STATE_TIMER_ACTIVE, 0);
RewardHonorToTeam(BG_WSG_Honor[BattlegroundMgr::IsBGWeekend(GetTypeID()) ? 1 : 0][BG_WSG_WIN], winner);
EndBattleground(winner);
}
}
@@ -1,201 +0,0 @@
/*
* 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 __BATTLEGROUNDWS_H
#define __BATTLEGROUNDWS_H
#include "Battleground.h"
#include "BattlegroundScore.h"
#include "Timer.h"
enum BG_WS_TimerOrScore
{
BG_WS_MAX_TEAM_SCORE = 3,
BG_WS_FLAG_RESPAWN_TIME = 23000,
BG_WS_FLAG_DROP_TIME = 10000,
BG_WS_SPELL_FORCE_TIME = 600000,
BG_WS_SPELL_BRUTAL_TIME = 900000
};
enum BG_WS_BroadcastTexts
{
BG_WS_TEXT_START_ONE_MINUTE = 10015,
BG_WS_TEXT_START_HALF_MINUTE = 10016,
BG_WS_TEXT_BATTLE_HAS_BEGUN = 10014,
BG_WS_TEXT_CAPTURED_HORDE_FLAG = 9801,
BG_WS_TEXT_CAPTURED_ALLIANCE_FLAG = 9802,
BG_WS_TEXT_FLAGS_PLACED = 9803,
BG_WS_TEXT_ALLIANCE_FLAG_PICKED_UP = 9804,
BG_WS_TEXT_ALLIANCE_FLAG_DROPPED = 9805,
BG_WS_TEXT_HORDE_FLAG_PICKED_UP = 9807,
BG_WS_TEXT_HORDE_FLAG_DROPPED = 9806,
BG_WS_TEXT_ALLIANCE_FLAG_RETURNED = 9808,
BG_WS_TEXT_HORDE_FLAG_RETURNED = 9809,
};
enum BG_WS_Sound
{
BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
BG_WS_SOUND_FLAG_CAPTURED_HORDE = 8213,
BG_WS_SOUND_FLAG_PLACED = 8232,
BG_WS_SOUND_FLAG_RETURNED = 8192,
BG_WS_SOUND_HORDE_FLAG_PICKED_UP = 8212,
BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP = 8174,
BG_WS_SOUND_FLAGS_RESPAWNED = 8232
};
enum BG_WS_SpellId
{
BG_WS_SPELL_WARSONG_FLAG = 23333,
BG_WS_SPELL_WARSONG_FLAG_DROPPED = 23334,
//BG_WS_SPELL_WARSONG_FLAG_PICKED = 61266,
BG_WS_SPELL_SILVERWING_FLAG = 23335,
BG_WS_SPELL_SILVERWING_FLAG_DROPPED = 23336,
//BG_WS_SPELL_SILVERWING_FLAG_PICKED = 61265,
BG_WS_SPELL_FOCUSED_ASSAULT = 46392,
BG_WS_SPELL_BRUTAL_ASSAULT = 46393,
BG_WS_SPELL_QUICK_CAP_TIMER = 183317, // serverside
};
enum BG_WS_WorldStates
{
BG_WS_FLAG_STATE_ALLIANCE = 1545,
BG_WS_FLAG_STATE_HORDE = 1546,
BG_WS_FLAG_STATE_NEUTRAL = 1547, // unused
BG_WS_HORDE_FLAG_COUNT_PICKED_UP = 17712, // brawl
BG_WS_ALLIANCE_FLAG_COUNT_PICKED_UP = 17713, // brawl
BG_WS_FLAG_CAPTURES_ALLIANCE = 1581,
BG_WS_FLAG_CAPTURES_HORDE = 1582,
BG_WS_FLAG_CAPTURES_MAX = 1601,
BG_WS_FLAG_CAPTURES_MAX_NEW = 17303,
BG_WS_FLAG_CONTROL_HORDE = 2338,
BG_WS_FLAG_CONTROL_ALLIANCE = 2339,
BG_WS_STATE_TIMER = 4248,
BG_WS_STATE_TIMER_ACTIVE = 4247
};
// save the day
// alliance criteria: BG_WS_FLAG_STATE_HORDE == 1 && BG_WS_FLAG_STATE_NEUTRAL == 0 && WS(1664) > 0
// horde criteria: BG_WS_FLAG_STATE_ALLIANCE == 1 && BG_WS_FLAG_STATE_NEUTRAL == 0 && WS(1664) > 0
enum BG_WS_ExploitTeleportLocations
{
WS_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 7051,
WS_EXPLOIT_TELEPORT_LOCATION_HORDE = 7050
};
enum BG_WS_ObjectEntry
{
// doors
BG_WS_OBJECT_ALLIANCE_DOOR = 309704,
BG_WS_OBJECT_PORTCULLIS_009 = 309705, // Doodad_7NE_Blackrook_Portcullis009
BG_WS_OBJECT_PORTCULLIS_002 = 309883, // Doodad_7NE_Blackrook_Portcullis002
BG_WS_OBJECT_COLLISION_PC_SIZE = 242273,
BG_WS_OBJECT_HORDE_GATE_1 = 352709,
BG_WS_OBJECT_HORDE_GATE_2 = 352710,
// flags
BG_WS_OBJECT_ALLIANCE_FLAG_IN_BASE = 227741,
BG_WS_OBJECT_HORDE_FLAG_IN_BASE = 227740
};
enum BG_WS_CarrierDebuffs
{
WS_SPELL_FOCUSED_ASSAULT = 46392,
WS_SPELL_BRUTAL_ASSAULT = 46393,
SPELL_CAPTURED_ALLIANCE_COSMETIC_FX = 262508,
SPELL_CAPTURED_HORDE_COSMETIC_FX = 262512,
};
enum BG_WS_AreaTriggers
{
AT_CAPTURE_POINT_ALLIANCE = 30,
AT_CAPTURE_POINT_HORDE = 31
};
static constexpr uint32 WS_EVENT_START_BATTLE = 35912;
static constexpr Seconds FLAG_ASSAULT_TIMER = 30s;
static constexpr uint16 FLAG_BRUTAL_ASSAULT_STACK_COUNT = 5;
class BattlegroundWS : public Battleground
{
public:
/* Construction */
BattlegroundWS(BattlegroundTemplate const* battlegroundTemplate);
~BattlegroundWS();
/* inherited from BattlegroundClass */
void StartingEventOpenDoors() override;
/* BG Flags */
FlagState GetFlagState(TeamId team) const;
ObjectGuid const& GetFlagCarrierGUID(TeamId team) const;
void HandleFlagRoomCapturePoint();
void HandleKillPlayer(Player* player, Player* killer) override;
bool SetupBattleground() override;
void Reset() override;
void EndBattleground(Team winner) override;
WorldSafeLocsEntry const* GetClosestGraveyard(Player* player) override;
WorldSafeLocsEntry const* GetExploitTeleportLocation(Team team) override;
void UpdateFlagState(uint32 team, FlagState value);
void SetLastFlagCapture(Team team) { _lastFlagCaptureTeam = team; }
void UpdateTeamScore(TeamId team);
/* Scorekeeping */
void AddPoint(Team team, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(team)] += Points; }
void SetTeamPoint(Team team, uint32 Points = 0) { m_TeamScores[GetTeamIndexByTeamId(team)] = Points; }
void RemovePoint(Team team, uint32 Points = 1) { m_TeamScores[GetTeamIndexByTeamId(team)] -= Points; }
Team GetPrematureWinner() override;
void OnGameObjectCreate(GameObject* gameObject) override;
void OnAreaTriggerCreate(AreaTrigger* areaTrigger) override;
void OnFlagStateChange(GameObject* flagInBase, FlagState oldValue, FlagState newValue, Player* player) override;
bool CanCaptureFlag(AreaTrigger* areatrigger, Player* player) override;
void OnCaptureFlag(AreaTrigger* areatrigger, Player* player) override;
protected:
void PostUpdateImpl(uint32 diff) override;
void DoForFlagKeepers(std::function<void(Player*)> action) const;
// Focused & Brutal Assault debuffs
void ResetAssaultDebuff();
void ApplyAssaultDebuffToPlayer(Player* player);
void RemoveAssaultDebuffFromPlayer(Player* player);
private:
Team _lastFlagCaptureTeam; // Winner is based on this if score is equal
uint32 m_ReputationCapture;
uint32 m_HonorWinKills;
uint32 m_HonorEndKills;
bool _bothFlagsKept;
GuidSet _doors;
std::array<ObjectGuid, 2> _flags;
TimeTracker _flagAssaultTimer;
uint16 _assaultStackCount;
std::array<ObjectGuid, 2> _capturePointAreaTriggers;
};
#endif
+2 -2
View File
@@ -20,7 +20,7 @@
#include "AreaTrigger.h"
#include "AreaTriggerDataStore.h"
#include "BattlePetMgr.h"
#include "Battleground.h"
#include "BattlegroundScript.h"
#include "Containers.h"
#include "ConversationDataStore.h"
#include "DB2Stores.h"
@@ -232,7 +232,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
}
else if (BattlegroundMap const* bgMap = map->ToBattlegroundMap())
{
ZoneScript const* zoneScript = bgMap->GetBG();
ZoneScript const* zoneScript = bgMap->GetBattlegroundScript();
switch (ConditionValue3)
{
case INSTANCE_INFO_DATA:
@@ -2264,8 +2264,6 @@ bool GameObject::ActivateToQuest(Player const* target) const
|| LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->chest.chestPersonalLoot, target)
|| LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->chest.chestPushLoot, target))
{
if (Battleground const* bg = target->GetBattleground())
return bg->CanActivateGO(GetEntry(), bg->GetPlayerTeam(target->GetGUID()));
return true;
}
break;
@@ -2576,10 +2574,6 @@ void GameObject::Use(Unit* user)
if (!player)
return;
if (Battleground* bg = player->GetBattleground())
if (!bg->CanActivateGO(GetEntry(), bg->GetPlayerTeam(user->GetGUID())))
return;
GameObjectTemplate const* info = GetGOInfo();
if (!m_loot && info->GetLootId())
{
@@ -3119,24 +3113,11 @@ void GameObject::Use(Unit* user)
if (player->CanUseBattlegroundObject(this))
{
// in battleground check
Battleground* bg = player->GetBattleground();
if (!bg)
return;
if (player->GetVehicle())
return;
player->RemoveAurasByType(SPELL_AURA_MOD_STEALTH);
player->RemoveAurasByType(SPELL_AURA_MOD_INVISIBILITY);
// BG flag click
// AB:
// 15001
// 15002
// 15003
// 15004
// 15005
bg->EventPlayerClickedOnFlag(player, this);
return; //we don;t need to delete flag ... it is despawned!
}
break;
@@ -3167,11 +3148,6 @@ void GameObject::Use(Unit* user)
if (player->CanUseBattlegroundObject(this))
{
// in battleground check
Battleground* bg = player->GetBattleground();
if (!bg)
return;
if (player->GetVehicle())
return;
@@ -3184,24 +3160,8 @@ void GameObject::Use(Unit* user)
// EotS:
// 184142 - Netherstorm Flag
GameObjectTemplate const* info = GetGOInfo();
if (info)
{
switch (info->entry)
{
case 179785: // Silverwing Flag
case 179786: // Warsong Flag
if (bg->GetTypeID() == BATTLEGROUND_WS)
bg->EventPlayerClickedOnFlag(player, this);
break;
case 184142: // Netherstorm Flag
if (bg->GetTypeID() == BATTLEGROUND_EY)
bg->EventPlayerClickedOnFlag(player, this);
break;
}
if (info->flagDrop.eventID)
GameEvents::Trigger(info->flagDrop.eventID, player, this);
}
if (info->flagDrop.eventID)
GameEvents::Trigger(info->flagDrop.eventID, player, this);
//this cause to call return, all flags must be deleted here!!
spellId = 0;
Delete();
@@ -3705,10 +3665,6 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, WorldOb
GameEvents::Trigger(GetGOInfo()->destructibleBuilding.DestroyedEvent, attackerOrHealer, this);
AI()->Destroyed(attackerOrHealer, m_goInfo->destructibleBuilding.DestroyedEvent);
if (Player* player = attackerOrHealer ? attackerOrHealer->GetCharmerOrOwnerPlayerOrPlayerItself() : nullptr)
if (Battleground* bg = player->GetBattleground())
bg->DestroyGate(player, this);
RemoveFlag(GO_FLAG_DAMAGED);
SetFlag(GO_FLAG_DESTROYED);
+1 -1
View File
@@ -2010,7 +2010,7 @@ ZoneScript* WorldObject::FindZoneScript() const
if (InstanceMap* instanceMap = map->ToInstanceMap())
return reinterpret_cast<ZoneScript*>(instanceMap->GetInstanceScript());
if (BattlegroundMap* bgMap = map->ToBattlegroundMap())
return reinterpret_cast<ZoneScript*>(bgMap->GetBG());
return reinterpret_cast<ZoneScript*>(bgMap->GetBattlegroundScript());
if (!map->IsBattlegroundOrArena())
{
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(map, GetZoneId()))
+1 -14
View File
@@ -4403,12 +4403,6 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
UpdateZone(newzone, newarea);
sOutdoorPvPMgr->HandlePlayerResurrects(this, newzone);
if (InBattleground())
{
if (Battleground* bg = GetBattleground())
bg->HandlePlayerResurrect(this);
}
// update visibility
UpdateObjectVisibility();
@@ -4796,9 +4790,7 @@ void Player::RepopAtGraveyard()
}
WorldSafeLocsEntry const* closestGrave = nullptr;
if (Battleground* bg = GetBattleground())
closestGrave = bg->GetClosestGraveyard(this);
else if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(GetMap(), GetZoneId()))
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(GetMap(), GetZoneId()))
closestGrave = bf->GetClosestGraveyard(this);
else if (InstanceScript* instance = GetInstanceScript())
closestGrave = sObjectMgr->GetWorldSafeLoc(instance->GetEntranceLocation());
@@ -24933,11 +24925,6 @@ void Player::SummonIfPossible(bool agree)
// stop taxi flight at summon
FinishTaxiFlight();
// drop flag at summon
// this code can be reached only when GM is summoning player who carries flag, because player should be immune to summoning spells when he carries flag
if (Battleground* bg = GetBattleground())
bg->EventPlayerDroppedFlag(this);
m_summon_expire = 0;
UpdateCriteria(CriteriaType::AcceptSummon, 1);
@@ -846,10 +846,6 @@ bool VehicleJoinEvent::Execute(uint64, uint32)
Player* player = Passenger->ToPlayer();
if (player)
{
// drop flag
if (Battleground* bg = player->GetBattleground())
bg->EventPlayerDroppedFlag(player);
player->StopCastingCharm();
player->StopCastingBindSight();
player->SendOnCancelExpectedVehicleRideAura();
-3
View File
@@ -573,9 +573,6 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPackets::AreaTrigger::AreaTrigge
return;
}
if (Battleground* bg = player->GetBattleground())
bg->HandleAreaTrigger(player, packet.AreaTriggerID, packet.Entered);
if (OutdoorPvP* pvp = player->GetOutdoorPvP())
if (pvp->HandleAreaTrigger(_player, packet.AreaTriggerID, packet.Entered))
return;
@@ -378,9 +378,6 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::Quest
{
if (_player->CanRewardQuest(quest, packet.Choice.LootItemType, packet.Choice.Item.ItemID, true)) // Then check if player can receive the reward item (if inventory is not full, if player doesn't have too many unique items, and so on). If not, the client will close the gossip window
{
if (Battleground* bg = _player->GetBattleground())
bg->HandleQuestComplete(packet.QuestID, _player);
_player->RewardQuest(quest, packet.Choice.LootItemType, packet.Choice.Item.ItemID, object);
}
}
+39 -1
View File
@@ -17,6 +17,8 @@
#include "Map.h"
#include "Battleground.h"
#include "BattlegroundMgr.h"
#include "BattlegroundScript.h"
#include "CellImpl.h"
#include "CharacterPackets.h"
#include "Containers.h"
@@ -3385,7 +3387,7 @@ TeamId InstanceMap::GetTeamIdInInstance() const
/* ******* Battleground Instance Maps ******* */
BattlegroundMap::BattlegroundMap(uint32 id, time_t expiry, uint32 InstanceId, Difficulty spawnMode)
: Map(id, expiry, InstanceId, spawnMode), m_bg(nullptr)
: Map(id, expiry, InstanceId, spawnMode), m_bg(nullptr), _battlegroundScript(nullptr), _scriptId(0)
{
//lets initialize visibility distance for BG/Arenas
BattlegroundMap::InitVisibilityDistance();
@@ -3408,6 +3410,36 @@ void BattlegroundMap::InitVisibilityDistance()
m_VisibilityNotifyPeriod = IsBattleArena() ? World::GetVisibilityNotifyPeriodInArenas() : World::GetVisibilityNotifyPeriodInBG();
}
std::string const& BattlegroundMap::GetScriptName() const
{
return sObjectMgr->GetScriptName(_scriptId);
}
void BattlegroundMap::InitScriptData()
{
if (_battlegroundScript)
return;
ASSERT(GetBG(), "Battleground not set yet!");
if (BattlegroundScriptTemplate const* scriptTemplate = sBattlegroundMgr->FindBattlegroundScriptTemplate(GetId(), GetBG()->GetTypeID()))
{
_scriptId = scriptTemplate->ScriptId;
_battlegroundScript.reset(sScriptMgr->CreateBattlegroundData(this));
}
// Make sure every battleground has a default script
if (!_battlegroundScript)
{
if (IsBattleArena())
_battlegroundScript = std::make_unique<ArenaScript>(this);
else
_battlegroundScript = std::make_unique<BattlegroundScript>(this);
}
_battlegroundScript->OnInit();
}
TransferAbortParams BattlegroundMap::CannotEnter(Player* player)
{
if (player->GetMapRef().getTarget() == this)
@@ -3451,6 +3483,12 @@ void BattlegroundMap::RemoveAllPlayers()
player->TeleportTo(player->GetBattlegroundEntryPoint());
}
void BattlegroundMap::Update(uint32 diff)
{
Map::Update(diff);
_battlegroundScript->OnUpdate(diff);
}
AreaTrigger* Map::GetAreaTrigger(ObjectGuid const& guid)
{
return _objectsStore.Find<AreaTrigger>(guid);
+11
View File
@@ -46,6 +46,7 @@
class Battleground;
class BattlegroundMap;
class BattlegroundScript;
class CreatureGroup;
class GameObjectModel;
class Group;
@@ -909,12 +910,22 @@ class TC_GAME_API BattlegroundMap : public Map
void SetUnload();
//void UnloadAll(bool pForce);
void RemoveAllPlayers() override;
void Update(uint32 diff) override;
virtual void InitVisibilityDistance() override;
Battleground* GetBG() const { return m_bg; }
void SetBG(Battleground* bg) { m_bg = bg; }
uint32 GetScriptId() const { return _scriptId; }
std::string const& GetScriptName() const;
BattlegroundScript* GetBattlegroundScript() { return _battlegroundScript.get(); }
BattlegroundScript const* GetBattlegroundScript() const { return _battlegroundScript.get(); }
void InitScriptData();
private:
Battleground* m_bg;
std::unique_ptr<BattlegroundScript> _battlegroundScript;
uint32 _scriptId;
};
template<class T, class CONTAINER>
+1
View File
@@ -127,6 +127,7 @@ BattlegroundMap* MapManager::CreateBattleground(uint32 mapId, uint32 instanceId,
ASSERT(map->IsBattlegroundOrArena());
map->SetBG(bg);
bg->SetBgMap(map);
map->InitScriptData();
map->InitSpawnGroupState();
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUNDMAP_LOAD_GRIDS))
+1 -1
View File
@@ -92,7 +92,7 @@ class TC_GAME_API ZoneScript
virtual void SetData(uint32 /*DataId*/, uint32 /*Value*/) { }
virtual void TriggerGameEvent(uint32 gameEventId, WorldObject* source = nullptr, WorldObject* target = nullptr);
virtual void ProcessEvent(WorldObject* /*obj*/, uint32 /*eventId*/, WorldObject* /*invoker*/) { }
virtual void ProcessEvent([[maybe_unused]] WorldObject* obj, [[maybe_unused]] uint32 eventId, [[maybe_unused]] WorldObject* invoker) { }
virtual void DoAction([[maybe_unused]] uint32 actionId, [[maybe_unused]] WorldObject* source = nullptr, [[maybe_unused]] WorldObject* target = nullptr) { }
virtual void OnFlagStateChange([[maybe_unused]] GameObject* flagInBase, [[maybe_unused]] FlagState oldValue, [[maybe_unused]] FlagState newValue, [[maybe_unused]] Player* player) { }
+43 -22
View File
@@ -90,7 +90,7 @@ struct is_script_database_bound<BattlefieldScript>
: std::true_type { };
template<>
struct is_script_database_bound<BattlegroundScript>
struct is_script_database_bound<BattlegroundMapScript>
: std::true_type { };
template<>
@@ -754,11 +754,6 @@ template<typename Base>
class ScriptRegistrySwapHooks<BattlefieldScript, Base>
: public UnsupportedScriptRegistrySwapHooks<Base> { };
/// This hook is responsible for swapping BattlegroundScript's
template<typename Base>
class ScriptRegistrySwapHooks<BattlegroundScript, Base>
: public UnsupportedScriptRegistrySwapHooks<Base> { };
/// This hook is responsible for swapping OutdoorPvP's
template<typename Base>
class ScriptRegistrySwapHooks<OutdoorPvPScript, Base>
@@ -826,6 +821,35 @@ private:
bool swapped;
};
/// This hook is responsible for swapping BattlegroundMapScript's
template<typename Base>
class ScriptRegistrySwapHooks<BattlegroundMapScript, Base>
: public ScriptRegistrySwapHookBase
{
public:
ScriptRegistrySwapHooks() : swapped(false) { }
void BeforeReleaseContext(std::string const& context) final override
{
auto const bounds = static_cast<Base*>(this)->_ids_of_contexts.equal_range(context);
if (bounds.first != bounds.second)
swapped = true;
}
void BeforeSwapContext(bool /*initialize*/) override
{
swapped = false;
}
void BeforeUnload() final override
{
ASSERT(!swapped);
}
private:
bool swapped;
};
/// This hook is responsible for swapping SceneScript's
template<typename Base>
class ScriptRegistrySwapHooks<SceneScript, Base>
@@ -1623,6 +1647,14 @@ InstanceScript* ScriptMgr::CreateInstanceData(InstanceMap* map)
return tmpscript->GetInstanceScript(map);
}
BattlegroundScript* ScriptMgr::CreateBattlegroundData(BattlegroundMap* map)
{
ASSERT(map);
GET_SCRIPT_RET(BattlegroundMapScript, map->GetScriptId(), tmpscript, NULL);
return tmpscript->GetBattlegroundScript(map);
}
bool ScriptMgr::OnQuestAccept(Player* player, Item* item, Quest const* quest)
{
ASSERT(player);
@@ -1726,13 +1758,6 @@ Battlefield* ScriptMgr::CreateBattlefield(uint32 scriptId, Map* map)
return tmpscript->GetBattlefield(map);
}
Battleground* ScriptMgr::CreateBattleground(BattlegroundTypeId /*typeId*/)
{
/// @todo Implement script-side battlegrounds.
ABORT();
return nullptr;
}
OutdoorPvP* ScriptMgr::CreateOutdoorPvP(uint32 scriptId, Map* map)
{
GET_SCRIPT_RET(OutdoorPvPScript, scriptId, tmpscript, nullptr);
@@ -2582,6 +2607,11 @@ BattlegroundMapScript::BattlegroundMapScript(char const* name, uint32 mapId)
BattlegroundMapScript::~BattlegroundMapScript() = default;
BattlegroundScript* BattlegroundMapScript::GetBattlegroundScript(BattlegroundMap* /*map*/) const
{
return nullptr;
}
ItemScript::ItemScript(char const* name)
: ScriptObject(name)
{
@@ -2702,14 +2732,6 @@ BattlefieldScript::BattlefieldScript(char const* name)
BattlefieldScript::~BattlefieldScript() = default;
BattlegroundScript::BattlegroundScript(char const* name)
: ScriptObject(name)
{
ScriptRegistry<BattlegroundScript>::Instance()->AddScript(this);
}
BattlegroundScript::~BattlegroundScript() = default;
OutdoorPvPScript::OutdoorPvPScript(char const* name)
: ScriptObject(name)
{
@@ -3247,7 +3269,6 @@ template class TC_GAME_API ScriptRegistry<CreatureScript>;
template class TC_GAME_API ScriptRegistry<GameObjectScript>;
template class TC_GAME_API ScriptRegistry<AreaTriggerScript>;
template class TC_GAME_API ScriptRegistry<BattlefieldScript>;
template class TC_GAME_API ScriptRegistry<BattlegroundScript>;
template class TC_GAME_API ScriptRegistry<OutdoorPvPScript>;
template class TC_GAME_API ScriptRegistry<CommandScript>;
template class TC_GAME_API ScriptRegistry<WeatherScript>;
+15 -15
View File
@@ -35,6 +35,7 @@ class AuraScript;
class Battlefield;
class Battleground;
class BattlegroundMap;
class BattlegroundScript;
class Channel;
class Conversation;
class Creature;
@@ -372,6 +373,9 @@ class TC_GAME_API BattlegroundMapScript : public ScriptObject, public MapScript<
public:
~BattlegroundMapScript();
// Gets an BattlegroundScript object for this battleground.
virtual BattlegroundScript* GetBattlegroundScript(BattlegroundMap* map) const;
};
class TC_GAME_API ItemScript : public ScriptObject
@@ -501,20 +505,6 @@ class TC_GAME_API BattlefieldScript : public ScriptObject
virtual Battlefield* GetBattlefield(Map* map) const = 0;
};
class TC_GAME_API BattlegroundScript : public ScriptObject
{
protected:
explicit BattlegroundScript(char const* name);
public:
~BattlegroundScript();
// Should return a fully valid Battleground object for the type ID.
virtual Battleground* GetBattleground() const = 0;
};
class TC_GAME_API OutdoorPvPScript : public ScriptObject
{
protected:
@@ -1151,7 +1141,7 @@ class TC_GAME_API ScriptMgr
public: /* BattlegroundScript */
Battleground* CreateBattleground(BattlegroundTypeId typeId);
BattlegroundScript* CreateBattlegroundData(BattlegroundMap* map);
public: /* OutdoorPvPScript */
@@ -1415,6 +1405,16 @@ class GenericAreaTriggerEntityScript : public AreaTriggerEntityScript
};
#define RegisterAreaTriggerAI(ai_name) new GenericAreaTriggerEntityScript<ai_name>(#ai_name)
template<class Script>
class GenericBattlegroundMapScript : public BattlegroundMapScript
{
public:
GenericBattlegroundMapScript(char const* name, uint32 mapId) : BattlegroundMapScript(name, mapId) { }
BattlegroundScript* GetBattlegroundScript(BattlegroundMap* map) const override { return new Script(map); }
};
#define RegisterBattlegroundMapScript(script_name, mapId) new GenericBattlegroundMapScript<script_name>(#script_name, mapId)
#define sScriptMgr ScriptMgr::instance()
#endif
@@ -3396,12 +3396,7 @@ void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint
Player* player = target->ToPlayer();
if (!apply && player && GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::StealthOrInvis))
{
if (player->InBattleground())
{
if (Battleground* bg = player->GetBattleground())
bg->EventPlayerDroppedFlag(player);
}
else
if (!player->InBattleground())
sOutdoorPvPMgr->HandleDropFlag(player, GetSpellInfo()->Id);
}
}
+1 -17
View File
@@ -1592,18 +1592,7 @@ void Spell::EffectOpenLock()
if (goInfo->GetNoDamageImmune() && player->HasUnitFlag(UNIT_FLAG_IMMUNE))
return;
if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND)
{
//CanUseBattlegroundObject() already called in CheckCast()
// in battleground check
if (Battleground* bg = player->GetBattleground())
{
if (bg->GetTypeID() == BATTLEGROUND_EY)
bg->EventPlayerClickedOnFlag(player, gameObjTarget);
return;
}
}
else if (m_spellInfo->Id == 1842 && gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && gameObjTarget->GetOwner())
if (m_spellInfo->Id == 1842 && gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_TRAP && gameObjTarget->GetOwner())
{
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
return;
@@ -2968,11 +2957,6 @@ void Spell::EffectSummonObjectWild()
// Wild object not have owner and check clickable by players
map->AddToMap(go);
if (go->GetGoType() == GAMEOBJECT_TYPE_FLAGDROP)
if (Player* player = m_caster->ToPlayer())
if (Battleground* bg = player->GetBattleground())
bg->SetDroppedFlagGUID(go->GetGUID(), bg->GetPlayerTeam(player->GetGUID()) == ALLIANCE ? TEAM_HORDE: TEAM_ALLIANCE);
if (GameObject* linkedTrap = go->GetLinkedTrap())
{
PhasingHandler::InheritPhaseShift(linkedTrap , m_caster);
-6
View File
@@ -743,12 +743,6 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32
if (!player || (auraSpell > 0 && !player->HasAura(auraSpell)) || (auraSpell < 0 && player->HasAura(-auraSpell)))
return false;
if (player)
{
if (Battleground* bg = player->GetBattleground())
return bg->IsSpellAllowed(spellId, player);
}
// Extra conditions
switch (spellId)
{
+1
View File
@@ -2465,6 +2465,7 @@ void World::SetInitialWorldSettings()
///- Initialize Battlegrounds
TC_LOG_INFO("server.loading", "Starting Battleground System");
sBattlegroundMgr->LoadBattlegroundTemplates();
sBattlegroundMgr->LoadBattlegroundScriptTemplate();
///- Initialize outdoor pvp
TC_LOG_INFO("server.loading", "Starting Outdoor PvP System");
@@ -15,8 +15,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "alterac_valley.h"
#include "ScriptMgr.h"
#include "BattlegroundAV.h"
#include "Battleground.h"
#include "GameObject.h"
#include "GameObjectAI.h"
#include "Player.h"
@@ -192,10 +193,36 @@ public:
}
};
template<AlteracValleySharedActions ActionId>
class quest_alterac_valley : public QuestScript
{
public:
quest_alterac_valley(char const* scriptName) : QuestScript(scriptName) { }
void OnQuestStatusChange(Player* player, Quest const* /*quest*/, QuestStatus /*oldStatus*/, QuestStatus newStatus) override
{
if (newStatus != QUEST_STATUS_REWARDED)
return;
if (ZoneScript* zoneScript = player->FindZoneScript())
zoneScript->DoAction(ActionId, player, player);
}
};
void AddSC_alterac_valley()
{
RegisterCreatureAI(npc_av_marshal_or_warmaster);
RegisterGameObjectAI(go_av_capturable_object);
RegisterGameObjectAI(go_av_contested_object);
new at_av_exploit();
new quest_alterac_valley<ACTION_TURN_IN_SCRAPS>("quest_alterac_valley_armor_scraps");
new quest_alterac_valley<ACTION_TURN_IN_COMMANDER_1>("quest_alterac_valley_call_of_air_slidore_guse");
new quest_alterac_valley<ACTION_TURN_IN_COMMANDER_2>("quest_alterac_valley_call_of_air_vipore_jeztor");
new quest_alterac_valley<ACTION_TURN_IN_COMMANDER_3>("quest_alterac_valley_call_of_air_ichman_mulverick");
new quest_alterac_valley<ACTION_TURN_IN_BOSS_1>("quest_alterac_valley_boss_5");
new quest_alterac_valley<ACTION_TURN_IN_BOSS_2>("quest_alterac_valley_boss_1");
new quest_alterac_valley<ACTION_TURN_IN_NEAR_MINE>("quest_alterac_valley_near_mine");
new quest_alterac_valley<ACTION_TURN_IN_OTHER_MINE>("quest_alterac_valley_other_mine");
new quest_alterac_valley<ACTION_TURN_IN_RIDER_HIDE>("quest_alterac_valley_ram_harnesses");
new quest_alterac_valley<ACTION_TURN_IN_RIDER_TAME>("quest_alterac_valley_empty_stables");
}
@@ -15,12 +15,25 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BattlegroundBFG.h"
#ifndef __ALTERAC_VALLEY_H
#define __ALTERAC_VALLEY_H
BattlegroundBFG::BattlegroundBFG(BattlegroundTemplate const* battlegroundTemplate) : Battleground(battlegroundTemplate)
enum AlteracValleySharedActions
{
}
ACTION_BUFF_YELL = -30001,
ACTION_AV_INTERACT_CAPTURABLE_OBJECT = 1,
ACTION_AV_CAPTURE_CAPTURABLE_OBJECT = 2,
BattlegroundBFG::~BattlegroundBFG()
{
}
ACTION_TURN_IN_SCRAPS = 3,
ACTION_TURN_IN_COMMANDER_1 = 4,
ACTION_TURN_IN_COMMANDER_2 = 5,
ACTION_TURN_IN_COMMANDER_3 = 6,
ACTION_TURN_IN_BOSS_1,
ACTION_TURN_IN_BOSS_2,
ACTION_TURN_IN_NEAR_MINE,
ACTION_TURN_IN_OTHER_MINE,
ACTION_TURN_IN_RIDER_HIDE,
ACTION_TURN_IN_RIDER_TAME
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,605 @@
/*
* 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/>.
*/
#include "BattlegroundScript.h"
#include "Battleground.h"
#include "BattlegroundMgr.h"
#include "BattlegroundPackets.h"
#include "Creature.h"
#include "GameObject.h"
#include "GameTime.h"
#include "Log.h"
#include "Map.h"
#include "ScriptMgr.h"
struct battleground_arathi_basin : BattlegroundScript
{
// Tick intervals and given points: case 0, 1, 2, 3, 4, 5 captured nodes
static constexpr uint32 BG_AB_TickInterval = 2000;
static constexpr uint32 BG_AB_TickPoints[6] = { 0, 2, 3, 4, 7, 60 };
static constexpr uint32 NORMAL_HONOR_TICKS = 160;
static constexpr uint32 WEEKEND_HONOR_TICKS = 260;
static constexpr uint32 NORMAL_REPUTATION_TICKS = 120;
static constexpr uint32 WEEKEND_REPUTATION_TICKS = 160;
enum PvpStats
{
PVP_STAT_BASES_ASSAULTED = 926,
PVP_STAT_BASES_DEFENDED = 927,
};
enum Events
{
AB_EVENT_START_BATTLE = 9158, // Achievement: Let's Get This Done
AB_EVENT_CONTESTED_STABLES_HORDE = 28523,
AB_EVENT_CAPTURE_STABLES_HORDE = 28527,
AB_EVENT_DEFENDED_STABLES_HORDE = 28525,
AB_EVENT_CONTESTED_STABLES_ALLIANCE = 28522,
AB_EVENT_CAPTURE_STABLES_ALLIANCE = 28526,
AB_EVENT_DEFENDED_STABLES_ALLIANCE = 28524,
AB_EVENT_CONTESTED_BLACKSMITH_HORDE = 8876,
AB_EVENT_CAPTURE_BLACKSMITH_HORDE = 8773,
AB_EVENT_DEFENDED_BLACKSMITH_HORDE = 8770,
AB_EVENT_CONTESTED_BLACKSMITH_ALLIANCE = 8874,
AB_EVENT_CAPTURE_BLACKSMITH_ALLIANCE = 8769,
AB_EVENT_DEFENDED_BLACKSMITH_ALLIANCE = 8774,
AB_EVENT_CONTESTED_FARM_HORDE = 39398,
AB_EVENT_CAPTURE_FARM_HORDE = 39399,
AB_EVENT_DEFENDED_FARM_HORDE = 39400,
AB_EVENT_CONTESTED_FARM_ALLIANCE = 39401,
AB_EVENT_CAPTURE_FARM_ALLIANCE = 39402,
AB_EVENT_DEFENDED_FARM_ALLIANCE = 39403,
AB_EVENT_CONTESTED_GOLD_MINE_HORDE = 39404,
AB_EVENT_CAPTURE_GOLD_MINE_HORDE = 39405,
AB_EVENT_DEFENDED_GOLD_MINE_HORDE = 39406,
AB_EVENT_CONTESTED_GOLD_MINE_ALLIANCE = 39407,
AB_EVENT_CAPTURE_GOLD_MINE_ALLIANCE = 39408,
AB_EVENT_DEFENDED_GOLD_MINE_ALLIANCE = 39409,
AB_EVENT_CONTESTED_LUMBER_MILL_HORDE = 39387,
AB_EVENT_CAPTURE_LUMBER_MILL_HORDE = 39388,
AB_EVENT_DEFENDED_LUMBER_MILL_HORDE = 39389,
AB_EVENT_CONTESTED_LUMBER_MILL_ALLIANCE = 39390,
AB_EVENT_CAPTURE_LUMBER_MILL_ALLIANCE = 39391,
AB_EVENT_DEFENDED_LUMBER_MILL_ALLIANCE = 39392
};
enum Sounds
{
BG_AB_SOUND_NODE_CLAIMED = 8192,
BG_AB_SOUND_NODE_CAPTURED_ALLIANCE = 8173,
BG_AB_SOUND_NODE_CAPTURED_HORDE = 8213,
BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE = 8212,
BG_AB_SOUND_NODE_ASSAULTED_HORDE = 8174,
BG_AB_SOUND_NEAR_VICTORY_ALLIANCE = 8456,
BG_AB_SOUND_NEAR_VICTORY_HORDE = 8457
};
enum BroadcastTexts
{
BG_AB_TEXT_ALLIANCE_NEAR_VICTORY = 10598,
BG_AB_TEXT_HORDE_NEAR_VICTORY = 10599,
};
enum Score
{
BG_AB_WARNING_NEAR_VICTORY_SCORE = 1200,
BG_AB_MAX_TEAM_SCORE = 1500
};
enum Creatures
{
BG_AB_NPC_THE_BLACK_BRIDE = 150501,
BG_AB_NPC_RADULF_LEDER = 150505
};
enum ObjectTypes
{
BG_AB_OBJECTID_CAPTURE_POINT_STABLES = 227420,
BG_AB_OBJECTID_CAPTURE_POINT_BLACKSMITH = 227522,
BG_AB_OBJECTID_CAPTURE_POINT_FARM = 227536,
BG_AB_OBJECTID_CAPTURE_POINT_GOLD_MINE = 227538,
BG_AB_OBJECTID_CAPTURE_POINT_LUMBER_MILL = 227544,
BG_AB_OBJECTID_GHOST_GATE = 180322,
BG_AB_OBJECTID_ALLIANCE_DOOR = 322273,
BG_AB_OBJECTID_HORDE_DOOR = 322274
};
enum WorldStates
{
BG_AB_WS_OCCUPIED_BASES_HORDE = 1778,
BG_AB_WS_OCCUPIED_BASES_ALLY = 1779,
BG_AB_WS_RESOURCES_ALLY = 1776,
BG_AB_WS_RESOURCES_HORDE = 1777,
BG_AB_WS_RESOURCES_MAX = 1780,
BG_AB_WS_RESOURCES_WARNING = 1955,
BG_AB_WS_STABLE_ICON = 1842, // Stable map icon (NONE)
BG_AB_WS_STABLE_STATE_ALIENCE = 1767, // Stable map state (ALIENCE)
BG_AB_WS_STABLE_STATE_HORDE = 1768, // Stable map state (HORDE)
BG_AB_WS_STABLE_STATE_CON_ALI = 1769, // Stable map state (CON ALIENCE)
BG_AB_WS_STABLE_STATE_CON_HOR = 1770, // Stable map state (CON HORDE)
BG_AB_WS_FARM_ICON = 1845, // Farm map icon (NONE)
BG_AB_WS_FARM_STATE_ALIENCE = 1772, // Farm state (ALIENCE)
BG_AB_WS_FARM_STATE_HORDE = 1773, // Farm state (HORDE)
BG_AB_WS_FARM_STATE_CON_ALI = 1774, // Farm state (CON ALIENCE)
BG_AB_WS_FARM_STATE_CON_HOR = 1775, // Farm state (CON HORDE)
BG_AB_WS_BLACKSMITH_ICON = 1846, // Blacksmith map icon (NONE)
BG_AB_WS_BLACKSMITH_STATE_ALIENCE = 1782, // Blacksmith map state (ALIENCE)
BG_AB_WS_BLACKSMITH_STATE_HORDE = 1783, // Blacksmith map state (HORDE)
BG_AB_WS_BLACKSMITH_STATE_CON_ALI = 1784, // Blacksmith map state (CON ALIENCE)
BG_AB_WS_BLACKSMITH_STATE_CON_HOR = 1785, // Blacksmith map state (CON HORDE)
BG_AB_WS_LUMBERMILL_ICON = 1844, // Lumber Mill map icon (NONE)
BG_AB_WS_LUMBERMILL_STATE_ALIENCE = 1792, // Lumber Mill map state (ALIENCE)
BG_AB_WS_LUMBERMILL_STATE_HORDE = 1793, // Lumber Mill map state (HORDE)
BG_AB_WS_LUMBERMILL_STATE_CON_ALI = 1794, // Lumber Mill map state (CON ALIENCE)
BG_AB_WS_LUMBERMILL_STATE_CON_HOR = 1795, // Lumber Mill map state (CON HORDE)
BG_AB_WS_GOLDMINE_ICON = 1843, // Gold Mine map icon (NONE)
BG_AB_WS_GOLDMINE_STATE_ALIENCE = 1787, // Gold Mine map state (ALIENCE)
BG_AB_WS_GOLDMINE_STATE_HORDE = 1788, // Gold Mine map state (HORDE)
BG_AB_WS_GOLDMINE_STATE_CON_ALI = 1789, // Gold Mine map state (CON ALIENCE
BG_AB_WS_GOLDMINE_STATE_CON_HOR = 1790, // Gold Mine map state (CON HORDE)
BG_AB_WS_HAD_500_DISADVANTAGE_ALLIANCE = 3644,
BG_AB_WS_HAD_500_DISADVANTAGE_HORDE = 3645,
BG_AB_WS_FARM_ICON_NEW = 8808, // Farm map icon
BG_AB_WS_LUMBER_MILL_ICON_NEW = 8805, // Lumber Mill map icon
BG_AB_WS_BLACKSMITH_ICON_NEW = 8799, // Blacksmith map icon
BG_AB_WS_GOLD_MINE_ICON_NEW = 8809, // Gold Mine map icon
BG_AB_WS_STABLES_ICON_NEW = 5834, // Stable map icon
BG_AB_WS_FARM_HORDE_CONTROL_STATE = 17328,
BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE = 17325,
BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE = 17330,
BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE = 17326,
BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE = 17327,
BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE = 17324,
BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE = 17329,
BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE = 17323,
BG_AB_WS_STABLES_HORDE_CONTROL_STATE = 17331,
BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE = 17322,
};
explicit battleground_arathi_basin(BattlegroundMap* map) : BattlegroundScript(map), _lastTick(0), _isInformedNearVictory(false)
{
bool const isBGWeekend = sBattlegroundMgr->IsBGWeekend(battleground->GetTypeID());
_honorTics = (isBGWeekend) ? WEEKEND_HONOR_TICKS : NORMAL_HONOR_TICKS;
_reputationTics = (isBGWeekend) ? WEEKEND_REPUTATION_TICKS : NORMAL_REPUTATION_TICKS;
_honorScoreTics = { { 0, 0 } };
_reputationScoreTics = { { 0, 0 } };
}
void OnInit() override
{
BattlegroundScript::OnInit();
UpdateWorldState(BG_AB_WS_RESOURCES_MAX, BG_AB_MAX_TEAM_SCORE);
UpdateWorldState(BG_AB_WS_RESOURCES_WARNING, BG_AB_WARNING_NEAR_VICTORY_SCORE);
}
void OnUpdate(uint32 diff) override
{
if (battleground->GetStatus() != STATUS_IN_PROGRESS)
return;
// Accumulate points
_lastTick += diff;
if (_lastTick > BG_AB_TickInterval)
{
_lastTick -= BG_AB_TickInterval;
uint8 ally = 0, horde = 0;
_CalculateTeamNodes(ally, horde);
uint8 points[PVP_TEAMS_COUNT] = { ally, horde };
for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
{
if (!points[team])
continue;
battleground->AddPoint(team == TEAM_HORDE ? HORDE : ALLIANCE, BG_AB_TickPoints[points[team]]);
_honorScoreTics[team] += BG_AB_TickPoints[points[team]];
_reputationScoreTics[team] += BG_AB_TickPoints[points[team]];
if (_reputationScoreTics[team] >= _reputationTics)
{
(team == TEAM_ALLIANCE) ? battleground->RewardReputationToTeam(509, 10, ALLIANCE) : battleground->RewardReputationToTeam(510, 10, HORDE);
_reputationScoreTics[team] -= _reputationTics;
}
if (_honorScoreTics[team] >= _honorTics)
{
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(1), (team == TEAM_ALLIANCE) ? ALLIANCE : HORDE);
_honorScoreTics[team] -= _honorTics;
}
const uint32 teamScore = battleground->GetTeamScore(static_cast<TeamId>(team));
if (!_isInformedNearVictory && teamScore > BG_AB_WARNING_NEAR_VICTORY_SCORE)
{
if (team == TEAM_ALLIANCE)
{
battleground->SendBroadcastText(BG_AB_TEXT_ALLIANCE_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
battleground->PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY_ALLIANCE);
}
else
{
battleground->SendBroadcastText(BG_AB_TEXT_HORDE_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
battleground->PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY_HORDE);
}
_isInformedNearVictory = true;
}
if (teamScore > BG_AB_MAX_TEAM_SCORE)
battleground->SetTeamPoint(team == TEAM_HORDE ? HORDE : ALLIANCE, BG_AB_MAX_TEAM_SCORE);
if (team == TEAM_ALLIANCE)
UpdateWorldState(BG_AB_WS_RESOURCES_ALLY, teamScore);
else
UpdateWorldState(BG_AB_WS_RESOURCES_HORDE, teamScore);
// update achievement flags
// we increased m_TeamScores[team] so we just need to check if it is 500 more than other teams resources
uint8 otherTeam = (team + 1) % PVP_TEAMS_COUNT;
if (teamScore > battleground->GetTeamScore(static_cast<TeamId>(otherTeam)) + 500)
{
if (team == TEAM_ALLIANCE)
UpdateWorldState(BG_AB_WS_HAD_500_DISADVANTAGE_HORDE, 1);
else
UpdateWorldState(BG_AB_WS_HAD_500_DISADVANTAGE_ALLIANCE, 1);
}
}
UpdateWorldState(BG_AB_WS_OCCUPIED_BASES_ALLY, ally);
UpdateWorldState(BG_AB_WS_OCCUPIED_BASES_HORDE, horde);
}
// Test win condition
if (battleground->GetTeamScore(TEAM_ALLIANCE) >= BG_AB_MAX_TEAM_SCORE && battleground->GetTeamScore(TEAM_HORDE) >= BG_AB_MAX_TEAM_SCORE)
battleground->EndBattleground(TEAM_OTHER); // draw
else if (battleground->GetTeamScore(TEAM_ALLIANCE) >= BG_AB_MAX_TEAM_SCORE)
battleground->EndBattleground(ALLIANCE);
else if (battleground->GetTeamScore(TEAM_HORDE) >= BG_AB_MAX_TEAM_SCORE)
battleground->EndBattleground(HORDE);
}
void OnStart() override
{
// Achievement: Let's Get This Done
TriggerGameEvent(AB_EVENT_START_BATTLE);
}
void _CalculateTeamNodes(uint8& alliance, uint8& horde) const
{
alliance = 0;
horde = 0;
for (ObjectGuid const& guid : _capturePoints)
{
if (GameObject const* capturePoint = battlegroundMap->GetGameObject(guid))
{
int32 const wsValue = battlegroundMap->GetWorldStateValue(capturePoint->GetGOInfo()->capturePoint.worldState1);
switch (WorldPackets::Battleground::BattlegroundCapturePointState(wsValue))
{
case WorldPackets::Battleground::BattlegroundCapturePointState::AllianceCaptured:
++alliance;
break;
case WorldPackets::Battleground::BattlegroundCapturePointState::HordeCaptured:
++horde;
break;
default:
break;
}
}
}
}
Team GetPrematureWinner() override
{
// How many bases each team owns
uint8 ally = 0, horde = 0;
_CalculateTeamNodes(ally, horde);
if (ally > horde)
return ALLIANCE;
if (horde > ally)
return HORDE;
// If the values are equal, fall back to the original result (based on number of players on each team)
return BattlegroundScript::GetPrematureWinner();
}
void ProcessEvent(WorldObject* /*source*/, uint32 eventId, WorldObject* invoker) override
{
switch (eventId)
{
case AB_EVENT_START_BATTLE:
{
for (ObjectGuid const& guid : _creaturesToRemoveOnMatchStart)
if (Creature* creature = battlegroundMap->GetCreature(guid))
creature->DespawnOrUnsummon();
for (ObjectGuid const& guid : _gameobjectsToRemoveOnMatchStart)
if (GameObject* gameObject = battlegroundMap->GetGameObject(guid))
gameObject->DespawnOrUnsummon();
for (ObjectGuid const& guid : _doors)
{
if (GameObject* gameObject = battlegroundMap->GetGameObject(guid))
{
gameObject->UseDoorOrButton();
gameObject->DespawnOrUnsummon(3s);
}
}
break;
}
case AB_EVENT_CONTESTED_BLACKSMITH_ALLIANCE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE, 1);
UpdateWorldState(BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE, 0);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_BLACKSMITH_ALLIANCE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE, 2);
UpdateWorldState(BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE, 0);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_BLACKSMITH_ALLIANCE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
break;
case AB_EVENT_CONTESTED_BLACKSMITH_HORDE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE, 1);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_HORDE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_BLACKSMITH_HORDE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_BLACKSMITH_HORDE:
UpdateWorldState(BG_AB_WS_BLACKSMITH_HORDE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
break;
case AB_EVENT_CONTESTED_FARM_ALLIANCE:
UpdateWorldState(BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE, 1);
UpdateWorldState(BG_AB_WS_FARM_HORDE_CONTROL_STATE, 0);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_FARM_ALLIANCE:
UpdateWorldState(BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE, 2);
UpdateWorldState(BG_AB_WS_FARM_HORDE_CONTROL_STATE, 0);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_FARM_ALLIANCE:
UpdateWorldState(BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
break;
case AB_EVENT_CONTESTED_FARM_HORDE:
UpdateWorldState(BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_FARM_HORDE_CONTROL_STATE, 1);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_HORDE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_FARM_HORDE:
UpdateWorldState(BG_AB_WS_FARM_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_FARM_HORDE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_FARM_HORDE:
UpdateWorldState(BG_AB_WS_FARM_HORDE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
break;
case AB_EVENT_CONTESTED_GOLD_MINE_ALLIANCE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE, 1);
UpdateWorldState(BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE, 0);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_GOLD_MINE_ALLIANCE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE, 2);
UpdateWorldState(BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE, 0);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_GOLD_MINE_ALLIANCE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
break;
case AB_EVENT_CONTESTED_GOLD_MINE_HORDE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE, 1);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_HORDE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_GOLD_MINE_HORDE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_GOLD_MINE_HORDE:
UpdateWorldState(BG_AB_WS_GOLD_MINE_HORDE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
break;
case AB_EVENT_CONTESTED_LUMBER_MILL_ALLIANCE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE, 1);
UpdateWorldState(BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE, 0);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_LUMBER_MILL_ALLIANCE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE, 2);
UpdateWorldState(BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE, 0);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_LUMBER_MILL_ALLIANCE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
break;
case AB_EVENT_CONTESTED_LUMBER_MILL_HORDE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE, 1);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_HORDE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_LUMBER_MILL_HORDE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_LUMBER_MILL_HORDE:
UpdateWorldState(BG_AB_WS_LUMBER_MILL_HORDE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
break;
case AB_EVENT_CONTESTED_STABLES_ALLIANCE:
UpdateWorldState(BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE, 1);
UpdateWorldState(BG_AB_WS_STABLES_HORDE_CONTROL_STATE, 0);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_STABLES_ALLIANCE:
UpdateWorldState(BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE, 2);
UpdateWorldState(BG_AB_WS_STABLES_HORDE_CONTROL_STATE, 0);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_STABLES_ALLIANCE:
UpdateWorldState(BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
break;
case AB_EVENT_CONTESTED_STABLES_HORDE:
UpdateWorldState(BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_STABLES_HORDE_CONTROL_STATE, 1);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_ASSAULTED_HORDE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
break;
case AB_EVENT_DEFENDED_STABLES_HORDE:
UpdateWorldState(BG_AB_WS_STABLES_ALLIANCE_CONTROL_STATE, 0);
UpdateWorldState(BG_AB_WS_STABLES_HORDE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
if (Player* player = invoker->ToPlayer())
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
break;
case AB_EVENT_CAPTURE_STABLES_HORDE:
UpdateWorldState(BG_AB_WS_STABLES_HORDE_CONTROL_STATE, 2);
battleground->PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
break;
default:
TC_LOG_WARN("bg.events", "BattlegroundAB::ProcessEvent: Unhandled event %u.", eventId);
break;
}
}
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
case BG_AB_NPC_THE_BLACK_BRIDE:
case BG_AB_NPC_RADULF_LEDER:
_creaturesToRemoveOnMatchStart.push_back(creature->GetGUID());
break;
default:
break;
}
}
void OnGameObjectCreate(GameObject* gameObject) override
{
if (gameObject->GetGOInfo()->type == GAMEOBJECT_TYPE_CAPTURE_POINT)
_capturePoints.push_back(gameObject->GetGUID());
switch (gameObject->GetEntry())
{
case BG_AB_OBJECTID_GHOST_GATE:
_gameobjectsToRemoveOnMatchStart.push_back(gameObject->GetGUID());
break;
case BG_AB_OBJECTID_ALLIANCE_DOOR:
case BG_AB_OBJECTID_HORDE_DOOR:
_doors.push_back(gameObject->GetGUID());
break;
default:
break;
}
}
void OnEnd(Team winner) override
{
BattlegroundScript::OnEnd(winner);
// Win reward
if (winner == ALLIANCE)
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(1), ALLIANCE);
if (winner == HORDE)
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(1), HORDE);
// Complete map_end rewards (even if no team wins)
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(1), HORDE);
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(1), ALLIANCE);
}
private:
uint32 _lastTick;
std::array<uint32, PVP_TEAMS_COUNT> _honorScoreTics;
std::array<uint32, PVP_TEAMS_COUNT> _reputationScoreTics;
bool _isInformedNearVictory;
uint32 _honorTics;
uint32 _reputationTics;
GuidVector _gameobjectsToRemoveOnMatchStart;
GuidVector _creaturesToRemoveOnMatchStart;
GuidVector _doors;
GuidVector _capturePoints;
};
void AddSC_battleground_arathi_basin()
{
RegisterBattlegroundMapScript(battleground_arathi_basin, 2107);
}
@@ -15,23 +15,21 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __BATTLEGROUNDTP_H
#define __BATTLEGROUNDTP_H
#include "BattlegroundScript.h"
#include "ScriptMgr.h"
#include "Battleground.h"
#include "BattlegroundScore.h"
enum BG_TP_Objectives
struct battleground_battle_for_gilneas : BattlegroundScript
{
BG_TP_FLAG_CAPTURES = 290,
BG_TP_FLAG_RETURNS = 291
enum PvpStats : uint32
{
BFG_OBJECTIVE_BASES_ASSAULTED = 370,
BFG_OBJECTIVE_BASES_DEFENDED = 371
};
explicit battleground_battle_for_gilneas(BattlegroundMap* map) : BattlegroundScript(map) { }
};
class BattlegroundTP : public Battleground
void AddSC_battleground_battle_for_gilneas()
{
public:
BattlegroundTP(BattlegroundTemplate const* battlegroundTemplate);
~BattlegroundTP();
};
#endif
RegisterBattlegroundMapScript(battleground_battle_for_gilneas, 761);
}
@@ -0,0 +1,84 @@
/*
* 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/>.
*/
#include "Battleground.h"
#include "BattlegroundScript.h"
#include "GameObject.h"
#include "Map.h"
#include "ScriptMgr.h"
#include "TaskScheduler.h"
struct arena_blades_edge : ArenaScript
{
enum GameObjects
{
BG_BE_OBJECT_TYPE_DOOR_1 = 183971,
BG_BE_OBJECT_TYPE_DOOR_2 = 183973,
BG_BE_OBJECT_TYPE_DOOR_3 = 183970,
BG_BE_OBJECT_TYPE_DOOR_4 = 183972,
BG_BE_OBJECT_TYPE_BUFF_1 = 184663,
BG_BE_OBJECT_TYPE_BUFF_2 = 184664
};
explicit arena_blades_edge(BattlegroundMap* map) : ArenaScript(map) { }
void OnUpdate(uint32 diff) override
{
_scheduler.Update(diff);
}
void OnInit() override
{
AddDoor(BG_BE_OBJECT_TYPE_DOOR_1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f);
AddDoor(BG_BE_OBJECT_TYPE_DOOR_2, 6189.546f, 241.7099f, 3.101481f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f);
AddDoor(BG_BE_OBJECT_TYPE_DOOR_3, 6299.116f, 296.5494f, 3.308032f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f);
AddDoor(BG_BE_OBJECT_TYPE_DOOR_4, 6177.708f, 227.3481f, 3.604374f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f);
}
void OnStart() override
{
for (ObjectGuid const& guid : _doorGUIDs)
{
if (GameObject* door = battlegroundMap->GetGameObject(guid))
{
door->UseDoorOrButton();
door->DespawnOrUnsummon(5s);
}
}
_scheduler.Schedule(1min, [&](TaskContext)
{
CreateObject(BG_BE_OBJECT_TYPE_BUFF_1, 6249.042f, 275.3239f, 11.22033f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f);
CreateObject(BG_BE_OBJECT_TYPE_BUFF_2, 6228.26f, 249.566f, 11.21812f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f);
});
}
void AddDoor(uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, GOState goState = GO_STATE_READY)
{
if (GameObject const* go = CreateObject(entry, x, y, z, o, rotation0, rotation1, rotation2, rotation3, goState))
_doorGUIDs.emplace_back(go->GetGUID());
}
private:
GuidVector _doorGUIDs;
TaskScheduler _scheduler;
};
void AddSC_arena_blades_edge()
{
RegisterBattlegroundMapScript(arena_blades_edge, 1672);
}
@@ -0,0 +1,266 @@
/*
* 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/>.
*/
#include "Battleground.h"
#include "BattlegroundScript.h"
#include "Creature.h"
#include "Duration.h"
#include "EventMap.h"
#include "GameObject.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "TaskScheduler.h"
struct arena_dalaran_sewers : ArenaScript
{
enum GameObjects
{
BG_DS_OBJECT_TYPE_DOOR_1 = 192642,
BG_DS_OBJECT_TYPE_DOOR_2 = 192643,
BG_DS_OBJECT_TYPE_WATER_1 = 194395, // Collision
BG_DS_OBJECT_TYPE_WATER_2 = 191877,
BG_DS_OBJECT_TYPE_BUFF_1 = 184663,
BG_DS_OBJECT_TYPE_BUFF_2 = 184664
};
enum Events
{
BG_DS_EVENT_WATERFALL_WARNING = 1, // Water starting to fall, but no LoS Blocking nor movement blocking
BG_DS_EVENT_WATERFALL_ON = 2, // LoS and Movement blocking active
BG_DS_EVENT_WATERFALL_OFF = 3,
BG_DS_EVENT_WATERFALL_KNOCKBACK = 4,
BG_DS_EVENT_PIPE_KNOCKBACK = 5
};
enum Creatures
{
BG_DS_NPC_TYPE_WATER_SPOUT = 28567
};
enum Spells
{
BG_DS_SPELL_FLUSH = 57405, // Visual and target selector for the starting knockback from the pipe
BG_DS_SPELL_FLUSH_KNOCKBACK = 61698, // Knockback effect for previous spell (triggered, not needed to be cast)
BG_DS_SPELL_WATER_SPOUT = 58873, // Knockback effect of the central waterfall
SPELL_WARL_DEMONIC_CIRCLE = 48018 // Demonic Circle Summon
};
enum Data
{
// These values are NOT blizzlike... need the correct data!
BG_DS_PIPE_KNOCKBACK_FIRST_DELAY = 5000,
BG_DS_PIPE_KNOCKBACK_DELAY = 3000
};
// These values are NOT blizzlike... need the correct data!
static constexpr Seconds BG_DS_WATERFALL_TIMER_MIN = 30s;
static constexpr Seconds BG_DS_WATERFALL_TIMER_MAX = 60s;
static constexpr Seconds BG_DS_WATERFALL_WARNING_DURATION = 5s;
static constexpr Seconds BG_DS_WATERFALL_DURATION = 30s;
static constexpr Milliseconds BG_DS_WATERFALL_KNOCKBACK_TIMER = 1500ms;
static constexpr uint32 BG_DS_DATA_PIPE_KNOCKBACK_COUNT = 1;
static constexpr uint32 BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT = 2;
explicit arena_dalaran_sewers(BattlegroundMap* map) : ArenaScript(map), _pipeKnockBackTimer(BG_DS_PIPE_KNOCKBACK_FIRST_DELAY), _pipeKnockBackCount(0) { }
void OnUpdate(uint32 diff) override
{
if (battleground->GetStatus() != STATUS_IN_PROGRESS)
return;
_events.Update(diff);
_scheduler.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case BG_DS_EVENT_WATERFALL_WARNING:
// Add the water
if (GameObject* go = battlegroundMap->GetGameObject(_water2GUID))
go->ResetDoorOrButton();
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_ON, BG_DS_WATERFALL_WARNING_DURATION);
break;
case BG_DS_EVENT_WATERFALL_ON:
// Active collision and start knockback timer
if (GameObject* go = battlegroundMap->GetGameObject(_water1GUID))
go->ResetDoorOrButton();
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_OFF, BG_DS_WATERFALL_DURATION);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_KNOCKBACK, BG_DS_WATERFALL_KNOCKBACK_TIMER);
break;
case BG_DS_EVENT_WATERFALL_OFF:
// Remove collision and water
if (GameObject* go = battlegroundMap->GetGameObject(_water1GUID))
go->UseDoorOrButton();
if (GameObject* go = battlegroundMap->GetGameObject(_water2GUID))
go->UseDoorOrButton();
_events.CancelEvent(BG_DS_EVENT_WATERFALL_KNOCKBACK);
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_WARNING, BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX);
break;
case BG_DS_EVENT_WATERFALL_KNOCKBACK:
// Repeat knockback while the waterfall still active
if (Creature* waterSpout = battlegroundMap->GetCreature(_waterfallCreatureGUID))
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_WATER_SPOUT, true);
_events.ScheduleEvent(eventId, BG_DS_WATERFALL_KNOCKBACK_TIMER);
break;
case BG_DS_EVENT_PIPE_KNOCKBACK:
for (ObjectGuid const& guid : _pipeCreatureGUIDs)
if (Creature* waterSpout = battlegroundMap->GetCreature(guid))
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_FLUSH, true);
break;
default:
break;
}
}
if (_pipeKnockBackCount < BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT)
{
if (_pipeKnockBackTimer < diff)
{
for (ObjectGuid const& guid : _pipeCreatureGUIDs)
if (Creature* waterSpout = battlegroundMap->GetCreature(guid))
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_FLUSH, true);
++_pipeKnockBackCount;
_pipeKnockBackTimer = BG_DS_PIPE_KNOCKBACK_DELAY;
}
else
_pipeKnockBackTimer -= diff;
}
}
void OnInit() override
{
AddObject(BG_DS_OBJECT_TYPE_DOOR_1, 1350.95f, 817.2f, 20.8096f, 3.15f, 0, 0, 0.99627f, 0.0862864f, GO_STATE_READY, _doorGUIDs);
AddObject(BG_DS_OBJECT_TYPE_DOOR_2, 1232.65f, 764.913f, 20.0729f, 6.3f, 0, 0, 0.0310211f, -0.999519f, GO_STATE_READY, _doorGUIDs);
if (GameObject const* go = CreateObject(BG_DS_OBJECT_TYPE_WATER_1, 1291.56f, 790.837f, 7.1f, 3.14238f, 0, 0, 0.694215f, -0.719768f, GO_STATE_READY))
_water1GUID = go->GetGUID();
if (GameObject const* go = CreateObject(BG_DS_OBJECT_TYPE_WATER_2, 1291.56f, 790.837f, 7.1f, 3.14238f, 0, 0, 0.694215f, -0.719768f, GO_STATE_READY))
_water2GUID = go->GetGUID();
}
void OnStart() override
{
for (ObjectGuid const& guid : _doorGUIDs)
{
if (GameObject* door = battlegroundMap->GetGameObject(guid))
{
door->UseDoorOrButton();
door->DespawnOrUnsummon(5s);
}
}
_scheduler.Schedule(1min, [&](TaskContext)
{
CreateObject(BG_DS_OBJECT_TYPE_BUFF_1, 1291.7f, 813.424f, 7.11472f, 4.64562f, 0, 0, 0.730314f, -0.683111f);
CreateObject(BG_DS_OBJECT_TYPE_BUFF_2, 1291.7f, 768.911f, 7.11472f, 1.55194f, 0, 0, 0.700409f, 0.713742f);
});
_events.ScheduleEvent(BG_DS_EVENT_WATERFALL_WARNING, BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX);
_pipeKnockBackTimer = BG_DS_PIPE_KNOCKBACK_FIRST_DELAY;
// Remove collision and water
if (GameObject* go = battlegroundMap->GetGameObject(_water1GUID))
go->UseDoorOrButton();
if (GameObject* go = battlegroundMap->GetGameObject(_water2GUID))
go->UseDoorOrButton();
for (const auto& [playerGuid, _] : battleground->GetPlayers())
if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
player->RemoveAurasDueToSpell(SPELL_WARL_DEMONIC_CIRCLE);
}
void AddObject(uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, GOState goState, GuidVector guidVector) const
{
if (GameObject const* go = CreateObject(entry, x, y, z, o, rotation0, rotation1, rotation2, rotation3, goState))
guidVector.emplace_back(go->GetGUID());
}
void SetData(uint32 dataId, uint32 value) override
{
ArenaScript::SetData(dataId, value);
if (dataId == BG_DS_DATA_PIPE_KNOCKBACK_COUNT)
_pipeKnockBackCount = value;
}
uint32 GetData(uint32 dataId) const override
{
if (dataId == BG_DS_DATA_PIPE_KNOCKBACK_COUNT)
return _pipeKnockBackCount;
return ArenaScript::GetData(dataId);
}
private:
GuidVector _doorGUIDs;
ObjectGuid _water1GUID;
ObjectGuid _water2GUID;
ObjectGuid _waterfallCreatureGUID;
GuidVector _pipeCreatureGUIDs;
TaskScheduler _scheduler;
EventMap _events;
uint32 _pipeKnockBackTimer;
uint8 _pipeKnockBackCount;
};
class at_ds_pipe_knockback : public AreaTriggerScript
{
public:
at_ds_pipe_knockback() : AreaTriggerScript("at_ds_pipe_knockback") { }
void Trigger(Player* player) const
{
if (Battleground const* battleground = player->GetBattleground())
{
if (battleground->GetStatus() != STATUS_IN_PROGRESS)
return;
// Remove effects of Demonic Circle Summon
player->RemoveAurasDueToSpell(arena_dalaran_sewers::SPELL_WARL_DEMONIC_CIRCLE);
// Someone has get back into the pipes and the knockback has already been performed,
// so we reset the knockback count for kicking the player again into the arena.
if (battleground->GetBgMap()->GetBattlegroundScript()->GetData(arena_dalaran_sewers::BG_DS_DATA_PIPE_KNOCKBACK_COUNT) >= arena_dalaran_sewers::BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT)
battleground->GetBgMap()->GetBattlegroundScript()->SetData(arena_dalaran_sewers::BG_DS_DATA_PIPE_KNOCKBACK_COUNT, 0);
}
}
bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override
{
Trigger(player);
return true;
}
bool OnExit(Player* player, AreaTriggerEntry const* /*trigger*/) override
{
Trigger(player);
return true;
}
};
void AddSC_arena_dalaran_sewers()
{
RegisterBattlegroundMapScript(arena_dalaran_sewers, 617);
new at_ds_pipe_knockback();
}
@@ -0,0 +1,677 @@
/*
* 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/>.
*/
#include "AreaTrigger.h"
#include "BattlegroundScript.h"
#include "Battleground.h"
#include "BattlegroundMgr.h"
#include "GameObject.h"
#include "GameTime.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "SpellAuras.h"
#include "Timer.h"
enum EyeOfTheStormWorldStates
{
EY_ALLIANCE_RESOURCES = 1776,
EY_HORDE_RESOURCES = 1777,
EY_MAX_RESOURCES = 1780,
EY_ALLIANCE_BASE = 2752,
EY_HORDE_BASE = 2753,
DRAENEI_RUINS_HORDE_CONTROL = 2733,
DRAENEI_RUINS_ALLIANCE_CONTROL = 2732,
DRAENEI_RUINS_UNCONTROL = 2731,
MAGE_TOWER_ALLIANCE_CONTROL = 2730,
MAGE_TOWER_HORDE_CONTROL = 2729,
MAGE_TOWER_UNCONTROL = 2728,
FEL_REAVER_HORDE_CONTROL = 2727,
FEL_REAVER_ALLIANCE_CONTROL = 2726,
FEL_REAVER_UNCONTROL = 2725,
BLOOD_ELF_HORDE_CONTROL = 2724,
BLOOD_ELF_ALLIANCE_CONTROL = 2723,
BLOOD_ELF_UNCONTROL = 2722,
PROGRESS_BAR_PERCENT_GREY = 2720, //100 = empty (only grey), 0 = blue|red (no grey)
PROGRESS_BAR_STATUS = 2719, //50 init!, 48 ... hordak bere .. 33 .. 0 = full 100% hordacky, 100 = full alliance
PROGRESS_BAR_SHOW = 2718, //1 init, 0 druhy send - bez messagu, 1 = controlled aliance
NETHERSTORM_FLAG = 8863,
//set to 2 when flag is picked up, and to 1 if it is dropped
NETHERSTORM_FLAG_STATE_ALLIANCE = 9808,
NETHERSTORM_FLAG_STATE_HORDE = 9809,
DRAENEI_RUINS_HORDE_CONTROL_STATE = 17362,
DRAENEI_RUINS_ALLIANCE_CONTROL_STATE = 17366,
MAGE_TOWER_HORDE_CONTROL_STATE = 17361,
MAGE_TOWER_ALLIANCE_CONTROL_STATE = 17368,
FEL_REAVER_HORDE_CONTROL_STATE = 17364,
FEL_REAVER_ALLIANCE_CONTROL_STATE = 17367,
BLOOD_ELF_HORDE_CONTROL_STATE = 17363,
BLOOD_ELF_ALLIANCE_CONTROL_STATE = 17365,
};
enum EyeOfTheStormSounds
{
//strange ids, but sure about them
BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212,
BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213,
BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174,
BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
BG_EY_SOUND_FLAG_RESET = 8192
};
enum EyeOfTheStormSpells
{
BG_EY_NETHERSTORM_FLAG_SPELL = 34976,
BG_EY_PLAYER_DROPPED_FLAG_SPELL = 34991,
// Focused/Brutal Assault
BG_EY_FOCUSED_ASSAULT_SPELL = 46392,
BG_EY_BRUTAL_ASSAULT_SPELL = 46393
};
enum EyeOfTheStormObjectEntry
{
BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door
BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door
BG_OBJECT_FLAG2_EY_ENTRY = 208977, //Netherstorm flag (flagstand)
BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt
BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt
BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt
BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083, //Draenei Tower Cap Pt
};
enum EyeOfTheStormPointsTrigger
{
AREATRIGGER_CAPTURE_FLAG = 33
};
enum EyeOfTheStormPoints
{
FEL_REAVER = 0,
BLOOD_ELF = 1,
DRAENEI_RUINS = 2,
MAGE_TOWER = 3,
EY_PLAYERS_OUT_OF_POINTS = 4,
EY_POINTS_MAX = 4
};
constexpr uint32 BG_EY_NotEYWeekendHonorTicks = 260;
constexpr uint32 BG_EY_EYWeekendHonorTicks = 160;
enum BG_EY_Score
{
BG_EY_WARNING_NEAR_VICTORY_SCORE = 1200,
BG_EY_MAX_TEAM_SCORE = 1500
};
enum BG_EY_FlagState
{
BG_EY_FLAG_STATE_ON_BASE = 0,
BG_EY_FLAG_STATE_WAIT_RESPAWN = 1,
BG_EY_FLAG_STATE_ON_PLAYER = 2,
BG_EY_FLAG_STATE_ON_GROUND = 3
};
enum EYBattlegroundPointState
{
EY_POINT_NO_OWNER = 0,
EY_POINT_STATE_UNCONTROLLED = 0,
EY_POINT_UNDER_CONTROL = 3
};
enum BG_EY_ExploitTeleportLocations
{
EY_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3773,
EY_EXPLOIT_TELEPORT_LOCATION_HORDE = 3772
};
enum EyeOFtheStormBroadcastTexts
{
BG_EY_TEXT_ALLIANCE_TAKEN_FEL_REAVER_RUINS = 17828,
BG_EY_TEXT_HORDE_TAKEN_FEL_REAVER_RUINS = 17829,
BG_EY_TEXT_ALLIANCE_LOST_FEL_REAVER_RUINS = 91961,
BG_EY_TEXT_HORDE_LOST_FEL_REAVER_RUINS = 91962,
BG_EY_TEXT_ALLIANCE_TAKEN_BLOOD_ELF_TOWER = 17819,
BG_EY_TEXT_HORDE_TAKEN_BLOOD_ELF_TOWER = 17823,
BG_EY_TEXT_ALLIANCE_LOST_BLOOD_ELF_TOWER = 91957,
BG_EY_TEXT_HORDE_LOST_BLOOD_ELF_TOWER = 91958,
BG_EY_TEXT_ALLIANCE_TAKEN_DRAENEI_RUINS = 17827,
BG_EY_TEXT_HORDE_TAKEN_DRAENEI_RUINS = 91917,
BG_EY_TEXT_ALLIANCE_LOST_DRAENEI_RUINS = 91959,
BG_EY_TEXT_HORDE_LOST_DRAENEI_RUINS = 91960,
BG_EY_TEXT_ALLIANCE_TAKEN_MAGE_TOWER = 17824,
BG_EY_TEXT_HORDE_TAKEN_MAGE_TOWER = 17825,
BG_EY_TEXT_ALLIANCE_LOST_MAGE_TOWER = 91963,
BG_EY_TEXT_HORDE_LOST_MAGE_TOWER = 91964,
BG_EY_TEXT_TAKEN_FLAG = 18359,
BG_EY_TEXT_FLAG_DROPPED = 18361,
BG_EY_TEXT_FLAG_RESET = 18364,
BG_EY_TEXT_ALLIANCE_CAPTURED_FLAG = 18375,
BG_EY_TEXT_HORDE_CAPTURED_FLAG = 18384,
};
struct BattlegroundEYPointIconsStruct
{
BattlegroundEYPointIconsStruct(uint32 _WorldStateControlIndex, uint32 _WorldStateAllianceControlledIndex, uint32 _WorldStateHordeControlledIndex,
uint32 worldStateAllianceStatusBarIcon, uint32 worldStateHordeStatusBarIcon)
: WorldStateControlIndex(_WorldStateControlIndex), WorldStateAllianceControlledIndex(_WorldStateAllianceControlledIndex), WorldStateHordeControlledIndex(_WorldStateHordeControlledIndex),
WorldStateAllianceStatusBarIcon(worldStateAllianceStatusBarIcon), WorldStateHordeStatusBarIcon(worldStateHordeStatusBarIcon) { }
uint32 WorldStateControlIndex;
uint32 WorldStateAllianceControlledIndex;
uint32 WorldStateHordeControlledIndex;
uint32 WorldStateAllianceStatusBarIcon;
uint32 WorldStateHordeStatusBarIcon;
};
struct BattlegroundEYLosingPointStruct
{
BattlegroundEYLosingPointStruct(uint32 _MessageIdAlliance, uint32 _MessageIdHorde)
: MessageIdAlliance(_MessageIdAlliance), MessageIdHorde(_MessageIdHorde)
{ }
uint32 MessageIdAlliance;
uint32 MessageIdHorde;
};
struct BattlegroundEYCapturingPointStruct
{
BattlegroundEYCapturingPointStruct(uint32 _MessageIdAlliance, uint32 _MessageIdHorde)
: MessageIdAlliance(_MessageIdAlliance), MessageIdHorde(_MessageIdHorde)
{ }
uint32 MessageIdAlliance;
uint32 MessageIdHorde;
};
class BattlegroundEYControlZoneHandler : public ControlZoneHandler
{
public:
explicit BattlegroundEYControlZoneHandler(uint32 point) : _point(point) { }
uint32 GetPoint() const { return _point; }
private:
uint32 _point;
};
const std::array<BattlegroundEYPointIconsStruct, EY_POINTS_MAX> m_PointsIconStruct =
{
BattlegroundEYPointIconsStruct(FEL_REAVER_UNCONTROL, FEL_REAVER_ALLIANCE_CONTROL, FEL_REAVER_HORDE_CONTROL, FEL_REAVER_ALLIANCE_CONTROL_STATE, FEL_REAVER_HORDE_CONTROL_STATE),
BattlegroundEYPointIconsStruct(BLOOD_ELF_UNCONTROL, BLOOD_ELF_ALLIANCE_CONTROL, BLOOD_ELF_HORDE_CONTROL, BLOOD_ELF_ALLIANCE_CONTROL_STATE, BLOOD_ELF_HORDE_CONTROL_STATE),
BattlegroundEYPointIconsStruct(DRAENEI_RUINS_UNCONTROL, DRAENEI_RUINS_ALLIANCE_CONTROL, DRAENEI_RUINS_HORDE_CONTROL, DRAENEI_RUINS_ALLIANCE_CONTROL_STATE, DRAENEI_RUINS_HORDE_CONTROL_STATE),
BattlegroundEYPointIconsStruct(MAGE_TOWER_UNCONTROL, MAGE_TOWER_ALLIANCE_CONTROL, MAGE_TOWER_HORDE_CONTROL, MAGE_TOWER_ALLIANCE_CONTROL_STATE, MAGE_TOWER_HORDE_CONTROL_STATE)
};
const std::array<BattlegroundEYLosingPointStruct, EY_POINTS_MAX> m_LosingPointTypes =
{
BattlegroundEYLosingPointStruct(BG_EY_TEXT_ALLIANCE_LOST_FEL_REAVER_RUINS, BG_EY_TEXT_HORDE_LOST_FEL_REAVER_RUINS),
BattlegroundEYLosingPointStruct(BG_EY_TEXT_ALLIANCE_LOST_BLOOD_ELF_TOWER, BG_EY_TEXT_HORDE_LOST_BLOOD_ELF_TOWER),
BattlegroundEYLosingPointStruct(BG_EY_TEXT_ALLIANCE_LOST_DRAENEI_RUINS, BG_EY_TEXT_HORDE_LOST_DRAENEI_RUINS),
BattlegroundEYLosingPointStruct(BG_EY_TEXT_ALLIANCE_LOST_MAGE_TOWER, BG_EY_TEXT_HORDE_LOST_MAGE_TOWER)
};
const std::array<BattlegroundEYCapturingPointStruct, EY_POINTS_MAX> m_CapturingPointTypes =
{
BattlegroundEYCapturingPointStruct(BG_EY_TEXT_ALLIANCE_TAKEN_FEL_REAVER_RUINS, BG_EY_TEXT_HORDE_TAKEN_FEL_REAVER_RUINS),
BattlegroundEYCapturingPointStruct(BG_EY_TEXT_ALLIANCE_TAKEN_BLOOD_ELF_TOWER, BG_EY_TEXT_HORDE_TAKEN_BLOOD_ELF_TOWER),
BattlegroundEYCapturingPointStruct(BG_EY_TEXT_ALLIANCE_TAKEN_DRAENEI_RUINS, BG_EY_TEXT_HORDE_TAKEN_DRAENEI_RUINS),
BattlegroundEYCapturingPointStruct(BG_EY_TEXT_ALLIANCE_TAKEN_MAGE_TOWER, BG_EY_TEXT_HORDE_TAKEN_MAGE_TOWER)
};
struct battleground_eye_of_the_storm : BattlegroundScript
{
enum PvpStats
{
PVP_STAT_FLAG_CAPTURES = 183
};
static constexpr Seconds POINTS_TICK_TIME = 2s;
static constexpr Seconds BG_EY_FLAG_ASSAULT_TIMER = 30s;
static constexpr uint16 BG_EY_FLAG_BRUTAL_ASSAULT_STACK_COUNT = 5;
static constexpr uint32 BG_EY_EVENT_START_BATTLE = 13180;
static constexpr std::array<uint8, EY_POINTS_MAX> BG_EY_TickPoints = { 1, 2, 5, 10 };
static constexpr std::array<uint32, EY_POINTS_MAX> BG_EY_FlagPoints = { 75, 85, 100, 500 };
explicit battleground_eye_of_the_storm(BattlegroundMap* map) : BattlegroundScript(map)
{
_honorScoreTics = { 0, 0 };
_honorTics = 0;
_pointsTimer.Reset(POINTS_TICK_TIME);
_assaultEnabled = false;
_assaultStackCount = 0;
_flagAssaultTimer.Reset(BG_EY_FLAG_ASSAULT_TIMER);
_controlZoneHandlers[BG_OBJECT_FR_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(FEL_REAVER);
_controlZoneHandlers[BG_OBJECT_BE_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(BLOOD_ELF);
_controlZoneHandlers[BG_OBJECT_DR_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(DRAENEI_RUINS);
_controlZoneHandlers[BG_OBJECT_HU_TOWER_CAP_EY_ENTRY] = std::make_unique<BattlegroundEYControlZoneHandler>(MAGE_TOWER);
bool isBGWeekend = sBattlegroundMgr->IsBGWeekend(battleground->GetTypeID());
_honorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks;
}
void OnInit() override
{
UpdateWorldState(EY_MAX_RESOURCES, BG_EY_MAX_TEAM_SCORE);
}
void OnUpdate(uint32 diff) override
{
if (battleground->GetStatus() != STATUS_IN_PROGRESS)
return;
_pointsTimer.Update(diff);
if (_pointsTimer.Passed())
{
_pointsTimer.Reset(POINTS_TICK_TIME);
uint8 baseCountAlliance = GetControlledBaseCount(TEAM_ALLIANCE);
uint8 baseCountHorde = GetControlledBaseCount(TEAM_HORDE);
if (baseCountAlliance > 0)
AddPoint(ALLIANCE, BG_EY_TickPoints[baseCountAlliance - 1]);
if (baseCountHorde > 0)
AddPoint(HORDE, BG_EY_TickPoints[baseCountHorde - 1]);
}
if (_assaultEnabled)
{
_flagAssaultTimer.Update(diff);
if (_flagAssaultTimer.Passed())
{
_flagAssaultTimer.Reset(BG_EY_FLAG_ASSAULT_TIMER);
if (_assaultStackCount < std::numeric_limits<uint8>::max())
{
_assaultStackCount++;
// update assault debuff stacks
DoForFlagKeepers([&](Player* player) -> void
{
ApplyAssaultDebuffToPlayer(player);
});
}
}
}
}
void OnStart() override
{
for (ObjectGuid const& door : _doorGUIDs)
{
if (GameObject* gameObject = battlegroundMap->GetGameObject(door))
{
gameObject->UseDoorOrButton();
gameObject->DespawnOrUnsummon(3s);
}
}
// Achievement: Flurry
TriggerGameEvent(BG_EY_EVENT_START_BATTLE);
}
void AddPoint(Team team, uint32 points)
{
battleground->AddPoint(team, points);
TeamId const team_index = Battleground::GetTeamIndexByTeamId(team);
_honorScoreTics[team_index] += points;
if (_honorScoreTics[team_index] >= _honorTics)
{
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(1), team);
_honorScoreTics[team_index] -= _honorTics;
}
UpdateTeamScore(team_index);
}
uint8 GetControlledBaseCount(TeamId teamId) const
{
uint8 baseCount = 0;
for (auto const& controlZoneHandler : _controlZoneHandlers)
{
uint32 point = controlZoneHandler.second->GetPoint();
switch (teamId)
{
case TEAM_ALLIANCE:
if (battlegroundMap->GetWorldStateValue(m_PointsIconStruct[point].WorldStateAllianceControlledIndex) == 1)
baseCount++;
break;
case TEAM_HORDE:
if (battlegroundMap->GetWorldStateValue(m_PointsIconStruct[point].WorldStateHordeControlledIndex) == 1)
baseCount++;
break;
default:
break;
}
}
return baseCount;
}
void DoForFlagKeepers(std::function<void(Player*)> const& action) const
{
if (GameObject const* flag = battlegroundMap->GetGameObject(_flagGUID))
if (Player* carrier = ObjectAccessor::FindPlayer(flag->GetFlagCarrierGUID()))
action(carrier);
}
void ResetAssaultDebuff()
{
_assaultEnabled = false;
_assaultStackCount = 0;
_flagAssaultTimer.Reset(BG_EY_FLAG_ASSAULT_TIMER);
DoForFlagKeepers([&](Player* player) -> void
{
RemoveAssaultDebuffFromPlayer(player);
});
}
void ApplyAssaultDebuffToPlayer(Player* player)
{
if (_assaultStackCount == 0)
return;
uint32 spellId = BG_EY_FOCUSED_ASSAULT_SPELL;
if (_assaultStackCount >= BG_EY_FLAG_BRUTAL_ASSAULT_STACK_COUNT)
{
player->RemoveAurasDueToSpell(BG_EY_FOCUSED_ASSAULT_SPELL);
spellId = BG_EY_BRUTAL_ASSAULT_SPELL;
}
Aura* aura = player->GetAura(spellId);
if (!aura)
{
player->CastSpell(player, spellId, true);
aura = player->GetAura(spellId);
}
if (aura)
aura->SetStackAmount(_assaultStackCount);
}
void RemoveAssaultDebuffFromPlayer(Player* player)
{
player->RemoveAurasDueToSpell(BG_EY_FOCUSED_ASSAULT_SPELL);
player->RemoveAurasDueToSpell(BG_EY_BRUTAL_ASSAULT_SPELL);
}
void UpdateTeamScore(TeamId Team) const
{
uint32 score = battleground->GetTeamScore(Team);
if (score >= BG_EY_MAX_TEAM_SCORE)
{
score = BG_EY_MAX_TEAM_SCORE;
if (Team == TEAM_ALLIANCE)
battleground->EndBattleground(ALLIANCE);
else
battleground->EndBattleground(HORDE);
}
if (Team == TEAM_ALLIANCE)
UpdateWorldState(EY_ALLIANCE_RESOURCES, score);
else
UpdateWorldState(EY_HORDE_RESOURCES, score);
}
void OnEnd(Team winner) override
{
BattlegroundScript::OnEnd(winner);
// Win reward
if (winner == ALLIANCE)
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(1), ALLIANCE);
if (winner == HORDE)
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(1), HORDE);
// Complete map reward
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(1), ALLIANCE);
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(1), HORDE);
}
void UpdatePointsCount(TeamId teamId) const
{
if (teamId == TEAM_ALLIANCE)
UpdateWorldState(EY_ALLIANCE_BASE, GetControlledBaseCount(TEAM_ALLIANCE));
else
UpdateWorldState(EY_HORDE_BASE, GetControlledBaseCount(TEAM_HORDE));
}
void OnGameObjectCreate(GameObject* gameObject) override
{
switch (gameObject->GetEntry())
{
case BG_OBJECT_A_DOOR_EY_ENTRY:
case BG_OBJECT_H_DOOR_EY_ENTRY:
_doorGUIDs.insert(gameObject->GetGUID());
break;
case BG_OBJECT_FLAG2_EY_ENTRY:
_flagGUID = gameObject->GetGUID();
break;
default:
break;
}
}
bool CanCaptureFlag(AreaTrigger* areaTrigger, Player* player) override
{
if (areaTrigger->GetEntry() != AREATRIGGER_CAPTURE_FLAG)
return false;
if (GameObject const* flag = battlegroundMap->GetGameObject(_flagGUID))
{
if (flag->GetFlagCarrierGUID() != player->GetGUID())
return false;
}
if (GameObject const* controlzone = player->FindNearestGameObjectWithOptions(40.0f, { .StringId = "bg_eye_of_the_storm_control_zone" }))
{
uint32 const point = _controlZoneHandlers[controlzone->GetEntry()]->GetPoint();
switch (battleground->GetPlayerTeam(player->GetGUID()))
{
case ALLIANCE:
return battlegroundMap->GetWorldStateValue(m_PointsIconStruct[point].WorldStateAllianceControlledIndex) == 1;
case HORDE:
return battlegroundMap->GetWorldStateValue(m_PointsIconStruct[point].WorldStateHordeControlledIndex) == 1;
default:
return false;
}
}
return false;
}
void OnCaptureFlag(AreaTrigger* areaTrigger, Player* player) override
{
if (areaTrigger->GetEntry() != AREATRIGGER_CAPTURE_FLAG)
return;
uint32 const baseCount = GetControlledBaseCount(Battleground::GetTeamIndexByTeamId(battleground->GetPlayerTeam(player->GetGUID())));
if (GameObject const* gameObject = battlegroundMap->GetGameObject(_flagGUID))
gameObject->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::Respawning, player));
Team const team = Team(battleground->GetPlayerTeam(player->GetGUID()));
if (team == ALLIANCE)
{
battleground->SendBroadcastText(BG_EY_TEXT_ALLIANCE_CAPTURED_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
battleground->PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE);
}
else
{
battleground->SendBroadcastText(BG_EY_TEXT_HORDE_CAPTURED_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, player);
battleground->PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE);
}
if (baseCount > 0)
AddPoint(team, BG_EY_FlagPoints[baseCount - 1]);
UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_ON_BASE);
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_ON_BASE);
battleground->UpdatePvpStat(player, PVP_STAT_FLAG_CAPTURES, 1);
ResetAssaultDebuff();
player->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL);
player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive);
}
void OnFlagStateChange(GameObject* /*flagInBase*/, FlagState /*oldValue*/, FlagState newValue, Player* player) override
{
switch (newValue)
{
case FlagState::InBase:
ResetAssaultDebuff();
break;
case FlagState::Dropped:
player->CastSpell(player, SPELL_RECENTLY_DROPPED_NEUTRAL_FLAG, true);
RemoveAssaultDebuffFromPlayer(player);
UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_WAIT_RESPAWN);
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_WAIT_RESPAWN);
if (battleground->GetPlayerTeam(player->GetGUID()) == ALLIANCE)
battleground->SendBroadcastText(BG_EY_TEXT_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_ALLIANCE);
else
battleground->SendBroadcastText(BG_EY_TEXT_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_HORDE);
break;
case FlagState::Taken:
if (battleground->GetPlayerTeam(player->GetGUID()) == ALLIANCE)
{
UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_ON_PLAYER);
battleground->PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE);
battleground->SendBroadcastText(BG_EY_TEXT_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
}
else
{
UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_ON_PLAYER);
battleground->PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_HORDE);
battleground->SendBroadcastText(BG_EY_TEXT_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, player);
}
ApplyAssaultDebuffToPlayer(player);
_assaultEnabled = true;
player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive);
break;
case FlagState::Respawning:
ResetAssaultDebuff();
break;
default:
break;
}
UpdateWorldState(NETHERSTORM_FLAG, AsUnderlyingType(newValue));
}
void EventTeamLostPoint(TeamId teamId, uint32 point, GameObject* controlZone) const
{
if (teamId == TEAM_ALLIANCE)
{
battleground->SendBroadcastText(m_LosingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, controlZone);
UpdateWorldState(m_PointsIconStruct[point].WorldStateAllianceControlledIndex, 0);
}
else if (teamId == TEAM_HORDE)
{
battleground->SendBroadcastText(m_LosingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE, controlZone);
UpdateWorldState(m_PointsIconStruct[point].WorldStateHordeControlledIndex, 0);
}
UpdateWorldState(m_PointsIconStruct[point].WorldStateControlIndex, 1);
UpdatePointsCount(teamId);
}
void EventTeamCapturedPoint(TeamId teamId, uint32 point, GameObject* controlZone) const
{
if (teamId == TEAM_ALLIANCE)
{
battleground->SendBroadcastText(m_CapturingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE, controlZone);
UpdateWorldState(m_PointsIconStruct[point].WorldStateAllianceControlledIndex, 1);
}
else if (teamId == TEAM_HORDE)
{
battleground->SendBroadcastText(m_CapturingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE, controlZone);
UpdateWorldState(m_PointsIconStruct[point].WorldStateHordeControlledIndex, 1);
}
UpdateWorldState(m_PointsIconStruct[point].WorldStateControlIndex, 0);
UpdatePointsCount(teamId);
}
Team GetPrematureWinner() override
{
if (battleground->GetTeamScore(TEAM_ALLIANCE) > battleground->GetTeamScore(TEAM_HORDE))
return ALLIANCE;
if (battleground->GetTeamScore(TEAM_HORDE) > battleground->GetTeamScore(TEAM_ALLIANCE))
return HORDE;
return BattlegroundScript::GetPrematureWinner();
}
void ProcessEvent(WorldObject* obj, uint32 eventId, WorldObject* invoker) override
{
BattlegroundScript::ProcessEvent(obj, eventId, invoker);
if (invoker)
{
if (GameObject* gameobject = invoker->ToGameObject())
{
if (gameobject->GetGoType() == GAMEOBJECT_TYPE_CONTROL_ZONE)
{
if (!_controlZoneHandlers.contains(gameobject->GetEntry()))
return;
auto controlzone = gameobject->GetGOInfo()->controlZone;
BattlegroundEYControlZoneHandler& handler = *_controlZoneHandlers[invoker->GetEntry()];
if (eventId == controlzone.NeutralEventAlliance)
EventTeamLostPoint(TEAM_ALLIANCE, handler.GetPoint(), gameobject);
else if (eventId == controlzone.NeutralEventHorde)
EventTeamLostPoint(TEAM_HORDE, handler.GetPoint(), gameobject);
else if (eventId == controlzone.ProgressEventAlliance)
EventTeamCapturedPoint(TEAM_ALLIANCE, handler.GetPoint(), gameobject);
else if (eventId == controlzone.ProgressEventHorde)
EventTeamCapturedPoint(TEAM_HORDE, handler.GetPoint(), gameobject);
}
}
}
}
private:
std::array<uint32, PVP_TEAMS_COUNT> _honorScoreTics;
TimeTracker _pointsTimer;
uint32 _honorTics;
std::unordered_map<uint32, std::unique_ptr<BattlegroundEYControlZoneHandler>> _controlZoneHandlers;
GuidUnorderedSet _doorGUIDs;
ObjectGuid _flagGUID;
// Focused/Brutal Assault
bool _assaultEnabled;
TimeTracker _flagAssaultTimer;
uint8 _assaultStackCount;
};
void AddSC_battleground_eye_of_the_storm()
{
RegisterBattlegroundMapScript(battleground_eye_of_the_storm, 566);
}
@@ -0,0 +1,902 @@
/*
* 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/>.
*/
#include "BattlegroundScript.h"
#include "Battleground.h"
#include "BattlegroundMgr.h"
#include "GameTime.h"
#include "isle_of_conquest.h"
#include "Map.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "TaskScheduler.h"
#include "TemporarySummon.h"
#include "Timer.h"
#include "Transport.h"
#include "TransportMgr.h"
#include "Vehicle.h"
inline constexpr uint16 MAX_REINFORCEMENTS = 400;
enum BannersTypes
{
BANNER_A_CONTROLLED,
BANNER_A_CONTESTED,
BANNER_H_CONTROLLED,
BANNER_H_CONTESTED
};
enum BG_IC_ExploitTeleportLocations
{
IC_EXPLOIT_TELEPORT_LOCATION_ALLIANCE = 3986,
IC_EXPLOIT_TELEPORT_LOCATION_HORDE = 3983
};
enum BG_IC_GateState
{
BG_IC_GATE_OK = 1,
BG_IC_GATE_DAMAGED = 2,
BG_IC_GATE_DESTROYED = 3
};
enum ICDoorList
{
BG_IC_H_FRONT,
BG_IC_H_WEST,
BG_IC_H_EAST,
BG_IC_A_FRONT,
BG_IC_A_WEST,
BG_IC_A_EAST,
BG_IC_MAXDOOR
};
enum ICNodePointType
{
NODE_TYPE_REFINERY,
NODE_TYPE_QUARRY,
NODE_TYPE_DOCKS,
NODE_TYPE_HANGAR,
NODE_TYPE_WORKSHOP,
// Graveyards
NODE_TYPE_GRAVEYARD_A,
NODE_TYPE_GRAVEYARD_H,
MAX_NODE_TYPES
};
enum class IsleOfConquestNodeState
{
Neutral,
ConflictA,
ConflictH,
ControlledA,
ControlledH
};
enum ICBroadcastTexts
{
BG_IC_TEXT_FRONT_GATE_HORDE_DESTROYED = 35409,
BG_IC_TEXT_FRONT_GATE_ALLIANCE_DESTROYED = 35410,
BG_IC_TEXT_WEST_GATE_HORDE_DESTROYED = 35411,
BG_IC_TEXT_WEST_GATE_ALLIANCE_DESTROYED = 35412,
BG_IC_TEXT_EAST_GATE_HORDE_DESTROYED = 35413,
BG_IC_TEXT_EAST_GATE_ALLIANCE_DESTROYED = 35414
};
// I.E: Hangar, Quarry, Graveyards .. etc
struct IoCStaticNodeInfo
{
ICNodePointType NodeType;
struct
{
uint32 Assaulted;
uint32 Defended;
uint32 AllianceTaken;
uint32 HordeTaken;
} TextIds;
struct
{
int32 Uncontrolled;
int32 ConflictA;
int32 ConflictH;
int32 ControlledA;
int32 ControlledH;
} WorldStateIds;
};
class ICNodePoint
{
public:
explicit ICNodePoint(IsleOfConquestNodeState state, IoCStaticNodeInfo const& nodeInfo) : _state(state), _nodeInfo(nodeInfo)
{
switch (state)
{
case IsleOfConquestNodeState::ControlledH:
_lastControlled = TEAM_HORDE;
break;
case IsleOfConquestNodeState::ControlledA:
_lastControlled = TEAM_ALLIANCE;
break;
case IsleOfConquestNodeState::ConflictA:
case IsleOfConquestNodeState::ConflictH:
case IsleOfConquestNodeState::Neutral:
_lastControlled = TEAM_NEUTRAL;
break;
}
}
IsleOfConquestNodeState GetState() const { return _state; }
bool IsContested() const
{
return _state == IsleOfConquestNodeState::ConflictA || _state == IsleOfConquestNodeState::ConflictH;
}
TeamId GetLastControlledTeam() const { return _lastControlled; }
IoCStaticNodeInfo const& GetNodeInfo() const { return _nodeInfo; }
void UpdateState(IsleOfConquestNodeState state)
{
switch (state)
{
case IsleOfConquestNodeState::ControlledA:
_lastControlled = TEAM_ALLIANCE;
break;
case IsleOfConquestNodeState::ControlledH:
_lastControlled = TEAM_HORDE;
break;
case IsleOfConquestNodeState::Neutral:
_lastControlled = TEAM_NEUTRAL;
break;
case IsleOfConquestNodeState::ConflictA:
case IsleOfConquestNodeState::ConflictH:
break;
}
_state = state;
}
private:
IsleOfConquestNodeState _state;
TeamId _lastControlled;
IoCStaticNodeInfo _nodeInfo;
};
const IoCStaticNodeInfo nodePointInitial[MAX_NODE_TYPES] =
{
{ NODE_TYPE_REFINERY, { 35377, 35378, 35379, 35380 }, { BG_IC_REFINERY_UNCONTROLLED, BG_IC_REFINERY_CONFLICT_A, BG_IC_REFINERY_CONFLICT_H, BG_IC_REFINERY_CONTROLLED_A, BG_IC_REFINERY_CONTROLLED_H } },
{ NODE_TYPE_QUARRY, { 35373, 35374, 35375, 35376 }, { BG_IC_QUARRY_UNCONTROLLED, BG_IC_QUARRY_CONFLICT_A, BG_IC_QUARRY_CONFLICT_H, BG_IC_QUARRY_CONTROLLED_A, BG_IC_QUARRY_CONTROLLED_H } },
{ NODE_TYPE_DOCKS, { 35365, 35366, 35367, 35368 }, { BG_IC_DOCKS_UNCONTROLLED, BG_IC_DOCKS_CONFLICT_A, BG_IC_DOCKS_CONFLICT_H, BG_IC_DOCKS_CONTROLLED_A, BG_IC_DOCKS_CONTROLLED_H } },
{ NODE_TYPE_HANGAR, { 35369, 35370, 35371, 35372 }, { BG_IC_HANGAR_UNCONTROLLED, BG_IC_HANGAR_CONFLICT_A, BG_IC_HANGAR_CONFLICT_H, BG_IC_HANGAR_CONTROLLED_A, BG_IC_HANGAR_CONTROLLED_H } },
{ NODE_TYPE_WORKSHOP, { 35278, 35286, 35279, 35280 }, { BG_IC_WORKSHOP_UNCONTROLLED, BG_IC_WORKSHOP_CONFLICT_A, BG_IC_WORKSHOP_CONFLICT_H, BG_IC_WORKSHOP_CONTROLLED_A, BG_IC_WORKSHOP_CONTROLLED_H } },
{ NODE_TYPE_GRAVEYARD_A, { 35461, 35459, 35463, 35466 }, { BG_IC_ALLIANCE_KEEP_UNCONTROLLED, BG_IC_ALLIANCE_KEEP_CONFLICT_A, BG_IC_ALLIANCE_KEEP_CONFLICT_H, BG_IC_ALLIANCE_KEEP_CONTROLLED_A, BG_IC_ALLIANCE_KEEP_CONTROLLED_H } },
{ NODE_TYPE_GRAVEYARD_H, { 35462, 35460, 35464, 35465 }, { BG_IC_HORDE_KEEP_UNCONTROLLED, BG_IC_HORDE_KEEP_CONFLICT_A, BG_IC_HORDE_KEEP_CONFLICT_H, BG_IC_HORDE_KEEP_CONTROLLED_A, BG_IC_HORDE_KEEP_CONTROLLED_H } }
};
enum HonorRewards
{
RESOURCE_HONOR_AMOUNT = 12,
WINNER_HONOR_AMOUNT = 500
};
enum IsleOfConquestPvpStats
{
PVP_STAT_BASES_ASSAULTED = 245,
PVP_STAT_BASES_DEFENDED = 246
};
enum IsleOfConquestGameObjects
{
GO_TELEPORTER_1 = 195314, // 195314 H-OUT 66549
GO_TELEPORTER_2 = 195313, // 195313 H-IN 66548
GO_TELEPORTER_3 = 195315, // 195315 A-OUT 66549
GO_TELEPORTER_4 = 195316, // 195316 A-IN 66548
GO_TELEPORTER_EFFECTS_A = 195701,
GO_TELEPORTER_EFFECTS_H = 195702,
GO_DOODAD_HU_PORTCULLIS01 = 195436,
GO_DOODAD_ND_HUMAN_GATE_CLOSEDFX_DOOR01 = 195703,
GO_DOODAD_PORTCULLISACTIVE02 = 195452,
GO_DOODAD_VR_PORTCULLIS01 = 195437,
GO_HORDE_GATE_1 = 195494,
GO_HORDE_GATE_2 = 195495,
GO_HORDE_GATE_3 = 195496,
GO_ALLIANCE_GATE_1 = 195699,
GO_ALLIANCE_GATE_2 = 195700,
GO_ALLIANCE_GATE_3 = 195698,
GO_DOODAD_ND_WINTERORC_WALL_GATEFX_DOOR01 = 195491,
// banners
GO_BANNER_WORKSHOP_CONTROLLED_H = 195130,
GO_BANNER_WORKSHOP_CONTROLLED_A = 195132,
GO_BANNER_WORKSHOP_CONTROLLED_N = 195133,
GO_BANNER_WORKSHOP_CONTESTED_A = 195144,
GO_BANNER_WORKSHOP_CONTESTED_H = 195145,
GO_BANNER_DOCKS_CONTROLLED_A = 195149,
GO_BANNER_DOCKS_CONTESTED_A = 195150,
GO_BANNER_DOCKS_CONTROLLED_H = 195151,
GO_BANNER_DOCKS_CONTESTED_H = 195152,
GO_BANNER_DOCKS_CONTROLLED_N = 195157,
GO_BANNER_HANGAR_CONTROLLED_A = 195153,
GO_BANNER_HANGAR_CONTESTED_A = 195154,
GO_BANNER_HANGAR_CONTROLLED_H = 195155,
GO_BANNER_HANGAR_CONTESTED_H = 195156,
GO_BANNER_HANGAR_CONTROLLED_N = 195158,
GO_BANNER_QUARRY_CONTROLLED_A = 195334,
GO_BANNER_QUARRY_CONTROLLED_H = 195336,
GO_BANNER_QUARRY_CONTESTED_A = 195335,
GO_BANNER_QUARRY_CONTESTED_H = 195337,
GO_BANNER_QUARRY_CONTROLLED_N = 195338,
GO_BANNER_REFINERY_CONTROLLED_A = 195339,
GO_BANNER_REFINERY_CONTROLLED_H = 195341,
GO_BANNER_REFINERY_CONTESTED_A = 195340,
GO_BANNER_REFINERY_CONTESTED_H = 195342,
GO_BANNER_REFINERY_CONTROLLED_N = 195343,
GO_BANNER_HORDE_KEEP_CONTROLLED_A = 195391,
GO_BANNER_HORDE_KEEP_CONTROLLED_H = 195393,
GO_BANNER_HORDE_KEEP_CONTESTED_A = 195392,
GO_BANNER_HORDE_KEEP_CONTESTED_H = 195394,
GO_BANNER_ALLIANCE_KEEP_CONTROLLED_A = 195396,
GO_BANNER_ALLIANCE_KEEP_CONTROLLED_H = 195398,
GO_BANNER_ALLIANCE_KEEP_CONTESTED_A = 195397,
GO_BANNER_ALLIANCE_KEEP_CONTESTED_H = 195399,
GO_KEEP_GATE_H = 195223,
GO_KEEP_GATE_A = 195451,
GO_KEEP_GATE_2_A = 195452,
GO_HORDE_GUNSHIP = 195276,
GO_ALLIANCE_GUNSHIP = 195121
};
static constexpr Seconds IOC_RESOURCE_TIMER = 45s;
static constexpr Position GunshipTeleportTriggerPosition[2] =
{
{ 11.69964981079101562f, 0.034145999699831008f, 20.62075996398925781f, 3.211405754089355468f },
{ 7.30560922622680664f, -0.09524600207805633f, 34.51021575927734375f, 3.159045934677124023f }
};
struct battleground_isle_of_conquest : BattlegroundScript
{
explicit battleground_isle_of_conquest(BattlegroundMap* map) : BattlegroundScript(map)
{
_factionReinforcements = { MAX_REINFORCEMENTS, MAX_REINFORCEMENTS };
_gateStatus = { BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK, BG_IC_GATE_OK };
_gunshipGUIDs = { };
_cannonGUIDs = { };
_nodePoints = { };
_keepGateGUIDs = { };
_keepBannerGUIDs = { };
_nodePoints[NODE_TYPE_REFINERY] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_REFINERY]);
_nodePoints[NODE_TYPE_QUARRY] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_QUARRY]);
_nodePoints[NODE_TYPE_DOCKS] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_DOCKS]);
_nodePoints[NODE_TYPE_HANGAR] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_HANGAR]);
_nodePoints[NODE_TYPE_WORKSHOP] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::Neutral, nodePointInitial[NODE_TYPE_WORKSHOP]);
_nodePoints[NODE_TYPE_GRAVEYARD_A] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::ControlledA, nodePointInitial[NODE_TYPE_GRAVEYARD_A]);
_nodePoints[NODE_TYPE_GRAVEYARD_H] = std::make_unique<ICNodePoint>(IsleOfConquestNodeState::ControlledH, nodePointInitial[NODE_TYPE_GRAVEYARD_H]);
_resourceTimer.Reset(IOC_RESOURCE_TIMER);
}
void OnUpdate(uint32 diff) override
{
BattlegroundScript::OnUpdate(diff);
if (battleground->GetStatus() != STATUS_IN_PROGRESS)
return;
_scheduler.Update(diff);
_resourceTimer.Update(diff);
if (_resourceTimer.Passed())
{
for (uint8 i = 0; i < NODE_TYPE_DOCKS; ++i)
{
if (_nodePoints[i]->GetLastControlledTeam() != TEAM_NEUTRAL && !_nodePoints[i]->IsContested())
{
_factionReinforcements[_nodePoints[i]->GetLastControlledTeam()] += 1;
battleground->RewardHonorToTeam(RESOURCE_HONOR_AMOUNT, _nodePoints[i]->GetLastControlledTeam() == TEAM_ALLIANCE ? ALLIANCE : HORDE);
UpdateWorldState((_nodePoints[i]->GetLastControlledTeam() == TEAM_ALLIANCE ? BG_IC_ALLIANCE_REINFORCEMENTS : BG_IC_HORDE_REINFORCEMENTS), _factionReinforcements[_nodePoints[i]->GetLastControlledTeam()]);
}
}
_resourceTimer.Reset(IOC_RESOURCE_TIMER);
}
}
void OnStart() override
{
BattlegroundScript::OnStart();
auto gameobjectAction = [&](GuidVector const& guids, std::function<void(GameObject*)> const& action) -> void
{
for (ObjectGuid const& guid : guids)
if (GameObject* gameObject = battlegroundMap->GetGameObject(guid))
action(gameObject);
};
gameobjectAction(_mainGateDoorGUIDs, [&](GameObject* gameobject) -> void
{
gameobject->UseDoorOrButton();
gameobject->DespawnOrUnsummon(20s);
});
gameobjectAction(_portcullisGUIDs, [&](GameObject* gameobject) -> void
{
gameobject->UseDoorOrButton();
});
gameobjectAction(_teleporterGUIDs, [&](GameObject* gameobject) -> void
{
gameobject->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
});
gameobjectAction(_teleporterEffectGUIDs, [&](GameObject* gameobject) -> void
{
gameobject->SetGoState(GO_STATE_ACTIVE);
});
_scheduler.Schedule(20s, [&](TaskContext)
{
for (ObjectGuid const& guid : _wallGUIDs)
if (GameObject* gameobject = battlegroundMap->GetGameObject(guid))
gameobject->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED);
});
}
void OnUnitKilled(Creature* unit, Unit* killer) override
{
BattlegroundScript::OnUnitKilled(unit, killer);
if (battleground->GetStatus() != STATUS_IN_PROGRESS)
return;
uint32 entry = unit->GetEntry();
if (entry == NPC_HIGH_COMMANDER_HALFORD_WYRMBANE)
{
battleground->RewardHonorToTeam(WINNER_HONOR_AMOUNT, HORDE);
battleground->EndBattleground(HORDE);
}
else if (entry == NPC_OVERLORD_AGMAR)
{
battleground->RewardHonorToTeam(WINNER_HONOR_AMOUNT, ALLIANCE);
battleground->EndBattleground(ALLIANCE);
}
//Achievement Mowed Down
// TO-DO: This should be done on the script of each vehicle of the BG.
if (unit->IsVehicle())
{
if (Player* killerPlayer = killer->GetCharmerOrOwnerPlayerOrPlayerItself())
killerPlayer->CastSpell(killerPlayer, SPELL_DESTROYED_VEHICLE_ACHIEVEMENT, true);
}
}
void OnPlayerKilled(Player* player, Player* killer) override
{
BattlegroundScript::OnPlayerKilled(player, killer);
if (battleground->GetStatus() != STATUS_IN_PROGRESS)
return;
TeamId const victimTeamId = Battleground::GetTeamIndexByTeamId(battleground->GetPlayerTeam(player->GetGUID()));
_factionReinforcements[victimTeamId] -= 1;
UpdateWorldState((battleground->GetPlayerTeam(player->GetGUID()) == ALLIANCE ? BG_IC_ALLIANCE_REINFORCEMENTS : BG_IC_HORDE_REINFORCEMENTS), _factionReinforcements[victimTeamId]);
// we must end the battleground
if (_factionReinforcements[victimTeamId] < 1)
battleground->EndBattleground(battleground->GetPlayerTeam(killer->GetGUID()));
}
static uint32 GetGateIDFromEntry(uint32 id)
{
switch (id)
{
case GO_HORDE_GATE_1:
return BG_IC_H_FRONT;
case GO_HORDE_GATE_2:
return BG_IC_H_WEST;
case GO_HORDE_GATE_3:
return BG_IC_H_EAST;
case GO_ALLIANCE_GATE_3:
return BG_IC_A_FRONT;
case GO_ALLIANCE_GATE_1:
return BG_IC_A_WEST;
case GO_ALLIANCE_GATE_2:
return BG_IC_A_EAST;
default:
return 0;
}
}
static int32 GetWorldStateFromGateEntry(uint32 id, bool open)
{
int32 uws = 0;
switch (id)
{
case GO_HORDE_GATE_1:
uws = (open ? BG_IC_GATE_FRONT_H_WS_OPEN : BG_IC_GATE_FRONT_H_WS_CLOSED);
break;
case GO_HORDE_GATE_2:
uws = (open ? BG_IC_GATE_WEST_H_WS_OPEN : BG_IC_GATE_WEST_H_WS_CLOSED);
break;
case GO_HORDE_GATE_3:
uws = (open ? BG_IC_GATE_EAST_H_WS_OPEN : BG_IC_GATE_EAST_H_WS_CLOSED);
break;
case GO_ALLIANCE_GATE_3:
uws = (open ? BG_IC_GATE_FRONT_A_WS_OPEN : BG_IC_GATE_FRONT_A_WS_CLOSED);
break;
case GO_ALLIANCE_GATE_1:
uws = (open ? BG_IC_GATE_WEST_A_WS_OPEN : BG_IC_GATE_WEST_A_WS_CLOSED);
break;
case GO_ALLIANCE_GATE_2:
uws = (open ? BG_IC_GATE_EAST_A_WS_OPEN : BG_IC_GATE_EAST_A_WS_CLOSED);
break;
default:
break;
}
return uws;
}
void UpdateNodeWorldState(ICNodePoint const& node) const
{
UpdateWorldState(node.GetNodeInfo().WorldStateIds.ConflictA, node.GetState() == IsleOfConquestNodeState::ConflictA);
UpdateWorldState(node.GetNodeInfo().WorldStateIds.ConflictH, node.GetState() == IsleOfConquestNodeState::ConflictH);
UpdateWorldState(node.GetNodeInfo().WorldStateIds.ControlledA, node.GetState() == IsleOfConquestNodeState::ControlledA);
UpdateWorldState(node.GetNodeInfo().WorldStateIds.ControlledH, node.GetState() == IsleOfConquestNodeState::ControlledH);
UpdateWorldState(node.GetNodeInfo().WorldStateIds.Uncontrolled, node.GetState() == IsleOfConquestNodeState::Neutral);
}
static ICNodePointType BannerToNodeType(uint32 bannerId)
{
switch (bannerId)
{
case GO_BANNER_ALLIANCE_KEEP_CONTESTED_A:
case GO_BANNER_ALLIANCE_KEEP_CONTESTED_H:
case GO_BANNER_ALLIANCE_KEEP_CONTROLLED_A:
case GO_BANNER_ALLIANCE_KEEP_CONTROLLED_H:
return NODE_TYPE_GRAVEYARD_A;
case GO_BANNER_HORDE_KEEP_CONTESTED_A:
case GO_BANNER_HORDE_KEEP_CONTESTED_H:
case GO_BANNER_HORDE_KEEP_CONTROLLED_A:
case GO_BANNER_HORDE_KEEP_CONTROLLED_H:
return NODE_TYPE_GRAVEYARD_H;
case GO_BANNER_DOCKS_CONTESTED_A:
case GO_BANNER_DOCKS_CONTESTED_H:
case GO_BANNER_DOCKS_CONTROLLED_A:
case GO_BANNER_DOCKS_CONTROLLED_H:
case GO_BANNER_DOCKS_CONTROLLED_N:
return NODE_TYPE_DOCKS;
case GO_BANNER_HANGAR_CONTESTED_A:
case GO_BANNER_HANGAR_CONTESTED_H:
case GO_BANNER_HANGAR_CONTROLLED_A:
case GO_BANNER_HANGAR_CONTROLLED_H:
case GO_BANNER_HANGAR_CONTROLLED_N:
return NODE_TYPE_HANGAR;
case GO_BANNER_WORKSHOP_CONTESTED_A:
case GO_BANNER_WORKSHOP_CONTESTED_H:
case GO_BANNER_WORKSHOP_CONTROLLED_A:
case GO_BANNER_WORKSHOP_CONTROLLED_H:
case GO_BANNER_WORKSHOP_CONTROLLED_N:
return NODE_TYPE_WORKSHOP;
case GO_BANNER_QUARRY_CONTESTED_A:
case GO_BANNER_QUARRY_CONTESTED_H:
case GO_BANNER_QUARRY_CONTROLLED_A:
case GO_BANNER_QUARRY_CONTROLLED_H:
case GO_BANNER_QUARRY_CONTROLLED_N:
return NODE_TYPE_QUARRY;
case GO_BANNER_REFINERY_CONTESTED_A:
case GO_BANNER_REFINERY_CONTESTED_H:
case GO_BANNER_REFINERY_CONTROLLED_A:
case GO_BANNER_REFINERY_CONTROLLED_H:
case GO_BANNER_REFINERY_CONTROLLED_N:
return NODE_TYPE_REFINERY;
default:
break;
}
return MAX_NODE_TYPES;
}
void HandleCapturedNodes(ICNodePoint& node)
{
if (node.GetLastControlledTeam() == TEAM_NEUTRAL)
return;
switch (node.GetNodeInfo().NodeType)
{
case NODE_TYPE_QUARRY:
case NODE_TYPE_REFINERY:
battlegroundMap->UpdateAreaDependentAuras();
break;
case NODE_TYPE_HANGAR:
if (Transport* transport = battlegroundMap->GetTransport(_gunshipGUIDs[node.GetLastControlledTeam()]))
{
// Can't have this in spawngroup, creature is on a transport
if (TempSummon* trigger = transport->SummonPassenger(NPC_WORLD_TRIGGER_NOT_FLOATING, GunshipTeleportTriggerPosition[node.GetLastControlledTeam()], TEMPSUMMON_MANUAL_DESPAWN))
_gunshipTeleportTarget = trigger->GetGUID();
transport->EnableMovement(true);
}
for (ObjectGuid const& guid : _cannonGUIDs[node.GetLastControlledTeam()])
if (Creature* cannon = battlegroundMap->GetCreature(guid))
cannon->SetUninteractible(false);
break;
default:
break;
}
}
void OnCreatureCreate(Creature* creature) override
{
BattlegroundScript::OnCreatureCreate(creature);
if (creature->HasStringId("bg_ioc_faction_1735"))
creature->SetFaction(FACTION_HORDE_GENERIC_WG);
else if (creature->HasStringId("bg_ioc_faction_1732"))
creature->SetFaction(FACTION_ALLIANCE_GENERIC_WG);
switch (creature->GetEntry())
{
case NPC_ALLIANCE_GUNSHIP_CANNON:
_cannonGUIDs[TEAM_ALLIANCE].emplace_back(creature->GetGUID());
creature->SetUninteractible(true);
creature->SetControlled(true, UNIT_STATE_ROOT);
break;
case NPC_HORDE_GUNSHIP_CANNON:
_cannonGUIDs[TEAM_HORDE].emplace_back(creature->GetGUID());
creature->SetUninteractible(true);
creature->SetControlled(true, UNIT_STATE_ROOT);
break;
default:
break;
}
}
void OnGameObjectCreate(GameObject* gameobject) override
{
BattlegroundScript::OnGameObjectCreate(gameobject);
if (gameobject->IsDestructibleBuilding())
_wallGUIDs.emplace_back(gameobject->GetGUID());
if (gameobject->HasStringId("bg_ioc_faction_1735"))
gameobject->SetFaction(FACTION_HORDE_GENERIC_WG);
else if (gameobject->HasStringId("bg_ioc_faction_1732"))
gameobject->SetFaction(FACTION_ALLIANCE_GENERIC_WG);
switch (gameobject->GetEntry())
{
case GO_TELEPORTER_1:
case GO_TELEPORTER_2:
case GO_TELEPORTER_3:
case GO_TELEPORTER_4:
_teleporterGUIDs.emplace_back(gameobject->GetGUID());
break;
case GO_TELEPORTER_EFFECTS_A:
case GO_TELEPORTER_EFFECTS_H:
_teleporterEffectGUIDs.emplace_back(gameobject->GetGUID());
break;
case GO_DOODAD_ND_HUMAN_GATE_CLOSEDFX_DOOR01:
case GO_DOODAD_ND_WINTERORC_WALL_GATEFX_DOOR01:
_mainGateDoorGUIDs.emplace_back(gameobject->GetGUID());
break;
case GO_DOODAD_HU_PORTCULLIS01:
case GO_DOODAD_VR_PORTCULLIS01:
_portcullisGUIDs.emplace_back(gameobject->GetGUID());
break;
case GO_KEEP_GATE_H:
_keepGateGUIDs[TEAM_HORDE].emplace_back(gameobject->GetGUID());
break;
case GO_KEEP_GATE_A:
case GO_KEEP_GATE_2_A:
_keepGateGUIDs[TEAM_ALLIANCE].emplace_back(gameobject->GetGUID());
break;
case GO_BANNER_ALLIANCE_KEEP_CONTROLLED_A:
_keepBannerGUIDs[TEAM_ALLIANCE] = gameobject->GetGUID();
break;
case GO_BANNER_HORDE_KEEP_CONTROLLED_H:
_keepBannerGUIDs[TEAM_HORDE] = gameobject->GetGUID();
break;
default:
break;
}
}
void OnInit() override
{
BattlegroundScript::OnInit();
if (Transport* transport = sTransportMgr->CreateTransport(GO_HORDE_GUNSHIP, battlegroundMap))
{
_gunshipGUIDs[TEAM_HORDE] = transport->GetGUID();
transport->EnableMovement(false);
}
if (Transport* transport = sTransportMgr->CreateTransport(GO_ALLIANCE_GUNSHIP, battlegroundMap))
{
_gunshipGUIDs[TEAM_ALLIANCE] = transport->GetGUID();
transport->EnableMovement(false);
}
}
void DoAction(uint32 actionId, WorldObject* source, WorldObject* target) override
{
BattlegroundScript::DoAction(actionId, source, target);
switch (actionId)
{
case ACTION_IOC_INTERACT_CAPTURABLE_OBJECT:
OnPlayerInteractWithBanner(WorldObject::ToPlayer(source), WorldObject::ToGameObject(target));
break;
case ACTION_IOC_CAPTURE_CAPTURABLE_OBJECT:
HandleCaptureNodeAction(WorldObject::ToGameObject(target));
break;
default:
break;
}
}
void OnPlayerInteractWithBanner(Player* player, GameObject* banner)
{
if (!player || !banner)
return;
Team const playerTeam = battleground->GetPlayerTeam(player->GetGUID());
TeamId const playerTeamId = Battleground::GetTeamIndexByTeamId(playerTeam);
ICNodePointType const nodeType = BannerToNodeType(banner->GetEntry());
if (nodeType == MAX_NODE_TYPES)
return;
ICNodePoint& node = *_nodePoints[nodeType];
bool assault = false;
bool defend = false;
switch (node.GetState())
{
case IsleOfConquestNodeState::Neutral:
assault = true;
break;
case IsleOfConquestNodeState::ControlledH:
assault = playerTeamId != TEAM_HORDE;
break;
case IsleOfConquestNodeState::ControlledA:
assault = playerTeamId != TEAM_ALLIANCE;
break;
case IsleOfConquestNodeState::ConflictA:
defend = playerTeamId == node.GetLastControlledTeam();
assault = !defend && playerTeamId == TEAM_HORDE;
break;
case IsleOfConquestNodeState::ConflictH:
defend = playerTeamId == node.GetLastControlledTeam();
assault = !defend && playerTeamId == TEAM_ALLIANCE;
break;
}
if (assault)
OnPlayerAssaultNode(player, node);
else if (defend)
OnPlayerDefendNode(player, node);
battlegroundMap->UpdateSpawnGroupConditions();
}
void OnPlayerAssaultNode(Player* player, ICNodePoint& node)
{
if (!player)
return;
Team const playerTeam = battleground->GetPlayerTeam(player->GetGUID());
TeamId const playerTeamId = Battleground::GetTeamIndexByTeamId(playerTeam);
IsleOfConquestNodeState const newState = playerTeamId == TEAM_HORDE ? IsleOfConquestNodeState::ConflictH : IsleOfConquestNodeState::ConflictA;
node.UpdateState(newState);
battleground->UpdatePvpStat(player, PVP_STAT_BASES_ASSAULTED, 1);
ChatMsg const messageType = playerTeamId == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
battleground->SendBroadcastText(node.GetNodeInfo().TextIds.Assaulted, messageType, player);
UpdateNodeWorldState(node);
// apply side effects of each node, only if it wasn't neutral before
if (node.GetLastControlledTeam() == TEAM_NEUTRAL)
return;
switch (node.GetNodeInfo().NodeType)
{
case NODE_TYPE_HANGAR:
if (Transport* transport = battlegroundMap->GetTransport(_gunshipGUIDs[node.GetLastControlledTeam()]))
transport->EnableMovement(false);
for (ObjectGuid const& guid : _cannonGUIDs[node.GetLastControlledTeam()])
{
if (Creature* cannon = battlegroundMap->GetCreature(guid))
{
cannon->GetVehicleKit()->RemoveAllPassengers();
cannon->SetUninteractible(true);
}
}
// Despawn teleport trigger target
if (Creature* creature = battlegroundMap->GetCreature(_gunshipTeleportTarget))
creature->DespawnOrUnsummon();
break;
default:
break;
}
}
void OnPlayerDefendNode(Player* player, ICNodePoint& node)
{
if (!player)
return;
Team const playerTeam = battleground->GetPlayerTeam(player->GetGUID());
TeamId const playerTeamId = Battleground::GetTeamIndexByTeamId(playerTeam);
node.UpdateState(playerTeamId == TEAM_HORDE ? IsleOfConquestNodeState::ControlledH : IsleOfConquestNodeState::ControlledA);
HandleCapturedNodes(node);
battleground->UpdatePvpStat(player, PVP_STAT_BASES_DEFENDED, 1);
ChatMsg const messageType = playerTeamId == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
battleground->SendBroadcastText(node.GetNodeInfo().TextIds.Defended, messageType, player);
UpdateNodeWorldState(node);
}
void ProcessEvent(WorldObject* target, uint32 eventId, WorldObject* invoker) override
{
BattlegroundScript::ProcessEvent(target, eventId, invoker);
if (GameObject* obj = Object::ToGameObject(target))
if (obj->GetGoType() == GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING)
if (obj->GetGOInfo()->destructibleBuilding.DestroyedEvent == eventId)
OnGateDestroyed(obj, invoker);
}
void HandleCaptureNodeAction(GameObject* banner)
{
if (!banner)
return;
ICNodePointType const nodeType = BannerToNodeType(banner->GetEntry());
if (nodeType == MAX_NODE_TYPES)
return;
ICNodePoint& node = *_nodePoints[nodeType];
if (node.GetState() == IsleOfConquestNodeState::ConflictH)
node.UpdateState(IsleOfConquestNodeState::ControlledH);
else if (node.GetState() == IsleOfConquestNodeState::ConflictA)
node.UpdateState(IsleOfConquestNodeState::ControlledA);
HandleCapturedNodes(node);
ChatMsg const messageType = node.GetLastControlledTeam() == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
uint32 const textId = node.GetLastControlledTeam() == TEAM_ALLIANCE ? node.GetNodeInfo().TextIds.AllianceTaken : node.GetNodeInfo().TextIds.HordeTaken;
battleground->SendBroadcastText(textId, messageType);
UpdateNodeWorldState(node);
}
void OnGateDestroyed(GameObject* gate, WorldObject* destroyer)
{
_gateStatus[GetGateIDFromEntry(gate->GetEntry())] = BG_IC_GATE_DESTROYED;
int32 const wsGateOpen = GetWorldStateFromGateEntry(gate->GetEntry(), true);
int32 const wsGateClosed = GetWorldStateFromGateEntry(gate->GetEntry(), false);
if (wsGateOpen)
{
UpdateWorldState(wsGateClosed, 0);
UpdateWorldState(wsGateOpen, 1);
}
TeamId teamId = TEAM_NEUTRAL;
uint32 textId;
ChatMsg msgType;
switch (gate->GetEntry())
{
case GO_HORDE_GATE_1:
textId = BG_IC_TEXT_FRONT_GATE_HORDE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
teamId = TEAM_HORDE;
break;
case GO_HORDE_GATE_2:
textId = BG_IC_TEXT_WEST_GATE_HORDE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
teamId = TEAM_HORDE;
break;
case GO_HORDE_GATE_3:
textId = BG_IC_TEXT_EAST_GATE_HORDE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_ALLIANCE;
teamId = TEAM_HORDE;
break;
case GO_ALLIANCE_GATE_1:
textId = BG_IC_TEXT_WEST_GATE_ALLIANCE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_HORDE;
teamId = TEAM_ALLIANCE;
break;
case GO_ALLIANCE_GATE_2:
textId = BG_IC_TEXT_EAST_GATE_ALLIANCE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_HORDE;
teamId = TEAM_ALLIANCE;
break;
case GO_ALLIANCE_GATE_3:
textId = BG_IC_TEXT_FRONT_GATE_ALLIANCE_DESTROYED;
msgType = CHAT_MSG_BG_SYSTEM_HORDE;
teamId = TEAM_ALLIANCE;
break;
default:
return;
}
if (teamId != TEAM_NEUTRAL)
{
GuidVector const keepGates = _keepGateGUIDs[teamId];
ObjectGuid const bannerGuid = _keepBannerGUIDs[teamId];
for (ObjectGuid const& guid : keepGates)
if (GameObject* keepGate = battlegroundMap->GetGameObject(guid))
keepGate->UseDoorOrButton();
if (GameObject* banner = battlegroundMap->GetGameObject(bannerGuid))
banner->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
}
battleground->SendBroadcastText(textId, msgType, destroyer);
}
private:
std::array<uint16, PVP_TEAMS_COUNT> _factionReinforcements;
std::array<BG_IC_GateState, 6> _gateStatus;
std::array<std::unique_ptr<ICNodePoint>, 7> _nodePoints;
std::array<ObjectGuid, PVP_TEAMS_COUNT> _gunshipGUIDs;
GuidVector _teleporterGUIDs;
GuidVector _teleporterEffectGUIDs;
GuidVector _mainGateDoorGUIDs;
GuidVector _portcullisGUIDs;
GuidVector _wallGUIDs;
std::array<GuidVector, PVP_TEAMS_COUNT> _cannonGUIDs;
std::array<GuidVector, PVP_TEAMS_COUNT> _keepGateGUIDs;
std::array<ObjectGuid, PVP_TEAMS_COUNT> _keepBannerGUIDs;
ObjectGuid _gunshipTeleportTarget;
TaskScheduler _scheduler;
TimeTracker _resourceTimer;
};
void AddSC_battleground_isle_of_conquest()
{
RegisterBattlegroundMapScript(battleground_isle_of_conquest, 628);
}
@@ -16,7 +16,7 @@
*/
#include "ScriptMgr.h"
#include "BattlegroundIC.h"
#include "isle_of_conquest.h"
#include "ScriptedCreature.h"
enum BossSpells
@@ -15,8 +15,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "isle_of_conquest.h"
#include "ScriptMgr.h"
#include "BattlegroundIC.h"
#include "Battleground.h"
#include "GameObject.h"
#include "GameObjectAI.h"
#include "Map.h"
@@ -0,0 +1,132 @@
/*
* 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 TRINITYCORE_ISLE_OF_CONQUEST_H
#define TRINITYCORE_ISLE_OF_CONQUEST_H
enum CreaturesIC
{
NPC_HIGH_COMMANDER_HALFORD_WYRMBANE = 34924, // Alliance Boss
NPC_OVERLORD_AGMAR = 34922, // Horde Boss
NPC_KOR_KRON_GUARD = 34918, // horde guard
NPC_SEVEN_TH_LEGION_INFANTRY = 34919, // alliance guard
NPC_KEEP_CANNON = 34944,
NPC_DEMOLISHER = 34775,
NPC_SIEGE_ENGINE_H = 35069,
NPC_SIEGE_ENGINE_A = 34776,
NPC_GLAIVE_THROWER_A = 34802,
NPC_GLAIVE_THROWER_H = 35273,
NPC_CATAPULT = 34793,
NPC_HORDE_GUNSHIP_CANNON = 34935,
NPC_ALLIANCE_GUNSHIP_CANNON = 34929,
NPC_HORDE_GUNSHIP_CAPTAIN = 35003,
NPC_ALLIANCE_GUNSHIP_CAPTAIN = 34960,
NPC_WORLD_TRIGGER_NOT_FLOATING = 34984,
NPC_WORLD_TRIGGER_ALLIANCE_FRIENDLY = 20213,
NPC_WORLD_TRIGGER_HORDE_FRIENDLY = 20212
};
enum Actions
{
ACTION_GUNSHIP_READY = 1,
ACTION_IOC_INTERACT_CAPTURABLE_OBJECT = 2,
ACTION_IOC_CAPTURE_CAPTURABLE_OBJECT = 3
};
enum Spells
{
SPELL_OIL_REFINERY = 68719,
SPELL_QUARRY = 68720,
SPELL_PARACHUTE = 66656,
SPELL_SLOW_FALL = 12438,
SPELL_DESTROYED_VEHICLE_ACHIEVEMENT = 68357,
SPELL_BACK_DOOR_JOB_ACHIEVEMENT = 68502,
SPELL_DRIVING_CREDIT_DEMOLISHER = 68365,
SPELL_DRIVING_CREDIT_GLAIVE = 68363,
SPELL_DRIVING_CREDIT_SIEGE = 68364,
SPELL_DRIVING_CREDIT_CATAPULT = 68362,
SPELL_SIMPLE_TELEPORT = 12980,
SPELL_TELEPORT_VISUAL_ONLY = 51347,
SPELL_PARACHUTE_IC = 66657,
SPELL_LAUNCH_NO_FALLING_DAMAGE = 66251
};
enum ICWorldStates
{
BG_IC_ALLIANCE_REINFORCEMENTS_SET = 4221,
BG_IC_HORDE_REINFORCEMENTS_SET = 4222,
BG_IC_ALLIANCE_REINFORCEMENTS = 4226,
BG_IC_HORDE_REINFORCEMENTS = 4227,
BG_IC_MAX_REINFORCEMENTS = 17377,
BG_IC_GATE_FRONT_H_WS_CLOSED = 4317,
BG_IC_GATE_WEST_H_WS_CLOSED = 4318,
BG_IC_GATE_EAST_H_WS_CLOSED = 4319,
BG_IC_GATE_FRONT_A_WS_CLOSED = 4328,
BG_IC_GATE_WEST_A_WS_CLOSED = 4327,
BG_IC_GATE_EAST_A_WS_CLOSED = 4326,
BG_IC_GATE_FRONT_H_WS_OPEN = 4322,
BG_IC_GATE_WEST_H_WS_OPEN = 4321,
BG_IC_GATE_EAST_H_WS_OPEN = 4320,
BG_IC_GATE_FRONT_A_WS_OPEN = 4323,
BG_IC_GATE_WEST_A_WS_OPEN = 4324,
BG_IC_GATE_EAST_A_WS_OPEN = 4325,
BG_IC_DOCKS_UNCONTROLLED = 4301,
BG_IC_DOCKS_CONFLICT_A = 4305,
BG_IC_DOCKS_CONFLICT_H = 4302,
BG_IC_DOCKS_CONTROLLED_A = 4304,
BG_IC_DOCKS_CONTROLLED_H = 4303,
BG_IC_HANGAR_UNCONTROLLED = 4296,
BG_IC_HANGAR_CONFLICT_A = 4300,
BG_IC_HANGAR_CONFLICT_H = 4297,
BG_IC_HANGAR_CONTROLLED_A = 4299,
BG_IC_HANGAR_CONTROLLED_H = 4298,
BG_IC_QUARRY_UNCONTROLLED = 4306,
BG_IC_QUARRY_CONFLICT_A = 4310,
BG_IC_QUARRY_CONFLICT_H = 4307,
BG_IC_QUARRY_CONTROLLED_A = 4309,
BG_IC_QUARRY_CONTROLLED_H = 4308,
BG_IC_REFINERY_UNCONTROLLED = 4311,
BG_IC_REFINERY_CONFLICT_A = 4315,
BG_IC_REFINERY_CONFLICT_H = 4312,
BG_IC_REFINERY_CONTROLLED_A = 4314,
BG_IC_REFINERY_CONTROLLED_H = 4313,
BG_IC_WORKSHOP_UNCONTROLLED = 4294,
BG_IC_WORKSHOP_CONFLICT_A = 4228,
BG_IC_WORKSHOP_CONFLICT_H = 4293,
BG_IC_WORKSHOP_CONTROLLED_A = 4229,
BG_IC_WORKSHOP_CONTROLLED_H = 4230,
BG_IC_ALLIANCE_KEEP_UNCONTROLLED = 4341,
BG_IC_ALLIANCE_KEEP_CONFLICT_A = 4342,
BG_IC_ALLIANCE_KEEP_CONFLICT_H = 4343,
BG_IC_ALLIANCE_KEEP_CONTROLLED_A = 4339,
BG_IC_ALLIANCE_KEEP_CONTROLLED_H = 4340,
BG_IC_HORDE_KEEP_UNCONTROLLED = 4346,
BG_IC_HORDE_KEEP_CONFLICT_A = 4347,
BG_IC_HORDE_KEEP_CONFLICT_H = 4348,
BG_IC_HORDE_KEEP_CONTROLLED_A = 4344,
BG_IC_HORDE_KEEP_CONTROLLED_H = 4345
};
#endif
@@ -0,0 +1,84 @@
/*
* 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/>.
*/
#include "Battleground.h"
#include "BattlegroundScript.h"
#include "GameObject.h"
#include "Map.h"
#include "ScriptMgr.h"
#include "TaskScheduler.h"
struct arena_nagrand : ArenaScript
{
enum GameObjects
{
BG_NA_OBJECT_TYPE_DOOR_1 = 183978,
BG_NA_OBJECT_TYPE_DOOR_2 = 183980,
BG_NA_OBJECT_TYPE_DOOR_3 = 183977,
BG_NA_OBJECT_TYPE_DOOR_4 = 183979,
BG_NA_OBJECT_TYPE_BUFF_1 = 184663,
BG_NA_OBJECT_TYPE_BUFF_2 = 184664
};
explicit arena_nagrand(BattlegroundMap* map) : ArenaScript(map) { }
void OnUpdate(uint32 diff) override
{
_scheduler.Update(diff);
}
void OnInit() override
{
AddDoor(BG_NA_OBJECT_TYPE_DOOR_1, 4031.854f, 2966.833f, 12.6462f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f);
AddDoor(BG_NA_OBJECT_TYPE_DOOR_2, 4081.179f, 2874.97f, 12.39171f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f);
AddDoor(BG_NA_OBJECT_TYPE_DOOR_3, 4023.709f, 2981.777f, 10.70117f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f);
AddDoor(BG_NA_OBJECT_TYPE_DOOR_4, 4090.064f, 2858.438f, 10.23631f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f);
}
void OnStart() override
{
for (ObjectGuid const& guid : _doorGUIDs)
{
if (GameObject* door = battlegroundMap->GetGameObject(guid))
{
door->UseDoorOrButton();
door->DespawnOrUnsummon(5s);
}
}
_scheduler.Schedule(1min, [&](TaskContext)
{
CreateObject(BG_NA_OBJECT_TYPE_BUFF_1, 4009.189941f, 2895.250000f, 13.052700f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f);
CreateObject(BG_NA_OBJECT_TYPE_BUFF_2, 4103.330078f, 2946.350098f, 13.051300f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f);
});
}
void AddDoor(uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, GOState goState = GO_STATE_READY)
{
if (GameObject const* go = CreateObject(entry, x, y, z, o, rotation0, rotation1, rotation2, rotation3, goState))
_doorGUIDs.emplace_back(go->GetGUID());
}
private:
GuidVector _doorGUIDs;
TaskScheduler _scheduler;
};
void AddSC_arena_nagrand()
{
RegisterBattlegroundMapScript(arena_nagrand, 1505);
}
@@ -0,0 +1,302 @@
/*
* 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/>.
*/
#include "Battleground.h"
#include "BattlegroundScript.h"
#include "GameObject.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "ScriptMgr.h"
#include "TaskScheduler.h"
struct arena_ring_of_valor : ArenaScript
{
enum BattlegroundRVGameObjects
{
BG_RV_OBJECT_TYPE_BUFF_1 = 184663,
BG_RV_OBJECT_TYPE_BUFF_2 = 184664,
BG_RV_OBJECT_TYPE_FIRE_1 = 192704,
BG_RV_OBJECT_TYPE_FIRE_2 = 192705,
BG_RV_OBJECT_TYPE_FIREDOOR_2 = 192387,
BG_RV_OBJECT_TYPE_FIREDOOR_1 = 192388,
BG_RV_OBJECT_TYPE_PULLEY_1 = 192389,
BG_RV_OBJECT_TYPE_PULLEY_2 = 192390,
BG_RV_OBJECT_TYPE_GEAR_1 = 192393,
BG_RV_OBJECT_TYPE_GEAR_2 = 192394,
BG_RV_OBJECT_TYPE_ELEVATOR_1 = 194582,
BG_RV_OBJECT_TYPE_ELEVATOR_2 = 194586,
BG_RV_OBJECT_TYPE_PILAR_COLLISION_1 = 194580, // axe
BG_RV_OBJECT_TYPE_PILAR_COLLISION_2 = 194579, // arena // big
BG_RV_OBJECT_TYPE_PILAR_COLLISION_3 = 194581, // lightning
BG_RV_OBJECT_TYPE_PILAR_COLLISION_4 = 194578, // ivory // big
BG_RV_OBJECT_TYPE_PILAR_1 = 194583, // axe
BG_RV_OBJECT_TYPE_PILAR_2 = 194584, // arena
BG_RV_OBJECT_TYPE_PILAR_3 = 194585, // lightning
BG_RV_OBJECT_TYPE_PILAR_4 = 194587 // ivory
};
enum BattlegroundRVData
{
BG_RV_STATE_OPEN_FENCES,
BG_RV_STATE_SWITCH_PILLARS,
BG_RV_STATE_CLOSE_FIRE,
BG_RV_PILLAR_SWITCH_TIMER = 25000,
BG_RV_FIRE_TO_PILLAR_TIMER = 20000,
BG_RV_CLOSE_FIRE_TIMER = 5000,
BG_RV_FIRST_TIMER = 20133,
};
explicit arena_ring_of_valor(BattlegroundMap* map) : ArenaScript(map), _timer(0), _state(0), _pillarCollision(false) { }
void OnUpdate(uint32 diff) override
{
if (battleground->GetStatus() != STATUS_IN_PROGRESS)
return;
_scheduler.Update(diff);
if (_timer < diff)
{
switch (_state)
{
case BG_RV_STATE_OPEN_FENCES:
// Open fire (only at game start)
for (ObjectGuid const& guid : _fireGUIDs)
if (GameObject* go = battlegroundMap->GetGameObject(guid))
go->UseDoorOrButton();
for (ObjectGuid const& guid : _firedoorGUIDs)
if (GameObject* go = battlegroundMap->GetGameObject(guid))
go->UseDoorOrButton();
_timer = BG_RV_CLOSE_FIRE_TIMER;
_state = BG_RV_STATE_CLOSE_FIRE;
break;
case BG_RV_STATE_CLOSE_FIRE:
for (ObjectGuid const& guid : _fireGUIDs)
if (GameObject* go = battlegroundMap->GetGameObject(guid))
go->ResetDoorOrButton();
for (ObjectGuid const& guid : _firedoorGUIDs)
if (GameObject* go = battlegroundMap->GetGameObject(guid))
go->ResetDoorOrButton();
// Fire got closed after five seconds, leaves twenty seconds before toggling pillars
_timer = BG_RV_FIRE_TO_PILLAR_TIMER;
_state = BG_RV_STATE_SWITCH_PILLARS;
break;
case BG_RV_STATE_SWITCH_PILLARS:
TogglePillarCollision();
_timer = BG_RV_PILLAR_SWITCH_TIMER;
break;
default:
break;
}
}
else
_timer -= diff;
}
void OnInit() override
{
CreateObject(BG_RV_OBJECT_TYPE_ELEVATOR_1, 763.536377f, -294.535767f, 0.505383f, 3.141593f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_ELEVATOR_2, 763.506348f, -273.873352f, 0.505383f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_FIRE_1, 743.543457f, -283.799469f, 28.286655f, 3.141593f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_FIRE_2, 782.971802f, -283.799469f, 28.286655f, 3.141593f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_FIREDOOR_1, 743.711060f, -284.099609f, 27.542587f, 3.141593f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_FIREDOOR_2, 783.221252f, -284.133362f, 27.535686f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_GEAR_1, 763.664551f, -261.872986f, 26.686588f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_GEAR_2, 763.578979f, -306.146149f, 26.665222f, 3.141593f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_PULLEY_1, 700.722290f, -283.990662f, 39.517582f, 3.141593f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_PULLEY_2, 826.303833f, -283.996429f, 39.517582f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_PILAR_1, 763.632385f, -306.162384f, 25.909504f, 3.141593f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_PILAR_2, 723.644287f, -284.493256f, 24.648525f, 3.141593f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_PILAR_3, 763.611145f, -261.856750f, 25.909504f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_PILAR_4, 802.211609f, -284.493256f, 24.648525f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_PILAR_COLLISION_1, 763.632385f, -306.162384f, 30.639660f, 3.141593f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_PILAR_COLLISION_2, 723.644287f, -284.493256f, 32.382710f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_PILAR_COLLISION_3, 763.611145f, -261.856750f, 30.639660f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_PILAR_COLLISION_4, 802.211609f, -284.493256f, 32.382710f, 3.141593f, 0.0f, 0.0f, 0.0f, 0.0f);
}
void OnStart() override
{
for (ObjectGuid const& guid : _elevatorGUIDs)
{
if (GameObject* door = battlegroundMap->GetGameObject(guid))
{
door->UseDoorOrButton();
door->DespawnOrUnsummon(5s);
}
}
_state = BG_RV_STATE_OPEN_FENCES;
_timer = BG_RV_FIRST_TIMER;
// Should be false at first, TogglePillarCollision will do it.
_pillarCollision = true;
TogglePillarCollision();
_scheduler.Schedule(1min, [&](TaskContext)
{
CreateObject(BG_RV_OBJECT_TYPE_BUFF_1, 735.551819f, -284.794678f, 28.276682f, 0.034906f, 0.0f, 0.0f, 0.0f, 0.0f);
CreateObject(BG_RV_OBJECT_TYPE_BUFF_2, 791.224487f, -284.794464f, 28.276682f, 2.600535f, 0.0f, 0.0f, 0.0f, 0.0f);
});
}
void TogglePillarCollision()
{
// Toggle visual pillars, pulley, gear, and collision based on previous state
GuidVector smallPillarGuids;
smallPillarGuids.insert(std::end(smallPillarGuids), std::begin(_pillarSmallGUIDs), std::end(_pillarSmallGUIDs));
smallPillarGuids.insert(std::end(smallPillarGuids), std::begin(_gearGUIDs), std::end(_gearGUIDs));
for (ObjectGuid const& guid : smallPillarGuids)
{
if (GameObject* go = battlegroundMap->GetGameObject(guid))
{
if (_pillarCollision)
go->UseDoorOrButton();
else
go->ResetDoorOrButton();
}
}
GuidVector bigPillarGuids;
bigPillarGuids.insert(std::end(bigPillarGuids), std::begin(_pillarBigGUIDs), std::end(_pillarBigGUIDs));
bigPillarGuids.insert(std::end(bigPillarGuids), std::begin(_pulleyGUIDs), std::end(_pulleyGUIDs));
for (ObjectGuid const& guid : bigPillarGuids)
{
if (GameObject* go = battlegroundMap->GetGameObject(guid))
{
if (_pillarCollision)
go->ResetDoorOrButton();
else
go->UseDoorOrButton();
}
}
GuidVector allObjects;
allObjects.insert(std::end(allObjects), std::begin(smallPillarGuids), std::end(smallPillarGuids));
allObjects.insert(std::end(allObjects), std::begin(bigPillarGuids), std::end(bigPillarGuids));
allObjects.insert(std::end(allObjects), std::begin(_pillarSmallCollisionGUIDs), std::end(_pillarSmallCollisionGUIDs));
allObjects.insert(std::end(allObjects), std::begin(_pillarBigCollisionGUIDs), std::end(_pillarBigCollisionGUIDs));
for (ObjectGuid const& guid : allObjects)
{
if (GameObject* go = battlegroundMap->GetGameObject(guid))
{
bool isCollision = false;
switch (go->GetEntry())
{
case BG_RV_OBJECT_TYPE_PILAR_COLLISION_1:
case BG_RV_OBJECT_TYPE_PILAR_COLLISION_2:
case BG_RV_OBJECT_TYPE_PILAR_COLLISION_3:
case BG_RV_OBJECT_TYPE_PILAR_COLLISION_4:
isCollision = true;
break;
default:
break;
}
if (isCollision)
{
GOState state = ((go->GetGOInfo()->door.startOpen != 0) == _pillarCollision) ? GO_STATE_ACTIVE : GO_STATE_READY;
go->SetGoState(state);
}
for (auto const& [playerGuid, _]: battleground->GetPlayers())
if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
go->SendUpdateToPlayer(player);
}
}
_pillarCollision = !_pillarCollision;
}
void OnGameObjectCreate(GameObject* gameobject) override
{
ArenaScript::OnGameObjectCreate(gameobject);
switch (gameobject->GetEntry())
{
case BG_RV_OBJECT_TYPE_ELEVATOR_1:
case BG_RV_OBJECT_TYPE_ELEVATOR_2:
_elevatorGUIDs.emplace_back(gameobject->GetGUID());
break;
case BG_RV_OBJECT_TYPE_FIRE_1:
case BG_RV_OBJECT_TYPE_FIRE_2:
_fireGUIDs.emplace_back(gameobject->GetGUID());
break;
case BG_RV_OBJECT_TYPE_FIREDOOR_1:
case BG_RV_OBJECT_TYPE_FIREDOOR_2:
_firedoorGUIDs.emplace_back(gameobject->GetGUID());
break;
case BG_RV_OBJECT_TYPE_GEAR_1:
case BG_RV_OBJECT_TYPE_GEAR_2:
_gearGUIDs.emplace_back(gameobject->GetGUID());
break;
case BG_RV_OBJECT_TYPE_PILAR_1:
case BG_RV_OBJECT_TYPE_PILAR_3:
_pillarSmallGUIDs.emplace_back(gameobject->GetGUID());
break;
case BG_RV_OBJECT_TYPE_PILAR_2:
case BG_RV_OBJECT_TYPE_PILAR_4:
_pillarBigGUIDs.emplace_back(gameobject->GetGUID());
break;
case BG_RV_OBJECT_TYPE_PILAR_COLLISION_1:
case BG_RV_OBJECT_TYPE_PILAR_COLLISION_3:
_pillarSmallCollisionGUIDs.emplace_back(gameobject->GetGUID());
break;
case BG_RV_OBJECT_TYPE_PILAR_COLLISION_2:
case BG_RV_OBJECT_TYPE_PILAR_COLLISION_4:
_pillarBigCollisionGUIDs.emplace_back(gameobject->GetGUID());
break;
case BG_RV_OBJECT_TYPE_PULLEY_1:
case BG_RV_OBJECT_TYPE_PULLEY_2:
_pulleyGUIDs.emplace_back(gameobject->GetGUID());
break;
default:
break;
}
}
private:
GuidVector _elevatorGUIDs;
GuidVector _gearGUIDs;
GuidVector _fireGUIDs;
GuidVector _firedoorGUIDs;
GuidVector _pillarSmallCollisionGUIDs;
GuidVector _pillarBigCollisionGUIDs;
GuidVector _pillarSmallGUIDs;
GuidVector _pillarBigGUIDs;
GuidVector _pulleyGUIDs;
TaskScheduler _scheduler;
uint32 _timer;
uint32 _state;
bool _pillarCollision;
};
void AddSC_arena_ring_of_valor()
{
RegisterBattlegroundMapScript(arena_ring_of_valor, 618);
}
@@ -0,0 +1,80 @@
/*
* 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/>.
*/
#include "Battleground.h"
#include "BattlegroundScript.h"
#include "GameObject.h"
#include "Map.h"
#include "ScriptMgr.h"
#include "TaskScheduler.h"
struct arena_ruins_of_lordaeron : ArenaScript
{
enum BattlegroundRLGameObjects
{
BG_RL_OBJECT_TYPE_DOOR_1 = 185918,
BG_RL_OBJECT_TYPE_DOOR_2 = 185917,
BG_RL_OBJECT_TYPE_BUFF_1 = 184663,
BG_RL_OBJECT_TYPE_BUFF_2 = 184664
};
explicit arena_ruins_of_lordaeron(BattlegroundMap* map) : ArenaScript(map) { }
void OnUpdate(uint32 diff) override
{
_scheduler.Update(diff);
}
void OnInit() override
{
AddDoor(BG_RL_OBJECT_TYPE_DOOR_1, 1293.561f, 1601.938f, 31.60557f, -1.457349f, 0, 0, -0.6658813f, 0.7460576f);
AddDoor(BG_RL_OBJECT_TYPE_DOOR_2, 1278.648f, 1730.557f, 31.60557f, 1.684245f, 0, 0, 0.7460582f, 0.6658807f);
}
void OnStart() override
{
for (ObjectGuid const& guid : _doorGUIDs)
{
if (GameObject* door = battlegroundMap->GetGameObject(guid))
{
door->UseDoorOrButton();
door->DespawnOrUnsummon(5s);
}
}
_scheduler.Schedule(1min, [&](TaskContext)
{
CreateObject(BG_RL_OBJECT_TYPE_BUFF_1, 1328.719971f, 1632.719971f, 36.730400f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f);
CreateObject(BG_RL_OBJECT_TYPE_BUFF_2, 1243.300049f, 1699.170044f, 34.872601f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f);
});
}
void AddDoor(uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, GOState goState = GO_STATE_READY)
{
if (GameObject const* go = CreateObject(entry, x, y, z, o, rotation0, rotation1, rotation2, rotation3, goState))
_doorGUIDs.emplace_back(go->GetGUID());
}
private:
GuidVector _doorGUIDs;
TaskScheduler _scheduler;
};
void AddSC_arena_ruins_of_lordaeron()
{
RegisterBattlegroundMapScript(arena_ruins_of_lordaeron, 572);
}
@@ -15,8 +15,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "strand_of_the_ancients.h"
#include "ScriptMgr.h"
#include "BattlegroundSA.h"
#include "GameObject.h"
#include "GameObjectAI.h"
#include "Player.h"
@@ -15,12 +15,12 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BattlegroundTP.h"
#ifndef TRINITYCORE_STRAND_OF_THE_ANCIENTS_H
#define TRINITYCORE_STRAND_OF_THE_ANCIENTS_H
BattlegroundTP::BattlegroundTP(BattlegroundTemplate const* battlegroundTemplate) : Battleground(battlegroundTemplate)
enum StrandOfTheAncientSharedActions
{
}
ACTION_SOTA_CAPTURE_GRAVEYARD
};
BattlegroundTP::~BattlegroundTP()
{
}
#endif
@@ -15,22 +15,21 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __BATTLEGROUNDBFG_H
#define __BATTLEGROUNDBFG_H
#include "BattlegroundScript.h"
#include "ScriptMgr.h"
#include "Battleground.h"
enum BG_BFG_Objectives
struct battleground_twin_peaks : BattlegroundScript
{
BFG_OBJECTIVE_BASES_ASSAULTED = 370,
BFG_OBJECTIVE_BASES_DEFENDED = 371
enum PvpStats : uint32
{
BG_TP_FLAG_CAPTURES = 290,
BG_TP_FLAG_RETURNS = 291
};
explicit battleground_twin_peaks(BattlegroundMap* map) : BattlegroundScript(map) { }
};
class BattlegroundBFG : public Battleground
void AddSC_battleground_twin_peaks()
{
public:
BattlegroundBFG(BattlegroundTemplate const* battlegroundTemplate);
~BattlegroundBFG();
};
#endif
RegisterBattlegroundMapScript(battleground_twin_peaks, 726);
}
@@ -0,0 +1,608 @@
/*
* 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/>.
*/
#include "AreaTrigger.h"
#include "BattlegroundScript.h"
#include "Battleground.h"
#include "BattlegroundMgr.h"
#include "GameObject.h"
#include "GameTime.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "SpellAuras.h"
#include "Timer.h"
struct battleground_warsong_gulch : BattlegroundScript
{
static constexpr Seconds FLAG_ASSAULT_TIMER = 30s;
enum Misc
{
MAX_TEAM_SCORE = 3,
FLAG_BRUTAL_ASSAULT_STACK_COUNT = 5
};
enum Spells : uint32
{
SPELL_FOCUSED_ASSAULT = 46392,
SPELL_BRUTAL_ASSAULT = 46393,
SPELL_CAPTURED_ALLIANCE_COSMETIC_FX = 262508,
SPELL_CAPTURED_HORDE_COSMETIC_FX = 262512,
SPELL_WARSONG_FLAG = 23333,
SPELL_WARSONG_FLAG_DROPPED = 23334,
SPELL_SILVERWING_FLAG = 23335,
SPELL_SILVERWING_FLAG_DROPPED = 23336,
SPELL_QUICK_CAP_TIMER = 183317,
};
enum AreaTriggers : uint32
{
AT_CAPTURE_POINT_ALLIANCE = 30,
AT_CAPTURE_POINT_HORDE = 31
};
enum Events : uint32
{
EVENT_START_BATTLE = 35912
};
enum PvpStats : uint32
{
PVP_STAT_FLAG_CAPTURES = 928,
PVP_STAT_FLAG_RETURNS = 929
};
enum WorldStates : int32
{
WORLD_STATE_FLAG_STATE_ALLIANCE = 1545,
WORLD_STATE_FLAG_STATE_HORDE = 1546,
WORLD_STATE_FLAG_STATE_NEUTRAL = 1547,
WORLD_STATE_HORDE_FLAG_COUNT_PICKED_UP = 17712,
WORLD_STATE_ALLIANCE_FLAG_COUNT_PICKED_UP = 17713,
WORLD_STATE_FLAG_CAPTURES_ALLIANCE = 1581,
WORLD_STATE_FLAG_CAPTURES_HORDE = 1582,
WORLD_STATE_FLAG_CAPTURES_MAX = 1601,
WORLD_STATE_FLAG_CAPTURES_MAX_NEW = 17303,
WORLD_STATE_FLAG_CONTROL_HORDE = 2338,
WORLD_STATE_FLAG_CONTROL_ALLIANCE = 2339,
WORLD_STATE_STATE_TIMER = 4248,
WORLD_STATE_STATE_TIMER_ACTIVE = 4247
};
enum Texts
{
TEXT_START_ONE_MINUTE = 10015,
TEXT_START_HALF_MINUTE = 10016,
TEXT_BATTLE_HAS_BEGUN = 10014,
TEXT_CAPTURED_HORDE_FLAG = 9801,
TEXT_CAPTURED_ALLIANCE_FLAG = 9802,
TEXT_FLAGS_PLACED = 9803,
TEXT_ALLIANCE_FLAG_PICKED_UP = 9804,
TEXT_ALLIANCE_FLAG_DROPPED = 9805,
TEXT_HORDE_FLAG_PICKED_UP = 9807,
TEXT_HORDE_FLAG_DROPPED = 9806,
TEXT_ALLIANCE_FLAG_RETURNED = 9808,
TEXT_HORDE_FLAG_RETURNED = 9809
};
enum Sounds
{
SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
SOUND_FLAG_CAPTURED_HORDE = 8213,
SOUND_FLAG_PLACED = 8232,
SOUND_FLAG_RETURNED = 8192,
SOUND_HORDE_FLAG_PICKED_UP = 8212,
SOUND_ALLIANCE_FLAG_PICKED_UP = 8174,
SOUND_FLAGS_RESPAWNED = 8232
};
enum GameObjects
{
OBJECT_ALLIANCE_DOOR = 309704,
OBJECT_PORTCULLIS_009 = 309705,
OBJECT_PORTCULLIS_002 = 309883,
OBJECT_COLLISION_PC_SIZE = 242273,
OBJECT_HORDE_GATE_1 = 352709,
OBJECT_HORDE_GATE_2 = 352710,
OBJECT_ALLIANCE_FLAG_IN_BASE = 227741,
OBJECT_HORDE_FLAG_IN_BASE = 227740
};
static constexpr std::array<std::array<uint32, 3>, 2> HONOR_REWARDS =
{{
{ 20, 40, 40 },
{ 60, 40, 80 }
}};
explicit battleground_warsong_gulch(BattlegroundMap* map) : BattlegroundScript(map), _lastFlagCaptureTeam(TEAM_OTHER), _bothFlagsKept(false), _flags({ }), _assaultStackCount(0), _capturePointAreaTriggers({ })
{
_flagAssaultTimer.Reset(FLAG_ASSAULT_TIMER);
if (sBattlegroundMgr->IsBGWeekend(battleground->GetTypeID()))
{
_reputationCapture = 45;
_honorWinKills = 3;
_honorEndKills = 4;
}
else
{
_reputationCapture = 35;
_honorWinKills = 1;
_honorEndKills = 2;
}
}
void OnUpdate(uint32 diff) override
{
BattlegroundScript::OnUpdate(diff);
if (battleground->GetStatus() == STATUS_IN_PROGRESS)
{
if (battleground->GetElapsedTime() >= 17 * MINUTE * IN_MILLISECONDS)
{
if (battleground->GetTeamScore(TEAM_ALLIANCE) == 0)
{
if (battleground->GetTeamScore(TEAM_HORDE) == 0) // No one scored - result is tie
battleground->EndBattleground(TEAM_OTHER);
else // Horde has more points and thus wins
battleground->EndBattleground(HORDE);
}
else if (battleground->GetTeamScore(TEAM_HORDE) == 0) // Alliance has > 0, Horde has 0, alliance wins
battleground->EndBattleground(ALLIANCE);
else if (battleground->GetTeamScore(TEAM_HORDE) == battleground->GetTeamScore(TEAM_ALLIANCE)) // Team score equal, winner is team that scored the last flag
battleground->EndBattleground(_lastFlagCaptureTeam);
else if (battleground->GetTeamScore(TEAM_HORDE) > battleground->GetTeamScore(TEAM_ALLIANCE)) // Last but not least, check who has the higher score
battleground->EndBattleground(HORDE);
else
battleground->EndBattleground(ALLIANCE);
}
}
if (_bothFlagsKept)
{
_flagAssaultTimer.Update(diff);
if (_flagAssaultTimer.Passed())
{
_flagAssaultTimer.Reset(FLAG_ASSAULT_TIMER);
if (_assaultStackCount < std::numeric_limits<uint8>::max())
{
_assaultStackCount++;
// update assault debuff stacks
DoForFlagKeepers([&](Player* player) -> void
{
ApplyAssaultDebuffToPlayer(player);
});
}
}
}
}
void OnStart() override
{
BattlegroundScript::OnStart();
for (ObjectGuid door : _doors)
{
if (GameObject* gameObject = battlegroundMap->GetGameObject(door))
{
gameObject->UseDoorOrButton();
gameObject->DespawnOrUnsummon(3s);
}
}
UpdateWorldState(WORLD_STATE_STATE_TIMER_ACTIVE, 1);
UpdateWorldState(WORLD_STATE_STATE_TIMER, std::chrono::system_clock::to_time_t(GameTime::GetSystemTime() + 15min));
// players joining later are not eligibles
TriggerGameEvent(EVENT_START_BATTLE);
}
void OnEnd(Team winner) override
{
BattlegroundScript::OnEnd(winner);
// Win reward
if (winner == ALLIANCE)
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(_honorWinKills), ALLIANCE);
if (winner == HORDE)
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(_honorWinKills), HORDE);
// Complete map_end rewards (even if no team wins)
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(_honorEndKills), ALLIANCE);
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(_honorEndKills), HORDE);
}
void DoForFlagKeepers(std::function<void(Player*)> const& action) const
{
for (ObjectGuid flagGUID : _flags)
if (GameObject const* flag = battlegroundMap->GetGameObject(flagGUID))
if (Player* carrier = ObjectAccessor::FindPlayer(flag->GetFlagCarrierGUID()))
action(carrier);
}
void ResetAssaultDebuff()
{
_bothFlagsKept = false;
_assaultStackCount = 0;
_flagAssaultTimer.Reset(FLAG_ASSAULT_TIMER);
DoForFlagKeepers([&](Player* player) -> void
{
RemoveAssaultDebuffFromPlayer(player);
});
}
void ApplyAssaultDebuffToPlayer(Player* player) const
{
if (_assaultStackCount == 0)
return;
uint32 spellId = SPELL_FOCUSED_ASSAULT;
if (_assaultStackCount >= FLAG_BRUTAL_ASSAULT_STACK_COUNT)
{
player->RemoveAurasDueToSpell(SPELL_FOCUSED_ASSAULT);
spellId = SPELL_BRUTAL_ASSAULT;
}
Aura* aura = player->GetAura(spellId);
if (!aura)
{
player->CastSpell(player, spellId, true);
aura = player->GetAura(spellId);
}
if (aura)
aura->SetStackAmount(_assaultStackCount);
}
void RemoveAssaultDebuffFromPlayer(Player* player) const
{
player->RemoveAurasDueToSpell(SPELL_FOCUSED_ASSAULT);
player->RemoveAurasDueToSpell(SPELL_BRUTAL_ASSAULT);
}
FlagState GetFlagState(TeamId team) const
{
if (GameObject const* flag = battlegroundMap->GetGameObject(_flags[team]))
return flag->GetFlagState();
return FlagState(0);
}
ObjectGuid const& GetFlagCarrierGUID(TeamId team) const
{
if (GameObject const* flag = battlegroundMap->GetGameObject(_flags[team]))
return flag->GetFlagCarrierGUID();
return ObjectGuid::Empty;
}
void HandleFlagRoomCapturePoint()
{
DoForFlagKeepers([&](Player* player) -> void
{
TeamId const team = Battleground::GetTeamIndexByTeamId(battleground->GetPlayerTeam(player->GetGUID()));
if (AreaTrigger* trigger = battlegroundMap->GetAreaTrigger(_capturePointAreaTriggers[team]))
if (trigger->GetInsideUnits().contains(player->GetGUID()))
if (CanCaptureFlag(trigger, player))
OnCaptureFlag(trigger, player);
});
}
void UpdateFlagState(uint32 team, FlagState value) const
{
auto transformValueToOtherTeamControlWorldState = [](FlagState state)
{
switch (state)
{
case FlagState::InBase:
case FlagState::Dropped:
case FlagState::Respawning:
return 1;
case FlagState::Taken:
return 2;
default:
return 0;
}
};
if (team == ALLIANCE)
{
UpdateWorldState(WORLD_STATE_FLAG_STATE_ALLIANCE, AsUnderlyingType(value));
UpdateWorldState(WORLD_STATE_FLAG_CONTROL_HORDE, transformValueToOtherTeamControlWorldState(value));
}
else
{
UpdateWorldState(WORLD_STATE_FLAG_STATE_HORDE, AsUnderlyingType(value));
UpdateWorldState(WORLD_STATE_FLAG_CONTROL_ALLIANCE, transformValueToOtherTeamControlWorldState(value));
}
}
void UpdateTeamScore(TeamId team) const
{
if (team == TEAM_ALLIANCE)
UpdateWorldState(WORLD_STATE_FLAG_CAPTURES_ALLIANCE, battleground->GetTeamScore(team));
else
UpdateWorldState(WORLD_STATE_FLAG_CAPTURES_HORDE, battleground->GetTeamScore(team));
}
void OnGameObjectCreate(GameObject* gameObject) override
{
BattlegroundScript::OnGameObjectCreate(gameObject);
switch (gameObject->GetEntry())
{
case OBJECT_ALLIANCE_DOOR:
case OBJECT_PORTCULLIS_009:
case OBJECT_PORTCULLIS_002:
case OBJECT_COLLISION_PC_SIZE:
case OBJECT_HORDE_GATE_1:
case OBJECT_HORDE_GATE_2:
_doors.insert(gameObject->GetGUID());
break;
case OBJECT_ALLIANCE_FLAG_IN_BASE:
_flags[TEAM_ALLIANCE] = gameObject->GetGUID();
break;
case OBJECT_HORDE_FLAG_IN_BASE:
_flags[TEAM_HORDE] = gameObject->GetGUID();
break;
default:
break;
}
}
void OnAreaTriggerCreate(AreaTrigger* areaTrigger) override
{
BattlegroundScript::OnAreaTriggerCreate(areaTrigger);
if (!areaTrigger->IsStaticSpawn())
return;
switch (areaTrigger->GetEntry())
{
case AT_CAPTURE_POINT_ALLIANCE:
_capturePointAreaTriggers[TEAM_ALLIANCE] = areaTrigger->GetGUID();
break;
case AT_CAPTURE_POINT_HORDE:
_capturePointAreaTriggers[TEAM_HORDE] = areaTrigger->GetGUID();
break;
default:
break;
}
}
void OnFlagStateChange(GameObject* flagInBase, FlagState oldValue, FlagState newValue, Player* player) override
{
BattlegroundScript::OnFlagStateChange(flagInBase, oldValue, newValue, player);
Team const team = flagInBase->GetEntry() == OBJECT_HORDE_FLAG_IN_BASE ? HORDE : ALLIANCE;
TeamId const otherTeamId = Battleground::GetTeamIndexByTeamId(GetOtherTeam(team));
UpdateFlagState(team, newValue);
switch (newValue)
{
case FlagState::InBase:
{
if (battleground->GetStatus() == STATUS_IN_PROGRESS)
{
ResetAssaultDebuff();
if (player)
{
// flag got returned to base by player interaction
battleground->UpdatePvpStat(player, PVP_STAT_FLAG_RETURNS, 1); // +1 flag returns
if (team == ALLIANCE)
{
battleground->SendBroadcastText(TEXT_ALLIANCE_FLAG_RETURNED, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
battleground->PlaySoundToAll(SOUND_FLAG_RETURNED);
}
else
{
battleground->SendBroadcastText(TEXT_HORDE_FLAG_RETURNED, CHAT_MSG_BG_SYSTEM_HORDE, player);
battleground->PlaySoundToAll(SOUND_FLAG_RETURNED);
}
}
// Flag respawned due to timeout/capture
else if (GetFlagState(otherTeamId) != FlagState::Respawning)
{
// if other flag is respawning, we will let that one handle the message and sound to prevent double message/sound.
battleground->SendBroadcastText(TEXT_FLAGS_PLACED, CHAT_MSG_BG_SYSTEM_NEUTRAL);
battleground->PlaySoundToAll(SOUND_FLAGS_RESPAWNED);
}
HandleFlagRoomCapturePoint();
}
break;
}
case FlagState::Dropped:
{
player->RemoveAurasDueToSpell(SPELL_QUICK_CAP_TIMER);
RemoveAssaultDebuffFromPlayer(player);
uint32 recentlyDroppedSpellId = SPELL_RECENTLY_DROPPED_HORDE_FLAG;
if (team == ALLIANCE)
{
recentlyDroppedSpellId = SPELL_RECENTLY_DROPPED_ALLIANCE_FLAG;
battleground->SendBroadcastText(TEXT_ALLIANCE_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
}
else
battleground->SendBroadcastText(TEXT_HORDE_FLAG_DROPPED, CHAT_MSG_BG_SYSTEM_HORDE, player);
player->CastSpell(player, recentlyDroppedSpellId, true);
break;
}
case FlagState::Taken:
{
if (team == HORDE)
{
battleground->SendBroadcastText(TEXT_HORDE_FLAG_PICKED_UP, CHAT_MSG_BG_SYSTEM_HORDE, player);
battleground->PlaySoundToAll(SOUND_HORDE_FLAG_PICKED_UP);
}
else
{
battleground->SendBroadcastText(TEXT_ALLIANCE_FLAG_PICKED_UP, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
battleground->PlaySoundToAll(SOUND_ALLIANCE_FLAG_PICKED_UP);
}
if (GetFlagState(otherTeamId) == FlagState::Taken)
_bothFlagsKept = true;
ApplyAssaultDebuffToPlayer(player);
flagInBase->CastSpell(player, SPELL_QUICK_CAP_TIMER, true);
player->StartCriteria(CriteriaStartEvent::BeSpellTarget, SPELL_QUICK_CAP_TIMER, Seconds(GameTime::GetGameTime() - flagInBase->GetFlagTakenFromBaseTime()));
break;
}
case FlagState::Respawning:
ResetAssaultDebuff();
break;
default:
break;
}
}
bool CanCaptureFlag(AreaTrigger* areaTrigger, Player* player) override
{
if (battleground->GetStatus() != STATUS_IN_PROGRESS)
return false;
Team const team = battleground->GetPlayerTeam(player->GetGUID());
TeamId const teamId = Battleground::GetTeamIndexByTeamId(team);
TeamId const otherTeamId = Battleground::GetTeamIndexByTeamId(GetOtherTeam(team));
if (areaTrigger->GetGUID() != _capturePointAreaTriggers[teamId])
return false;
// check if enemy flag's carrier is this player
if (GetFlagCarrierGUID(otherTeamId) != player->GetGUID())
return false;
// check that team's flag is in base
return GetFlagState(teamId) == FlagState::InBase;
}
void OnCaptureFlag(AreaTrigger* areaTrigger, Player* player) override
{
BattlegroundScript::OnCaptureFlag(areaTrigger, player);
Team winner = TEAM_OTHER;
Team const team = battleground->GetPlayerTeam(player->GetGUID());
TeamId const teamId = Battleground::GetTeamIndexByTeamId(team);
TeamId const otherTeamId = Battleground::GetTeamIndexByTeamId(GetOtherTeam(team));
/*
1. Update flag states & score world states
2. update points
3. chat message & sound
4. update criterias & achievements
5. remove all related auras
?. Reward honor & reputation
*/
// 1. update the flag states
for (ObjectGuid const& flagGuid: _flags)
if (GameObject const* flag = battlegroundMap->GetGameObject(flagGuid))
flag->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::Respawning, player));
// 2. update points
if (battleground->GetTeamScore(teamId) < MAX_TEAM_SCORE)
battleground->AddPoint(team, 1);
UpdateTeamScore(teamId);
// 3. chat message & sound
if (team == ALLIANCE)
{
battleground->SendBroadcastText(TEXT_CAPTURED_HORDE_FLAG, CHAT_MSG_BG_SYSTEM_HORDE, player);
battleground->PlaySoundToAll(SOUND_FLAG_CAPTURED_ALLIANCE);
battleground->RewardReputationToTeam(890, _reputationCapture, ALLIANCE);
player->CastSpell(player, SPELL_CAPTURED_ALLIANCE_COSMETIC_FX);
}
else
{
battleground->SendBroadcastText(TEXT_CAPTURED_ALLIANCE_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
battleground->PlaySoundToAll(SOUND_FLAG_CAPTURED_HORDE);
battleground->RewardReputationToTeam(889, _reputationCapture, HORDE);
player->CastSpell(player, SPELL_CAPTURED_HORDE_COSMETIC_FX);
}
// 4. update criteria's for achievement, player score etc.
battleground->UpdatePvpStat(player, PVP_STAT_FLAG_CAPTURES, 1); // +1 flag captures
// 5. Remove all related auras
RemoveAssaultDebuffFromPlayer(player);
if (GameObject const* flag = battlegroundMap->GetGameObject(_flags[otherTeamId]))
player->RemoveAurasDueToSpell(flag->GetGOInfo()->newflag.pickupSpell, flag->GetGUID());
player->RemoveAurasDueToSpell(SPELL_QUICK_CAP_TIMER);
player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive);
battleground->RewardHonorToTeam(battleground->GetBonusHonorFromKill(2), team);
// update last flag capture to be used if teamscore is equal
SetLastFlagCapture(team);
if (battleground->GetTeamScore(teamId) == MAX_TEAM_SCORE)
winner = team;
if (winner)
{
UpdateWorldState(WORLD_STATE_FLAG_STATE_ALLIANCE, 1);
UpdateWorldState(WORLD_STATE_FLAG_STATE_HORDE, 1);
UpdateWorldState(WORLD_STATE_STATE_TIMER_ACTIVE, 0);
battleground->RewardHonorToTeam(HONOR_REWARDS[BattlegroundMgr::IsBGWeekend(battleground->GetTypeID()) ? 1 : 0][0], winner);
battleground->EndBattleground(winner);
}
}
Team GetPrematureWinner() override
{
if (battleground->GetTeamScore(TEAM_ALLIANCE) > battleground->GetTeamScore(TEAM_HORDE))
return ALLIANCE;
if (battleground->GetTeamScore(TEAM_HORDE) > battleground->GetTeamScore(TEAM_ALLIANCE))
return HORDE;
return BattlegroundScript::GetPrematureWinner();
}
void SetLastFlagCapture(Team team)
{
_lastFlagCaptureTeam = team;
}
private:
Team _lastFlagCaptureTeam;
bool _bothFlagsKept;
GuidSet _doors;
std::array<ObjectGuid, PVP_TEAMS_COUNT> _flags;
TimeTracker _flagAssaultTimer;
uint8 _assaultStackCount;
std::array<ObjectGuid, PVP_TEAMS_COUNT> _capturePointAreaTriggers;
uint32 _honorWinKills;
uint32 _honorEndKills;
uint32 _reputationCapture;
};
void AddSC_battleground_warsong_gulch()
{
RegisterBattlegroundMapScript(battleground_warsong_gulch, 2106);
}
@@ -0,0 +1,95 @@
/*
* 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/>.
*/
// This is where scripts' loading functions should be declared:
// Alterac Valley
void AddSC_alterac_valley();
void AddSC_boss_balinda();
void AddSC_boss_drekthar();
void AddSC_boss_galvangar();
void AddSC_boss_vanndar();
void AddSC_battleground_alterac_valley();
// Arathi Basin
void AddSC_arathi_basin();
void AddSC_battleground_arathi_basin();
// Eye of the storm
void AddSC_battleground_eye_of_the_storm();
// Warsong Gulch
void AddSC_battleground_warsong_gulch();
// Isle of Conquest
void AddSC_battleground_isle_of_conquest();
void AddSC_isle_of_conquest();
void AddSC_boss_ioc_horde_alliance();
// Strand of the Ancients
void AddSC_battleground_strand_of_the_ancients();
void AddSC_strand_of_the_ancients();
// Blade's Edge Arena
void AddSC_arena_blades_edge();
void AddSC_arena_dalaran_sewers();
void AddSC_arena_nagrand();
void AddSC_arena_ruins_of_lordaeron();
void AddSC_arena_ring_of_valor();
void AddSC_battleground_twin_peaks();
void AddSC_battleground_battle_for_gilneas();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
void AddBattlegroundsScripts()
{
// Alterac Valley
AddSC_alterac_valley();
AddSC_boss_balinda();
AddSC_boss_drekthar();
AddSC_boss_galvangar();
AddSC_boss_vanndar();
AddSC_battleground_alterac_valley();
// Arathi Basin
AddSC_arathi_basin();
AddSC_battleground_arathi_basin();
// Eye of the Storm
AddSC_battleground_eye_of_the_storm();
// Warsong Gulch
AddSC_battleground_warsong_gulch();
// Isle of Conquest
AddSC_battleground_isle_of_conquest();
AddSC_isle_of_conquest();
AddSC_boss_ioc_horde_alliance();
// Strand of the Ancients
AddSC_battleground_strand_of_the_ancients();
AddSC_strand_of_the_ancients();
AddSC_arena_blades_edge();
AddSC_arena_dalaran_sewers();
AddSC_arena_nagrand();
AddSC_arena_ruins_of_lordaeron();
AddSC_arena_ring_of_valor();
AddSC_battleground_twin_peaks();
AddSC_battleground_battle_for_gilneas();
}
+4 -8
View File
@@ -1418,15 +1418,11 @@ public:
if (linked)
{
if (Battleground* bg = player->GetBattleground())
nearestLoc = bg->GetClosestGraveyard(player);
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetMap(), player->GetZoneId()))
nearestLoc = bf->GetClosestGraveyard(player);
else
{
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetMap(), player->GetZoneId()))
nearestLoc = bf->GetClosestGraveyard(player);
else
nearestLoc = sObjectMgr->GetClosestGraveyard(*player, player->GetTeam(), player);
}
nearestLoc = sObjectMgr->GetClosestGraveyard(*player, player->GetTeam(), player);
}
else
{
@@ -16,12 +16,6 @@
*/
// This is where scripts' loading functions should be declared:
void AddSC_alterac_valley(); //Alterac Valley
void AddSC_boss_balinda();
void AddSC_boss_drekthar();
void AddSC_boss_galvangar();
void AddSC_boss_vanndar();
void AddSC_arathi_basin(); //Arathi Basin
void AddSC_boss_alizabal(); //Baradin Hold
void AddSC_boss_occuthar();
void AddSC_boss_argaloth();
@@ -211,12 +205,6 @@ void AddSC_undercity();
// void Add${NameOfDirectory}Scripts()
void AddEasternKingdomsScripts()
{
AddSC_alterac_valley(); //Alterac Valley
AddSC_boss_balinda();
AddSC_boss_drekthar();
AddSC_boss_galvangar();
AddSC_boss_vanndar();
AddSC_arathi_basin(); //Arathi Basin
AddSC_boss_alizabal(); //Baradin Hold
AddSC_boss_occuthar();
AddSC_boss_argaloth();
@@ -194,9 +194,6 @@ void AddSC_boss_baltharus_the_warborn();
void AddSC_boss_saviana_ragefire();
void AddSC_boss_general_zarithrian();
void AddSC_boss_halion();
// Isle of Conquest
void AddSC_isle_of_conquest();
void AddSC_boss_ioc_horde_alliance();
void AddSC_dalaran();
void AddSC_borean_tundra();
@@ -210,8 +207,6 @@ void AddSC_wintergrasp();
void AddSC_zuldrak();
void AddSC_crystalsong_forest();
void AddSC_strand_of_the_ancients();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
void AddNorthrendScripts()
@@ -394,9 +389,6 @@ void AddNorthrendScripts()
AddSC_boss_saviana_ragefire();
AddSC_boss_general_zarithrian();
AddSC_boss_halion();
// Isle of Conquest
AddSC_isle_of_conquest();
AddSC_boss_ioc_horde_alliance();
AddSC_dalaran();
AddSC_borean_tundra();
@@ -408,6 +400,4 @@ void AddNorthrendScripts()
AddSC_storm_peaks();
AddSC_wintergrasp();
AddSC_zuldrak();
AddSC_strand_of_the_ancients();
}
@@ -24,7 +24,6 @@ SDCategory: Dalaran
Script Data End */
#include "ScriptMgr.h"
#include "BattlegroundDS.h"
#include "Containers.h"
#include "DatabaseEnv.h"
#include "Mail.h"
@@ -254,44 +253,8 @@ private:
EventMap events;
};
class at_ds_pipe_knockback : public AreaTriggerScript
{
public:
at_ds_pipe_knockback() : AreaTriggerScript("at_ds_pipe_knockback") { }
void Trigger(Player* player) const
{
if (Battleground* battleground = player->GetBattleground())
{
if (battleground->GetStatus() != STATUS_IN_PROGRESS)
return;
// Remove effects of Demonic Circle Summon
player->RemoveAurasDueToSpell(SPELL_WARL_DEMONIC_CIRCLE);
// Someone has get back into the pipes and the knockback has already been performed,
// so we reset the knockback count for kicking the player again into the arena.
if (battleground->GetData(BG_DS_DATA_PIPE_KNOCKBACK_COUNT) >= BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT)
battleground->SetData(BG_DS_DATA_PIPE_KNOCKBACK_COUNT, 0);
}
}
bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) override
{
Trigger(player);
return true;
}
bool OnExit(Player* player, AreaTriggerEntry const* /*trigger*/) override
{
Trigger(player);
return true;
}
};
void AddSC_dalaran()
{
RegisterCreatureAI(npc_mageguard_dalaran);
RegisterCreatureAI(npc_minigob_manabonk);
new at_ds_pipe_knockback();
}
-3
View File
@@ -3081,9 +3081,6 @@ class spell_item_rocket_boots : public SpellScript
void HandleDummy(SpellEffIndex /* effIndex */)
{
Player* caster = GetCaster()->ToPlayer();
if (Battleground* bg = caster->GetBattleground())
bg->EventPlayerDroppedFlag(caster);
caster->GetSpellHistory()->ResetCooldown(SPELL_ROCKET_BOOTS_PROC);
caster->CastSpell(caster, SPELL_ROCKET_BOOTS_PROC, true);
}