[7721] Fixed possible source crash at rogue stealth lost in some special cases.
[AHbot.git] / src / game / BattleGroundAB.cpp
blob65c2ea50102af414bc76c39cca3b7076f16f94fb
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]);
149 // Test win condition
150 if (m_TeamScores[BG_TEAM_ALLIANCE] >= BG_AB_MAX_TEAM_SCORE)
151 EndBattleGround(ALLIANCE);
152 if (m_TeamScores[BG_TEAM_HORDE] >= BG_AB_MAX_TEAM_SCORE)
153 EndBattleGround(HORDE);
157 void BattleGroundAB::StartingEventCloseDoors()
159 // despawn banners, auras and buffs
160 for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj)
161 SpawnBGObject(obj, RESPAWN_ONE_DAY);
162 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i)
163 SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY);
165 // Starting doors
166 DoorClose(BG_AB_OBJECT_GATE_A);
167 DoorClose(BG_AB_OBJECT_GATE_H);
168 SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY);
169 SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY);
171 // Starting base spirit guides
172 _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE);
173 _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE);
176 void BattleGroundAB::StartingEventOpenDoors()
178 // spawn neutral banners
179 for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
180 SpawnBGObject(banner, RESPAWN_IMMEDIATELY);
181 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
183 //randomly select buff to spawn
184 uint8 buff = urand(0, 2);
185 SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY);
187 DoorOpen(BG_AB_OBJECT_GATE_A);
188 DoorOpen(BG_AB_OBJECT_GATE_H);
191 void BattleGroundAB::AddPlayer(Player *plr)
193 BattleGround::AddPlayer(plr);
194 //create score and add it to map, default values are set in the constructor
195 BattleGroundABScore* sc = new BattleGroundABScore;
197 m_PlayerScores[plr->GetGUID()] = sc;
200 void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
205 void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger)
207 if (GetStatus() != STATUS_IN_PROGRESS)
208 return;
210 switch(Trigger)
212 case 3948: // Arathi Basin Alliance Exit.
213 if (Source->GetTeam() != ALLIANCE)
214 Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
215 else
216 Source->LeaveBattleground();
217 break;
218 case 3949: // Arathi Basin Horde Exit.
219 if (Source->GetTeam() != HORDE)
220 Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
221 else
222 Source->LeaveBattleground();
223 break;
224 case 3866: // Stables
225 case 3869: // Gold Mine
226 case 3867: // Farm
227 case 3868: // Lumber Mill
228 case 3870: // Black Smith
229 case 4020: // Unk1
230 case 4021: // Unk2
231 //break;
232 default:
233 //sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
234 //Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
235 break;
239 /* type: 0-neutral, 1-contested, 3-occupied
240 teamIndex: 0-ally, 1-horde */
241 void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay)
243 // Just put it into the queue
244 if (delay)
246 m_BannerTimers[node].timer = 2000;
247 m_BannerTimers[node].type = type;
248 m_BannerTimers[node].teamIndex = teamIndex;
249 return;
252 uint8 obj = node*8 + type + teamIndex;
254 SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
256 // handle aura with banner
257 if (!type)
258 return;
259 obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
260 SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
263 void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)
265 uint8 obj = node*8 + type + teamIndex;
266 SpawnBGObject(obj, RESPAWN_ONE_DAY);
268 // handle aura with banner
269 if (!type)
270 return;
271 obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
272 SpawnBGObject(obj, RESPAWN_ONE_DAY);
275 int32 BattleGroundAB::_GetNodeNameId(uint8 node)
277 switch (node)
279 case BG_AB_NODE_STABLES: return LANG_BG_AB_NODE_STABLES;
280 case BG_AB_NODE_BLACKSMITH: return LANG_BG_AB_NODE_BLACKSMITH;
281 case BG_AB_NODE_FARM: return LANG_BG_AB_NODE_FARM;
282 case BG_AB_NODE_LUMBER_MILL:return LANG_BG_AB_NODE_LUMBER_MILL;
283 case BG_AB_NODE_GOLD_MINE: return LANG_BG_AB_NODE_GOLD_MINE;
284 default:
285 ASSERT(0);
287 return 0;
290 void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
292 const uint8 plusArray[] = {0, 2, 3, 0, 1};
294 // Node icons
295 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
296 data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node]==0)?1:0);
298 // Node occupied states
299 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
300 for (uint8 i = 1; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
301 data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node]==i)?1:0);
303 // How many bases each team owns
304 uint8 ally = 0, horde = 0;
305 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
306 if (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED)
307 ++ally;
308 else if (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
309 ++horde;
311 data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally);
312 data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde);
314 // Team scores
315 data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE);
316 data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_NEAR_VICTORY_SCORE);
317 data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]);
318 data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]);
320 // other unknown
321 data << uint32(0x745) << uint32(0x2); // 37 1861 unk
324 void BattleGroundAB::_SendNodeUpdate(uint8 node)
326 // Send node owner state update to refresh map icons on client
327 const uint8 plusArray[] = {0, 2, 3, 0, 1};
329 if (m_prevNodes[node])
330 UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0);
331 else
332 UpdateWorldState(BG_AB_OP_NODEICONS[node], 0);
334 UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1);
336 // How many bases each team owns
337 uint8 ally = 0, horde = 0;
338 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
339 if (m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED)
340 ++ally;
341 else if (m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED)
342 ++horde;
344 UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally);
345 UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, horde);
348 void BattleGroundAB::_NodeOccupied(uint8 node,Team team)
350 if (!AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team))
351 sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team);
352 // SpawnBGCreature(node,RESPAWN_IMMEDIATELY);
354 uint8 capturedNodes = 0;
355 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
357 if (m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i])
358 ++capturedNodes;
360 if (capturedNodes >= 5)
361 CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team);
362 if (capturedNodes >= 4)
363 CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team);
366 void BattleGroundAB::_NodeDeOccupied(uint8 node)
368 if (node >= BG_AB_DYNAMIC_NODES_COUNT)
369 return;
371 // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
372 std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]];
373 if (!ghost_list.empty())
375 WorldSafeLocsEntry const *ClosestGrave = NULL;
376 for (std::vector<uint64>::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
378 Player* plr = objmgr.GetPlayer(*itr);
379 if (!plr)
380 continue;
382 if (!ClosestGrave) // cache
383 ClosestGrave = GetClosestGraveYard(plr);
385 if (ClosestGrave)
386 plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
390 if (m_BgCreatures[node])
391 DelCreature(node);
393 // buff object isn't despawned
396 /* Invoked if a player used a banner as a gameobject */
397 void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/)
399 if (GetStatus() != STATUS_IN_PROGRESS)
400 return;
402 uint8 node = BG_AB_NODE_STABLES;
403 GameObject* obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+7]);
404 while ( (node < BG_AB_DYNAMIC_NODES_COUNT) && ((!obj) || (!source->IsWithinDistInMap(obj,10))))
406 ++node;
407 obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]);
410 if (node == BG_AB_DYNAMIC_NODES_COUNT)
412 // this means our player isn't close to any of banners - maybe cheater ??
413 return;
416 uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam());
418 // Check if player really could use this banner, not cheated
419 if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2))
420 return;
422 source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
423 uint32 sound = 0;
424 // If node is neutral, change to contested
425 if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL)
427 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
428 m_prevNodes[node] = m_Nodes[node];
429 m_Nodes[node] = teamIndex + 1;
430 // burn current neutral banner
431 _DelBanner(node, BG_AB_NODE_TYPE_NEUTRAL, 0);
432 // create new contested banner
433 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
434 _SendNodeUpdate(node);
435 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
437 // FIXME: team and node names not localized
438 if (teamIndex == 0)
439 SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node), LANG_BG_AB_ALLY);
440 else
441 SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE);
443 sound = BG_AB_SOUND_NODE_CLAIMED;
445 // If node is contested
446 else if ((m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED))
448 // If last state is NOT occupied, change node to enemy-contested
449 if (m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED)
451 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
452 m_prevNodes[node] = m_Nodes[node];
453 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
454 // burn current contested banner
455 _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
456 // create new contested banner
457 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
458 _SendNodeUpdate(node);
459 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
461 // FIXME: node names not localized
462 if (teamIndex == 0)
463 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
464 else
465 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
467 // If contested, change back to occupied
468 else
470 UpdatePlayerScore(source, SCORE_BASES_DEFENDED, 1);
471 m_prevNodes[node] = m_Nodes[node];
472 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_OCCUPIED;
473 // burn current contested banner
474 _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
475 // create new occupied banner
476 _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
477 _SendNodeUpdate(node);
478 m_NodeTimers[node] = 0;
479 _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
481 // FIXME: node names not localized
482 if (teamIndex == 0)
483 SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
484 else
485 SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
487 sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
489 // If node is occupied, change to enemy-contested
490 else
492 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
493 m_prevNodes[node] = m_Nodes[node];
494 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
495 // burn current occupied banner
496 _DelBanner(node, BG_AB_NODE_TYPE_OCCUPIED, !teamIndex);
497 // create new contested banner
498 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
499 _SendNodeUpdate(node);
500 _NodeDeOccupied(node);
501 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
503 // FIXME: node names not localized
504 if (teamIndex == 0)
505 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node));
506 else
507 SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node));
509 sound = (teamIndex == 0) ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
512 // If node is occupied again, send "X has taken the Y" msg.
513 if (m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED)
515 // FIXME: team and node names not localized
516 if (teamIndex == 0)
517 SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node));
518 else
519 SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node));
521 PlaySoundToAll(sound);
524 bool BattleGroundAB::SetupBattleGround()
526 for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
528 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)
529 || !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)
530 || !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)
531 || !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)
532 || !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)
533 || !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)
534 || !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)
535 || !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)
538 sLog.outErrorDb("BatteGroundAB: Failed to spawn some object BattleGround not created!");
539 return false;
542 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)
543 || !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)
546 sLog.outErrorDb("BatteGroundAB: Failed to spawn door object BattleGround not created!");
547 return false;
549 //buffs
550 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
552 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)
553 || !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)
554 || !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)
556 sLog.outErrorDb("BatteGroundAB: Failed to spawn buff object!");
559 return true;
562 void BattleGroundAB::Reset()
564 //call parent's class reset
565 BattleGround::Reset();
567 m_TeamScores[BG_TEAM_ALLIANCE] = 0;
568 m_TeamScores[BG_TEAM_HORDE] = 0;
569 m_lastTick[BG_TEAM_ALLIANCE] = 0;
570 m_lastTick[BG_TEAM_HORDE] = 0;
571 m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0;
572 m_HonorScoreTics[BG_TEAM_HORDE] = 0;
573 m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0;
574 m_ReputationScoreTics[BG_TEAM_HORDE] = 0;
575 m_IsInformedNearVictory = false;
576 bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call!
577 m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks;
578 m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks;
580 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
582 m_Nodes[i] = 0;
583 m_prevNodes[i] = 0;
584 m_NodeTimers[i] = 0;
585 m_BannerTimers[i].timer = 0;
588 for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT; ++i)
589 if (m_BgCreatures[i])
590 DelCreature(i);
593 void BattleGroundAB::EndBattleGround(uint32 winner)
595 //win reward
596 if (winner == ALLIANCE)
597 RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
598 if (winner == HORDE)
599 RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
600 //complete map_end rewards (even if no team wins)
601 RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE);
602 RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE);
604 BattleGround::EndBattleGround(winner);
607 WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player)
609 uint8 teamIndex = GetTeamIndexByTeamId(player->GetTeam());
611 // Is there any occupied node for this team?
612 std::vector<uint8> nodes;
613 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
614 if (m_Nodes[i] == teamIndex + 3)
615 nodes.push_back(i);
617 WorldSafeLocsEntry const* good_entry = NULL;
618 // If so, select the closest node to place ghost on
619 if (!nodes.empty())
621 float plr_x = player->GetPositionX();
622 float plr_y = player->GetPositionY();
624 float mindist = 999999.0f;
625 for (uint8 i = 0; i < nodes.size(); ++i)
627 WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[nodes[i]] );
628 if (!entry)
629 continue;
630 float dist = (entry->x - plr_x)*(entry->x - plr_x)+(entry->y - plr_y)*(entry->y - plr_y);
631 if (mindist > dist)
633 mindist = dist;
634 good_entry = entry;
637 nodes.clear();
639 // If not, place ghost on starting location
640 if (!good_entry)
641 good_entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[teamIndex+5] );
643 return good_entry;
646 void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
648 std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
650 if( itr == m_PlayerScores.end() ) // player not found...
651 return;
653 switch(type)
655 case SCORE_BASES_ASSAULTED:
656 ((BattleGroundABScore*)itr->second)->BasesAssaulted += value;
657 break;
658 case SCORE_BASES_DEFENDED:
659 ((BattleGroundABScore*)itr->second)->BasesDefended += value;
660 break;
661 default:
662 BattleGround::UpdatePlayerScore(Source,type,value);
663 break;