[7770] Prevent access to possible deleted aura's spell proto in Aura::HandleModStealth.
[AHbot.git] / src / game / BattleGroundMgr.cpp
blob2f162bf02910e8fd917d4818a8379c0eb66632bf
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 "Common.h"
20 #include "SharedDefines.h"
21 #include "Player.h"
22 #include "BattleGroundMgr.h"
23 #include "BattleGroundAV.h"
24 #include "BattleGroundAB.h"
25 #include "BattleGroundEY.h"
26 #include "BattleGroundWS.h"
27 #include "BattleGroundNA.h"
28 #include "BattleGroundBE.h"
29 #include "BattleGroundAA.h"
30 #include "BattleGroundRL.h"
31 #include "BattleGroundSA.h"
32 #include "BattleGroundDS.h"
33 #include "BattleGroundRV.h"
34 #include "MapManager.h"
35 #include "Map.h"
36 #include "MapInstanced.h"
37 #include "ObjectMgr.h"
38 #include "ProgressBar.h"
39 #include "Chat.h"
40 #include "ArenaTeam.h"
41 #include "World.h"
42 #include "WorldPacket.h"
43 #include "ProgressBar.h"
45 #include "Policies/SingletonImp.h"
47 INSTANTIATE_SINGLETON_1( BattleGroundMgr );
49 /*********************************************************/
50 /*** BATTLEGROUND QUEUE SYSTEM ***/
51 /*********************************************************/
53 BattleGroundQueue::BattleGroundQueue()
55 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
57 for(uint32 j = 0; j < MAX_BATTLEGROUND_QUEUES; j++)
59 m_SumOfWaitTimes[i][j] = 0;
60 m_WaitTimeLastPlayer[i][j] = 0;
61 for(uint32 k = 0; k < COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME; k++)
62 m_WaitTimes[i][j][k] = 0;
67 BattleGroundQueue::~BattleGroundQueue()
69 m_QueuedPlayers.clear();
70 for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
72 for(uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; j++)
74 for(GroupsQueueType::iterator itr = m_QueuedGroups[i][j].begin(); itr!= m_QueuedGroups[i][j].end(); ++itr)
75 delete (*itr);
76 m_QueuedGroups[i][j].clear();
81 /*********************************************************/
82 /*** BATTLEGROUND QUEUE SELECTION POOLS ***/
83 /*********************************************************/
85 // selection pool initialization, used to clean up from prev selection
86 void BattleGroundQueue::SelectionPool::Init()
88 SelectedGroups.clear();
89 PlayerCount = 0;
92 // remove group info from selection pool
93 // returns true when we need to try to add new group to selection pool
94 // returns false when selection pool is ok or when we kicked smaller group than we need to kick
95 // sometimes it can be called on empty selection pool
96 bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size)
98 //find maxgroup or LAST group with size == size and kick it
99 bool found = false;
100 GroupsQueueType::iterator groupToKick = SelectedGroups.begin();
101 for (GroupsQueueType::iterator itr = groupToKick; itr != SelectedGroups.end(); ++itr)
103 if (abs((int32)((*itr)->Players.size() - size)) <= 1)
105 groupToKick = itr;
106 found = true;
108 else if (!found && (*itr)->Players.size() >= (*groupToKick)->Players.size())
109 groupToKick = itr;
111 //if pool is empty, do nothing
112 if (GetPlayerCount())
114 //update player count
115 GroupQueueInfo* ginfo = (*groupToKick);
116 SelectedGroups.erase(groupToKick);
117 PlayerCount -= ginfo->Players.size();
118 //return false if we kicked smaller group or there are enough players in selection pool
119 if (ginfo->Players.size() <= size + 1)
120 return false;
122 return true;
125 // add group to selection pool
126 // used when building selection pools
127 // returns true if we can invite more players, or when we added group to selection pool
128 // returns false when selection pool is full
129 bool BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount)
131 //if group is larger than desired count - don't allow to add it to pool
132 if (!ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size())
134 SelectedGroups.push_back(ginfo);
135 // increase selected players count
136 PlayerCount += ginfo->Players.size();
137 return true;
139 if (PlayerCount < desiredCount)
140 return true;
141 return false;
144 /*********************************************************/
145 /*** BATTLEGROUND QUEUES ***/
146 /*********************************************************/
148 // add group to bg queue with the given leader and bg specifications
149 GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId BgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 arenateamid)
151 BGQueueIdBasedOnLevel queue_id = leader->GetBattleGroundQueueIdFromLevel(BgTypeId);
153 // create new ginfo
154 // cannot use the method like in addplayer, because that could modify an in-queue group's stats
155 // (e.g. leader leaving queue then joining as individual again)
156 GroupQueueInfo* ginfo = new GroupQueueInfo;
157 ginfo->BgTypeId = BgTypeId;
158 ginfo->ArenaType = ArenaType;
159 ginfo->ArenaTeamId = arenateamid;
160 ginfo->IsRated = isRated;
161 ginfo->IsInvitedToBGInstanceGUID = 0;
162 ginfo->JoinTime = getMSTime();
163 ginfo->RemoveInviteTime = 0;
164 ginfo->Team = leader->GetTeam();
165 ginfo->ArenaTeamRating = arenaRating;
166 ginfo->OpponentsTeamRating = 0;
168 ginfo->Players.clear();
170 //compute index (if group is premade or joined a rated match) to queues
171 uint32 index = 0;
172 if (!isRated && !isPremade)
173 index += BG_TEAMS_COUNT;
174 if (ginfo->Team == HORDE)
175 index++;
176 sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index);
178 m_QueuedGroups[queue_id][index].push_back(ginfo);
180 // return ginfo, because it is needed to add players to this group info
181 return ginfo;
184 //add player to playermap
185 void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
187 //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
188 PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()];
189 info.LastOnlineTime = getMSTime();
190 info.GroupInfo = ginfo;
192 // add the pinfo to ginfo's list
193 ginfo->Players[plr->GetGUID()] = &info;
196 void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
198 uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, getMSTime());
199 uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
200 if (!ginfo->ArenaType)
202 if (ginfo->Team == HORDE)
203 team_index = BG_TEAM_HORDE;
205 else
207 if (ginfo->IsRated)
208 team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
211 //store pointer to arrayindex of player that was added first
212 uint32* lastPlayerAddedPointer = &(m_WaitTimeLastPlayer[team_index][queue_id]);
213 //remove his time from sum
214 m_SumOfWaitTimes[team_index][queue_id] -= m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)];
215 //set average time to new
216 m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)] = timeInQueue;
217 //add new time to sum
218 m_SumOfWaitTimes[team_index][queue_id] += timeInQueue;
219 //set index of last player added to next one
220 (*lastPlayerAddedPointer)++;
221 (*lastPlayerAddedPointer) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME;
224 uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
226 uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
227 if (!ginfo->ArenaType)
229 if (ginfo->Team == HORDE)
230 team_index = BG_TEAM_HORDE;
232 else
234 if (ginfo->IsRated)
235 team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
237 //check if there is enought values(we always add values > 0)
238 if (m_WaitTimes[team_index][queue_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] )
239 return (m_SumOfWaitTimes[team_index][queue_id] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME);
240 else
241 //if there aren't enough values return 0 - not available
242 return 0;
245 //remove player from queue and from group info, if group info is empty then remove it too
246 void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
248 //Player *plr = objmgr.GetPlayer(guid);
250 int32 queue_id = -1; // signed for proper for-loop finish
251 QueuedPlayersMap::iterator itr;
253 //remove player from map, if he's there
254 itr = m_QueuedPlayers.find(guid);
255 if (itr == m_QueuedPlayers.end())
257 sLog.outError("BattleGroundQueue: couldn't find player to remove GUID: %u", GUID_LOPART(guid));
258 return;
261 GroupQueueInfo* group = itr->second.GroupInfo;
262 GroupsQueueType::iterator group_itr, group_itr_tmp;
263 // mostly people with the highest levels are in battlegrounds, thats why
264 // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0
265 // variable index removes useless searching in other team's queue
266 uint32 index = (group->Team == HORDE) ? BG_TEAM_HORDE : BG_TEAM_ALLIANCE;
268 for (int32 queue_id_tmp = MAX_BATTLEGROUND_QUEUES - 1; queue_id_tmp >= 0 && queue_id == -1; --queue_id_tmp)
270 //we must check premade and normal team's queue - because when players from premade are joining bg,
271 //they leave groupinfo so we can't use its players size to find out index
272 for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_QUEUE_NORMAL_ALLIANCE)
274 for(group_itr_tmp = m_QueuedGroups[queue_id_tmp][j].begin(); group_itr_tmp != m_QueuedGroups[queue_id_tmp][j].end(); ++group_itr_tmp)
276 if ((*group_itr_tmp) == group)
278 queue_id = queue_id_tmp;
279 group_itr = group_itr_tmp;
280 //we must store index to be able to erase iterator
281 index = j;
282 break;
287 //player can't be in queue without group, but just in case
288 if (queue_id == -1)
290 sLog.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid));
291 return;
293 sLog.outDebug("BattleGroundQueue: Removing player GUID %u, from queue_id %u", GUID_LOPART(guid), (uint32)queue_id);
295 // ALL variables are correctly set
296 // We can ignore leveling up in queue - it should not cause crash
297 // remove player from group
298 // if only one player there, remove group
300 // remove player queue info from group queue info
301 std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
302 if (pitr != group->Players.end())
303 group->Players.erase(pitr);
305 // if invited to bg, and should decrease invited count, then do it
306 if (decreaseInvitedCount && group->IsInvitedToBGInstanceGUID)
308 BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID, group->BgTypeId);
309 if (bg)
310 bg->DecreaseInvitedCount(group->Team);
313 // remove player queue info
314 m_QueuedPlayers.erase(itr);
316 //if we left BG queue(not porting) OR if arena team left queue for rated match
317 if ((decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()))
318 AnnounceWorld(group, guid, false);
320 //if player leaves queue and he is invited to rated arena match, then he have to loose
321 if (group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount)
323 ArenaTeam * at = objmgr.GetArenaTeamById(group->ArenaTeamId);
324 if (at)
326 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating);
327 Player *plr = objmgr.GetPlayer(guid);
328 if (plr)
329 at->MemberLost(plr, group->OpponentsTeamRating);
330 else
331 at->OfflineMemberLost(guid, group->OpponentsTeamRating);
332 at->SaveToDB();
336 // remove group queue info if needed
337 if (group->Players.empty())
339 m_QueuedGroups[queue_id][index].erase(group_itr);
340 delete group;
342 // if group wasn't empty, so it wasn't deleted, and player have left a rated
343 // queue -> everyone from the group should leave too
344 // don't remove recursively if already invited to bg!
345 else if (!group->IsInvitedToBGInstanceGUID && group->IsRated)
347 // remove next player, this is recursive
348 // first send removal information
349 if (Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
351 BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
352 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType);
353 uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
354 plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to
355 // queue->removeplayer, it causes bugs
356 WorldPacket data;
357 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
358 plr2->GetSession()->SendPacket(&data);
360 // then actually delete, this may delete the group as well!
361 RemovePlayer(group->Players.begin()->first, decreaseInvitedCount);
365 //Announce world message
366 void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue)
368 if(ginfo->ArenaType) //if Arena
370 if (sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated)
372 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
373 if (!bg)
374 return;
376 char const* bgName = bg->GetName();
377 if (isAddedToQueue)
378 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
379 else
380 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
383 else //if BG
385 if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
387 Player *plr = objmgr.GetPlayer(playerGUID);
388 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
389 if (!bg || !plr)
390 return;
392 BGQueueIdBasedOnLevel queue_id = plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID());
393 char const* bgName = bg->GetName();
394 uint32 MinPlayers = bg->GetMinPlayersPerTeam();
395 uint32 qHorde = 0;
396 uint32 qAlliance = 0;
397 uint32 q_min_level = (queue_id + 1) * 10;
398 GroupsQueueType::const_iterator itr;
399 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
400 if (!(*itr)->IsInvitedToBGInstanceGUID)
401 qAlliance += (*itr)->Players.size();
402 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
403 if (!(*itr)->IsInvitedToBGInstanceGUID)
404 qHorde += (*itr)->Players.size();
406 // Show queue status to player only (when joining queue)
407 if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
409 ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
410 bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
412 // System message
413 else
415 sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
416 bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
422 bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
424 // set side if needed
425 if (side)
426 ginfo->Team = side;
428 if (!ginfo->IsInvitedToBGInstanceGUID)
430 // not yet invited
431 // set invitation
432 ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
433 BattleGroundTypeId bgTypeId = bg->GetTypeID();
434 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, bg->GetArenaType());
435 BGQueueIdBasedOnLevel queue_id = bg->GetQueueId();
437 // set ArenaTeamId for rated matches
438 if (bg->isArena() && bg->isRated())
439 bg->SetArenaTeamIdForTeam(ginfo->Team, ginfo->ArenaTeamId);
441 ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME;
443 // loop through the players
444 for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
446 // get the player
447 Player* plr = objmgr.GetPlayer(itr->first);
448 // if offline, skip him, this should not happen - player is removed from queue when he logs out
449 if (!plr)
450 continue;
452 // invite the player
453 PlayerInvitedToBGUpdateAverageWaitTime(ginfo, queue_id);
454 //sBattleGroundMgr.InvitePlayer(plr, bg, ginfo->Team);
456 // set invited player counters
457 bg->IncreaseInvitedCount(ginfo->Team);
459 plr->SetInviteForBattleGroundQueueType(bgQueueTypeId, ginfo->IsInvitedToBGInstanceGUID);
461 // create remind invite events
462 BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->RemoveInviteTime);
463 plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME));
464 // create automatic remove events
465 BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, bgQueueTypeId, ginfo->RemoveInviteTime);
466 plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
468 WorldPacket data;
470 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
472 sLog.outDebug("Battleground: invited plr %s (%u) to BG instance %u queueindex %u bgtype %u, I can't help it if they don't press the enter battle button.",plr->GetName(),plr->GetGUIDLow(),bg->GetInstanceID(),queueSlot,bg->GetTypeID());
474 // send status packet
475 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType);
476 plr->GetSession()->SendPacket(&data);
478 return true;
481 return false;
485 This function is inviting players to already running battlegrounds
486 Invitation type is based on config file
487 large groups are disadvantageous, because they will be kicked first if invitation type = 1
489 void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id)
491 int32 hordeFree = bg->GetFreeSlotsForTeam(HORDE);
492 int32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE);
494 //iterator for iterating through bg queue
495 GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin();
496 //count of groups in queue - used to stop cycles
497 uint32 aliCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].size();
498 //index to queue which group is current
499 uint32 aliIndex = 0;
500 for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++)
501 ++Ali_itr;
502 //the same thing for horde
503 GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin();
504 uint32 hordeCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].size();
505 uint32 hordeIndex = 0;
506 for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++)
507 ++Horde_itr;
509 //if ofc like BG queue invitation is set in config, then we are happy
510 if (sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == 0)
511 return;
514 if we reached this code, then we have to solve NP - complete problem called Subset sum problem
515 So one solution is to check all possible invitation subgroups, or we can use these conditions:
516 1. Last time when BattleGroundQueue::Update was executed we invited all possible players - so there is only small possibility
517 that we will invite now whole queue, because only 1 change has been made to queues from the last BattleGroundQueue::Update call
518 2. Other thing we should consider is group order in queue
521 // At first we need to compare free space in bg and our selection pool
522 int32 diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
523 int32 diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
524 while( abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0) )
526 //each cycle execution we need to kick at least 1 group
527 if (diffAli < diffHorde)
529 //kick alliance group, add to pool new group if needed
530 if (m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli))
532 for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++)
533 ++Ali_itr;
535 //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break;
536 if (!m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
538 if (aliFree <= diffHorde + 1)
539 break;
540 m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli);
543 else
545 //kick horde group, add to pool new group if needed
546 if (m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde))
548 for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++)
549 ++Horde_itr;
551 if (!m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
553 if (hordeFree <= diffAli + 1)
554 break;
555 m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde);
558 //count diffs after small update
559 diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
560 diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
564 // this method checks if premade versus premade battleground is possible
565 // then after 30 mins (default) in queue it moves premade group to normal queue
566 // it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players
567 bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
569 //check match
570 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
572 //start premade match
573 //if groups aren't invited
574 GroupsQueueType::const_iterator ali_group, horde_group;
575 for( ali_group = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin(); ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++ali_group)
576 if (!(*ali_group)->IsInvitedToBGInstanceGUID)
577 break;
578 for( horde_group = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin(); horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++horde_group)
579 if (!(*horde_group)->IsInvitedToBGInstanceGUID)
580 break;
582 if (ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end())
584 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
585 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
586 //add groups/players from normal queue to size of bigger group
587 uint32 maxPlayers = std::max(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
588 GroupsQueueType::const_iterator itr;
589 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
591 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
593 //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
594 if (!(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers))
595 break;
598 //premade selection pools are set
599 return true;
602 // now check if we can move group from Premade queue to normal queue (timer has expired) or group size lowered!!
603 // this could be 2 cycles but i'm checking only first team in queue - it can cause problem -
604 // if first is invited to BG and seconds timer expired, but we can ignore it, because players have only 80 seconds to click to enter bg
605 // and when they click or after 80 seconds the queue info is removed from queue
606 uint32 time_before = getMSTime() - sWorld.getConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
607 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
609 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
611 GroupsQueueType::iterator itr = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin();
612 if (!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam))
614 //we must insert group to normal queue and erase pointer from premade queue
615 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
616 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr);
620 //selection pools are not set
621 return false;
624 // this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
625 bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers)
627 GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
628 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
630 itr_team[i] = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
631 for(; itr_team[i] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i]))
633 if (!(*(itr_team[i]))->IsInvitedToBGInstanceGUID)
635 m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers);
636 if (m_SelectionPools[i].GetPlayerCount() >= minPlayers)
637 break;
641 //try to invite same number of players - this cycle may cause longer wait time even if there are enough players in queue, but we want ballanced bg
642 uint32 j = BG_TEAM_ALLIANCE;
643 if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
644 j = BG_TEAM_HORDE;
645 if( sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != 0
646 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers )
648 //we will try to invite more groups to team with less players indexed by j
649 ++(itr_team[j]); //this will not cause a crash, because for cycle above reached break;
650 for(; itr_team[j] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
652 if (!(*(itr_team[j]))->IsInvitedToBGInstanceGUID)
653 if (!m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()))
654 break;
656 // do not allow to start bg with more than 2 players more on 1 faction
657 if (abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2)
658 return false;
660 //allow 1v0 if debug bg
661 if (sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()))
662 return true;
663 //return true if there are enough players in selection pools - enable to work .debug bg command correctly
664 return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers;
667 // this method will check if we can invite players to same faction skirmish match
668 bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam)
670 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam)
671 return false;
672 uint32 teamIndex = BG_TEAM_ALLIANCE;
673 uint32 otherTeam = BG_TEAM_HORDE;
674 uint32 otherTeamId = HORDE;
675 if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam )
677 teamIndex = BG_TEAM_HORDE;
678 otherTeam = BG_TEAM_ALLIANCE;
679 otherTeamId = ALLIANCE;
681 //clear other team's selection
682 m_SelectionPools[otherTeam].Init();
683 //store last ginfo pointer
684 GroupQueueInfo* ginfo = m_SelectionPools[teamIndex].SelectedGroups.back();
685 //set itr_team to group that was added to selection pool latest
686 GroupsQueueType::iterator itr_team = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin();
687 for(; itr_team != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team)
688 if (ginfo == *itr_team)
689 break;
690 if (itr_team == m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end())
691 return false;
692 GroupsQueueType::iterator itr_team2 = itr_team;
693 ++itr_team2;
694 //invite players to other selection pool
695 for(; itr_team2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team2)
697 //if selection pool is full then break;
698 if (!(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam))
699 break;
701 if (m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam)
702 return false;
704 //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue
705 for(GroupsQueueType::iterator itr = m_SelectionPools[otherTeam].SelectedGroups.begin(); itr != m_SelectionPools[otherTeam].SelectedGroups.end(); ++itr)
707 //set correct team
708 (*itr)->Team = otherTeamId;
709 //add team to other queue
710 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + otherTeam].push_front(*itr);
711 //remove team from old queue
712 GroupsQueueType::iterator itr2 = itr_team;
713 ++itr2;
714 for(; itr2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2)
716 if (*itr2 == *itr)
718 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].erase(itr2);
719 break;
723 return true;
727 this method is called when group is inserted, or player / group is removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue
728 it must be called after fully adding the members of a group to ensure group joining
729 should be called from BattleGround::RemovePlayer function in some cases
731 void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated, uint32 arenaRating)
733 //if no players in queue - do nothing
734 if( m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
735 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() &&
736 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
737 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].empty() )
738 return;
740 //battleground with free slot for player should be always in the beggining of the queue
741 // maybe it would be better to create bgfreeslotqueue for each queue_id_based_on_level
742 BGFreeSlotQueueType::iterator itr, next;
743 for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
745 next = itr;
746 ++next;
747 // DO NOT allow queue manager to invite new player to arena
748 if( (*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueId() == queue_id &&
749 (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE )
751 BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
752 // and iterator is invalid
754 // clear selection pools
755 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
756 m_SelectionPools[BG_TEAM_HORDE].Init();
758 // call a function that does the job for us
759 FillPlayersToBG(bg, queue_id);
761 // now everything is set, invite players
762 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.end(); ++citr)
763 InviteGroupToBG((*citr), bg, (*citr)->Team);
764 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.end(); ++citr)
765 InviteGroupToBG((*citr), bg, (*citr)->Team);
767 if (!bg->HasFreeSlots())
769 // remove BG from BGFreeSlotQueue
770 bg->RemoveFromBGFreeSlotQueue();
775 // finished iterating through the bgs with free slots, maybe we need to create a new bg
777 BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
778 if (!bg_template)
780 sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
781 return;
783 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
784 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
785 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
786 if (sBattleGroundMgr.isTesting())
787 MinPlayersPerTeam = 1;
788 if (bg_template->isArena())
790 if (sBattleGroundMgr.isArenaTesting())
792 MaxPlayersPerTeam = 1;
793 MinPlayersPerTeam = 1;
795 else
797 //this switch can be much shorter
798 MaxPlayersPerTeam = arenaType;
799 MinPlayersPerTeam = arenaType;
800 /*switch(arenaType)
802 case ARENA_TYPE_2v2:
803 MaxPlayersPerTeam = 2;
804 MinPlayersPerTeam = 2;
805 break;
806 case ARENA_TYPE_3v3:
807 MaxPlayersPerTeam = 3;
808 MinPlayersPerTeam = 3;
809 break;
810 case ARENA_TYPE_5v5:
811 MaxPlayersPerTeam = 5;
812 MinPlayersPerTeam = 5;
813 break;
818 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
819 m_SelectionPools[BG_TEAM_HORDE].Init();
821 if (bg_template->isBattleGround())
823 //check if there is premade against premade match
824 if (CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam))
826 //create new battleground
827 BattleGround * bg2 = NULL;
828 if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, 0, false)))
830 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
831 return;
833 //invite those selection pools
834 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
835 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
836 InviteGroupToBG((*citr), bg2, (*citr)->Team);
837 //start bg
838 bg2->StartBattleGround();
839 //clear structures
840 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
841 m_SelectionPools[BG_TEAM_HORDE].Init();
845 // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
846 if (!isRated)
848 // if there are enough players in pools, start new battleground or non rated arena
849 if (CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam)
850 || (bg_template->isArena() && CheckSkirmishForSameFaction(queue_id, MinPlayersPerTeam)) )
852 // we successfully created a pool
853 BattleGround * bg2 = NULL;
854 if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, false)))
856 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
857 return;
860 // invite those selection pools
861 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
862 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
863 InviteGroupToBG((*citr), bg2, (*citr)->Team);
864 // start bg
865 bg2->StartBattleGround();
868 else if (bg_template->isArena())
870 // found out the minimum and maximum ratings the newly added team should battle against
871 // arenaRating is the rating of the latest joined team, or 0
872 // 0 is on (automatic update call) and we must set it to team's with longest wait time
873 if (!arenaRating )
875 GroupQueueInfo* front1 = NULL;
876 GroupQueueInfo* front2 = NULL;
877 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty())
879 front1 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].front();
880 arenaRating = front1->ArenaTeamRating;
882 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
884 front2 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].front();
885 arenaRating = front2->ArenaTeamRating;
887 if (front1 && front2)
889 if (front1->JoinTime < front2->JoinTime)
890 arenaRating = front1->ArenaTeamRating;
892 else if (!front1 && !front2)
893 return; //queues are empty
896 //set rating range
897 uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
898 uint32 arenaMaxRating = arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
899 // if max rating difference is set and the time past since server startup is greater than the rating discard time
900 // (after what time the ratings aren't taken into account when making teams) then
901 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
902 // else leave the discard time on 0, this way all ratings will be discarded
903 uint32 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
905 // we need to find 2 teams which will play next game
907 GroupsQueueType::iterator itr_team[BG_TEAMS_COUNT];
909 //optimalization : --- we dont need to use selection_pools - each update we select max 2 groups
911 for(uint32 i = BG_QUEUE_PREMADE_ALLIANCE; i < BG_QUEUE_NORMAL_ALLIANCE; i++)
913 // take the group that joined first
914 itr_team[i] = m_QueuedGroups[queue_id][i].begin();
915 for(; itr_team[i] != m_QueuedGroups[queue_id][i].end(); ++(itr_team[i]))
917 // if group match conditions, then add it to pool
918 if( !(*itr_team[i])->IsInvitedToBGInstanceGUID
919 && (((*itr_team[i])->ArenaTeamRating >= arenaMinRating && (*itr_team[i])->ArenaTeamRating <= arenaMaxRating)
920 || (*itr_team[i])->JoinTime < discardTime) )
922 m_SelectionPools[i].AddGroup((*itr_team[i]), MaxPlayersPerTeam);
923 // break for cycle to be able to start selecting another group from same faction queue
924 break;
928 // now we are done if we have 2 groups - ali vs horde!
929 // if we don't have, we must try to continue search in same queue
930 // tmp variables are correctly set
931 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue
932 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
934 itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE];
935 ++itr_team[BG_TEAM_ALLIANCE];
936 for(; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE]))
938 if( !(*itr_team[BG_TEAM_ALLIANCE])->IsInvitedToBGInstanceGUID
939 && (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
940 || (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime) )
942 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*itr_team[BG_TEAM_ALLIANCE]), MaxPlayersPerTeam);
943 break;
947 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue
948 if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
950 itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE];
951 ++itr_team[BG_TEAM_HORDE];
952 for(; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE]))
954 if( !(*itr_team[BG_TEAM_HORDE])->IsInvitedToBGInstanceGUID
955 && (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating)
956 || (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime) )
958 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*itr_team[BG_TEAM_HORDE]), MaxPlayersPerTeam);
959 break;
964 //if we have 2 teams, then start new arena and invite players!
965 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
967 BattleGround* arena = NULL;
968 if (!(arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, true)))
970 sLog.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
971 return;
974 (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating;
975 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating);
976 (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating;
977 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating);
978 // now we must move team if we changed its faction to another faction queue, because then we will spam log by errors in Queue::RemovePlayer
979 if ((*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE)
981 // add to alliance queue
982 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE]));
983 // erase from horde queue
984 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]);
985 itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
987 if ((*(itr_team[BG_TEAM_HORDE]))->Team != HORDE)
989 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE]));
990 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]);
991 itr_team[BG_TEAM_HORDE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin();
994 InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE);
995 InviteGroupToBG(*(itr_team[BG_TEAM_HORDE]), arena, HORDE);
997 sLog.outDebug("Starting rated arena match!");
999 arena->StartBattleGround();
1004 /*********************************************************/
1005 /*** BATTLEGROUND QUEUE EVENTS ***/
1006 /*********************************************************/
1008 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1010 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
1011 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1012 if (!plr)
1013 return true;
1015 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1016 //if battleground ended and its instance deleted - do nothing
1017 if (!bg)
1018 return true;
1020 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1021 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1022 if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue or in battleground
1024 // check if player is invited to this bg
1025 BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
1026 BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
1027 if( qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID
1028 && qItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime )
1030 WorldPacket data;
1031 //we must send remaining time in queue
1032 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, qItr->second.GroupInfo->ArenaType);
1033 plr->GetSession()->SendPacket(&data);
1036 return true; //event will be deleted
1039 void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
1041 //do nothing
1045 this event has many possibilities when it is executed:
1046 1. player is in battleground ( he clicked enter on invitation window )
1047 2. player left battleground queue and he isn't there any more
1048 3. player left battleground queue and he joined it again and IsInvitedToBGInstanceGUID = 0
1049 4. player left queue and he joined again and he has been invited to same battleground again -> we should not remove him from queue yet
1050 5. player is invited to bg and he didn't choose what to do and timer expired - only in this condition we should call queue::RemovePlayer
1051 we must remove player in the 5. case even if battleground object doesn't exist!
1053 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1055 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
1056 if (!plr)
1057 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1058 return true;
1060 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1061 //battleground can be deleted already when we are removing queue info
1062 //bg pointer can be NULL! so use it carefully!
1064 uint32 queueSlot = plr->GetBattleGroundQueueIndex(m_BgQueueTypeId);
1065 if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue, or in Battleground
1067 // check if player is in queue for this BG and if we are removing his invite event
1068 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].m_QueuedPlayers;
1069 BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid);
1070 if( qMapItr != qpMap.end() && qMapItr->second.GroupInfo
1071 && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID
1072 && qMapItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime )
1074 sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
1076 plr->RemoveBattleGroundQueueId(m_BgQueueTypeId);
1077 sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
1078 //update queues if battleground isn't ended
1079 if (bg)
1080 sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].Update(m_BgTypeId, bg->GetQueueId());
1082 WorldPacket data;
1083 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
1084 plr->GetSession()->SendPacket(&data);
1088 //event will be deleted
1089 return true;
1092 void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
1094 //do nothing
1097 /*********************************************************/
1098 /*** BATTLEGROUND MANAGER ***/
1099 /*********************************************************/
1101 BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
1103 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1104 m_BattleGrounds[i].clear();
1105 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1106 m_Testing=false;
1109 BattleGroundMgr::~BattleGroundMgr()
1111 DeleteAllBattleGrounds();
1114 void BattleGroundMgr::DeleteAllBattleGrounds()
1116 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1118 for(BattleGroundSet::iterator itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end();)
1120 BattleGround * bg = itr->second;
1121 m_BattleGrounds[i].erase(itr++);
1122 if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
1123 m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
1124 delete bg;
1128 // destroy template battlegrounds that listed only in queues (other already terminated)
1129 for(uint32 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId)
1131 // ~BattleGround call unregistring BG from queue
1132 while(!BGFreeSlotQueue[bgTypeId].empty())
1133 delete BGFreeSlotQueue[bgTypeId].front();
1137 // used to update running battlegrounds, and delete finished ones
1138 void BattleGroundMgr::Update(uint32 diff)
1140 BattleGroundSet::iterator itr, next;
1141 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1143 itr = m_BattleGrounds[i].begin();
1144 // skip updating battleground template
1145 if (itr != m_BattleGrounds[i].end())
1146 ++itr;
1147 for(; itr != m_BattleGrounds[i].end(); itr = next)
1149 next = itr;
1150 ++next;
1151 itr->second->Update(diff);
1152 // use the SetDeleteThis variable
1153 // direct deletion caused crashes
1154 if (itr->second->m_SetDeleteThis)
1156 BattleGround * bg = itr->second;
1157 m_BattleGrounds[i].erase(itr);
1158 if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
1159 m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
1160 delete bg;
1164 // if rating difference counts, maybe force-update queues
1165 if (sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER))
1167 // it's time to force update
1168 if (m_NextRatingDiscardUpdate < diff)
1170 // forced update for level 70 rated arenas
1171 sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
1172 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_2v2, true, 0);
1173 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_2v2, true, 0);
1174 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_3v3, true, 0);
1175 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_3v3, true, 0);
1176 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_5v5, true, 0);
1177 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_5v5, true, 0);
1178 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1180 else
1181 m_NextRatingDiscardUpdate -= diff;
1183 if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1185 if (m_AutoDistributionTimeChecker < diff)
1187 if (sWorld.GetGameTime() > m_NextAutoDistributionTime)
1189 DistributeArenaPoints();
1190 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1191 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"I64FMTD"'", uint64(m_NextAutoDistributionTime));
1193 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1195 else
1196 m_AutoDistributionTimeChecker -= diff;
1200 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype)
1202 // we can be in 3 queues in same time...
1204 if (StatusID == 0 || !bg)
1206 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
1207 *data << uint32(QueueSlot); // queue id (0...2)
1208 *data << uint64(0);
1209 return;
1212 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
1213 *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1214 // uint64 in client
1215 *data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1216 *data << uint32(bg->GetClientInstanceID());
1217 // alliance/horde for BG and skirmish/rated for Arenas
1218 // following displays the minimap-icon 0 = faction icon 1 = arenaicon
1219 *data << uint8(bg->isRated());
1220 /* *data << uint8(arenatype ? arenatype : bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas // NOT PROPER VALUE IF ARENA ISN'T RUNNING YET!!!!
1221 switch(bg->GetTypeID()) // value depends on bg id
1223 case BATTLEGROUND_AV:
1224 *data << uint8(1);
1225 break;
1226 case BATTLEGROUND_WS:
1227 *data << uint8(2);
1228 break;
1229 case BATTLEGROUND_AB:
1230 *data << uint8(3);
1231 break;
1232 case BATTLEGROUND_NA:
1233 *data << uint8(4);
1234 break;
1235 case BATTLEGROUND_BE:
1236 *data << uint8(5);
1237 break;
1238 case BATTLEGROUND_AA:
1239 *data << uint8(6);
1240 break;
1241 case BATTLEGROUND_EY:
1242 *data << uint8(7);
1243 break;
1244 case BATTLEGROUND_RL:
1245 *data << uint8(8);
1246 break;
1247 case BATTLEGROUND_SA:
1248 *data << uint8(9);
1249 break;
1250 case BATTLEGROUND_DS:
1251 *data << uint8(10);
1252 break;
1253 case BATTLEGROUND_RV:
1254 *data << uint8(11);
1255 break;
1256 default: // unknown
1257 *data << uint8(0);
1258 break;
1261 if (bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1262 *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1263 else
1264 *data << uint32(bg->GetTypeID()); // BG id from DBC
1266 *data << uint16(0x1F90); // unk value 8080
1267 *data << uint32(bg->GetInstanceID()); // instance id
1269 *data << uint8(bg->isArena()); // minimap-icon 0=faction 1=arena
1271 *data << uint32(StatusID); // status
1272 switch(StatusID)
1274 case STATUS_WAIT_QUEUE: // status_in_queue
1275 *data << uint32(Time1); // average wait time, milliseconds
1276 *data << uint32(Time2); // time in queue, updated every minute!, milliseconds
1277 break;
1278 case STATUS_WAIT_JOIN: // status_invite
1279 *data << uint32(bg->GetMapId()); // map id
1280 *data << uint32(Time1); // time to remove from queue, milliseconds
1281 break;
1282 case STATUS_IN_PROGRESS: // status_in_progress
1283 *data << uint32(bg->GetMapId()); // map id
1284 *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
1285 *data << uint32(Time2); // time from bg start, milliseconds
1286 *data << uint8(0x1); // unk sometimes 0x0!
1287 break;
1288 default:
1289 sLog.outError("Unknown BG status!");
1290 break;
1294 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1296 uint8 type = (bg->isArena() ? 1 : 0);
1297 // last check on 3.0.3
1298 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1299 *data << uint8(type); // type (battleground=0/arena=1)
1301 if(type) // arena
1303 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1304 for(int i = 1; i >= 0; --i)
1306 *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
1307 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1308 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1310 for(int i = 1; i >= 0; --i)
1312 uint32 at_id = bg->m_ArenaTeamIds[i];
1313 ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
1314 if (at)
1315 *data << at->GetName();
1316 else
1317 *data << (uint8)0;
1321 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
1323 *data << uint8(0); // bg not ended
1325 else
1327 *data << uint8(1); // bg ended
1328 *data << uint8(bg->GetWinner()); // who win
1331 *data << (int32)(bg->GetPlayerScoresSize());
1333 for(std::map<uint64, BattleGroundScore*>::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1335 *data << (uint64)itr->first;
1336 *data << (int32)itr->second->KillingBlows;
1337 if (type == 0)
1339 *data << (int32)itr->second->HonorableKills;
1340 *data << (int32)itr->second->Deaths;
1341 *data << (int32)(itr->second->BonusHonor);
1343 else
1345 Player *plr = objmgr.GetPlayer(itr->first);
1346 uint32 team = bg->GetPlayerTeam(itr->first);
1347 if (!team && plr)
1348 team = plr->GetTeam();
1349 if (( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ))
1350 *data << uint8(1);
1351 else
1352 *data << uint8(0);
1354 *data << (int32)itr->second->DamageDone; // damage done
1355 *data << (int32)itr->second->HealingDone; // healing done
1356 switch(bg->GetTypeID()) // battleground specific things
1358 case BATTLEGROUND_AV:
1359 *data << (uint32)0x00000005; // count of next fields
1360 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1361 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1362 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1363 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1364 *data << (uint32)((BattleGroundAVScore*)itr->second)->MinesCaptured; // MinesCaptured
1365 break;
1366 case BATTLEGROUND_WS:
1367 *data << (uint32)0x00000002; // count of next fields
1368 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1369 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1370 break;
1371 case BATTLEGROUND_AB:
1372 *data << (uint32)0x00000002; // count of next fields
1373 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1374 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1375 break;
1376 case BATTLEGROUND_EY:
1377 *data << (uint32)0x00000001; // count of next fields
1378 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1379 break;
1380 case BATTLEGROUND_NA:
1381 case BATTLEGROUND_BE:
1382 case BATTLEGROUND_AA:
1383 case BATTLEGROUND_RL:
1384 case BATTLEGROUND_SA: // wotlk
1385 case BATTLEGROUND_DS: // wotlk
1386 case BATTLEGROUND_RV: // wotlk
1387 *data << (int32)0; // 0
1388 break;
1389 default:
1390 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1391 *data << (int32)0;
1392 break;
1397 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
1399 /*bgTypeId is:
1400 0 - Your group has joined a battleground queue, but you are not eligible
1401 1 - Your group has joined the queue for AV
1402 2 - Your group has joined the queue for WS
1403 3 - Your group has joined the queue for AB
1404 4 - Your group has joined the queue for NA
1405 5 - Your group has joined the queue for BE Arena
1406 6 - Your group has joined the queue for All Arenas
1407 7 - Your group has joined the queue for EotS*/
1408 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1409 *data << uint32(bgTypeId);
1412 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1414 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1415 *data << uint32(field);
1416 *data << uint32(value);
1419 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1421 data->Initialize(SMSG_PLAY_SOUND, 4);
1422 *data << uint32(soundid);
1425 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid)
1427 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1428 *data << uint64(guid);
1431 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1433 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1434 *data << uint64(plr->GetGUID());
1437 BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId)
1439 //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from
1440 //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
1441 BattleGround* bg = GetBattleGroundTemplate(bgTypeId);
1442 if (!bg)
1443 return NULL;
1445 if (bg->isArena())
1446 return GetBattleGround(instanceId, bgTypeId);
1448 for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr)
1450 if (itr->second->GetClientInstanceID() == instanceId)
1451 return itr->second;
1453 return NULL;
1456 BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
1458 //search if needed
1459 BattleGroundSet::iterator itr;
1460 if (bgTypeId == BATTLEGROUND_TYPE_NONE)
1462 for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1464 itr = m_BattleGrounds[i].find(InstanceID);
1465 if (itr != m_BattleGrounds[i].end())
1466 return itr->second;
1468 return NULL;
1470 itr = m_BattleGrounds[bgTypeId].find(InstanceID);
1471 return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL );
1474 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
1476 //map is sorted and we can be sure that lowest instance id has only BG template
1477 return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second;
1480 uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
1482 if (IsArenaType(bgTypeId))
1483 return 0; //arenas don't have client-instanceids
1485 // we create here an instanceid, which is just for
1486 // displaying this to the client and without any other use..
1487 // the client-instanceIds are unique for each battleground-type
1488 // the instance-id just needs to be as low as possible, beginning with 1
1489 // the following works, because std::set is default ordered with "<"
1490 // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
1491 uint32 lastId = 0;
1492 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();)
1494 if( (++lastId) != *itr) //if there is a gap between the ids, we will break..
1495 break;
1496 lastId = *itr;
1498 m_ClientBattleGroundIds[bgTypeId][queue_id].insert(lastId + 1);
1499 return lastId + 1;
1502 // create a new battleground that will really be used to play
1503 BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated)
1505 // get the template BG
1506 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1507 if (!bg_template)
1509 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1510 return NULL;
1513 //for arenas there is random map used
1514 if (bg_template->isArena())
1516 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
1517 uint32 arena_num = urand(0,2);
1518 bgTypeId = arenas[arena_num];
1519 bg_template = GetBattleGroundTemplate(bgTypeId);
1520 if (!bg_template)
1522 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1523 return NULL;
1527 BattleGround *bg = NULL;
1528 // create a copy of the BG template
1529 switch(bgTypeId)
1531 case BATTLEGROUND_AV:
1532 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1533 break;
1534 case BATTLEGROUND_WS:
1535 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1536 break;
1537 case BATTLEGROUND_AB:
1538 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1539 break;
1540 case BATTLEGROUND_NA:
1541 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1542 break;
1543 case BATTLEGROUND_BE:
1544 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1545 break;
1546 case BATTLEGROUND_AA:
1547 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1548 break;
1549 case BATTLEGROUND_EY:
1550 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1551 break;
1552 case BATTLEGROUND_RL:
1553 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1554 break;
1555 case BATTLEGROUND_SA:
1556 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1557 break;
1558 case BATTLEGROUND_DS:
1559 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1560 break;
1561 case BATTLEGROUND_RV:
1562 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1563 break;
1564 default:
1565 //error, but it is handled few lines above
1566 return 0;
1569 // generate a new instance id
1570 bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
1571 bg->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId, queue_id));
1573 // reset the new bg (set status to status_wait_queue from status_none)
1574 bg->Reset();
1576 // start the joining of the bg
1577 bg->SetStatus(STATUS_WAIT_JOIN);
1578 bg->SetQueueId(queue_id);
1579 bg->SetArenaType(arenaType);
1580 bg->SetRated(isRated);
1582 // add BG to free slot queue
1583 bg->AddToBGFreeSlotQueue();
1585 // add bg to update list
1586 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1588 return bg;
1591 // used to create the BG templates
1592 uint32 BattleGroundMgr::CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsArena, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO)
1594 // Create the BG
1595 BattleGround *bg = NULL;
1596 switch(bgTypeId)
1598 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1599 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1600 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1601 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1602 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1603 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1604 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1605 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1606 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1607 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1608 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1609 default:bg = new BattleGround; break; // placeholder for non implemented BG
1612 bg->SetMapId(MapID);
1613 bg->SetTypeID(bgTypeId);
1614 bg->SetInstanceID(0);
1615 bg->SetArenaorBGType(IsArena);
1616 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1617 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1618 bg->SetMinPlayers(MinPlayersPerTeam * 2);
1619 bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
1620 bg->SetName(BattleGroundName);
1621 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1622 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1623 bg->SetLevelRange(LevelMin, LevelMax);
1625 // add bg to update list
1626 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1628 // return some not-null value, bgTypeId is good enough for me
1629 return bgTypeId;
1632 void BattleGroundMgr::CreateInitialBattleGrounds()
1634 float AStartLoc[4];
1635 float HStartLoc[4];
1636 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1637 BattlemasterListEntry const *bl;
1638 WorldSafeLocsEntry const *start;
1639 bool IsArena;
1641 uint32 count = 0;
1643 // 0 1 2 3 4 5 6 7 8
1644 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1646 if (!result)
1648 barGoLink bar(1);
1650 bar.step();
1652 sLog.outString();
1653 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1654 return;
1657 barGoLink bar(result->GetRowCount());
1661 Field *fields = result->Fetch();
1662 bar.step();
1664 uint32 bgTypeID_ = fields[0].GetUInt32();
1666 // can be overwrite by values from DB
1667 bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
1668 if (!bl)
1670 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
1671 continue;
1674 BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
1676 IsArena = (bl->type == TYPE_ARENA);
1677 MinPlayersPerTeam = fields[1].GetUInt32();
1678 MaxPlayersPerTeam = fields[2].GetUInt32();
1679 MinLvl = fields[3].GetUInt32();
1680 MaxLvl = fields[4].GetUInt32();
1681 //check values from DB
1682 if (MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam)
1684 MaxPlayersPerTeam = bl->maxplayersperteam;
1685 MinPlayersPerTeam = bl->maxplayersperteam / 2;
1687 if (MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl)
1689 MinLvl = bl->minlvl;
1690 MaxLvl = bl->maxlvl;
1693 start1 = fields[5].GetUInt32();
1695 start = sWorldSafeLocsStore.LookupEntry(start1);
1696 if (start)
1698 AStartLoc[0] = start->x;
1699 AStartLoc[1] = start->y;
1700 AStartLoc[2] = start->z;
1701 AStartLoc[3] = fields[6].GetFloat();
1703 else if (bgTypeID == BATTLEGROUND_AA)
1705 AStartLoc[0] = 0;
1706 AStartLoc[1] = 0;
1707 AStartLoc[2] = 0;
1708 AStartLoc[3] = fields[6].GetFloat();
1710 else
1712 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
1713 continue;
1716 start2 = fields[7].GetUInt32();
1718 start = sWorldSafeLocsStore.LookupEntry(start2);
1719 if (start)
1721 HStartLoc[0] = start->x;
1722 HStartLoc[1] = start->y;
1723 HStartLoc[2] = start->z;
1724 HStartLoc[3] = fields[8].GetFloat();
1726 else if (bgTypeID == BATTLEGROUND_AA)
1728 HStartLoc[0] = 0;
1729 HStartLoc[1] = 0;
1730 HStartLoc[2] = 0;
1731 HStartLoc[3] = fields[8].GetFloat();
1733 else
1735 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
1736 continue;
1739 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1740 if (!CreateBattleGround(bgTypeID, IsArena, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, bl->name[sWorld.GetDefaultDbcLocale()], bl->mapid[0], AStartLoc[0], AStartLoc[1], AStartLoc[2], AStartLoc[3], HStartLoc[0], HStartLoc[1], HStartLoc[2], HStartLoc[3]))
1741 continue;
1743 ++count;
1744 } while (result->NextRow());
1746 delete result;
1748 sLog.outString();
1749 sLog.outString( ">> Loaded %u battlegrounds", count );
1752 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1754 if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1756 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1757 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1758 if (!result)
1760 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1761 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1762 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"I64FMTD"')", uint64(m_NextAutoDistributionTime));
1764 else
1766 m_NextAutoDistributionTime = time_t((*result)[0].GetUInt64());
1767 delete result;
1769 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1773 void BattleGroundMgr::DistributeArenaPoints()
1775 // used to distribute arena points based on last week's stats
1776 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
1778 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
1780 //temporary structure for storing maximum points to add values for all players
1781 std::map<uint32, uint32> PlayerPoints;
1783 //at first update all points for all team members
1784 for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
1786 if (ArenaTeam * at = team_itr->second)
1788 at->UpdateArenaPointsHelper(PlayerPoints);
1792 //cycle that gives points to all players
1793 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1795 //update to database
1796 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
1797 //add points if player is online
1798 Player* pl = objmgr.GetPlayer(plr_itr->first);
1799 if (pl)
1800 pl->ModifyArenaPoints(plr_itr->second);
1803 PlayerPoints.clear();
1805 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
1807 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
1808 for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
1810 if (ArenaTeam * at = titr->second)
1812 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1813 at->SaveToDB(); // save changes
1814 at->NotifyStatsChanged(); // notify the players of the changes
1818 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
1820 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
1823 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId)
1825 if (!plr)
1826 return;
1828 uint32 PlayerLevel = 10;
1829 PlayerLevel = plr->getLevel();
1831 data->Initialize(SMSG_BATTLEFIELD_LIST);
1832 *data << uint64(guid); // battlemaster guid
1833 *data << uint32(bgTypeId); // battleground id
1834 if(bgTypeId == BATTLEGROUND_AA) // arena
1836 *data << uint8(5); // unk
1837 *data << uint32(0); // unk
1839 else // battleground
1841 *data << uint8(0x00); // unk
1843 size_t count_pos = data->wpos();
1844 uint32 count = 0;
1845 *data << uint32(0x00); // number of bg instances
1847 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(bgTypeId);
1848 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();++itr)
1850 *data << uint32(*itr);
1851 ++count;
1853 data->put<uint32>( count_pos , count);
1857 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId)
1859 BattleGround *bg = GetBattleGround(instanceId, bgTypeId);
1860 if (bg)
1862 uint32 mapid = bg->GetMapId();
1863 float x, y, z, O;
1864 uint32 team = pl->GetBGTeam();
1865 if (team==0)
1866 team = pl->GetTeam();
1867 bg->GetTeamStartLoc(team, x, y, z, O);
1869 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1870 pl->TeleportTo(mapid, x, y, z, O);
1872 else
1874 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1878 void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid)
1880 WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
1881 uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
1882 if (time_ == uint32(-1))
1883 time_ = 0;
1884 data << guid << time_;
1885 pl->GetSession()->SendPacket(&data);
1888 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
1890 return ( bgTypeId == BATTLEGROUND_AA ||
1891 bgTypeId == BATTLEGROUND_BE ||
1892 bgTypeId == BATTLEGROUND_NA ||
1893 bgTypeId == BATTLEGROUND_RL );
1896 BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
1898 switch(bgTypeId)
1900 case BATTLEGROUND_WS:
1901 return BATTLEGROUND_QUEUE_WS;
1902 case BATTLEGROUND_AB:
1903 return BATTLEGROUND_QUEUE_AB;
1904 case BATTLEGROUND_AV:
1905 return BATTLEGROUND_QUEUE_AV;
1906 case BATTLEGROUND_EY:
1907 return BATTLEGROUND_QUEUE_EY;
1908 case BATTLEGROUND_SA:
1909 return BATTLEGROUND_QUEUE_SA;
1910 case BATTLEGROUND_AA:
1911 case BATTLEGROUND_NA:
1912 case BATTLEGROUND_RL:
1913 case BATTLEGROUND_BE:
1914 case BATTLEGROUND_DS:
1915 case BATTLEGROUND_RV:
1916 switch(arenaType)
1918 case ARENA_TYPE_2v2:
1919 return BATTLEGROUND_QUEUE_2v2;
1920 case ARENA_TYPE_3v3:
1921 return BATTLEGROUND_QUEUE_3v3;
1922 case ARENA_TYPE_5v5:
1923 return BATTLEGROUND_QUEUE_5v5;
1924 default:
1925 return BATTLEGROUND_QUEUE_NONE;
1927 default:
1928 return BATTLEGROUND_QUEUE_NONE;
1932 BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId)
1934 switch(bgQueueTypeId)
1936 case BATTLEGROUND_QUEUE_WS:
1937 return BATTLEGROUND_WS;
1938 case BATTLEGROUND_QUEUE_AB:
1939 return BATTLEGROUND_AB;
1940 case BATTLEGROUND_QUEUE_AV:
1941 return BATTLEGROUND_AV;
1942 case BATTLEGROUND_QUEUE_EY:
1943 return BATTLEGROUND_EY;
1944 case BATTLEGROUND_QUEUE_SA:
1945 return BATTLEGROUND_SA;
1946 case BATTLEGROUND_QUEUE_2v2:
1947 case BATTLEGROUND_QUEUE_3v3:
1948 case BATTLEGROUND_QUEUE_5v5:
1949 return BATTLEGROUND_AA;
1950 default:
1951 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
1955 uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId)
1957 switch(bgQueueTypeId)
1959 case BATTLEGROUND_QUEUE_2v2:
1960 return ARENA_TYPE_2v2;
1961 case BATTLEGROUND_QUEUE_3v3:
1962 return ARENA_TYPE_3v3;
1963 case BATTLEGROUND_QUEUE_5v5:
1964 return ARENA_TYPE_5v5;
1965 default:
1966 return 0;
1970 void BattleGroundMgr::ToggleTesting()
1972 m_Testing = !m_Testing;
1973 if (m_Testing)
1974 sWorld.SendWorldText(LANG_DEBUG_BG_ON);
1975 else
1976 sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
1979 void BattleGroundMgr::ToggleArenaTesting()
1981 m_ArenaTesting = !m_ArenaTesting;
1982 if (m_ArenaTesting)
1983 sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
1984 else
1985 sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
1988 uint32 BattleGroundMgr::GetMaxRatingDifference() const
1990 // this is for stupid people who can't use brain and set max rating difference to 0
1991 uint32 diff = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
1992 if (diff == 0)
1993 diff = 5000;
1994 return diff;
1997 uint32 BattleGroundMgr::GetRatingDiscardTimer() const
1999 return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
2002 uint32 BattleGroundMgr::GetPrematureFinishTime() const
2004 return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
2007 void BattleGroundMgr::LoadBattleMastersEntry()
2009 mBattleMastersMap.clear(); // need for reload case
2011 QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
2013 uint32 count = 0;
2015 if (!result)
2017 barGoLink bar( 1 );
2018 bar.step();
2020 sLog.outString();
2021 sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
2022 return;
2025 barGoLink bar( result->GetRowCount() );
2029 ++count;
2030 bar.step();
2032 Field *fields = result->Fetch();
2034 uint32 entry = fields[0].GetUInt32();
2035 uint32 bgTypeId = fields[1].GetUInt32();
2036 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
2038 sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
2039 continue;
2042 mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
2044 } while( result->NextRow() );
2046 delete result;
2048 sLog.outString();
2049 sLog.outString( ">> Loaded %u battlemaster entries", count );