[8483] Implement glyph 43361.
[getmangos.git] / src / game / BattleGroundMgr.cpp
blobf0a30dbd34276399f8c395c594154fac19f251d0
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.ScheduleQueueUpdate(m_BgQueueTypeId, 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;
1165 // update scheduled queues
1166 if (!m_QueueUpdateScheduler.empty())
1168 //copy vector and clear the other
1169 // TODO add lock
1170 // TODO maybe std::list would be better and then unlock after end of cycle
1171 std::vector<uint32> scheduled(m_QueueUpdateScheduler);
1172 m_QueueUpdateScheduler.clear();
1173 // TODO drop lock
1174 for (uint8 i = 0; i < scheduled.size(); i++)
1176 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundQueueTypeId(scheduled[i] >> 16);
1177 BattleGroundTypeId bgTypeId = BattleGroundTypeId((scheduled[i] >> 8) & 255);
1178 BGQueueIdBasedOnLevel queue_id = BGQueueIdBasedOnLevel(scheduled[i] & 255);
1179 m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, queue_id);
1183 // if rating difference counts, maybe force-update queues
1184 if (sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER))
1186 // it's time to force update
1187 if (m_NextRatingDiscardUpdate < diff)
1189 // forced update for level 70 rated arenas
1190 sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
1191 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_2v2, true, 0);
1192 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_2v2, true, 0);
1193 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_3v3, true, 0);
1194 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_3v3, true, 0);
1195 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_5v5, true, 0);
1196 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_5v5, true, 0);
1197 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1199 else
1200 m_NextRatingDiscardUpdate -= diff;
1202 if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1204 if (m_AutoDistributionTimeChecker < diff)
1206 if (sWorld.GetGameTime() > m_NextAutoDistributionTime)
1208 DistributeArenaPoints();
1209 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1210 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"UI64FMTD"'", uint64(m_NextAutoDistributionTime));
1212 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1214 else
1215 m_AutoDistributionTimeChecker -= diff;
1219 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype)
1221 // we can be in 3 queues in same time...
1223 if (StatusID == 0 || !bg)
1225 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
1226 *data << uint32(QueueSlot); // queue id (0...2)
1227 *data << uint64(0);
1228 return;
1231 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
1232 *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1233 // uint64 in client
1234 *data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1235 *data << uint32(bg->GetClientInstanceID());
1236 // alliance/horde for BG and skirmish/rated for Arenas
1237 // following displays the minimap-icon 0 = faction icon 1 = arenaicon
1238 *data << uint8(bg->isRated());
1239 /* *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!!!!
1240 switch(bg->GetTypeID()) // value depends on bg id
1242 case BATTLEGROUND_AV:
1243 *data << uint8(1);
1244 break;
1245 case BATTLEGROUND_WS:
1246 *data << uint8(2);
1247 break;
1248 case BATTLEGROUND_AB:
1249 *data << uint8(3);
1250 break;
1251 case BATTLEGROUND_NA:
1252 *data << uint8(4);
1253 break;
1254 case BATTLEGROUND_BE:
1255 *data << uint8(5);
1256 break;
1257 case BATTLEGROUND_AA:
1258 *data << uint8(6);
1259 break;
1260 case BATTLEGROUND_EY:
1261 *data << uint8(7);
1262 break;
1263 case BATTLEGROUND_RL:
1264 *data << uint8(8);
1265 break;
1266 case BATTLEGROUND_SA:
1267 *data << uint8(9);
1268 break;
1269 case BATTLEGROUND_DS:
1270 *data << uint8(10);
1271 break;
1272 case BATTLEGROUND_RV:
1273 *data << uint8(11);
1274 break;
1275 default: // unknown
1276 *data << uint8(0);
1277 break;
1280 if (bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1281 *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1282 else
1283 *data << uint32(bg->GetTypeID()); // BG id from DBC
1285 *data << uint16(0x1F90); // unk value 8080
1286 *data << uint32(bg->GetInstanceID()); // instance id
1288 *data << uint8(bg->isArena()); // minimap-icon 0=faction 1=arena
1290 *data << uint32(StatusID); // status
1291 switch(StatusID)
1293 case STATUS_WAIT_QUEUE: // status_in_queue
1294 *data << uint32(Time1); // average wait time, milliseconds
1295 *data << uint32(Time2); // time in queue, updated every minute!, milliseconds
1296 break;
1297 case STATUS_WAIT_JOIN: // status_invite
1298 *data << uint32(bg->GetMapId()); // map id
1299 *data << uint32(Time1); // time to remove from queue, milliseconds
1300 break;
1301 case STATUS_IN_PROGRESS: // status_in_progress
1302 *data << uint32(bg->GetMapId()); // map id
1303 *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
1304 *data << uint32(Time2); // time from bg start, milliseconds
1305 *data << uint8(0x1); // unk sometimes 0x0!
1306 break;
1307 default:
1308 sLog.outError("Unknown BG status!");
1309 break;
1313 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1315 uint8 type = (bg->isArena() ? 1 : 0);
1316 // last check on 3.0.3
1317 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1318 *data << uint8(type); // type (battleground=0/arena=1)
1320 if(type) // arena
1322 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1323 for(int i = 1; i >= 0; --i)
1325 *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
1326 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1327 *data << uint32(0); // added again in 3.1
1328 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1330 for(int i = 1; i >= 0; --i)
1332 uint32 at_id = bg->m_ArenaTeamIds[i];
1333 ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
1334 if (at)
1335 *data << at->GetName();
1336 else
1337 *data << (uint8)0;
1341 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
1343 *data << uint8(0); // bg not ended
1345 else
1347 *data << uint8(1); // bg ended
1348 *data << uint8(bg->GetWinner()); // who win
1351 *data << (int32)(bg->GetPlayerScoresSize());
1353 for(BattleGround::BattleGroundScoreMap::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1355 *data << (uint64)itr->first;
1356 *data << (int32)itr->second->KillingBlows;
1357 if (type == 0)
1359 *data << (int32)itr->second->HonorableKills;
1360 *data << (int32)itr->second->Deaths;
1361 *data << (int32)(itr->second->BonusHonor);
1363 else
1365 Player *plr = objmgr.GetPlayer(itr->first);
1366 uint32 team = bg->GetPlayerTeam(itr->first);
1367 if (!team && plr)
1368 team = plr->GetTeam();
1369 if (( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ))
1370 *data << uint8(1);
1371 else
1372 *data << uint8(0);
1374 *data << (int32)itr->second->DamageDone; // damage done
1375 *data << (int32)itr->second->HealingDone; // healing done
1376 switch(bg->GetTypeID()) // battleground specific things
1378 case BATTLEGROUND_AV:
1379 *data << (uint32)0x00000005; // count of next fields
1380 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1381 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1382 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1383 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1384 *data << (uint32)((BattleGroundAVScore*)itr->second)->MinesCaptured; // MinesCaptured
1385 break;
1386 case BATTLEGROUND_WS:
1387 *data << (uint32)0x00000002; // count of next fields
1388 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1389 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1390 break;
1391 case BATTLEGROUND_AB:
1392 *data << (uint32)0x00000002; // count of next fields
1393 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1394 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1395 break;
1396 case BATTLEGROUND_EY:
1397 *data << (uint32)0x00000001; // count of next fields
1398 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1399 break;
1400 case BATTLEGROUND_NA:
1401 case BATTLEGROUND_BE:
1402 case BATTLEGROUND_AA:
1403 case BATTLEGROUND_RL:
1404 case BATTLEGROUND_SA: // wotlk
1405 case BATTLEGROUND_DS: // wotlk
1406 case BATTLEGROUND_RV: // wotlk
1407 *data << (int32)0; // 0
1408 break;
1409 default:
1410 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1411 *data << (int32)0;
1412 break;
1417 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
1419 /*bgTypeId is:
1420 0 - Your group has joined a battleground queue, but you are not eligible
1421 1 - Your group has joined the queue for AV
1422 2 - Your group has joined the queue for WS
1423 3 - Your group has joined the queue for AB
1424 4 - Your group has joined the queue for NA
1425 5 - Your group has joined the queue for BE Arena
1426 6 - Your group has joined the queue for All Arenas
1427 7 - Your group has joined the queue for EotS*/
1428 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1429 *data << uint32(bgTypeId);
1432 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1434 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1435 *data << uint32(field);
1436 *data << uint32(value);
1439 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1441 data->Initialize(SMSG_PLAY_SOUND, 4);
1442 *data << uint32(soundid);
1445 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid)
1447 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1448 *data << uint64(guid);
1451 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1453 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1454 *data << uint64(plr->GetGUID());
1457 BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId)
1459 //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from
1460 //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
1461 BattleGround* bg = GetBattleGroundTemplate(bgTypeId);
1462 if (!bg)
1463 return NULL;
1465 if (bg->isArena())
1466 return GetBattleGround(instanceId, bgTypeId);
1468 for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr)
1470 if (itr->second->GetClientInstanceID() == instanceId)
1471 return itr->second;
1473 return NULL;
1476 BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
1478 //search if needed
1479 BattleGroundSet::iterator itr;
1480 if (bgTypeId == BATTLEGROUND_TYPE_NONE)
1482 for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1484 itr = m_BattleGrounds[i].find(InstanceID);
1485 if (itr != m_BattleGrounds[i].end())
1486 return itr->second;
1488 return NULL;
1490 itr = m_BattleGrounds[bgTypeId].find(InstanceID);
1491 return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL );
1494 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
1496 //map is sorted and we can be sure that lowest instance id has only BG template
1497 return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second;
1500 uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
1502 if (IsArenaType(bgTypeId))
1503 return 0; //arenas don't have client-instanceids
1505 // we create here an instanceid, which is just for
1506 // displaying this to the client and without any other use..
1507 // the client-instanceIds are unique for each battleground-type
1508 // the instance-id just needs to be as low as possible, beginning with 1
1509 // the following works, because std::set is default ordered with "<"
1510 // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
1511 uint32 lastId = 0;
1512 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();)
1514 if( (++lastId) != *itr) //if there is a gap between the ids, we will break..
1515 break;
1516 lastId = *itr;
1518 m_ClientBattleGroundIds[bgTypeId][queue_id].insert(lastId + 1);
1519 return lastId + 1;
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
1591 bg->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId, queue_id));
1593 // reset the new bg (set status to status_wait_queue from status_none)
1594 bg->Reset();
1596 // start the joining of the bg
1597 bg->SetStatus(STATUS_WAIT_JOIN);
1598 bg->SetQueueId(queue_id);
1599 bg->SetArenaType(arenaType);
1600 bg->SetRated(isRated);
1602 return bg;
1605 // used to create the BG templates
1606 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)
1608 // Create the BG
1609 BattleGround *bg = NULL;
1610 switch(bgTypeId)
1612 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1613 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1614 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1615 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1616 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1617 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1618 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1619 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1620 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1621 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1622 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1623 default:bg = new BattleGround; break; // placeholder for non implemented BG
1626 bg->SetMapId(MapID);
1627 bg->SetTypeID(bgTypeId);
1628 bg->SetInstanceID(0);
1629 bg->SetArenaorBGType(IsArena);
1630 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1631 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1632 bg->SetMinPlayers(MinPlayersPerTeam * 2);
1633 bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
1634 bg->SetName(BattleGroundName);
1635 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1636 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1637 bg->SetLevelRange(LevelMin, LevelMax);
1639 // add bg to update list
1640 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1642 // return some not-null value, bgTypeId is good enough for me
1643 return bgTypeId;
1646 void BattleGroundMgr::CreateInitialBattleGrounds()
1648 float AStartLoc[4];
1649 float HStartLoc[4];
1650 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1651 BattlemasterListEntry const *bl;
1652 WorldSafeLocsEntry const *start;
1653 bool IsArena;
1655 uint32 count = 0;
1657 // 0 1 2 3 4 5 6 7 8
1658 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1660 if (!result)
1662 barGoLink bar(1);
1664 bar.step();
1666 sLog.outString();
1667 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1668 return;
1671 barGoLink bar(result->GetRowCount());
1675 Field *fields = result->Fetch();
1676 bar.step();
1678 uint32 bgTypeID_ = fields[0].GetUInt32();
1680 // can be overwrite by values from DB
1681 bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
1682 if (!bl)
1684 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
1685 continue;
1688 BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
1690 IsArena = (bl->type == TYPE_ARENA);
1691 MinPlayersPerTeam = fields[1].GetUInt32();
1692 MaxPlayersPerTeam = fields[2].GetUInt32();
1693 MinLvl = fields[3].GetUInt32();
1694 MaxLvl = fields[4].GetUInt32();
1695 //check values from DB
1696 if (MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam)
1698 MaxPlayersPerTeam = bl->maxplayersperteam;
1699 MinPlayersPerTeam = bl->maxplayersperteam / 2;
1701 if (MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl)
1703 MinLvl = bl->minlvl;
1704 MaxLvl = bl->maxlvl;
1707 start1 = fields[5].GetUInt32();
1709 start = sWorldSafeLocsStore.LookupEntry(start1);
1710 if (start)
1712 AStartLoc[0] = start->x;
1713 AStartLoc[1] = start->y;
1714 AStartLoc[2] = start->z;
1715 AStartLoc[3] = fields[6].GetFloat();
1717 else if (bgTypeID == BATTLEGROUND_AA)
1719 AStartLoc[0] = 0;
1720 AStartLoc[1] = 0;
1721 AStartLoc[2] = 0;
1722 AStartLoc[3] = fields[6].GetFloat();
1724 else
1726 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
1727 continue;
1730 start2 = fields[7].GetUInt32();
1732 start = sWorldSafeLocsStore.LookupEntry(start2);
1733 if (start)
1735 HStartLoc[0] = start->x;
1736 HStartLoc[1] = start->y;
1737 HStartLoc[2] = start->z;
1738 HStartLoc[3] = fields[8].GetFloat();
1740 else if (bgTypeID == BATTLEGROUND_AA)
1742 HStartLoc[0] = 0;
1743 HStartLoc[1] = 0;
1744 HStartLoc[2] = 0;
1745 HStartLoc[3] = fields[8].GetFloat();
1747 else
1749 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
1750 continue;
1753 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1754 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]))
1755 continue;
1757 ++count;
1758 } while (result->NextRow());
1760 delete result;
1762 sLog.outString();
1763 sLog.outString( ">> Loaded %u battlegrounds", count );
1766 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1768 if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1770 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1771 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1772 if (!result)
1774 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1775 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1776 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"UI64FMTD"')", uint64(m_NextAutoDistributionTime));
1778 else
1780 m_NextAutoDistributionTime = time_t((*result)[0].GetUInt64());
1781 delete result;
1783 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1787 void BattleGroundMgr::DistributeArenaPoints()
1789 // used to distribute arena points based on last week's stats
1790 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
1792 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
1794 //temporary structure for storing maximum points to add values for all players
1795 std::map<uint32, uint32> PlayerPoints;
1797 //at first update all points for all team members
1798 for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
1800 if (ArenaTeam * at = team_itr->second)
1802 at->UpdateArenaPointsHelper(PlayerPoints);
1806 //cycle that gives points to all players
1807 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1809 //update to database
1810 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
1811 //add points if player is online
1812 Player* pl = objmgr.GetPlayer(plr_itr->first);
1813 if (pl)
1814 pl->ModifyArenaPoints(plr_itr->second);
1817 PlayerPoints.clear();
1819 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
1821 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
1822 for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
1824 if (ArenaTeam * at = titr->second)
1826 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1827 at->SaveToDB(); // save changes
1828 at->NotifyStatsChanged(); // notify the players of the changes
1832 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
1834 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
1837 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId, uint8 fromWhere)
1839 if (!plr)
1840 return;
1842 uint32 PlayerLevel = 10;
1843 PlayerLevel = plr->getLevel();
1845 data->Initialize(SMSG_BATTLEFIELD_LIST);
1846 *data << uint64(guid); // battlemaster guid
1847 *data << uint8(fromWhere); // from where you joined
1848 *data << uint32(bgTypeId); // battleground id
1849 if(bgTypeId == BATTLEGROUND_AA) // arena
1851 *data << uint8(4); // unk
1852 *data << uint32(0); // unk (count?)
1854 else // battleground
1856 *data << uint8(0x00); // unk, different for each bg type
1858 size_t count_pos = data->wpos();
1859 uint32 count = 0;
1860 *data << uint32(0x00); // number of bg instances
1862 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(bgTypeId);
1863 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();++itr)
1865 *data << uint32(*itr);
1866 ++count;
1868 data->put<uint32>( count_pos , count);
1872 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId)
1874 BattleGround *bg = GetBattleGround(instanceId, bgTypeId);
1875 if (bg)
1877 uint32 mapid = bg->GetMapId();
1878 float x, y, z, O;
1879 uint32 team = pl->GetBGTeam();
1880 if (team==0)
1881 team = pl->GetTeam();
1882 bg->GetTeamStartLoc(team, x, y, z, O);
1884 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1885 pl->TeleportTo(mapid, x, y, z, O);
1887 else
1889 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1893 void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid)
1895 WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
1896 uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
1897 if (time_ == uint32(-1))
1898 time_ = 0;
1899 data << guid << time_;
1900 pl->GetSession()->SendPacket(&data);
1903 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
1905 return ( bgTypeId == BATTLEGROUND_AA ||
1906 bgTypeId == BATTLEGROUND_BE ||
1907 bgTypeId == BATTLEGROUND_NA ||
1908 bgTypeId == BATTLEGROUND_RL );
1911 BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
1913 switch(bgTypeId)
1915 case BATTLEGROUND_WS:
1916 return BATTLEGROUND_QUEUE_WS;
1917 case BATTLEGROUND_AB:
1918 return BATTLEGROUND_QUEUE_AB;
1919 case BATTLEGROUND_AV:
1920 return BATTLEGROUND_QUEUE_AV;
1921 case BATTLEGROUND_EY:
1922 return BATTLEGROUND_QUEUE_EY;
1923 case BATTLEGROUND_SA:
1924 return BATTLEGROUND_QUEUE_SA;
1925 case BATTLEGROUND_AA:
1926 case BATTLEGROUND_NA:
1927 case BATTLEGROUND_RL:
1928 case BATTLEGROUND_BE:
1929 case BATTLEGROUND_DS:
1930 case BATTLEGROUND_RV:
1931 switch(arenaType)
1933 case ARENA_TYPE_2v2:
1934 return BATTLEGROUND_QUEUE_2v2;
1935 case ARENA_TYPE_3v3:
1936 return BATTLEGROUND_QUEUE_3v3;
1937 case ARENA_TYPE_5v5:
1938 return BATTLEGROUND_QUEUE_5v5;
1939 default:
1940 return BATTLEGROUND_QUEUE_NONE;
1942 default:
1943 return BATTLEGROUND_QUEUE_NONE;
1947 BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId)
1949 switch(bgQueueTypeId)
1951 case BATTLEGROUND_QUEUE_WS:
1952 return BATTLEGROUND_WS;
1953 case BATTLEGROUND_QUEUE_AB:
1954 return BATTLEGROUND_AB;
1955 case BATTLEGROUND_QUEUE_AV:
1956 return BATTLEGROUND_AV;
1957 case BATTLEGROUND_QUEUE_EY:
1958 return BATTLEGROUND_EY;
1959 case BATTLEGROUND_QUEUE_SA:
1960 return BATTLEGROUND_SA;
1961 case BATTLEGROUND_QUEUE_2v2:
1962 case BATTLEGROUND_QUEUE_3v3:
1963 case BATTLEGROUND_QUEUE_5v5:
1964 return BATTLEGROUND_AA;
1965 default:
1966 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
1970 uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId)
1972 switch(bgQueueTypeId)
1974 case BATTLEGROUND_QUEUE_2v2:
1975 return ARENA_TYPE_2v2;
1976 case BATTLEGROUND_QUEUE_3v3:
1977 return ARENA_TYPE_3v3;
1978 case BATTLEGROUND_QUEUE_5v5:
1979 return ARENA_TYPE_5v5;
1980 default:
1981 return 0;
1985 void BattleGroundMgr::ToggleTesting()
1987 m_Testing = !m_Testing;
1988 if (m_Testing)
1989 sWorld.SendWorldText(LANG_DEBUG_BG_ON);
1990 else
1991 sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
1994 void BattleGroundMgr::ToggleArenaTesting()
1996 m_ArenaTesting = !m_ArenaTesting;
1997 if (m_ArenaTesting)
1998 sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
1999 else
2000 sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
2003 void BattleGroundMgr::ScheduleQueueUpdate(BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
2005 //This method must be atomic, TODO add mutex
2006 //we will use only 1 number created of bgTypeId and queue_id
2007 uint32 schedule_id = (bgQueueTypeId << 16) | (bgTypeId << 8) | queue_id;
2008 bool found = false;
2009 for (uint8 i = 0; i < m_QueueUpdateScheduler.size(); i++)
2011 if (m_QueueUpdateScheduler[i] == schedule_id)
2013 found = true;
2014 break;
2017 if (!found)
2018 m_QueueUpdateScheduler.push_back(schedule_id);
2021 uint32 BattleGroundMgr::GetMaxRatingDifference() const
2023 // this is for stupid people who can't use brain and set max rating difference to 0
2024 uint32 diff = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
2025 if (diff == 0)
2026 diff = 5000;
2027 return diff;
2030 uint32 BattleGroundMgr::GetRatingDiscardTimer() const
2032 return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
2035 uint32 BattleGroundMgr::GetPrematureFinishTime() const
2037 return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
2040 void BattleGroundMgr::LoadBattleMastersEntry()
2042 mBattleMastersMap.clear(); // need for reload case
2044 QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
2046 uint32 count = 0;
2048 if (!result)
2050 barGoLink bar( 1 );
2051 bar.step();
2053 sLog.outString();
2054 sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
2055 return;
2058 barGoLink bar( result->GetRowCount() );
2062 ++count;
2063 bar.step();
2065 Field *fields = result->Fetch();
2067 uint32 entry = fields[0].GetUInt32();
2068 uint32 bgTypeId = fields[1].GetUInt32();
2069 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
2071 sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
2072 continue;
2075 mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
2077 } while( result->NextRow() );
2079 delete result;
2081 sLog.outString();
2082 sLog.outString( ">> Loaded %u battlemaster entries", count );