[7297] Fixed profession spells sorting in trainer spell list at client.
[getmangos.git] / src / game / BattleGroundAB.cpp
blob9c6c040e0aa4fa9c615ba39c9cb73e5eeadd62c0
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 "Chat.h"
25 #include "ObjectMgr.h"
26 #include "MapManager.h"
27 #include "Language.h"
28 #include "Util.h"
29 #include "WorldPacket.h"
31 BattleGroundAB::BattleGroundAB()
33 m_BuffChange = true;
34 m_BgObjects.resize(BG_AB_OBJECT_MAX);
35 m_BgCreatures.resize(BG_AB_ALL_NODES_COUNT);
38 BattleGroundAB::~BattleGroundAB()
42 void BattleGroundAB::Update(uint32 diff)
44 BattleGround::Update(diff);
46 if( GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize() )
48 ModifyStartDelayTime(diff);
50 if( !(m_Events & 0x01) )
52 m_Events |= 0x01;
54 // setup here, only when at least one player has ported to the map
55 if(!SetupBattleGround())
57 EndNow();
58 return;
61 sLog.outDebug("Arathi Basin: entering state STATUS_WAIT_JOIN ...");
63 // despawn banners, auras and buffs
64 for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj)
65 SpawnBGObject(obj, RESPAWN_ONE_DAY);
66 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i)
67 SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY);
69 // Starting doors
70 SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY);
71 SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY);
72 DoorClose(BG_AB_OBJECT_GATE_A);
73 DoorClose(BG_AB_OBJECT_GATE_H);
75 // Starting base spirit guides
76 _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE);
77 _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE);
79 SetStartDelayTime(START_DELAY0);
81 // After 1 minute, warning is signalled
82 else if( GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04) )
84 m_Events |= 0x04;
85 SendMessageToAll(GetMangosString(LANG_BG_AB_ONEMINTOSTART));
87 // After 1,5 minute, warning is signalled
88 else if( GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08) )
90 m_Events |= 0x08;
91 SendMessageToAll(GetMangosString(LANG_BG_AB_HALFMINTOSTART));
93 // After 2 minutes, gates OPEN ! x)
94 else if( GetStartDelayTime() < 0 && !(m_Events & 0x10) )
96 m_Events |= 0x10;
97 SendMessageToAll(GetMangosString(LANG_BG_AB_STARTED));
99 // spawn neutral banners
100 for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i)
101 SpawnBGObject(banner, RESPAWN_IMMEDIATELY);
102 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
104 //randomly select buff to spawn
105 uint8 buff = urand(0, 2);
106 SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY);
108 DoorOpen(BG_AB_OBJECT_GATE_A);
109 DoorOpen(BG_AB_OBJECT_GATE_H);
111 PlaySoundToAll(SOUND_BG_START);
112 SetStatus(STATUS_IN_PROGRESS);
114 for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
115 if(Player* plr = objmgr.GetPlayer(itr->first))
116 plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
120 else if( GetStatus() == STATUS_IN_PROGRESS )
122 int team_points[2] = { 0, 0 };
124 for (int node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
126 // 3 sec delay to spawn new banner instead previous despawned one
127 if( m_BannerTimers[node].timer )
129 if( m_BannerTimers[node].timer > diff )
130 m_BannerTimers[node].timer -= diff;
131 else
133 m_BannerTimers[node].timer = 0;
134 _CreateBanner(node, m_BannerTimers[node].type, m_BannerTimers[node].teamIndex, false);
138 // 1-minute to occupy a node from contested state
139 if( m_NodeTimers[node] )
141 if( m_NodeTimers[node] > diff )
142 m_NodeTimers[node] -= diff;
143 else
145 m_NodeTimers[node] = 0;
146 // Change from contested to occupied !
147 uint8 teamIndex = m_Nodes[node]-1;
148 m_prevNodes[node] = m_Nodes[node];
149 m_Nodes[node] += 2;
150 // burn current contested banner
151 _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex);
152 // create new occupied banner
153 _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
154 _SendNodeUpdate(node);
155 _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
156 // Message to chatlog
157 char buf[256];
158 uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
159 sprintf(buf, GetMangosString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE), _GetNodeName(node));
160 WorldPacket data;
161 ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL);
162 SendPacketToAll(&data);
163 PlaySoundToAll((teamIndex == 0) ? SOUND_NODE_CAPTURED_ALLIANCE : SOUND_NODE_CAPTURED_HORDE);
167 for (int team = 0; team < 2; ++team)
168 if( m_Nodes[node] == team + BG_AB_NODE_TYPE_OCCUPIED )
169 ++team_points[team];
172 // Accumulate points
173 for (int team = 0; team < 2; ++team)
175 int points = team_points[team];
176 if( !points )
177 continue;
178 m_lastTick[team] += diff;
179 if( m_lastTick[team] > BG_AB_TickIntervals[points] )
181 m_lastTick[team] -= BG_AB_TickIntervals[points];
182 m_TeamScores[team] += BG_AB_TickPoints[points];
183 m_HonorScoreTics[team] += BG_AB_TickPoints[points];
184 m_ReputationScoreTics[team] += BG_AB_TickPoints[points];
185 if( m_ReputationScoreTics[team] >= 200 )
187 (team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE);
188 m_ReputationScoreTics[team] -= 200;
190 if( m_HonorScoreTics[team] >= BG_HONOR_SCORE_TICKS )
192 (team == BG_TEAM_ALLIANCE) ? RewardHonorToTeam(20, ALLIANCE) : RewardHonorToTeam(20, HORDE);
193 m_HonorScoreTics[team] -= BG_HONOR_SCORE_TICKS;
195 if( !m_IsInformedNearVictory && m_TeamScores[team] > 1800 )
197 if( team == BG_TEAM_ALLIANCE )
198 SendMessageToAll(GetMangosString(LANG_BG_AB_A_NEAR_VICTORY));
199 else
200 SendMessageToAll(GetMangosString(LANG_BG_AB_H_NEAR_VICTORY));
201 PlaySoundToAll(SOUND_NEAR_VICTORY);
202 m_IsInformedNearVictory = true;
205 if( m_TeamScores[team] > 2000 )
206 m_TeamScores[team] = 2000;
207 if( team == BG_TEAM_ALLIANCE )
208 UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]);
209 if( team == BG_TEAM_HORDE )
210 UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]);
214 // Test win condition
215 if( m_TeamScores[BG_TEAM_ALLIANCE] >= 2000 )
216 EndBattleGround(ALLIANCE);
217 if( m_TeamScores[BG_TEAM_HORDE] >= 2000 )
218 EndBattleGround(HORDE);
222 void BattleGroundAB::AddPlayer(Player *plr)
224 BattleGround::AddPlayer(plr);
225 //create score and add it to map, default values are set in the constructor
226 BattleGroundABScore* sc = new BattleGroundABScore;
228 m_PlayerScores[plr->GetGUID()] = sc;
231 void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/)
236 void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger)
238 if( GetStatus() != STATUS_IN_PROGRESS )
239 return;
241 switch(Trigger)
243 case 3948: // Arathi Basin Alliance Exit.
244 if( Source->GetTeam() != ALLIANCE )
245 Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
246 else
247 Source->LeaveBattleground();
248 break;
249 case 3949: // Arathi Basin Horde Exit.
250 if( Source->GetTeam() != HORDE )
251 Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
252 else
253 Source->LeaveBattleground();
254 break;
255 case 3866: // Stables
256 case 3869: // Gold Mine
257 case 3867: // Farm
258 case 3868: // Lumber Mill
259 case 3870: // Black Smith
260 case 4020: // Unk1
261 case 4021: // Unk2
262 //break;
263 default:
264 //sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
265 //Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
266 break;
270 /* type: 0-neutral, 1-contested, 3-occupied
271 teamIndex: 0-ally, 1-horde */
272 void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay)
274 // Just put it into the queue
275 if( delay )
277 m_BannerTimers[node].timer = 2000;
278 m_BannerTimers[node].type = type;
279 m_BannerTimers[node].teamIndex = teamIndex;
280 return;
283 uint8 obj = node*8 + type + teamIndex;
285 SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
287 // handle aura with banner
288 if( !type )
289 return;
290 obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
291 SpawnBGObject(obj, RESPAWN_IMMEDIATELY);
294 void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)
296 uint8 obj = node*8 + type + teamIndex;
297 SpawnBGObject(obj, RESPAWN_ONE_DAY);
299 // handle aura with banner
300 if( !type )
301 return;
302 obj = node * 8 + ((type == BG_AB_NODE_TYPE_OCCUPIED) ? (5 + teamIndex) : 7);
303 SpawnBGObject(obj, RESPAWN_ONE_DAY);
306 const char* BattleGroundAB::_GetNodeName(uint8 node)
308 switch (node)
310 case BG_AB_NODE_STABLES:
311 return GetMangosString(LANG_BG_AB_NODE_STABLES);
312 case BG_AB_NODE_BLACKSMITH:
313 return GetMangosString(LANG_BG_AB_NODE_BLACKSMITH);
314 case BG_AB_NODE_FARM:
315 return GetMangosString(LANG_BG_AB_NODE_FARM);
316 case BG_AB_NODE_LUMBER_MILL:
317 return GetMangosString(LANG_BG_AB_NODE_LUMBER_MILL);
318 case BG_AB_NODE_GOLD_MINE:
319 return GetMangosString(LANG_BG_AB_NODE_GOLD_MINE);
320 default:
321 ASSERT(0);
323 return "";
326 void BattleGroundAB::FillInitialWorldStates(WorldPacket& data)
328 const uint8 plusArray[] = {0, 2, 3, 0, 1};
330 // Node icons
331 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
332 data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node]==0)?1:0);
334 // Node occupied states
335 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
336 for (uint8 i = 1; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
337 data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node]==i)?1:0);
339 // How many bases each team owns
340 uint8 ally = 0, horde = 0;
341 for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
342 if( m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED )
343 ++ally;
344 else if( m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED )
345 ++horde;
347 data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally);
348 data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde);
350 // Team scores
351 data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE);
352 data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_SCORE);
353 data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]);
354 data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]);
356 // other unknown
357 data << uint32(0x745) << uint32(0x2); // 37 1861 unk
360 void BattleGroundAB::_SendNodeUpdate(uint8 node)
362 // Send node owner state update to refresh map icons on client
363 const uint8 plusArray[] = {0, 2, 3, 0, 1};
365 if( m_prevNodes[node] )
366 UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0);
367 else
368 UpdateWorldState(BG_AB_OP_NODEICONS[node], 0);
370 UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1);
372 // How many bases each team owns
373 uint8 ally = 0, horde = 0;
374 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
375 if( m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED )
376 ++ally;
377 else if( m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED )
378 ++horde;
380 UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally);
381 UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, horde);
384 void BattleGroundAB::_NodeOccupied(uint8 node,Team team)
386 if( !AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], team) )
387 sLog.outError("Failed to spawn spirit guide! point: %u, team: %u,", node, team);
388 // SpawnBGCreature(node,RESPAWN_IMMEDIATELY);
390 uint8 capturedNodes = 0;
391 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
393 if( m_Nodes[node] == GetTeamIndexByTeamId(team) + BG_AB_NODE_TYPE_OCCUPIED && !m_NodeTimers[i])
394 ++capturedNodes;
396 if(capturedNodes >= 5)
397 CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, team);
398 if(capturedNodes >= 4)
399 CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, team);
402 void BattleGroundAB::_NodeDeOccupied(uint8 node)
404 if( node >= BG_AB_DYNAMIC_NODES_COUNT)
405 return;
407 // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard
408 std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]];
409 if( !ghost_list.empty() )
411 WorldSafeLocsEntry const *ClosestGrave = NULL;
412 Player *plr;
413 for (std::vector<uint64>::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
415 plr = objmgr.GetPlayer(*itr);
416 if( !plr )
417 continue;
418 if( !ClosestGrave )
419 ClosestGrave = GetClosestGraveYard(plr->GetPositionX(), plr->GetPositionY(), plr->GetPositionZ(), plr->GetTeam());
421 plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
425 if( m_BgCreatures[node] )
426 DelCreature(node);
428 // buff object isn't despawned
431 /* Invoked if a player used a banner as a gameobject */
432 void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*target_obj*/)
434 if( GetStatus() != STATUS_IN_PROGRESS )
435 return;
437 uint8 node = BG_AB_NODE_STABLES;
438 GameObject* obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+7]);
439 while ( (node < BG_AB_DYNAMIC_NODES_COUNT) && ((!obj) || (!source->IsWithinDistInMap(obj,10))))
441 ++node;
442 obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]);
445 if( node == BG_AB_DYNAMIC_NODES_COUNT)
447 // this means our player isn't close to any of banners - maybe cheater ??
448 return;
451 uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam());
453 // Message to chatlog
454 char buf[256];
455 uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE;
457 // Check if player really could use this banner, not cheated
458 if( !(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2) )
459 return;
461 source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
462 uint32 sound = 0;
463 // If node is neutral, change to contested
464 if( m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL )
466 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
467 m_prevNodes[node] = m_Nodes[node];
468 m_Nodes[node] = teamIndex + 1;
469 // burn current neutral banner
470 _DelBanner(node, BG_AB_NODE_TYPE_NEUTRAL, 0);
471 // create new contested banner
472 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
473 _SendNodeUpdate(node);
474 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
475 sprintf(buf, GetMangosString(LANG_BG_AB_NODE_CLAIMED), _GetNodeName(node), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE));
476 sound = SOUND_NODE_CLAIMED;
478 // If node is contested
479 else if( (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_CONTESTED) || (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_CONTESTED) )
481 // If last state is NOT occupied, change node to enemy-contested
482 if( m_prevNodes[node] < BG_AB_NODE_TYPE_OCCUPIED )
484 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
485 m_prevNodes[node] = m_Nodes[node];
486 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
487 // burn current contested banner
488 _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
489 // create new contested banner
490 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
491 _SendNodeUpdate(node);
492 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
493 sprintf(buf, GetMangosString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node));
495 // If contested, change back to occupied
496 else
498 UpdatePlayerScore(source, SCORE_BASES_DEFENDED, 1);
499 m_prevNodes[node] = m_Nodes[node];
500 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_OCCUPIED;
501 // burn current contested banner
502 _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex);
503 // create new occupied banner
504 _CreateBanner(node, BG_AB_NODE_TYPE_OCCUPIED, teamIndex, true);
505 _SendNodeUpdate(node);
506 m_NodeTimers[node] = 0;
507 _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE);
508 sprintf(buf, GetMangosString(LANG_BG_AB_NODE_DEFENDED), _GetNodeName(node));
510 sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE;
512 // If node is occupied, change to enemy-contested
513 else
515 UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1);
516 m_prevNodes[node] = m_Nodes[node];
517 m_Nodes[node] = teamIndex + BG_AB_NODE_TYPE_CONTESTED;
518 // burn current occupied banner
519 _DelBanner(node, BG_AB_NODE_TYPE_OCCUPIED, !teamIndex);
520 // create new contested banner
521 _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true);
522 _SendNodeUpdate(node);
523 _NodeDeOccupied(node);
524 m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME;
525 sprintf(buf, GetMangosString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node));
526 sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE;
528 WorldPacket data;
529 ChatHandler::FillMessageData(&data, source->GetSession(), type, LANG_UNIVERSAL, NULL, source->GetGUID(), buf, NULL);
530 SendPacketToAll(&data);
531 // If node is occupied again, send "X has taken the Y" msg.
532 if( m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED )
534 sprintf(buf, GetMangosString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE), _GetNodeName(node));
535 ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL);
536 SendPacketToAll(&data);
538 PlaySoundToAll(sound);
541 bool BattleGroundAB::SetupBattleGround()
543 for (int i = 0 ; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
545 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)
546 || !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)
547 || !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)
548 || !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)
549 || !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)
550 || !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)
551 || !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)
552 || !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)
555 sLog.outErrorDb("BatteGroundAB: Failed to spawn some object BattleGround not created!");
556 return false;
559 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)
560 || !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)
563 sLog.outErrorDb("BatteGroundAB: Failed to spawn door object BattleGround not created!");
564 return false;
566 //buffs
567 for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
569 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)
570 || !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)
571 || !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)
573 sLog.outErrorDb("BatteGroundAB: Failed to spawn buff object!");
576 return true;
579 void BattleGroundAB::Reset()
581 //call parent's class reset
582 BattleGround::Reset();
584 m_TeamScores[BG_TEAM_ALLIANCE] = 0;
585 m_TeamScores[BG_TEAM_HORDE] = 0;
586 m_lastTick[BG_TEAM_ALLIANCE] = 0;
587 m_lastTick[BG_TEAM_HORDE] = 0;
588 m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0;
589 m_HonorScoreTics[BG_TEAM_HORDE] = 0;
590 m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0;
591 m_ReputationScoreTics[BG_TEAM_HORDE] = 0;
592 m_IsInformedNearVictory = false;
593 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
595 m_Nodes[i] = 0;
596 m_prevNodes[i] = 0;
597 m_NodeTimers[i] = 0;
598 m_BannerTimers[i].timer = 0;
601 for (uint8 i = 0; i < BG_AB_ALL_NODES_COUNT; ++i)
602 if(m_BgCreatures[i])
603 DelCreature(i);
606 WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(float x, float y, float /*z*/, uint32 team)
608 uint8 teamIndex = GetTeamIndexByTeamId(team);
610 // Is there any occupied node for this team?
611 std::vector<uint8> nodes;
612 for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
613 if( m_Nodes[i] == teamIndex + 3 )
614 nodes.push_back(i);
616 WorldSafeLocsEntry const* good_entry = NULL;
617 // If so, select the closest node to place ghost on
618 if( !nodes.empty() )
620 float mindist = 999999.0f;
621 for (uint8 i = 0; i < nodes.size(); ++i)
623 WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[nodes[i]] );
624 if( !entry )
625 continue;
626 float dist = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y);
627 if( mindist > dist )
629 mindist = dist;
630 good_entry = entry;
633 nodes.clear();
635 // If not, place ghost on starting location
636 if( !good_entry )
637 good_entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[teamIndex+5] );
639 return good_entry;
642 void BattleGroundAB::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
644 std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
646 if( itr == m_PlayerScores.end() ) // player not found...
647 return;
649 switch(type)
651 case SCORE_BASES_ASSAULTED:
652 ((BattleGroundABScore*)itr->second)->BasesAssaulted += value;
653 break;
654 case SCORE_BASES_DEFENDED:
655 ((BattleGroundABScore*)itr->second)->BasesDefended += value;
656 break;
657 default:
658 BattleGround::UpdatePlayerScore(Source,type,value);
659 break;