[8483] Implement glyph 43361.
[getmangos.git] / src / game / BattleGroundAB.cpp
blob8737b9395245b697ba6e6bcf40d9244b1916defb
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Object.h"
20 #include "Player.h"
21 #include "BattleGround.h"
22 #include "BattleGroundAB.h"
23 #include "Creature.h"
24 #include "ObjectMgr.h"
25 #include "Language.h"
26 #include "Util.h"
27 #include "WorldPacket.h"
29 BattleGroundAB::BattleGroundAB()
31 m_BuffChange = true;
32 m_BgObjects.resize(BG_AB_OBJECT_MAX);
33 m_BgCreatures.resize(BG_AB_ALL_NODES_COUNT);
35 m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AB_START_TWO_MINUTES;
36 m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AB_START_ONE_MINUTE;
37 m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AB_START_HALF_MINUTE;
38 m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AB_HAS_BEGUN;
41 BattleGroundAB::~BattleGroundAB()
45 void BattleGroundAB::Update(uint32 diff)
47 BattleGround::Update(diff);
49 if (GetStatus() == STATUS_IN_PROGRESS)
51 int team_points[BG_TEAMS_COUNT] = { 0, 0 };
53 for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
55 // 3 sec delay to spawn new banner instead previous despawned one
56 if (m_BannerTimers[node].timer)
58 if (m_BannerTimers[node].timer > diff)
59 m_BannerTimers[node].timer -= diff;
60 else
62 m_BannerTimers[node].timer = 0;
63 _CreateBanner(node, m_BannerTimers[node].type, m_BannerTimers[node].teamIndex, false);
67 // 1-minute to occupy a node from contested state
68 if (m_NodeTimers[node])
70 if (m_NodeTimers[node] > diff)
71 m_NodeTimers[node] -= diff;
72 else
74 m_NodeTimers[node] = 0;
75 // Change from contested to occupied !
76 uint8 teamIndex = m_Nodes[node]-1;
77 m_prevNodes[node] = m_Nodes[node];
78 m_Nodes[node] += 2;
79 // burn current contested banner
80 _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex);
81 // create new occupied banner
82 _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
83 _SendNodeUpdate(node);
84 _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
85 // Message to chatlog
87 if (teamIndex == 0)
89 // FIXME: team and node names not localized
90 SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE,NULL,LANG_BG_AB_ALLY,_GetNodeNameId(node));
91 PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_ALLIANCE);
93 else
95 // FIXME: team and node names not localized
96 SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE,NULL,LANG_BG_AB_HORDE,_GetNodeNameId(node));
97 PlaySoundToAll(BG_AB_SOUND_NODE_CAPTURED_HORDE);
102 for (int team = 0; team < BG_TEAMS_COUNT; ++team)
103 if (m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED)
104 ++team_points[team];
107 // Accumulate points
108 for (int team = 0; team < BG_TEAMS_COUNT; ++team)
110 int points = team_points[team];
111 if (!points)
112 continue;
113 m_lastTick[team] += diff;
114 if (m_lastTick[team] > BG_AB_TickIntervals[points])
116 m_lastTick[team] -= BG_AB_TickIntervals[points];
117 m_TeamScores[team] += BG_AB_TickPoints[points];
118 m_HonorScoreTics[team] += BG_AB_TickPoints[points];
119 m_ReputationScoreTics[team] += BG_AB_TickPoints[points];
120 if (m_ReputationScoreTics[team] >= m_ReputationTics)
122 (team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE);
123 m_ReputationScoreTics[team] -= m_ReputationTics;
125 if (m_HonorScoreTics[team] >= m_HonorTics)
127 RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE);
128 m_HonorScoreTics[team] -= m_HonorTics;
130 if (!m_IsInformedNearVictory && m_TeamScores[team] > BG_AB_WARNING_NEAR_VICTORY_SCORE)
132 if (team == BG_TEAM_ALLIANCE)
133 SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
134 else
135 SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
136 PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY);
137 m_IsInformedNearVictory = true;
140 if (m_TeamScores[team] > BG_AB_MAX_TEAM_SCORE)
141 m_TeamScores[team] = BG_AB_MAX_TEAM_SCORE;
142 if (team == BG_TEAM_ALLIANCE)
143 UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]);
144 if (team == BG_TEAM_HORDE)
145 UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]);
147 // update achievement flags
148 // we increased m_TeamScores[team] so we just need to check if it is 500 more than other teams resources
149 // horde will be a bit disadvantaged, but we can assume that points aren't updated for both team in same Update() call
150 uint8 otherTeam = (team + 1) % BG_TEAMS_COUNT;
151 if (m_TeamScores[team] > m_TeamScores[otherTeam] + 500)
152 m_TeamScores500Disadvantage[otherTeam] = true;
156 // Test win condition
157 if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE)
158 EndBattleGround(ALLIANCE);
159 if (m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE)
160 EndBattleGround(HORDE);
164 void BattleGroundAB::StartingEventCloseDoors()
166 // despawn banners, auras and buffs
167 for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj)
168 SpawnBGObject(obj, RESPAWN_ONE_DAY);
169 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i)
170 SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY);
172 // Starting doors
173 DoorClose(BG_AB_OBJECT_GATE_A);
174 DoorClose(BG_AB_OBJECT_GATE_H);
175 SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY);
176 SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY);
178 // Starting base spirit guides
179 _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE);
180 _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE);
183 void BattleGroundAB::StartingEventOpenDoors()
185 // spawn neutral banners
186 for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
187 SpawnBGObject(banner, RESPAWN_IMMEDIATELY);
188 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
190 //randomly select buff to spawn
191 uint8 buff = urand(0, 2);
192 SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY);
194 DoorOpen(BG_AB_OBJECT_GATE_A);
195 DoorOpen(BG_AB_OBJECT_GATE_H);
198 void BattleGroundAB::AddPlayer(Player *plr)
200 BattleGround::AddPlayer(plr);
201 //create score and add it to map, default values are set in the constructor
202 BattleGroundABScore* sc = new BattleGroundABScore;
204 m_PlayerScores[plr->GetGUID()] = sc;
207 void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
212 void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger)
214 if (GetStatus() != STATUS_IN_PROGRESS)
215 return;
217 switch(Trigger)
219 case 3948: // Arathi Basin Alliance Exit.
220 if (Source->GetTeam() != ALLIANCE)
221 Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
222 else
223 Source->LeaveBattleground();
224 break;
225 case 3949: // Arathi Basin Horde Exit.
226 if (Source->GetTeam() != HORDE)
227 Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
228 else
229 Source->LeaveBattleground();
230 break;
231 case 3866: // Stables
232 case 3869: // Gold Mine
233 case 3867: // Farm
234 case 3868: // Lumber Mill
235 case 3870: // Black Smith
236 case 4020: // Unk1
237 case 4021: // Unk2
238 //break;
239 default:
240 //sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
241 //Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
242 break;
246 /* type: 0-neutral, 1-contested, 3-occupied
247 teamIndex: 0-ally, 1-horde */
248 void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay)
250 // Just put it into the queue
251 if (delay)
253 m_BannerTimers[node].timer = 2000;
254 m_BannerTimers[node].type = type;
255 m_BannerTimers[node].teamIndex = teamIndex;
256 return;
259 uint8 obj = node*8 + type + teamIndex;
261 SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
263 // handle aura with banner
264 if (!type)
265 return;
266 obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
267 SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
270 void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)
272 uint8 obj = node*8 + type + teamIndex;
273 SpawnBGObject(obj, RESPAWN_ONE_DAY);
275 // handle aura with banner
276 if (!type)
277 return;
278 obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
279 SpawnBGObject(obj, RESPAWN_ONE_DAY);
282 int32 BattleGroundAB::_GetNodeNameId(uint8 node)
284 switch (node)
286 case BG_AB_NODE_STABLES: return LANG_BG_AB_NODE_STABLES;
287 case BG_AB_NODE_BLACKSMITH: return LANG_BG_AB_NODE_BLACKSMITH;
288 case BG_AB_NODE_FARM: return LANG_BG_AB_NODE_FARM;
289 case BG_AB_NODE_LUMBER_MILL:return LANG_BG_AB_NODE_LUMBER_MILL;
290 case BG_AB_NODE_GOLD_MINE: return LANG_BG_AB_NODE_GOLD_MINE;
291 default:
292 ASSERT(0);
294 return 0;
297 void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
299 const uint8 plusArray[] = {0, 2, 3, 0, 1};
301 // Node icons
302 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
303 data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node]==0)?1:0);
305 // Node occupied states
306 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
307 for (uint8 i = 1; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
308 data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node]==i)?1:0);
310 // How many bases each team owns
311 uint8 ally = 0, horde = 0;
312 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
313 if (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED)
314 ++ally;
315 else if (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
316 ++horde;
318 data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally);
319 data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde);
321 // Team scores
322 data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE);
323 data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_NEAR_VICTORY_SCORE);
324 data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]);
325 data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]);
327 // other unknown
328 data << uint32(0x745) << uint32(0x2); // 37 1861 unk
331 void BattleGroundAB::_SendNodeUpdate(uint8 node)
333 // Send node owner state update to refresh map icons on client
334 const uint8 plusArray[] = {0, 2, 3, 0, 1};
336 if (m_prevNodes[node])
337 UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0);
338 else
339 UpdateWorldState(BG_AB_OP_NODEICONS[node], 0);
341 UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1);
343 // How many bases each team owns
344 uint8 ally = 0, horde = 0;
345 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
346 if (m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED)
347 ++ally;
348 else if (m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
349 ++horde;
351 UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally);
352 UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, horde);
355 void BattleGroundAB::_NodeOccupied(uint8 node,Team team)
357 if (!AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team))
358 sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team);
359 // SpawnBGCreature(node,RESPAWN_IMMEDIATELY);
361 uint8 capturedNodes = 0;
362 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
364 if (m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i])
365 ++capturedNodes;
367 if (capturedNodes >= 5)
368 CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team);
369 if (capturedNodes >= 4)
370 CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team);
373 void BattleGroundAB::_NodeDeOccupied(uint8 node)
375 if (node >= BG_AB_DYNAMIC_NODES_COUNT)
376 return;
378 // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
379 std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]];
380 if (!ghost_list.empty())
382 WorldSafeLocsEntry const *ClosestGrave = NULL;
383 for (std::vector<uint64>::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
385 Player* plr = objmgr.GetPlayer(*itr);
386 if (!plr)
387 continue;
389 if (!ClosestGrave) // cache
390 ClosestGrave = GetClosestGraveYard(plr);
392 if (ClosestGrave)
393 plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
397 if (m_BgCreatures[node])
398 DelCreature(node);
400 // buff object isn't despawned
403 /* Invoked if a player used a banner as a gameobject */
404 void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/)
406 if (GetStatus() != STATUS_IN_PROGRESS)
407 return;
409 uint8 node = BG_AB_NODE_STABLES;
410 GameObject* obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+7]);
411 while ( (node < BG_AB_DYNAMIC_NODES_COUNT) && ((!obj) || (!source->IsWithinDistInMap(obj,10))))
413 ++node;
414 obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]);
417 if (node == BG_AB_DYNAMIC_NODES_COUNT)
419 // this means our player isn't close to any of banners - maybe cheater ??
420 return;
423 BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(source->GetTeam());
425 // Check if player really could use this banner, not cheated
426 if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2))
427 return;
429 source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
430 uint32 sound = 0;
431 // If node is neutral, change to contested
432 if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL)
434 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
435 m_prevNodes[node] = m_Nodes[node];
436 m_Nodes[node] = teamIndex + 1;
437 // burn current neutral banner
438 _DelBanner(node, BG_AB_NODE_TYPE_NEUTRAL, 0);
439 // create new contested banner
440 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
441 _SendNodeUpdate(node);
442 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
444 // FIXME: team and node names not localized
445 if (teamIndex == 0)
446 SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node), LANG_BG_AB_ALLY);
447 else
448 SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE);
450 sound = BG_AB_SOUND_NODE_CLAIMED;
452 // If node is contested
453 else if ((m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED))
455 // If last state is NOT occupied, change node to enemy-contested
456 if (m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED)
458 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
459 m_prevNodes[node] = m_Nodes[node];
460 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
461 // burn current contested banner
462 _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
463 // create new contested banner
464 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
465 _SendNodeUpdate(node);
466 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
468 // FIXME: node names not localized
469 if (teamIndex == BG_TEAM_ALLIANCE)
470 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
471 else
472 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
474 // If contested, change back to occupied
475 else
477 UpdatePlayerScore(source, SCORE_BASES_DEFENDED, 1);
478 m_prevNodes[node] = m_Nodes[node];
479 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_OCCUPIED;
480 // burn current contested banner
481 _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
482 // create new occupied banner
483 _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
484 _SendNodeUpdate(node);
485 m_NodeTimers[node] = 0;
486 _NodeOccupied(node,(teamIndex == BG_TEAM_ALLIANCE) ? ALLIANCE:HORDE);
488 // FIXME: node names not localized
489 if (teamIndex == BG_TEAM_ALLIANCE)
490 SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
491 else
492 SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
494 sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
496 // If node is occupied, change to enemy-contested
497 else
499 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
500 m_prevNodes[node] = m_Nodes[node];
501 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
502 // burn current occupied banner
503 _DelBanner(node, BG_AB_NODE_TYPE_OCCUPIED, !teamIndex);
504 // create new contested banner
505 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
506 _SendNodeUpdate(node);
507 _NodeDeOccupied(node);
508 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
510 // FIXME: node names not localized
511 if (teamIndex == BG_TEAM_ALLIANCE)
512 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
513 else
514 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
516 sound = (teamIndex == BG_TEAM_ALLIANCE) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
519 // If node is occupied again, send "X has taken the Y" msg.
520 if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED)
522 // FIXME: team and node names not localized
523 if (teamIndex == BG_TEAM_ALLIANCE)
524 SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node));
525 else
526 SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node));
528 PlaySoundToAll(sound);
531 bool BattleGroundAB::SetupBattleGround()
533 for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
535 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)
536 || !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)
537 || !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)
538 || !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)
539 || !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)
540 || !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)
541 || !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)
542 || !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)
545 sLog.outErrorDb("BatteGroundAB: Failed to spawn some object BattleGround not created!");
546 return false;
549 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)
550 || !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)
553 sLog.outErrorDb("BatteGroundAB: Failed to spawn door object BattleGround not created!");
554 return false;
556 //buffs
557 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
559 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)
560 || !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)
561 || !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)
563 sLog.outErrorDb("BatteGroundAB: Failed to spawn buff object!");
566 return true;
569 void BattleGroundAB::Reset()
571 //call parent's class reset
572 BattleGround::Reset();
574 m_TeamScores[BG_TEAM_ALLIANCE] = 0;
575 m_TeamScores[BG_TEAM_HORDE] = 0;
576 m_lastTick[BG_TEAM_ALLIANCE] = 0;
577 m_lastTick[BG_TEAM_HORDE] = 0;
578 m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0;
579 m_HonorScoreTics[BG_TEAM_HORDE] = 0;
580 m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0;
581 m_ReputationScoreTics[BG_TEAM_HORDE] = 0;
582 m_IsInformedNearVictory = false;
583 bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call!
584 m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks;
585 m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks;
586 m_TeamScores500Disadvantage[BG_TEAM_ALLIANCE] = false;
587 m_TeamScores500Disadvantage[BG_TEAM_HORDE] = false;
589 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
591 m_Nodes[i] = 0;
592 m_prevNodes[i] = 0;
593 m_NodeTimers[i] = 0;
594 m_BannerTimers[i].timer = 0;
597 for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT; ++i)
598 if (m_BgCreatures[i])
599 DelCreature(i);
602 void BattleGroundAB::EndBattleGround(uint32 winner)
604 //win reward
605 if (winner == ALLIANCE)
606 RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
607 if (winner == HORDE)
608 RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
609 //complete map_end rewards (even if no team wins)
610 RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
611 RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
613 BattleGround::EndBattleGround(winner);
616 WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player)
618 BattleGroundTeamId teamIndex = GetTeamIndexByTeamId(player->GetTeam());
620 // Is there any occupied node for this team?
621 std::vector<uint8> nodes;
622 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
623 if (m_Nodes[i] == teamIndex + 3)
624 nodes.push_back(i);
626 WorldSafeLocsEntry const* good_entry = NULL;
627 // If so, select the closest node to place ghost on
628 if (!nodes.empty())
630 float plr_x = player->GetPositionX();
631 float plr_y = player->GetPositionY();
633 float mindist = 999999.0f;
634 for (uint8 i = 0; i < nodes.size(); ++i)
636 WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[nodes[i]] );
637 if (!entry)
638 continue;
639 float dist = (entry->x - plr_x)*(entry->x - plr_x)+(entry->y - plr_y)*(entry->y - plr_y);
640 if (mindist > dist)
642 mindist = dist;
643 good_entry = entry;
646 nodes.clear();
648 // If not, place ghost on starting location
649 if (!good_entry)
650 good_entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[teamIndex+5] );
652 return good_entry;
655 void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
657 BattleGroundScoreMap::iterator itr = m_PlayerScores.find(Source->GetGUID());
658 if( itr == m_PlayerScores.end() ) // player not found...
659 return;
661 switch(type)
663 case SCORE_BASES_ASSAULTED:
664 ((BattleGroundABScore*)itr->second)->BasesAssaulted += value;
665 break;
666 case SCORE_BASES_DEFENDED:
667 ((BattleGroundABScore*)itr->second)->BasesDefended += value;
668 break;
669 default:
670 BattleGround::UpdatePlayerScore(Source,type,value);
671 break;
675 bool BattleGroundAB::IsAllNodesConrolledByTeam(uint32 team) const
677 uint32 count = 0;
678 for(int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
679 if ((team == ALLIANCE && m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) ||
680 (team == HORDE && m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED))
681 ++count;
683 return count == BG_AB_DYNAMIC_NODES_COUNT;