[7436] Fixed Average Wait time for all BG/arena queue types. Patch has been made...
[getmangos.git] / src / game / BattleGroundMgr.cpp
blob1d5088673b0f04699ef7dbe6d7aa4268f5136f88
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 = sWorld.GetGameTime() * IN_MILISECONDS;
163 ginfo->Team = leader->GetTeam();
164 ginfo->ArenaTeamRating = arenaRating;
165 ginfo->OpponentsTeamRating = 0;
167 ginfo->Players.clear();
169 //compute index (if group is premade or joined a rated match) to queues
170 uint32 index = 0;
171 if(!isRated && !isPremade)
172 index += BG_TEAMS_COUNT;
173 if(ginfo->Team == HORDE)
174 index++;
175 sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index);
177 m_QueuedGroups[queue_id][index].push_back(ginfo);
179 // return ginfo, because it is needed to add players to this group info
180 return ginfo;
183 //add player to playermap
184 void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
186 //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
187 PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()];
188 info.LastOnlineTime = getMSTime();
189 info.GroupInfo = ginfo;
191 // add the pinfo to ginfo's list
192 ginfo->Players[plr->GetGUID()] = &info;
195 void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
197 uint32 timeInQueue = (sWorld.GetGameTime() * IN_MILISECONDS) - ginfo->JoinTime;
198 uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
199 if( !ginfo->ArenaType )
201 if( ginfo->Team == HORDE )
202 team_index = BG_TEAM_HORDE;
204 else
206 if( ginfo->IsRated )
207 team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
210 //store pointer to arrayindex of player that was added first
211 uint32* lastPlayerAddedPointer = &(m_WaitTimeLastPlayer[team_index][queue_id]);
212 //remove his time from sum
213 m_SumOfWaitTimes[team_index][queue_id] -= m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)];
214 //set average time to new
215 m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)] = timeInQueue;
216 //add new time to sum
217 m_SumOfWaitTimes[team_index][queue_id] += timeInQueue;
218 //set index of last player added to next one
219 (*lastPlayerAddedPointer)++;
220 (*lastPlayerAddedPointer) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME;
223 uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
225 uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
226 if( !ginfo->ArenaType )
228 if( ginfo->Team == HORDE )
229 team_index = BG_TEAM_HORDE;
231 else
233 if( ginfo->IsRated )
234 team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
236 //check if there is enought values(we always add values > 0)
237 if(m_WaitTimes[team_index][queue_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] )
238 return (m_SumOfWaitTimes[team_index][queue_id] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME);
239 else
240 //if there aren't enough values return 0 - not available
241 return 0;
244 //remove player from queue and from group info, if group info is empty then remove it too
245 void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
247 //Player *plr = objmgr.GetPlayer(guid);
249 int32 queue_id = -1; // signed for proper for-loop finish
250 QueuedPlayersMap::iterator itr;
252 //remove player from map, if he's there
253 itr = m_QueuedPlayers.find(guid);
254 if( itr == m_QueuedPlayers.end() )
256 sLog.outError("BattleGroundQueue: couldn't find player to remove GUID: %u", GUID_LOPART(guid));
257 return;
260 GroupQueueInfo* group = itr->second.GroupInfo;
261 GroupsQueueType::iterator group_itr, group_itr_tmp;
262 // mostly people with the highest levels are in battlegrounds, thats why
263 // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0
264 // variable index removes useless searching in other team's queue
265 uint32 index = (group->Team == HORDE) ? BG_TEAM_HORDE : BG_TEAM_ALLIANCE;
267 for (int32 queue_id_tmp = MAX_BATTLEGROUND_QUEUES - 1; queue_id_tmp >= 0 && queue_id == -1; --queue_id_tmp)
269 //we must check premade and normal team's queue - because when players from premade are joining bg,
270 //they leave groupinfo so we can't use its players size to find out index
271 for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_QUEUE_NORMAL_ALLIANCE)
273 for(group_itr_tmp = m_QueuedGroups[queue_id_tmp][j].begin(); group_itr_tmp != m_QueuedGroups[queue_id_tmp][j].end(); ++group_itr_tmp)
275 if( (*group_itr_tmp) == group )
277 queue_id = queue_id_tmp;
278 group_itr = group_itr_tmp;
279 //we must store index to be able to erase iterator
280 index = j;
281 break;
286 //player can't be in queue without group, but just in case
287 if( queue_id == -1 )
289 sLog.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid));
290 return;
292 sLog.outDebug("BattleGroundQueue: Removing player GUID %u, from queue_id %u", GUID_LOPART(guid), (uint32)queue_id);
294 // ALL variables are correctly set
295 // We can ignore leveling up in queue - it should not cause crash
296 // remove player from group
297 // if only one player there, remove group
299 // remove player queue info from group queue info
300 std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
301 if( pitr != group->Players.end() )
302 group->Players.erase(pitr);
304 // if invited to bg, and should decrease invited count, then do it
305 if( decreaseInvitedCount && group->IsInvitedToBGInstanceGUID )
307 BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID, group->BgTypeId);
308 if( bg )
309 bg->DecreaseInvitedCount(group->Team);
312 // remove player queue info
313 m_QueuedPlayers.erase(itr);
315 //if we left BG queue(not porting) OR if arena team left queue for rated match
316 if( (decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()) )
317 AnnounceWorld(group, guid, false);
319 //if player leaves queue and he is invited to rated arena match, then he have to loose
320 if( group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount )
322 ArenaTeam * at = objmgr.GetArenaTeamById(group->ArenaTeamId);
323 if( at )
325 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating);
326 Player *plr = objmgr.GetPlayer(guid);
327 if( plr )
328 at->MemberLost(plr, group->OpponentsTeamRating);
329 else
330 at->OfflineMemberLost(guid, group->OpponentsTeamRating);
331 at->SaveToDB();
335 // remove group queue info if needed
336 if( group->Players.empty() )
338 m_QueuedGroups[queue_id][index].erase(group_itr);
339 delete group;
341 // if group wasn't empty, so it wasn't deleted, and player have left a rated
342 // queue -> everyone from the group should leave too
343 // don't remove recursively if already invited to bg!
344 else if( !group->IsInvitedToBGInstanceGUID && group->IsRated )
346 // remove next player, this is recursive
347 // first send removal information
348 if(Player *plr2 = objmgr.GetPlayer(group->Players.begin()->first))
350 BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
351 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType);
352 uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
353 plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to
354 // queue->removeplayer, it causes bugs
355 WorldPacket data;
356 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0);
357 plr2->GetSession()->SendPacket(&data);
359 // then actually delete, this may delete the group as well!
360 RemovePlayer(group->Players.begin()->first, decreaseInvitedCount);
364 //Announce world message
365 void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue)
367 if(ginfo->ArenaType) //if Arena
369 if( sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated )
371 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
372 if(!bg)
373 return;
375 char const* bgName = bg->GetName();
376 if(isAddedToQueue)
377 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
378 else
379 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
382 else //if BG
384 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
386 Player *plr = objmgr.GetPlayer(playerGUID);
387 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
388 if(!bg || !plr)
389 return;
391 BGQueueIdBasedOnLevel queue_id = plr->GetBattleGroundQueueIdFromLevel(bg->GetTypeID());
392 char const* bgName = bg->GetName();
393 uint32 MinPlayers = bg->GetMinPlayersPerTeam();
394 uint32 qHorde = 0;
395 uint32 qAlliance = 0;
396 uint32 q_min_level = (queue_id + 1) * 10;
397 GroupsQueueType::const_iterator itr;
398 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
399 if( !(*itr)->IsInvitedToBGInstanceGUID )
400 qAlliance += (*itr)->Players.size();
401 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
402 if( !(*itr)->IsInvitedToBGInstanceGUID )
403 qHorde += (*itr)->Players.size();
405 // Show queue status to player only (when joining queue)
406 if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY) )
408 ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
409 bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
411 // System message
412 else
414 sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
415 bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
421 bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
423 // set side if needed
424 if( side )
425 ginfo->Team = side;
427 if( !ginfo->IsInvitedToBGInstanceGUID )
429 // not yet invited
430 // set invitation
431 ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
432 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
433 BGQueueIdBasedOnLevel queue_id = bg->GetQueueId();
434 // loop through the players
435 for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
437 // get the player
438 Player* plr = objmgr.GetPlayer(itr->first);
439 // if offline, skip him, this should not happen - player is removed from queue when he logs out
440 if( !plr )
441 continue;
443 // invite the player
444 PlayerInvitedToBGUpdateAverageWaitTime(ginfo, queue_id);
445 sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(), bg->GetTypeID(), ginfo->Team);
447 WorldPacket data;
449 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
451 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());
453 // send status packet
454 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);
455 plr->GetSession()->SendPacket(&data);
457 return true;
460 return false;
463 // used to remove the Enter Battle window if the battle has already ended, but someone still has it
464 // (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event
465 void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
467 BGQueueIdBasedOnLevel queue_id = bg->GetQueueId();
468 uint32 bgInstanceId = bg->GetInstanceID();
469 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
470 GroupsQueueType::iterator itr, next;
471 for(uint32 i = 0; i < BG_QUEUE_GROUP_TYPES_COUNT; i++)
473 itr = m_QueuedGroups[queue_id][i].begin();
474 next = itr;
475 while (next != m_QueuedGroups[queue_id][i].end())
477 // must do this way, because the groupinfo will be deleted when all playerinfos are removed
478 itr = next;
479 ++next;
480 GroupQueueInfo * ginfo = (*itr);
481 // if group was invited to this bg instance, then remove all references
482 if( ginfo->IsInvitedToBGInstanceGUID == bgInstanceId )
484 // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop
485 uint32 to_remove = ginfo->Players.size();
486 for(uint32 j = 0; j < to_remove; j++)
488 // always remove the first one in the group
489 std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();
490 if( itr2 == ginfo->Players.end() )
492 sLog.outError("Empty Players in ginfo, this should never happen!");
493 return;
495 // get the player
496 Player * plr = objmgr.GetPlayer(itr2->first);
497 if( !plr )
499 sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");
500 continue;
503 // get the queueslot
504 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
505 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
507 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
508 // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!
509 RemovePlayer(itr2->first, true);
510 WorldPacket data;
511 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0);
512 plr->GetSession()->SendPacket(&data);
521 This function is inviting players to already running battlegrounds
522 Invitation type is based on config file
523 large groups are disadvantageous, because they will be kicked first if invitation type = 1
525 void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id)
527 uint32 hordeFree = bg->GetFreeSlotsForTeam(HORDE);
528 uint32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE);
530 //iterator for iterating through bg queue
531 GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin();
532 //count of groups in queue - used to stop cycles
533 uint32 aliCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].size();
534 //index to queue which group is current
535 uint32 aliIndex = 0;
536 for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++)
537 ++Ali_itr;
538 //the same thing for horde
539 GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin();
540 uint32 hordeCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].size();
541 uint32 hordeIndex = 0;
542 for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++)
543 ++Horde_itr;
545 //if ofc like BG queue invitation is set in config, then we are happy
546 if (sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == 0)
547 return;
550 if we reached this code, then we have to solve NP - complete problem called Subset sum problem
551 So one solution is to check all possible invitation subgroups, or we can use these conditions:
552 1. Last time when BattleGroundQueue::Update was executed we invited all possible players - so there is only small possibility
553 that we will invite now whole queue, because only 1 change has been made to queues from the last BattleGroundQueue::Update call
554 2. Other thing we should consider is group order in queue
557 // At first we need to compare free space in bg and our selection pool
558 int32 diffAli = aliFree - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount();
559 int32 diffHorde = hordeFree - m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount();
560 while( abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0) )
562 //each cycle execution we need to kick at least 1 group
563 if( diffAli < diffHorde )
565 //kick alliance group, add to pool new group if needed
566 if( m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli) )
568 for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++)
569 ++Ali_itr;
571 //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break;
572 if( !m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() )
574 if( aliFree <= diffHorde + 1 )
575 break;
576 m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli);
579 else
581 //kick horde group, add to pool new group if needed
582 if( m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde) )
584 for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++)
585 ++Horde_itr;
587 if( !m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() )
589 if( hordeFree <= diffAli + 1 )
590 break;
591 m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde);
594 //count diffs after small update
595 diffAli = aliFree - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount();
596 diffHorde = hordeFree - m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount();
600 // this method checks if premade versus premade battleground is possible
601 // then after 30 mins (default) in queue it moves premade group to normal queue
602 // it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players
603 bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
605 //check match
606 if(!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
608 //start premade match
609 //if groups aren't invited
610 GroupsQueueType::const_iterator ali_group, horde_group;
611 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)
612 if( !(*ali_group)->IsInvitedToBGInstanceGUID )
613 break;
614 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)
615 if( !(*horde_group)->IsInvitedToBGInstanceGUID )
616 break;
618 if( ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end())
620 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
621 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
622 //add groups/players from normal queue to size of bigger group
623 uint32 maxPlayers = std::max(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
624 GroupsQueueType::const_iterator itr;
625 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
627 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
629 //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
630 if( !(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers) )
631 break;
634 //premade selection pools are set
635 return true;
638 // now check if we can move group from Premade queue to normal queue (timer has expired) or group size lowered!!
639 // this could be 2 cycles but i'm checking only first team in queue - it can cause problem -
640 // 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
641 // and when they click or after 80 seconds the queue info is removed from queue
642 uint32 time_before = getMSTime() - sWorld.getConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
643 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
645 if(!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
647 GroupsQueueType::iterator itr = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin();
648 if(!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam))
650 //we must insert group to normal queue and erase pointer from premade queue
651 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
652 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr);
656 //selection pools are not set
657 return false;
660 // this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
661 bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers)
663 GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
664 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
666 itr_team[i] = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
667 for(; itr_team[i] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i]))
669 if( !(*(itr_team[i]))->IsInvitedToBGInstanceGUID )
671 m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers);
672 if( m_SelectionPools[i].GetPlayerCount() >= minPlayers )
673 break;
677 //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
678 uint32 j = BG_TEAM_ALLIANCE;
679 if( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() )
680 j = BG_TEAM_HORDE;
681 if( sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != 0
682 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers )
684 //we will try to invite more groups to team with less players indexed by j
685 ++(itr_team[j]); //this will not cause a crash, because for cycle above reached break;
686 for(; itr_team[j] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
688 if( !(*(itr_team[j]))->IsInvitedToBGInstanceGUID )
689 if( !m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()) )
690 break;
692 // do not allow to start bg with more than 2 players more on 1 faction
693 if( abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2 )
694 return false;
696 //allow 1v0 if debug bg
697 if( sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) )
698 return true;
699 //return true if there are enough players in selection pools - enable to work .debug bg command correctly
700 return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers;
703 // this method will check if we can invite players to same faction skirmish match
704 bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam)
706 if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam )
707 return false;
708 uint32 teamIndex = BG_TEAM_ALLIANCE;
709 uint32 otherTeam = BG_TEAM_HORDE;
710 uint32 otherTeamId = HORDE;
711 if ( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam )
713 teamIndex = BG_TEAM_HORDE;
714 otherTeam = BG_TEAM_ALLIANCE;
715 otherTeamId = ALLIANCE;
717 //clear other team's selection
718 m_SelectionPools[otherTeam].Init();
719 //store last ginfo pointer
720 GroupQueueInfo* ginfo = m_SelectionPools[teamIndex].SelectedGroups.back();
721 //set itr_team to group that was added to selection pool latest
722 GroupsQueueType::iterator itr_team = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin();
723 for(; itr_team != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team)
724 if( ginfo == *itr_team )
725 break;
726 if( itr_team == m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end() )
727 return false;
728 GroupsQueueType::iterator itr_team2 = itr_team;
729 ++itr_team2;
730 //invite players to other selection pool
731 for(; itr_team2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team2)
733 //if selection pool is full then break;
734 if( !(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam) )
735 break;
737 if( m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam )
738 return false;
740 //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue
741 for(GroupsQueueType::iterator itr = m_SelectionPools[otherTeam].SelectedGroups.begin(); itr != m_SelectionPools[otherTeam].SelectedGroups.end(); ++itr)
743 //set correct team
744 (*itr)->Team = otherTeamId;
745 //add team to other queue
746 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + otherTeam].push_front(*itr);
747 //remove team from old queue
748 GroupsQueueType::iterator itr2 = itr_team;
749 ++itr2;
750 for(; itr2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2)
752 if( *itr2 == *itr )
754 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].erase(itr2);
755 break;
759 return true;
763 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
764 it must be called after fully adding the members of a group to ensure group joining
765 should be called from BattleGround::RemovePlayer function in some cases
767 void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated, uint32 arenaRating)
769 //if no players in queue - do nothing
770 if( m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
771 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() &&
772 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
773 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].empty() )
774 return;
776 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, arenaType);
778 //battleground with free slot for player should be always in the beggining of the queue
779 // maybe it would be better to create bgfreeslotqueue for each queue_id_based_on_level
780 BGFreeSlotQueueType::iterator itr, next;
781 for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
783 next = itr;
784 ++next;
785 // DO NOT allow queue manager to invite new player to arena
786 if( (*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueId() == queue_id &&
787 (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE )
789 BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
790 // and iterator is invalid
792 // clear selection pools
793 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
794 m_SelectionPools[BG_TEAM_HORDE].Init();
796 // call a function that does the job for us
797 FillPlayersToBG(bg, queue_id);
799 // now everything is set, invite players
800 for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.end(); ++itr)
801 InviteGroupToBG((*itr), bg, (*itr)->Team);
802 for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.end(); ++itr)
803 InviteGroupToBG((*itr), bg, (*itr)->Team);
805 if( !bg->HasFreeSlots() )
807 // remove BG from BGFreeSlotQueue
808 bg->RemoveFromBGFreeSlotQueue();
813 // finished iterating through the bgs with free slots, maybe we need to create a new bg
815 BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
816 if( !bg_template )
818 sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
819 return;
821 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
822 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
823 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
824 if( sBattleGroundMgr.isTesting() )
825 MinPlayersPerTeam = 1;
826 if( bg_template->isArena() )
828 if( sBattleGroundMgr.isArenaTesting() )
830 MaxPlayersPerTeam = 1;
831 MinPlayersPerTeam = 1;
833 else
835 //this switch can be much shorter
836 MaxPlayersPerTeam = arenaType;
837 MinPlayersPerTeam = arenaType;
838 /*switch(arenaType)
840 case ARENA_TYPE_2v2:
841 MaxPlayersPerTeam = 2;
842 MinPlayersPerTeam = 2;
843 break;
844 case ARENA_TYPE_3v3:
845 MaxPlayersPerTeam = 3;
846 MinPlayersPerTeam = 3;
847 break;
848 case ARENA_TYPE_5v5:
849 MaxPlayersPerTeam = 5;
850 MinPlayersPerTeam = 5;
851 break;
856 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
857 m_SelectionPools[BG_TEAM_HORDE].Init();
859 if( bg_template->isBattleGround() )
861 //check if there is premade against premade match
862 if( CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam) )
864 //create new battleground
865 BattleGround * bg2 = NULL;
866 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, 0, false)) )
868 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
869 return;
871 //invite those selection pools
872 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
873 for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++itr)
874 InviteGroupToBG((*itr), bg2, (*itr)->Team);
875 //start bg
876 bg2->StartBattleGround();
877 //clear structures
878 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
879 m_SelectionPools[BG_TEAM_HORDE].Init();
883 // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
884 if( !isRated )
886 // if there are enough players in pools, start new battleground or non rated arena
887 if( CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam)
888 || (bg_template->isArena() && CheckSkirmishForSameFaction(queue_id, MinPlayersPerTeam)) )
890 // we successfully created a pool
891 BattleGround * bg2 = NULL;
892 if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, false)) )
894 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
895 return;
898 // invite those selection pools
899 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
900 for(GroupsQueueType::const_iterator itr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); itr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++itr)
901 InviteGroupToBG((*itr), bg2, (*itr)->Team);
902 // start bg
903 bg2->StartBattleGround();
906 else if( bg_template->isArena() )
908 // found out the minimum and maximum ratings the newly added team should battle against
909 // arenaRating is the rating of the latest joined team, or 0
910 // 0 is on (automatic update call) and we must set it to team's with longest wait time
911 if ( !arenaRating )
913 GroupQueueInfo* front1 = NULL;
914 GroupQueueInfo* front2 = NULL;
915 if( !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() )
917 front1 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].front();
918 arenaRating = front1->ArenaTeamRating;
920 if( !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() )
922 front2 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].front();
923 arenaRating = front2->ArenaTeamRating;
925 if( front1 && front2 )
927 if( front1->JoinTime < front2->JoinTime )
928 arenaRating = front1->ArenaTeamRating;
930 else if( !front1 && !front2 )
931 return; //queues are empty
934 //set rating range
935 uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
936 uint32 arenaMaxRating = arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
937 // if max rating difference is set and the time past since server startup is greater than the rating discard time
938 // (after what time the ratings aren't taken into account when making teams) then
939 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
940 // else leave the discard time on 0, this way all ratings will be discarded
941 uint32 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
943 // we need to find 2 teams which will play next game
945 GroupsQueueType::iterator itr_team[BG_TEAMS_COUNT];
947 //optimalization : --- we dont need to use selection_pools - each update we select max 2 groups
949 for(uint32 i = BG_QUEUE_PREMADE_ALLIANCE; i < BG_QUEUE_NORMAL_ALLIANCE; i++)
951 // take the group that joined first
952 itr_team[i] = m_QueuedGroups[queue_id][i].begin();
953 for(; itr_team[i] != m_QueuedGroups[queue_id][i].end(); ++(itr_team[i]))
955 // if group match conditions, then add it to pool
956 if( !(*itr_team[i])->IsInvitedToBGInstanceGUID
957 && (((*itr_team[i])->ArenaTeamRating >= arenaMinRating && (*itr_team[i])->ArenaTeamRating <= arenaMaxRating)
958 || (*itr_team[i])->JoinTime < discardTime) )
960 m_SelectionPools[i].AddGroup((*itr_team[i]), MaxPlayersPerTeam);
961 // break for cycle to be able to start selecting another group from same faction queue
962 break;
966 // now we are done if we have 2 groups - ali vs horde!
967 // if we don't have, we must try to continue search in same queue
968 // tmp variables are correctly set
969 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue
970 if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() )
972 itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE];
973 ++itr_team[BG_TEAM_ALLIANCE];
974 for(; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE]))
976 if( !(*itr_team[BG_TEAM_ALLIANCE])->IsInvitedToBGInstanceGUID
977 && (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
978 || (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime) )
980 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*itr_team[BG_TEAM_ALLIANCE]), MaxPlayersPerTeam);
981 break;
985 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue
986 if( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() )
988 itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE];
989 ++itr_team[BG_TEAM_HORDE];
990 for(; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE]))
992 if( !(*itr_team[BG_TEAM_HORDE])->IsInvitedToBGInstanceGUID
993 && (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating)
994 || (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime) )
996 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*itr_team[BG_TEAM_HORDE]), MaxPlayersPerTeam);
997 break;
1002 //if we have 2 teams, then start new arena and invite players!
1003 if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() )
1005 BattleGround* arena = NULL;
1006 if( !(arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, true)) )
1008 sLog.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
1009 return;
1012 (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating;
1013 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating);
1014 (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating;
1015 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating);
1016 // 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
1017 if( (*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE )
1019 // add to alliance queue
1020 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE]));
1021 // erase from horde queue
1022 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]);
1023 itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
1025 if( (*(itr_team[BG_TEAM_HORDE]))->Team != HORDE )
1027 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE]));
1028 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]);
1029 itr_team[BG_TEAM_HORDE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin();
1032 InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE);
1033 InviteGroupToBG(*(itr_team[BG_TEAM_HORDE]), arena, HORDE);
1035 sLog.outDebug("Starting rated arena match!");
1037 arena->StartBattleGround();
1042 /*********************************************************/
1043 /*** BATTLEGROUND QUEUE EVENTS ***/
1044 /*********************************************************/
1046 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1048 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
1050 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1051 if (!plr)
1052 return true;
1054 // Player can be in another BG queue and must be removed in normal way in any case
1056 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1057 if (!bg)
1058 return true;
1060 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1061 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1062 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1064 // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
1065 BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
1066 BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
1067 if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1069 WorldPacket data;
1070 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITATION_REMIND_TIME, 0);
1071 plr->GetSession()->SendPacket(&data);
1074 return true; //event will be deleted
1077 void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
1079 //this should not be called
1080 sLog.outError("Battleground invite event ABORTED!");
1083 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1085 Player* plr = objmgr.GetPlayer( m_PlayerGuid );
1086 if (!plr)
1087 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1088 return true;
1090 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1091 if (!bg)
1092 return true;
1094 sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
1096 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1097 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1098 if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue
1100 // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems
1101 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
1102 BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid);
1103 if (qMapItr != qpMap.end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID)
1105 plr->RemoveBattleGroundQueueId(bgQueueTypeId);
1106 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
1107 sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bg->GetTypeID(), bg->GetQueueId());
1108 WorldPacket data;
1109 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0);
1110 plr->GetSession()->SendPacket(&data);
1113 else
1114 sLog.outDebug("Battleground: Player was already removed from queue");
1116 //event will be deleted
1117 return true;
1120 void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
1122 //this should not be called
1123 sLog.outError("Battleground remove event ABORTED!");
1126 /*********************************************************/
1127 /*** BATTLEGROUND MANAGER ***/
1128 /*********************************************************/
1130 BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
1132 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1133 m_BattleGrounds[i].clear();
1134 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1135 m_Testing=false;
1138 BattleGroundMgr::~BattleGroundMgr()
1140 DeleteAllBattleGrounds();
1143 void BattleGroundMgr::DeleteAllBattleGrounds()
1145 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1147 for(BattleGroundSet::iterator itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end();)
1149 BattleGround * bg = itr->second;
1150 m_BattleGrounds[i].erase(itr++);
1151 delete bg;
1155 // destroy template battlegrounds that listed only in queues (other already terminated)
1156 for(uint32 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId)
1158 // ~BattleGround call unregistring BG from queue
1159 while(!BGFreeSlotQueue[bgTypeId].empty())
1160 delete BGFreeSlotQueue[bgTypeId].front();
1164 // used to update running battlegrounds, and delete finished ones
1165 void BattleGroundMgr::Update(uint32 diff)
1167 BattleGroundSet::iterator itr, next;
1168 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1170 itr = m_BattleGrounds[i].begin();
1171 // skip updating battleground template
1172 if( itr != m_BattleGrounds[i].end() )
1173 ++itr;
1174 for(itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end(); itr = next)
1176 next = itr;
1177 ++next;
1178 itr->second->Update(diff);
1179 // use the SetDeleteThis variable
1180 // direct deletion caused crashes
1181 if(itr->second->m_SetDeleteThis)
1183 BattleGround * bg = itr->second;
1184 m_BattleGrounds[i].erase(itr);
1185 delete bg;
1189 // if rating difference counts, maybe force-update queues
1190 if(sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER))
1192 // it's time to force update
1193 if(m_NextRatingDiscardUpdate < diff)
1195 // forced update for level 70 rated arenas
1196 sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
1197 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_2v2, true, 0);
1198 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_2v2, true, 0);
1199 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_3v3, true, 0);
1200 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_3v3, true, 0);
1201 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_5v5, true, 0);
1202 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_5v5, true, 0);
1203 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1205 else
1206 m_NextRatingDiscardUpdate -= diff;
1208 if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1210 if(m_AutoDistributionTimeChecker < diff)
1212 if(sWorld.GetGameTime() > m_NextAutoDistributionTime)
1214 DistributeArenaPoints();
1215 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1216 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"I64FMTD"'", m_NextAutoDistributionTime);
1218 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1220 else
1221 m_AutoDistributionTimeChecker -= diff;
1225 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype)
1227 // we can be in 3 queues in same time...
1228 if(StatusID == 0)
1230 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
1231 *data << uint32(QueueSlot); // queue id (0...2)
1232 *data << uint64(0);
1233 return;
1236 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
1237 *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1238 // uint64 in client
1239 *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1240 *data << uint32(0); // unknown
1241 // alliance/horde for BG and skirmish/rated for Arenas
1242 // following displays the minimap-icon 0 = faction icon 1 = arenaicon
1243 *data << uint8(bg->isArena());
1244 /* *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!!!!
1245 switch(bg->GetTypeID()) // value depends on bg id
1247 case BATTLEGROUND_AV:
1248 *data << uint8(1);
1249 break;
1250 case BATTLEGROUND_WS:
1251 *data << uint8(2);
1252 break;
1253 case BATTLEGROUND_AB:
1254 *data << uint8(3);
1255 break;
1256 case BATTLEGROUND_NA:
1257 *data << uint8(4);
1258 break;
1259 case BATTLEGROUND_BE:
1260 *data << uint8(5);
1261 break;
1262 case BATTLEGROUND_AA:
1263 *data << uint8(6);
1264 break;
1265 case BATTLEGROUND_EY:
1266 *data << uint8(7);
1267 break;
1268 case BATTLEGROUND_RL:
1269 *data << uint8(8);
1270 break;
1271 case BATTLEGROUND_SA:
1272 *data << uint8(9);
1273 break;
1274 case BATTLEGROUND_DS:
1275 *data << uint8(10);
1276 break;
1277 case BATTLEGROUND_RV:
1278 *data << uint8(11);
1279 break;
1280 default: // unknown
1281 *data << uint8(0);
1282 break;
1285 if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1286 *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1287 else
1288 *data << uint32(bg->GetTypeID()); // BG id from DBC
1290 *data << uint16(0x1F90); // unk value 8080
1291 *data << uint32(bg->GetInstanceID()); // instance id
1293 *data << uint8(bg->isArena()); // minimap-icon 0=faction 1=arena
1295 *data << uint32(StatusID); // status
1296 switch(StatusID)
1298 case STATUS_WAIT_QUEUE: // status_in_queue
1299 *data << uint32(Time1); // average wait time, milliseconds
1300 *data << uint32(Time2); // time in queue, updated every minute?
1301 break;
1302 case STATUS_WAIT_JOIN: // status_invite
1303 *data << uint32(bg->GetMapId()); // map id
1304 *data << uint32(Time1); // time to remove from queue, milliseconds
1305 break;
1306 case STATUS_IN_PROGRESS: // status_in_progress
1307 *data << uint32(bg->GetMapId()); // map id
1308 *data << uint32(Time1); // 0 at bg start, 120000 after bg end, time to bg auto leave, milliseconds
1309 *data << uint32(Time2); // time from bg start, milliseconds
1310 *data << uint8(0x1); // unk sometimes 0x0!
1311 break;
1312 default:
1313 sLog.outError("Unknown BG status!");
1314 break;
1318 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1320 uint8 type = (bg->isArena() ? 1 : 0);
1321 // last check on 3.0.3
1322 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1323 *data << uint8(type); // type (battleground=0/arena=1)
1325 if(type) // arena
1327 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1328 for(int i = 1; i >= 0; --i)
1330 *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
1331 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1332 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1334 for(int i = 1; i >= 0; --i)
1336 uint32 at_id = bg->m_ArenaTeamIds[i];
1337 ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
1338 if(at)
1339 *data << at->GetName();
1340 else
1341 *data << (uint8)0;
1345 if(bg->GetStatus() != STATUS_WAIT_LEAVE)
1347 *data << uint8(0); // bg not ended
1349 else
1351 *data << uint8(1); // bg ended
1352 *data << uint8(bg->GetWinner()); // who win
1355 *data << (int32)(bg->GetPlayerScoresSize());
1357 for(std::map<uint64, BattleGroundScore*>::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1359 *data << (uint64)itr->first;
1360 *data << (int32)itr->second->KillingBlows;
1361 if(type == 0)
1363 *data << (int32)itr->second->HonorableKills;
1364 *data << (int32)itr->second->Deaths;
1365 *data << (int32)(itr->second->BonusHonor);
1367 else
1369 Player *plr = objmgr.GetPlayer(itr->first);
1370 uint32 team = bg->GetPlayerTeam(itr->first);
1371 if(!team && plr)
1372 team = plr->GetTeam();
1373 if( ( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ) )
1374 *data << uint8(1);
1375 else
1376 *data << uint8(0);
1378 *data << (int32)itr->second->DamageDone; // damage done
1379 *data << (int32)itr->second->HealingDone; // healing done
1380 switch(bg->GetTypeID()) // battleground specific things
1382 case BATTLEGROUND_AV:
1383 *data << (uint32)0x00000005; // count of next fields
1384 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1385 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1386 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1387 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1388 *data << (uint32)((BattleGroundAVScore*)itr->second)->MinesCaptured; // MinesCaptured
1389 break;
1390 case BATTLEGROUND_WS:
1391 *data << (uint32)0x00000002; // count of next fields
1392 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1393 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1394 break;
1395 case BATTLEGROUND_AB:
1396 *data << (uint32)0x00000002; // count of next fields
1397 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1398 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1399 break;
1400 case BATTLEGROUND_EY:
1401 *data << (uint32)0x00000001; // count of next fields
1402 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1403 break;
1404 case BATTLEGROUND_NA:
1405 case BATTLEGROUND_BE:
1406 case BATTLEGROUND_AA:
1407 case BATTLEGROUND_RL:
1408 case BATTLEGROUND_SA: // wotlk
1409 case BATTLEGROUND_DS: // wotlk
1410 case BATTLEGROUND_RV: // wotlk
1411 *data << (int32)0; // 0
1412 break;
1413 default:
1414 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1415 *data << (int32)0;
1416 break;
1421 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
1423 /*bgTypeId is:
1424 0 - Your group has joined a battleground queue, but you are not eligible
1425 1 - Your group has joined the queue for AV
1426 2 - Your group has joined the queue for WS
1427 3 - Your group has joined the queue for AB
1428 4 - Your group has joined the queue for NA
1429 5 - Your group has joined the queue for BE Arena
1430 6 - Your group has joined the queue for All Arenas
1431 7 - Your group has joined the queue for EotS*/
1432 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1433 *data << uint32(bgTypeId);
1436 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1438 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1439 *data << uint32(field);
1440 *data << uint32(value);
1443 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1445 data->Initialize(SMSG_PLAY_SOUND, 4);
1446 *data << uint32(soundid);
1449 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid)
1451 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1452 *data << uint64(guid);
1455 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1457 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1458 *data << uint64(plr->GetGUID());
1461 void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, BattleGroundTypeId bgTypeId, uint32 team)
1463 // set invited player counters:
1464 BattleGround* bg = GetBattleGround(bgInstanceGUID, bgTypeId);
1465 if(!bg)
1466 return;
1467 bg->IncreaseInvitedCount(team);
1469 plr->SetInviteForBattleGroundQueueType(BGQueueTypeId(bg->GetTypeID(),bg->GetArenaType()), bgInstanceGUID);
1471 // set the arena teams for rated matches
1472 if(bg->isArena() && bg->isRated())
1474 switch(bg->GetArenaType())
1476 case ARENA_TYPE_2v2:
1477 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));
1478 break;
1479 case ARENA_TYPE_3v3:
1480 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));
1481 break;
1482 case ARENA_TYPE_5v5:
1483 bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));
1484 break;
1485 default:
1486 break;
1490 // create invite events:
1491 //add events to player's counters ---- this is not good way - there should be something like global event processor, where we should add those events
1492 BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID, bgTypeId);
1493 plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME));
1494 BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, bgTypeId, team);
1495 plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
1498 BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
1500 //search if needed
1501 BattleGroundSet::iterator itr;
1502 if( bgTypeId == BATTLEGROUND_TYPE_NONE)
1504 for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1506 itr = m_BattleGrounds[i].find(InstanceID);
1507 if( itr != m_BattleGrounds[i].end() )
1508 return itr->second;
1510 return NULL;
1512 itr = m_BattleGrounds[bgTypeId].find(InstanceID);
1513 return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL );
1516 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
1518 //map is sorted and we can be sure that lowest instance id has only BG template
1519 return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second;
1522 // create a new battleground that will really be used to play
1523 BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated)
1525 // get the template BG
1526 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1527 if(!bg_template)
1529 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1530 return NULL;
1533 //for arenas there is random map used
1534 if(bg_template->isArena())
1536 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
1537 uint32 arena_num = urand(0,2);
1538 bgTypeId = arenas[arena_num];
1539 bg_template = GetBattleGroundTemplate(bgTypeId);
1540 if(!bg_template)
1542 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1543 return NULL;
1547 BattleGround *bg = NULL;
1548 // create a copy of the BG template
1549 switch(bgTypeId)
1551 case BATTLEGROUND_AV:
1552 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1553 break;
1554 case BATTLEGROUND_WS:
1555 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1556 break;
1557 case BATTLEGROUND_AB:
1558 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1559 break;
1560 case BATTLEGROUND_NA:
1561 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1562 break;
1563 case BATTLEGROUND_BE:
1564 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1565 break;
1566 case BATTLEGROUND_AA:
1567 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1568 break;
1569 case BATTLEGROUND_EY:
1570 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1571 break;
1572 case BATTLEGROUND_RL:
1573 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1574 break;
1575 case BATTLEGROUND_SA:
1576 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1577 break;
1578 case BATTLEGROUND_DS:
1579 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1580 break;
1581 case BATTLEGROUND_RV:
1582 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1583 break;
1584 default:
1585 //error, but it is handled few lines above
1586 return 0;
1589 // generate a new instance id
1590 bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
1592 // reset the new bg (set status to status_wait_queue from status_none)
1593 bg->Reset();
1595 // start the joining of the bg
1596 bg->SetStatus(STATUS_WAIT_JOIN);
1597 bg->SetQueueId(queue_id);
1598 bg->SetArenaType(arenaType);
1599 bg->SetRated(isRated);
1601 // add BG to free slot queue
1602 bg->AddToBGFreeSlotQueue();
1604 // add bg to update list
1605 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1607 return bg;
1610 // used to create the BG templates
1611 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)
1613 // Create the BG
1614 BattleGround *bg = NULL;
1615 switch(bgTypeId)
1617 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1618 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1619 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1620 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1621 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1622 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1623 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1624 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1625 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1626 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1627 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1628 default:bg = new BattleGround; break; // placeholder for non implemented BG
1631 bg->SetMapId(MapID);
1632 bg->SetTypeID(bgTypeId);
1633 bg->SetInstanceID(0);
1634 bg->SetArenaorBGType(IsArena);
1635 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1636 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1637 bg->SetMinPlayers(MinPlayersPerTeam * 2);
1638 bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
1639 bg->SetName(BattleGroundName);
1640 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1641 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1642 bg->SetLevelRange(LevelMin, LevelMax);
1644 // add bg to update list
1645 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1647 // return some not-null value, bgTypeId is good enough for me
1648 return bgTypeId;
1651 void BattleGroundMgr::CreateInitialBattleGrounds()
1653 float AStartLoc[4];
1654 float HStartLoc[4];
1655 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1656 BattlemasterListEntry const *bl;
1657 WorldSafeLocsEntry const *start;
1658 bool IsArena;
1660 uint32 count = 0;
1662 // 0 1 2 3 4 5 6 7 8
1663 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1665 if(!result)
1667 barGoLink bar(1);
1669 bar.step();
1671 sLog.outString();
1672 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1673 return;
1676 barGoLink bar(result->GetRowCount());
1680 Field *fields = result->Fetch();
1681 bar.step();
1683 uint32 bgTypeID_ = fields[0].GetUInt32();
1685 // can be overwrite by values from DB
1686 bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
1687 if(!bl)
1689 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
1690 continue;
1693 BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
1695 IsArena = (bl->type == TYPE_ARENA);
1696 MinPlayersPerTeam = fields[1].GetUInt32();
1697 MaxPlayersPerTeam = fields[2].GetUInt32();
1698 MinLvl = fields[3].GetUInt32();
1699 MaxLvl = fields[4].GetUInt32();
1700 //check values from DB
1701 if( MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam )
1703 MaxPlayersPerTeam = bl->maxplayersperteam;
1704 MinPlayersPerTeam = bl->maxplayersperteam / 2;
1706 if( MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl )
1708 MinLvl = bl->minlvl;
1709 MaxLvl = bl->maxlvl;
1712 start1 = fields[5].GetUInt32();
1714 start = sWorldSafeLocsStore.LookupEntry(start1);
1715 if(start)
1717 AStartLoc[0] = start->x;
1718 AStartLoc[1] = start->y;
1719 AStartLoc[2] = start->z;
1720 AStartLoc[3] = fields[6].GetFloat();
1722 else if(bgTypeID == BATTLEGROUND_AA)
1724 AStartLoc[0] = 0;
1725 AStartLoc[1] = 0;
1726 AStartLoc[2] = 0;
1727 AStartLoc[3] = fields[6].GetFloat();
1729 else
1731 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
1732 continue;
1735 start2 = fields[7].GetUInt32();
1737 start = sWorldSafeLocsStore.LookupEntry(start2);
1738 if(start)
1740 HStartLoc[0] = start->x;
1741 HStartLoc[1] = start->y;
1742 HStartLoc[2] = start->z;
1743 HStartLoc[3] = fields[8].GetFloat();
1745 else if(bgTypeID == BATTLEGROUND_AA)
1747 HStartLoc[0] = 0;
1748 HStartLoc[1] = 0;
1749 HStartLoc[2] = 0;
1750 HStartLoc[3] = fields[8].GetFloat();
1752 else
1754 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
1755 continue;
1758 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1759 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]))
1760 continue;
1762 ++count;
1763 } while (result->NextRow());
1765 delete result;
1767 sLog.outString();
1768 sLog.outString( ">> Loaded %u battlegrounds", count );
1771 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1773 if(sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1775 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1776 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1777 if(!result)
1779 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1780 m_NextAutoDistributionTime = sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS);
1781 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"I64FMTD"')", m_NextAutoDistributionTime);
1783 else
1785 m_NextAutoDistributionTime = (*result)[0].GetUInt64();
1786 delete result;
1788 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1792 void BattleGroundMgr::DistributeArenaPoints()
1794 // used to distribute arena points based on last week's stats
1795 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
1797 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
1799 //temporary structure for storing maximum points to add values for all players
1800 std::map<uint32, uint32> PlayerPoints;
1802 //at first update all points for all team members
1803 for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
1805 if(ArenaTeam * at = team_itr->second)
1807 at->UpdateArenaPointsHelper(PlayerPoints);
1811 //cycle that gives points to all players
1812 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1814 //update to database
1815 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
1816 //add points if player is online
1817 Player* pl = objmgr.GetPlayer(plr_itr->first);
1818 if (pl)
1819 pl->ModifyArenaPoints(plr_itr->second);
1822 PlayerPoints.clear();
1824 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
1826 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
1827 for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
1829 if(ArenaTeam * at = titr->second)
1831 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1832 at->SaveToDB(); // save changes
1833 at->NotifyStatsChanged(); // notify the players of the changes
1837 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
1839 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
1842 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId)
1844 uint32 PlayerLevel = 10;
1846 if(plr)
1847 PlayerLevel = plr->getLevel();
1849 data->Initialize(SMSG_BATTLEFIELD_LIST);
1850 *data << uint64(guid); // battlemaster guid
1851 *data << uint32(bgTypeId); // battleground id
1852 if(bgTypeId == BATTLEGROUND_AA) // arena
1854 *data << uint8(5); // unk
1855 *data << uint32(0); // unk
1857 else // battleground
1859 *data << uint8(0x00); // unk
1861 size_t count_pos = data->wpos();
1862 uint32 count = 0;
1863 *data << uint32(0x00); // number of bg instances
1865 for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr)
1867 // skip sending battleground template
1868 if( itr == m_BattleGrounds[bgTypeId].begin() )
1869 continue;
1870 if( PlayerLevel >= itr->second->GetMinLevel() && PlayerLevel <= itr->second->GetMaxLevel() )
1872 *data << uint32(itr->second->GetInstanceID());
1873 ++count;
1876 data->put<uint32>( count_pos , count);
1880 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId)
1882 BattleGround *bg = GetBattleGround(instanceId, bgTypeId);
1883 if(bg)
1885 uint32 mapid = bg->GetMapId();
1886 float x, y, z, O;
1887 uint32 team = pl->GetBGTeam();
1888 if(team==0)
1889 team = pl->GetTeam();
1890 bg->GetTeamStartLoc(team, x, y, z, O);
1892 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1893 pl->TeleportTo(mapid, x, y, z, O);
1895 else
1897 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1901 void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid)
1903 WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
1904 uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
1905 if(time_ == uint32(-1))
1906 time_ = 0;
1907 data << guid << time_;
1908 pl->GetSession()->SendPacket(&data);
1911 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
1913 return ( bgTypeId == BATTLEGROUND_AA ||
1914 bgTypeId == BATTLEGROUND_BE ||
1915 bgTypeId == BATTLEGROUND_NA ||
1916 bgTypeId == BATTLEGROUND_RL );
1919 BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
1921 switch(bgTypeId)
1923 case BATTLEGROUND_WS:
1924 return BATTLEGROUND_QUEUE_WS;
1925 case BATTLEGROUND_AB:
1926 return BATTLEGROUND_QUEUE_AB;
1927 case BATTLEGROUND_AV:
1928 return BATTLEGROUND_QUEUE_AV;
1929 case BATTLEGROUND_EY:
1930 return BATTLEGROUND_QUEUE_EY;
1931 case BATTLEGROUND_SA:
1932 return BATTLEGROUND_QUEUE_SA;
1933 case BATTLEGROUND_AA:
1934 case BATTLEGROUND_NA:
1935 case BATTLEGROUND_RL:
1936 case BATTLEGROUND_BE:
1937 case BATTLEGROUND_DS:
1938 case BATTLEGROUND_RV:
1939 switch(arenaType)
1941 case ARENA_TYPE_2v2:
1942 return BATTLEGROUND_QUEUE_2v2;
1943 case ARENA_TYPE_3v3:
1944 return BATTLEGROUND_QUEUE_3v3;
1945 case ARENA_TYPE_5v5:
1946 return BATTLEGROUND_QUEUE_5v5;
1947 default:
1948 return BATTLEGROUND_QUEUE_NONE;
1950 default:
1951 return BATTLEGROUND_QUEUE_NONE;
1955 BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId)
1957 switch(bgQueueTypeId)
1959 case BATTLEGROUND_QUEUE_WS:
1960 return BATTLEGROUND_WS;
1961 case BATTLEGROUND_QUEUE_AB:
1962 return BATTLEGROUND_AB;
1963 case BATTLEGROUND_QUEUE_AV:
1964 return BATTLEGROUND_AV;
1965 case BATTLEGROUND_QUEUE_EY:
1966 return BATTLEGROUND_EY;
1967 case BATTLEGROUND_QUEUE_SA:
1968 return BATTLEGROUND_SA;
1969 case BATTLEGROUND_QUEUE_2v2:
1970 case BATTLEGROUND_QUEUE_3v3:
1971 case BATTLEGROUND_QUEUE_5v5:
1972 return BATTLEGROUND_AA;
1973 default:
1974 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
1978 uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId)
1980 switch(bgQueueTypeId)
1982 case BATTLEGROUND_QUEUE_2v2:
1983 return ARENA_TYPE_2v2;
1984 case BATTLEGROUND_QUEUE_3v3:
1985 return ARENA_TYPE_3v3;
1986 case BATTLEGROUND_QUEUE_5v5:
1987 return ARENA_TYPE_5v5;
1988 default:
1989 return 0;
1993 void BattleGroundMgr::ToggleTesting()
1995 m_Testing = !m_Testing;
1996 if(m_Testing)
1997 sWorld.SendWorldText(LANG_DEBUG_BG_ON);
1998 else
1999 sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
2002 void BattleGroundMgr::ToggleArenaTesting()
2004 m_ArenaTesting = !m_ArenaTesting;
2005 if(m_ArenaTesting)
2006 sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
2007 else
2008 sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
2011 uint32 BattleGroundMgr::GetMaxRatingDifference() const
2013 // this is for stupid people who can't use brain and set max rating difference to 0
2014 uint32 diff = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
2015 if (diff == 0)
2016 diff = 5000;
2017 return diff;
2020 uint32 BattleGroundMgr::GetRatingDiscardTimer() const
2022 return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
2025 uint32 BattleGroundMgr::GetPrematureFinishTime() const
2027 return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
2030 void BattleGroundMgr::LoadBattleMastersEntry()
2032 mBattleMastersMap.clear(); // need for reload case
2034 QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
2036 uint32 count = 0;
2038 if( !result )
2040 barGoLink bar( 1 );
2041 bar.step();
2043 sLog.outString();
2044 sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
2045 return;
2048 barGoLink bar( result->GetRowCount() );
2052 ++count;
2053 bar.step();
2055 Field *fields = result->Fetch();
2057 uint32 entry = fields[0].GetUInt32();
2058 uint32 bgTypeId = fields[1].GetUInt32();
2059 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
2061 sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
2062 continue;
2065 mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
2067 } while( result->NextRow() );
2069 delete result;
2071 sLog.outString();
2072 sLog.outString( ">> Loaded %u battlemaster entries", count );