aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/BattleGrounds/BattleGroundAB.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/BattleGrounds/BattleGroundAB.cpp')
-rw-r--r--src/server/game/BattleGrounds/BattleGroundAB.cpp715
1 files changed, 715 insertions, 0 deletions
diff --git a/src/server/game/BattleGrounds/BattleGroundAB.cpp b/src/server/game/BattleGrounds/BattleGroundAB.cpp
new file mode 100644
index 00000000000..38671e85597
--- /dev/null
+++ b/src/server/game/BattleGrounds/BattleGroundAB.cpp
@@ -0,0 +1,715 @@
+/*
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "World.h"
+#include "WorldPacket.h"
+#include "ObjectMgr.h"
+#include "BattleGroundMgr.h"
+#include "BattleGround.h"
+#include "BattleGroundAB.h"
+#include "Creature.h"
+#include "Language.h"
+#include "Object.h"
+#include "Player.h"
+#include "Util.h"
+
+// these variables aren't used outside of this file, so declare them only here
+uint32 BG_AB_HonorScoreTicks[BG_HONOR_MODE_NUM] = {
+ 330, // normal honor
+ 200 // holiday
+};
+
+uint32 BG_AB_ReputationScoreTicks[BG_HONOR_MODE_NUM] = {
+ 200, // normal honor
+ 150 // holiday
+};
+
+BattleGroundAB::BattleGroundAB()
+{
+ m_BuffChange = true;
+ m_BgObjects.resize(BG_AB_OBJECT_MAX);
+ m_BgCreatures.resize(BG_AB_ALL_NODES_COUNT + 5);//+5 for aura triggers
+
+ m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AB_START_TWO_MINUTES;
+ m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AB_START_ONE_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AB_START_HALF_MINUTE;
+ m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AB_HAS_BEGUN;
+}
+
+BattleGroundAB::~BattleGroundAB()
+{
+}
+
+void BattleGroundAB::Update(uint32 diff)
+{
+ BattleGround::Update(diff);
+
+ if (GetStatus() == STATUS_IN_PROGRESS)
+ {
+ int team_points[BG_TEAMS_COUNT] = { 0, 0 };
+
+ for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
+ {
+ // 3 sec delay to spawn new banner instead previous despawned one
+ if (m_BannerTimers[node].timer)
+ {
+ if (m_BannerTimers[node].timer > diff)
+ m_BannerTimers[node].timer -= diff;
+ else
+ {
+ m_BannerTimers[node].timer = 0;
+ _CreateBanner(node, m_BannerTimers[node].type, m_BannerTimers[node].teamIndex, false);
+ }
+ }
+
+ // 1-minute to occupy a node from contested state
+ if (m_NodeTimers[node])
+ {
+ if (m_NodeTimers[node] > diff)
+ m_NodeTimers[node] -= diff;
+ else
+ {
+ m_NodeTimers[node] = 0;
+ // Change from contested to occupied !
+ uint8 teamIndex = m_Nodes[node]-1;
+ m_prevNodes[node] = m_Nodes[node];
+ m_Nodes[node] += 2;
+ // burn current contested banner
+ _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex);
+ // create new occupied banner
+ _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
+ _SendNodeUpdate(node);
+ _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
+ // Message to chatlog
+
+ if (teamIndex == 0)
+ {
+ // FIXME: team and node names not localized
+ SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE,NULL,LANG_BG_AB_ALLY,_GetNodeNameId(node));
+ PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
+ }
+ else
+ {
+ // FIXME: team and node names not localized
+ SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE,NULL,LANG_BG_AB_HORDE,_GetNodeNameId(node));
+ PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
+ }
+ }
+ }
+
+ for (int team = 0; team < BG_TEAMS_COUNT; ++team)
+ if (m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED)
+ ++team_points[team];
+ }
+
+ // Accumulate points
+ for (int team = 0; team < BG_TEAMS_COUNT; ++team)
+ {
+ int points = team_points[team];
+ if (!points)
+ continue;
+ m_lastTick[team] += diff;
+ if (m_lastTick[team] > BG_AB_TickIntervals[points])
+ {
+ m_lastTick[team] -= BG_AB_TickIntervals[points];
+ m_TeamScores[team] += BG_AB_TickPoints[points];
+ m_HonorScoreTics[team] += BG_AB_TickPoints[points];
+ m_ReputationScoreTics[team] += BG_AB_TickPoints[points];
+ if (m_ReputationScoreTics[team] >= m_ReputationTics)
+ {
+ (team == BG_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 == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE);
+ m_HonorScoreTics[team] -= m_HonorTics;
+ }
+ if (!m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE)
+ {
+ if (team == BG_TEAM_ALLIANCE)
+ SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
+ else
+ SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
+ PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY);
+ m_IsInformedNearVictory = true;
+ }
+
+ if (m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE)
+ m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE;
+ if (team == BG_TEAM_ALLIANCE)
+ UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]);
+ if (team == BG_TEAM_HORDE)
+ UpdateWorldState(BG_AB_OP_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) % BG_TEAMS_COUNT;
+ if (m_TeamScores[team] > m_TeamScores[otherTeam] + 500)
+ m_TeamScores500Disadvantage[otherTeam] = true;
+ }
+ }
+
+ // Test win condition
+ if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE)
+ EndBattleGround(ALLIANCE);
+ if (m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE)
+ EndBattleGround(HORDE);
+ }
+}
+
+void BattleGroundAB::StartingEventCloseDoors()
+{
+ // despawn banners, auras and buffs
+ for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj)
+ SpawnBGObject(obj, RESPAWN_ONE_DAY);
+ for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i)
+ SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY);
+
+ // Starting doors
+ DoorClose(BG_AB_OBJECT_GATE_A);
+ DoorClose(BG_AB_OBJECT_GATE_H);
+ SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY);
+ SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY);
+
+ // Starting base spirit guides
+ _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE);
+ _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE);
+}
+
+void BattleGroundAB::StartingEventOpenDoors()
+{
+ // spawn neutral banners
+ for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
+ SpawnBGObject(banner, RESPAWN_IMMEDIATELY);
+ for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ {
+ //randomly select buff to spawn
+ uint8 buff = urand(0, 2);
+ SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY);
+ }
+ DoorOpen(BG_AB_OBJECT_GATE_A);
+ DoorOpen(BG_AB_OBJECT_GATE_H);
+}
+
+void BattleGroundAB::AddPlayer(Player *plr)
+{
+ BattleGround::AddPlayer(plr);
+ //create score and add it to map, default values are set in the constructor
+ BattleGroundABScore* sc = new BattleGroundABScore;
+
+ m_PlayerScores[plr->GetGUID()] = sc;
+}
+
+void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
+{
+
+}
+
+void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger)
+{
+ if (GetStatus() != STATUS_IN_PROGRESS)
+ return;
+
+ switch(Trigger)
+ {
+ case 3948: // Arathi Basin Alliance Exit.
+ if (Source->GetTeam() != ALLIANCE)
+ Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
+ else
+ Source->LeaveBattleground();
+ break;
+ case 3949: // Arathi Basin Horde Exit.
+ if (Source->GetTeam() != HORDE)
+ Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
+ else
+ Source->LeaveBattleground();
+ break;
+ case 3866: // Stables
+ case 3869: // Gold Mine
+ case 3867: // Farm
+ case 3868: // Lumber Mill
+ case 3870: // Black Smith
+ case 4020: // Unk1
+ case 4021: // Unk2
+ //break;
+ default:
+ //sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
+ //Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
+ break;
+ }
+}
+
+/* type: 0-neutral, 1-contested, 3-occupied
+ teamIndex: 0-ally, 1-horde */
+void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay)
+{
+ // Just put it into the queue
+ if (delay)
+ {
+ m_BannerTimers[node].timer = 2000;
+ m_BannerTimers[node].type = type;
+ m_BannerTimers[node].teamIndex = teamIndex;
+ return;
+ }
+
+ uint8 obj = node*8 + type + teamIndex;
+
+ SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
+
+ // handle aura with banner
+ if (!type)
+ return;
+ obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
+ SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
+}
+
+void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)
+{
+ uint8 obj = node*8 + type + teamIndex;
+ SpawnBGObject(obj, RESPAWN_ONE_DAY);
+
+ // handle aura with banner
+ if (!type)
+ return;
+ obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
+ SpawnBGObject(obj, RESPAWN_ONE_DAY);
+}
+
+int32 BattleGroundAB::_GetNodeNameId(uint8 node)
+{
+ switch (node)
+ {
+ case BG_AB_NODE_STABLES: return LANG_BG_AB_NODE_STABLES;
+ case BG_AB_NODE_BLACKSMITH: return LANG_BG_AB_NODE_BLACKSMITH;
+ case BG_AB_NODE_FARM: return LANG_BG_AB_NODE_FARM;
+ case BG_AB_NODE_LUMBER_MILL:return LANG_BG_AB_NODE_LUMBER_MILL;
+ case BG_AB_NODE_GOLD_MINE: return LANG_BG_AB_NODE_GOLD_MINE;
+ default:
+ ASSERT(0);
+ }
+ return 0;
+}
+
+void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
+{
+ const uint8 plusArray[] = {0, 2, 3, 0, 1};
+
+ // Node icons
+ for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
+ data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node] == 0)?1:0);
+
+ // Node occupied states
+ for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
+ for (uint8 i = 1; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node] == i)?1:0);
+
+ // How many bases each team owns
+ uint8 ally = 0, horde = 0;
+ for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
+ if (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED)
+ ++ally;
+ else if (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
+ ++horde;
+
+ data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally);
+ data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde);
+
+ // Team scores
+ data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE);
+ data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_NEAR_VICTORY_SCORE);
+ data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]);
+ data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]);
+
+ // other unknown
+ data << uint32(0x745) << uint32(0x2); // 37 1861 unk
+}
+
+void BattleGroundAB::_SendNodeUpdate(uint8 node)
+{
+ // Send node owner state update to refresh map icons on client
+ const uint8 plusArray[] = {0, 2, 3, 0, 1};
+
+ if (m_prevNodes[node])
+ UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0);
+ else
+ UpdateWorldState(BG_AB_OP_NODEICONS[node], 0);
+
+ UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1);
+
+ // How many bases each team owns
+ uint8 ally = 0, horde = 0;
+ for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ if (m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED)
+ ++ally;
+ else if (m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
+ ++horde;
+
+ UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally);
+ UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, horde);
+}
+
+void BattleGroundAB::_NodeOccupied(uint8 node,Team team)
+{
+ if (!AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team))
+ sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team);
+
+ uint8 capturedNodes = 0;
+ for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ {
+ if (m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i])
+ ++capturedNodes;
+ }
+ if (capturedNodes >= 5)
+ CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team);
+ if (capturedNodes >= 4)
+ CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team);
+
+ if(node >= BG_AB_DYNAMIC_NODES_COUNT)//only dynamic nodes, no start points
+ return;
+ Creature* trigger = GetBGCreature(node+7);//0-6 spirit guides
+ if (!trigger)
+ trigger = AddCreature(WORLD_TRIGGER,node+7,team,BG_AB_NodePositions[node][0],BG_AB_NodePositions[node][1],BG_AB_NodePositions[node][2],BG_AB_NodePositions[node][3]);
+
+ //add bonus honor aura trigger creature when node is accupied
+ //cast bonus aura (+50% honor in 25yards)
+ //aura should only apply to players who have accupied the node, set correct faction for trigger
+ if (trigger)
+ {
+ trigger->setFaction(team == ALLIANCE ? 84 : 83);
+ trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false);
+ }
+}
+
+void BattleGroundAB::_NodeDeOccupied(uint8 node)
+{
+ if (node >= BG_AB_DYNAMIC_NODES_COUNT)
+ return;
+
+ //remove bonus honor aura trigger creature when node is lost
+ if(node < BG_AB_DYNAMIC_NODES_COUNT)//only dynamic nodes, no start points
+ DelCreature(node+7);//NULL checks are in DelCreature! 0-6 spirit guides
+
+ // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
+ std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]];
+ if (!ghost_list.empty())
+ {
+ WorldSafeLocsEntry const *ClosestGrave = NULL;
+ for (std::vector<uint64>::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
+ {
+ Player* plr = objmgr.GetPlayer(*itr);
+ if (!plr)
+ continue;
+
+ if (!ClosestGrave) // cache
+ ClosestGrave = GetClosestGraveYard(plr);
+
+ if (ClosestGrave)
+ plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
+ }
+ }
+
+ if (m_BgCreatures[node])
+ DelCreature(node);
+
+ // buff object isn't despawned
+}
+
+/* Invoked if a player used a banner as a gameobject */
+void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/)
+{
+ if (GetStatus() != STATUS_IN_PROGRESS)
+ return;
+
+ uint8 node = BG_AB_NODE_STABLES;
+ GameObject* obj=GetBgMap()->GetGameObject(m_BgObjects[node*8+7]);
+ while ((node < BG_AB_DYNAMIC_NODES_COUNT) && ((!obj) || (!source->IsWithinDistInMap(obj,10))))
+ {
+ ++node;
+ obj=GetBgMap()->GetGameObject(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]);
+ }
+
+ if (node == BG_AB_DYNAMIC_NODES_COUNT)
+ {
+ // this means our player isn't close to any of banners - maybe cheater ??
+ return;
+ }
+
+ BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(source->GetTeam());
+
+ // Check if player really could use this banner, not cheated
+ if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2))
+ return;
+
+ source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
+ uint32 sound = 0;
+ // If node is neutral, change to contested
+ if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL)
+ {
+ UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
+ m_prevNodes[node] = m_Nodes[node];
+ m_Nodes[node] = teamIndex + 1;
+ // burn current neutral banner
+ _DelBanner(node, BG_AB_NODE_TYPE_NEUTRAL, 0);
+ // create new contested banner
+ _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
+ _SendNodeUpdate(node);
+ m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
+
+ // FIXME: team and node names not localized
+ if (teamIndex == 0)
+ SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node), LANG_BG_AB_ALLY);
+ else
+ SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE);
+
+ sound = BG_AB_SOUND_NODE_CLAIMED;
+ }
+ // If node is contested
+ else if ((m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED))
+ {
+ // If last state is NOT occupied, change node to enemy-contested
+ if (m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED)
+ {
+ UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
+ m_prevNodes[node] = m_Nodes[node];
+ m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
+ // burn current contested banner
+ _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
+ // create new contested banner
+ _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
+ _SendNodeUpdate(node);
+ m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
+
+ // FIXME: node names not localized
+ if (teamIndex == BG_TEAM_ALLIANCE)
+ SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
+ else
+ SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
+ }
+ // If contested, change back to occupied
+ else
+ {
+ UpdatePlayerScore(source, SCORE_BASES_DEFENDED, 1);
+ m_prevNodes[node] = m_Nodes[node];
+ m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_OCCUPIED;
+ // burn current contested banner
+ _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
+ // create new occupied banner
+ _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
+ _SendNodeUpdate(node);
+ m_NodeTimers[node] = 0;
+ _NodeOccupied(node,(teamIndex == BG_TEAM_ALLIANCE) ? ALLIANCE:HORDE);
+
+ // FIXME: node names not localized
+ if (teamIndex == BG_TEAM_ALLIANCE)
+ SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
+ else
+ SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
+ }
+ sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
+ }
+ // If node is occupied, change to enemy-contested
+ else
+ {
+ UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
+ m_prevNodes[node] = m_Nodes[node];
+ m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
+ // burn current occupied banner
+ _DelBanner(node, BG_AB_NODE_TYPE_OCCUPIED, !teamIndex);
+ // create new contested banner
+ _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
+ _SendNodeUpdate(node);
+ _NodeDeOccupied(node);
+ m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
+
+ // FIXME: node names not localized
+ if (teamIndex == BG_TEAM_ALLIANCE)
+ SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
+ else
+ SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
+
+ sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
+ }
+
+ // If node is occupied again, send "X has taken the Y" msg.
+ if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED)
+ {
+ // FIXME: team and node names not localized
+ if (teamIndex == BG_TEAM_ALLIANCE)
+ SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node));
+ else
+ SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node));
+ }
+ PlaySoundToAll(sound);
+}
+
+bool BattleGroundAB::SetupBattleGround()
+{
+ for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ {
+ if (!AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + 8*i,BG_AB_OBJECTID_NODE_BANNER_0 + i,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AB_OBJECT_BANNER_CONT_A + 8*i,BG_AB_OBJECTID_BANNER_CONT_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AB_OBJECT_BANNER_CONT_H + 8*i,BG_AB_OBJECTID_BANNER_CONT_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AB_OBJECT_BANNER_ALLY + 8*i,BG_AB_OBJECTID_BANNER_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AB_OBJECT_BANNER_HORDE + 8*i,BG_AB_OBJECTID_BANNER_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AB_OBJECT_AURA_ALLY + 8*i,BG_AB_OBJECTID_AURA_A,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AB_OBJECT_AURA_HORDE + 8*i,BG_AB_OBJECTID_AURA_H,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AB_OBJECT_AURA_CONTESTED + 8*i,BG_AB_OBJECTID_AURA_C,BG_AB_NodePositions[i][0],BG_AB_NodePositions[i][1],BG_AB_NodePositions[i][2],BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2),RESPAWN_ONE_DAY)
+)
+ {
+ sLog.outErrorDb("BatteGroundAB: Failed to spawn some object BattleGround not created!");
+ return false;
+ }
+ }
+ if (!AddObject(BG_AB_OBJECT_GATE_A,BG_AB_OBJECTID_GATE_A,BG_AB_DoorPositions[0][0],BG_AB_DoorPositions[0][1],BG_AB_DoorPositions[0][2],BG_AB_DoorPositions[0][3],BG_AB_DoorPositions[0][4],BG_AB_DoorPositions[0][5],BG_AB_DoorPositions[0][6],BG_AB_DoorPositions[0][7],RESPAWN_IMMEDIATELY)
+ || !AddObject(BG_AB_OBJECT_GATE_H,BG_AB_OBJECTID_GATE_H,BG_AB_DoorPositions[1][0],BG_AB_DoorPositions[1][1],BG_AB_DoorPositions[1][2],BG_AB_DoorPositions[1][3],BG_AB_DoorPositions[1][4],BG_AB_DoorPositions[1][5],BG_AB_DoorPositions[1][6],BG_AB_DoorPositions[1][7],RESPAWN_IMMEDIATELY)
+)
+ {
+ sLog.outErrorDb("BatteGroundAB: Failed to spawn door object BattleGround not created!");
+ return false;
+ }
+ //buffs
+ for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ {
+ if (!AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
+ || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 1, Buff_Entries[1], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
+ || !AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 2, Buff_Entries[2], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY)
+)
+ sLog.outErrorDb("BatteGroundAB: Failed to spawn buff object!");
+ }
+
+ return true;
+}
+
+void BattleGroundAB::Reset()
+{
+ //call parent's class reset
+ BattleGround::Reset();
+
+ m_TeamScores[BG_TEAM_ALLIANCE] = 0;
+ m_TeamScores[BG_TEAM_HORDE] = 0;
+ m_lastTick[BG_TEAM_ALLIANCE] = 0;
+ m_lastTick[BG_TEAM_HORDE] = 0;
+ m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0;
+ m_HonorScoreTics[BG_TEAM_HORDE] = 0;
+ m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0;
+ m_ReputationScoreTics[BG_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;
+ m_TeamScores500Disadvantage[BG_TEAM_ALLIANCE] = false;
+ m_TeamScores500Disadvantage[BG_TEAM_HORDE] = false;
+
+ for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ {
+ m_Nodes[i] = 0;
+ m_prevNodes[i] = 0;
+ m_NodeTimers[i] = 0;
+ m_BannerTimers[i].timer = 0;
+ }
+
+ for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT + 5; ++i)//+5 for aura triggers
+ if (m_BgCreatures[i])
+ DelCreature(i);
+}
+
+void BattleGroundAB::EndBattleGround(uint32 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)
+{
+ BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(player->GetTeam());
+
+ // Is there any occupied node for this team?
+ std::vector<uint8> nodes;
+ for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ if (m_Nodes[i] == teamIndex + 3)
+ nodes.push_back(i);
+
+ WorldSafeLocsEntry const* good_entry = NULL;
+ // If so, select the closest node to place ghost on
+ if (!nodes.empty())
+ {
+ float plr_x = player->GetPositionX();
+ float plr_y = player->GetPositionY();
+
+ float mindist = 999999.0f;
+ for (uint8 i = 0; i < nodes.size(); ++i)
+ {
+ WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry(BG_AB_GraveyardIds[nodes[i]]);
+ if (!entry)
+ continue;
+ float dist = (entry->x - plr_x)*(entry->x - plr_x)+(entry->y - plr_y)*(entry->y - plr_y);
+ if (mindist > dist)
+ {
+ mindist = dist;
+ good_entry = entry;
+ }
+ }
+ nodes.clear();
+ }
+ // If not, place ghost on starting location
+ if (!good_entry)
+ good_entry = sWorldSafeLocsStore.LookupEntry(BG_AB_GraveyardIds[teamIndex+5]);
+
+ return good_entry;
+}
+
+void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value, bool doAddHonor)
+{
+ BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
+ if (itr == m_PlayerScores.end()) // player not found...
+ return;
+
+ switch(type)
+ {
+ case SCORE_BASES_ASSAULTED:
+ ((BattleGroundABScore*)itr->second)->BasesAssaulted += value;
+ break;
+ case SCORE_BASES_DEFENDED:
+ ((BattleGroundABScore*)itr->second)->BasesDefended += value;
+ break;
+ default:
+ BattleGround::UpdatePlayerScore(Source,type,value, doAddHonor);
+ break;
+ }
+}
+
+bool BattleGroundAB::IsAllNodesConrolledByTeam(uint32 team) const
+{
+ uint32 count = 0;
+ for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
+ if ((team == ALLIANCE && m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) ||
+ (team == HORDE && m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED))
+ ++count;
+
+ return count == BG_AB_DYNAMIC_NODES_COUNT;
+}