[8449] Deprecate healing/damage item mods and merge internal data in to spell power.
[getmangos.git] / src / game / BattleGroundMgr.cpp
blob3c4be95b69e23b4fdd858a3a0b3943d0270dacfa
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 std::vector<uint32> scheduled(m_QueueUpdateScheduler);
1170 m_QueueUpdateScheduler.clear();
1171 for (uint8 i = 0; i < scheduled.size(); i++)
1173 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundQueueTypeId(scheduled[i] / 65536);
1174 BattleGroundTypeId bgTypeId = BattleGroundTypeId((scheduled[i] % 65536) / 256);
1175 BGQueueIdBasedOnLevel queue_id = BGQueueIdBasedOnLevel(scheduled[i] % 256);
1176 m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, queue_id);
1180 // if rating difference counts, maybe force-update queues
1181 if (sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER))
1183 // it's time to force update
1184 if (m_NextRatingDiscardUpdate < diff)
1186 // forced update for level 70 rated arenas
1187 sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
1188 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_2v2, true, 0);
1189 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_2v2, true, 0);
1190 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_3v3, true, 0);
1191 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_3v3, true, 0);
1192 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_5v5, true, 0);
1193 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_5v5, true, 0);
1194 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1196 else
1197 m_NextRatingDiscardUpdate -= diff;
1199 if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1201 if (m_AutoDistributionTimeChecker < diff)
1203 if (sWorld.GetGameTime() > m_NextAutoDistributionTime)
1205 DistributeArenaPoints();
1206 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1207 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"UI64FMTD"'", uint64(m_NextAutoDistributionTime));
1209 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1211 else
1212 m_AutoDistributionTimeChecker -= diff;
1216 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype)
1218 // we can be in 3 queues in same time...
1220 if (StatusID == 0 || !bg)
1222 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
1223 *data << uint32(QueueSlot); // queue id (0...2)
1224 *data << uint64(0);
1225 return;
1228 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
1229 *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1230 // uint64 in client
1231 *data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1232 *data << uint32(bg->GetClientInstanceID());
1233 // alliance/horde for BG and skirmish/rated for Arenas
1234 // following displays the minimap-icon 0 = faction icon 1 = arenaicon
1235 *data << uint8(bg->isRated());
1236 /* *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!!!!
1237 switch(bg->GetTypeID()) // value depends on bg id
1239 case BATTLEGROUND_AV:
1240 *data << uint8(1);
1241 break;
1242 case BATTLEGROUND_WS:
1243 *data << uint8(2);
1244 break;
1245 case BATTLEGROUND_AB:
1246 *data << uint8(3);
1247 break;
1248 case BATTLEGROUND_NA:
1249 *data << uint8(4);
1250 break;
1251 case BATTLEGROUND_BE:
1252 *data << uint8(5);
1253 break;
1254 case BATTLEGROUND_AA:
1255 *data << uint8(6);
1256 break;
1257 case BATTLEGROUND_EY:
1258 *data << uint8(7);
1259 break;
1260 case BATTLEGROUND_RL:
1261 *data << uint8(8);
1262 break;
1263 case BATTLEGROUND_SA:
1264 *data << uint8(9);
1265 break;
1266 case BATTLEGROUND_DS:
1267 *data << uint8(10);
1268 break;
1269 case BATTLEGROUND_RV:
1270 *data << uint8(11);
1271 break;
1272 default: // unknown
1273 *data << uint8(0);
1274 break;
1277 if (bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1278 *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1279 else
1280 *data << uint32(bg->GetTypeID()); // BG id from DBC
1282 *data << uint16(0x1F90); // unk value 8080
1283 *data << uint32(bg->GetInstanceID()); // instance id
1285 *data << uint8(bg->isArena()); // minimap-icon 0=faction 1=arena
1287 *data << uint32(StatusID); // status
1288 switch(StatusID)
1290 case STATUS_WAIT_QUEUE: // status_in_queue
1291 *data << uint32(Time1); // average wait time, milliseconds
1292 *data << uint32(Time2); // time in queue, updated every minute!, milliseconds
1293 break;
1294 case STATUS_WAIT_JOIN: // status_invite
1295 *data << uint32(bg->GetMapId()); // map id
1296 *data << uint32(Time1); // time to remove from queue, milliseconds
1297 break;
1298 case STATUS_IN_PROGRESS: // status_in_progress
1299 *data << uint32(bg->GetMapId()); // map id
1300 *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
1301 *data << uint32(Time2); // time from bg start, milliseconds
1302 *data << uint8(0x1); // unk sometimes 0x0!
1303 break;
1304 default:
1305 sLog.outError("Unknown BG status!");
1306 break;
1310 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1312 uint8 type = (bg->isArena() ? 1 : 0);
1313 // last check on 3.0.3
1314 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1315 *data << uint8(type); // type (battleground=0/arena=1)
1317 if(type) // arena
1319 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1320 for(int i = 1; i >= 0; --i)
1322 *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
1323 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1324 *data << uint32(0); // added again in 3.1
1325 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1327 for(int i = 1; i >= 0; --i)
1329 uint32 at_id = bg->m_ArenaTeamIds[i];
1330 ArenaTeam * at = objmgr.GetArenaTeamById(at_id);
1331 if (at)
1332 *data << at->GetName();
1333 else
1334 *data << (uint8)0;
1338 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
1340 *data << uint8(0); // bg not ended
1342 else
1344 *data << uint8(1); // bg ended
1345 *data << uint8(bg->GetWinner()); // who win
1348 *data << (int32)(bg->GetPlayerScoresSize());
1350 for(BattleGround::BattleGroundScoreMap::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1352 *data << (uint64)itr->first;
1353 *data << (int32)itr->second->KillingBlows;
1354 if (type == 0)
1356 *data << (int32)itr->second->HonorableKills;
1357 *data << (int32)itr->second->Deaths;
1358 *data << (int32)(itr->second->BonusHonor);
1360 else
1362 Player *plr = objmgr.GetPlayer(itr->first);
1363 uint32 team = bg->GetPlayerTeam(itr->first);
1364 if (!team && plr)
1365 team = plr->GetTeam();
1366 if (( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ))
1367 *data << uint8(1);
1368 else
1369 *data << uint8(0);
1371 *data << (int32)itr->second->DamageDone; // damage done
1372 *data << (int32)itr->second->HealingDone; // healing done
1373 switch(bg->GetTypeID()) // battleground specific things
1375 case BATTLEGROUND_AV:
1376 *data << (uint32)0x00000005; // count of next fields
1377 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1378 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1379 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1380 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1381 *data << (uint32)((BattleGroundAVScore*)itr->second)->MinesCaptured; // MinesCaptured
1382 break;
1383 case BATTLEGROUND_WS:
1384 *data << (uint32)0x00000002; // count of next fields
1385 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1386 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1387 break;
1388 case BATTLEGROUND_AB:
1389 *data << (uint32)0x00000002; // count of next fields
1390 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1391 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1392 break;
1393 case BATTLEGROUND_EY:
1394 *data << (uint32)0x00000001; // count of next fields
1395 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1396 break;
1397 case BATTLEGROUND_NA:
1398 case BATTLEGROUND_BE:
1399 case BATTLEGROUND_AA:
1400 case BATTLEGROUND_RL:
1401 case BATTLEGROUND_SA: // wotlk
1402 case BATTLEGROUND_DS: // wotlk
1403 case BATTLEGROUND_RV: // wotlk
1404 *data << (int32)0; // 0
1405 break;
1406 default:
1407 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1408 *data << (int32)0;
1409 break;
1414 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
1416 /*bgTypeId is:
1417 0 - Your group has joined a battleground queue, but you are not eligible
1418 1 - Your group has joined the queue for AV
1419 2 - Your group has joined the queue for WS
1420 3 - Your group has joined the queue for AB
1421 4 - Your group has joined the queue for NA
1422 5 - Your group has joined the queue for BE Arena
1423 6 - Your group has joined the queue for All Arenas
1424 7 - Your group has joined the queue for EotS*/
1425 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1426 *data << uint32(bgTypeId);
1429 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1431 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1432 *data << uint32(field);
1433 *data << uint32(value);
1436 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1438 data->Initialize(SMSG_PLAY_SOUND, 4);
1439 *data << uint32(soundid);
1442 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid)
1444 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1445 *data << uint64(guid);
1448 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1450 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1451 *data << uint64(plr->GetGUID());
1454 BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId)
1456 //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from
1457 //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
1458 BattleGround* bg = GetBattleGroundTemplate(bgTypeId);
1459 if (!bg)
1460 return NULL;
1462 if (bg->isArena())
1463 return GetBattleGround(instanceId, bgTypeId);
1465 for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr)
1467 if (itr->second->GetClientInstanceID() == instanceId)
1468 return itr->second;
1470 return NULL;
1473 BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
1475 //search if needed
1476 BattleGroundSet::iterator itr;
1477 if (bgTypeId == BATTLEGROUND_TYPE_NONE)
1479 for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1481 itr = m_BattleGrounds[i].find(InstanceID);
1482 if (itr != m_BattleGrounds[i].end())
1483 return itr->second;
1485 return NULL;
1487 itr = m_BattleGrounds[bgTypeId].find(InstanceID);
1488 return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL );
1491 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
1493 //map is sorted and we can be sure that lowest instance id has only BG template
1494 return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second;
1497 uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
1499 if (IsArenaType(bgTypeId))
1500 return 0; //arenas don't have client-instanceids
1502 // we create here an instanceid, which is just for
1503 // displaying this to the client and without any other use..
1504 // the client-instanceIds are unique for each battleground-type
1505 // the instance-id just needs to be as low as possible, beginning with 1
1506 // the following works, because std::set is default ordered with "<"
1507 // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
1508 uint32 lastId = 0;
1509 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();)
1511 if( (++lastId) != *itr) //if there is a gap between the ids, we will break..
1512 break;
1513 lastId = *itr;
1515 m_ClientBattleGroundIds[bgTypeId][queue_id].insert(lastId + 1);
1516 return lastId + 1;
1519 // create a new battleground that will really be used to play
1520 BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated)
1522 // get the template BG
1523 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1524 if (!bg_template)
1526 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1527 return NULL;
1530 //for arenas there is random map used
1531 if (bg_template->isArena())
1533 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
1534 uint32 arena_num = urand(0,2);
1535 bgTypeId = arenas[arena_num];
1536 bg_template = GetBattleGroundTemplate(bgTypeId);
1537 if (!bg_template)
1539 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1540 return NULL;
1544 BattleGround *bg = NULL;
1545 // create a copy of the BG template
1546 switch(bgTypeId)
1548 case BATTLEGROUND_AV:
1549 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1550 break;
1551 case BATTLEGROUND_WS:
1552 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1553 break;
1554 case BATTLEGROUND_AB:
1555 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1556 break;
1557 case BATTLEGROUND_NA:
1558 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1559 break;
1560 case BATTLEGROUND_BE:
1561 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1562 break;
1563 case BATTLEGROUND_AA:
1564 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1565 break;
1566 case BATTLEGROUND_EY:
1567 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1568 break;
1569 case BATTLEGROUND_RL:
1570 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1571 break;
1572 case BATTLEGROUND_SA:
1573 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1574 break;
1575 case BATTLEGROUND_DS:
1576 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1577 break;
1578 case BATTLEGROUND_RV:
1579 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1580 break;
1581 default:
1582 //error, but it is handled few lines above
1583 return 0;
1586 // generate a new instance id
1587 bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id
1588 bg->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId, queue_id));
1590 // reset the new bg (set status to status_wait_queue from status_none)
1591 bg->Reset();
1593 // start the joining of the bg
1594 bg->SetStatus(STATUS_WAIT_JOIN);
1595 bg->SetQueueId(queue_id);
1596 bg->SetArenaType(arenaType);
1597 bg->SetRated(isRated);
1599 // add BG to free slot queue
1600 bg->AddToBGFreeSlotQueue();
1602 // add bg to update list
1603 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1605 return bg;
1608 // used to create the BG templates
1609 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)
1611 // Create the BG
1612 BattleGround *bg = NULL;
1613 switch(bgTypeId)
1615 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1616 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1617 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1618 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1619 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1620 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1621 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1622 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1623 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1624 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1625 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1626 default:bg = new BattleGround; break; // placeholder for non implemented BG
1629 bg->SetMapId(MapID);
1630 bg->SetTypeID(bgTypeId);
1631 bg->SetInstanceID(0);
1632 bg->SetArenaorBGType(IsArena);
1633 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1634 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1635 bg->SetMinPlayers(MinPlayersPerTeam * 2);
1636 bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
1637 bg->SetName(BattleGroundName);
1638 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1639 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1640 bg->SetLevelRange(LevelMin, LevelMax);
1642 // add bg to update list
1643 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1645 // return some not-null value, bgTypeId is good enough for me
1646 return bgTypeId;
1649 void BattleGroundMgr::CreateInitialBattleGrounds()
1651 float AStartLoc[4];
1652 float HStartLoc[4];
1653 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1654 BattlemasterListEntry const *bl;
1655 WorldSafeLocsEntry const *start;
1656 bool IsArena;
1658 uint32 count = 0;
1660 // 0 1 2 3 4 5 6 7 8
1661 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1663 if (!result)
1665 barGoLink bar(1);
1667 bar.step();
1669 sLog.outString();
1670 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1671 return;
1674 barGoLink bar(result->GetRowCount());
1678 Field *fields = result->Fetch();
1679 bar.step();
1681 uint32 bgTypeID_ = fields[0].GetUInt32();
1683 // can be overwrite by values from DB
1684 bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
1685 if (!bl)
1687 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
1688 continue;
1691 BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
1693 IsArena = (bl->type == TYPE_ARENA);
1694 MinPlayersPerTeam = fields[1].GetUInt32();
1695 MaxPlayersPerTeam = fields[2].GetUInt32();
1696 MinLvl = fields[3].GetUInt32();
1697 MaxLvl = fields[4].GetUInt32();
1698 //check values from DB
1699 if (MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam)
1701 MaxPlayersPerTeam = bl->maxplayersperteam;
1702 MinPlayersPerTeam = bl->maxplayersperteam / 2;
1704 if (MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl)
1706 MinLvl = bl->minlvl;
1707 MaxLvl = bl->maxlvl;
1710 start1 = fields[5].GetUInt32();
1712 start = sWorldSafeLocsStore.LookupEntry(start1);
1713 if (start)
1715 AStartLoc[0] = start->x;
1716 AStartLoc[1] = start->y;
1717 AStartLoc[2] = start->z;
1718 AStartLoc[3] = fields[6].GetFloat();
1720 else if (bgTypeID == BATTLEGROUND_AA)
1722 AStartLoc[0] = 0;
1723 AStartLoc[1] = 0;
1724 AStartLoc[2] = 0;
1725 AStartLoc[3] = fields[6].GetFloat();
1727 else
1729 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
1730 continue;
1733 start2 = fields[7].GetUInt32();
1735 start = sWorldSafeLocsStore.LookupEntry(start2);
1736 if (start)
1738 HStartLoc[0] = start->x;
1739 HStartLoc[1] = start->y;
1740 HStartLoc[2] = start->z;
1741 HStartLoc[3] = fields[8].GetFloat();
1743 else if (bgTypeID == BATTLEGROUND_AA)
1745 HStartLoc[0] = 0;
1746 HStartLoc[1] = 0;
1747 HStartLoc[2] = 0;
1748 HStartLoc[3] = fields[8].GetFloat();
1750 else
1752 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
1753 continue;
1756 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1757 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]))
1758 continue;
1760 ++count;
1761 } while (result->NextRow());
1763 delete result;
1765 sLog.outString();
1766 sLog.outString( ">> Loaded %u battlegrounds", count );
1769 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1771 if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1773 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1774 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1775 if (!result)
1777 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1778 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1779 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"UI64FMTD"')", uint64(m_NextAutoDistributionTime));
1781 else
1783 m_NextAutoDistributionTime = time_t((*result)[0].GetUInt64());
1784 delete result;
1786 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1790 void BattleGroundMgr::DistributeArenaPoints()
1792 // used to distribute arena points based on last week's stats
1793 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
1795 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
1797 //temporary structure for storing maximum points to add values for all players
1798 std::map<uint32, uint32> PlayerPoints;
1800 //at first update all points for all team members
1801 for(ObjectMgr::ArenaTeamMap::iterator team_itr = objmgr.GetArenaTeamMapBegin(); team_itr != objmgr.GetArenaTeamMapEnd(); ++team_itr)
1803 if (ArenaTeam * at = team_itr->second)
1805 at->UpdateArenaPointsHelper(PlayerPoints);
1809 //cycle that gives points to all players
1810 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1812 //update to database
1813 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
1814 //add points if player is online
1815 Player* pl = objmgr.GetPlayer(plr_itr->first);
1816 if (pl)
1817 pl->ModifyArenaPoints(plr_itr->second);
1820 PlayerPoints.clear();
1822 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
1824 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
1825 for(ObjectMgr::ArenaTeamMap::iterator titr = objmgr.GetArenaTeamMapBegin(); titr != objmgr.GetArenaTeamMapEnd(); ++titr)
1827 if (ArenaTeam * at = titr->second)
1829 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1830 at->SaveToDB(); // save changes
1831 at->NotifyStatsChanged(); // notify the players of the changes
1835 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
1837 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
1840 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId, uint8 fromWhere)
1842 if (!plr)
1843 return;
1845 uint32 PlayerLevel = 10;
1846 PlayerLevel = plr->getLevel();
1848 data->Initialize(SMSG_BATTLEFIELD_LIST);
1849 *data << uint64(guid); // battlemaster guid
1850 *data << uint8(fromWhere); // from where you joined
1851 *data << uint32(bgTypeId); // battleground id
1852 if(bgTypeId == BATTLEGROUND_AA) // arena
1854 *data << uint8(4); // unk
1855 *data << uint32(0); // unk (count?)
1857 else // battleground
1859 *data << uint8(0x00); // unk, different for each bg type
1861 size_t count_pos = data->wpos();
1862 uint32 count = 0;
1863 *data << uint32(0x00); // number of bg instances
1865 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(bgTypeId);
1866 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();++itr)
1868 *data << uint32(*itr);
1869 ++count;
1871 data->put<uint32>( count_pos , count);
1875 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId)
1877 BattleGround *bg = GetBattleGround(instanceId, bgTypeId);
1878 if (bg)
1880 uint32 mapid = bg->GetMapId();
1881 float x, y, z, O;
1882 uint32 team = pl->GetBGTeam();
1883 if (team==0)
1884 team = pl->GetTeam();
1885 bg->GetTeamStartLoc(team, x, y, z, O);
1887 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1888 pl->TeleportTo(mapid, x, y, z, O);
1890 else
1892 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1896 void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid)
1898 WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
1899 uint32 time_ = 30000 - bg->GetLastResurrectTime(); // resurrect every 30 seconds
1900 if (time_ == uint32(-1))
1901 time_ = 0;
1902 data << guid << time_;
1903 pl->GetSession()->SendPacket(&data);
1906 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
1908 return ( bgTypeId == BATTLEGROUND_AA ||
1909 bgTypeId == BATTLEGROUND_BE ||
1910 bgTypeId == BATTLEGROUND_NA ||
1911 bgTypeId == BATTLEGROUND_RL );
1914 BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
1916 switch(bgTypeId)
1918 case BATTLEGROUND_WS:
1919 return BATTLEGROUND_QUEUE_WS;
1920 case BATTLEGROUND_AB:
1921 return BATTLEGROUND_QUEUE_AB;
1922 case BATTLEGROUND_AV:
1923 return BATTLEGROUND_QUEUE_AV;
1924 case BATTLEGROUND_EY:
1925 return BATTLEGROUND_QUEUE_EY;
1926 case BATTLEGROUND_SA:
1927 return BATTLEGROUND_QUEUE_SA;
1928 case BATTLEGROUND_AA:
1929 case BATTLEGROUND_NA:
1930 case BATTLEGROUND_RL:
1931 case BATTLEGROUND_BE:
1932 case BATTLEGROUND_DS:
1933 case BATTLEGROUND_RV:
1934 switch(arenaType)
1936 case ARENA_TYPE_2v2:
1937 return BATTLEGROUND_QUEUE_2v2;
1938 case ARENA_TYPE_3v3:
1939 return BATTLEGROUND_QUEUE_3v3;
1940 case ARENA_TYPE_5v5:
1941 return BATTLEGROUND_QUEUE_5v5;
1942 default:
1943 return BATTLEGROUND_QUEUE_NONE;
1945 default:
1946 return BATTLEGROUND_QUEUE_NONE;
1950 BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId)
1952 switch(bgQueueTypeId)
1954 case BATTLEGROUND_QUEUE_WS:
1955 return BATTLEGROUND_WS;
1956 case BATTLEGROUND_QUEUE_AB:
1957 return BATTLEGROUND_AB;
1958 case BATTLEGROUND_QUEUE_AV:
1959 return BATTLEGROUND_AV;
1960 case BATTLEGROUND_QUEUE_EY:
1961 return BATTLEGROUND_EY;
1962 case BATTLEGROUND_QUEUE_SA:
1963 return BATTLEGROUND_SA;
1964 case BATTLEGROUND_QUEUE_2v2:
1965 case BATTLEGROUND_QUEUE_3v3:
1966 case BATTLEGROUND_QUEUE_5v5:
1967 return BATTLEGROUND_AA;
1968 default:
1969 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
1973 uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId)
1975 switch(bgQueueTypeId)
1977 case BATTLEGROUND_QUEUE_2v2:
1978 return ARENA_TYPE_2v2;
1979 case BATTLEGROUND_QUEUE_3v3:
1980 return ARENA_TYPE_3v3;
1981 case BATTLEGROUND_QUEUE_5v5:
1982 return ARENA_TYPE_5v5;
1983 default:
1984 return 0;
1988 void BattleGroundMgr::ToggleTesting()
1990 m_Testing = !m_Testing;
1991 if (m_Testing)
1992 sWorld.SendWorldText(LANG_DEBUG_BG_ON);
1993 else
1994 sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
1997 void BattleGroundMgr::ToggleArenaTesting()
1999 m_ArenaTesting = !m_ArenaTesting;
2000 if (m_ArenaTesting)
2001 sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
2002 else
2003 sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
2006 void BattleGroundMgr::ScheduleQueueUpdate(BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
2008 //This method must be atomic!
2009 //we will use only 1 number created of bgTypeId and queue_id
2010 uint32 schedule_id = (bgQueueTypeId * 65536) + (bgTypeId * 256) + queue_id;
2011 bool found = false;
2012 for (uint8 i = 0; i < m_QueueUpdateScheduler.size(); i++)
2014 if (m_QueueUpdateScheduler[i] == schedule_id)
2016 found = true;
2017 break;
2020 if (!found)
2021 m_QueueUpdateScheduler.push_back(schedule_id);
2024 uint32 BattleGroundMgr::GetMaxRatingDifference() const
2026 // this is for stupid people who can't use brain and set max rating difference to 0
2027 uint32 diff = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
2028 if (diff == 0)
2029 diff = 5000;
2030 return diff;
2033 uint32 BattleGroundMgr::GetRatingDiscardTimer() const
2035 return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
2038 uint32 BattleGroundMgr::GetPrematureFinishTime() const
2040 return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
2043 void BattleGroundMgr::LoadBattleMastersEntry()
2045 mBattleMastersMap.clear(); // need for reload case
2047 QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
2049 uint32 count = 0;
2051 if (!result)
2053 barGoLink bar( 1 );
2054 bar.step();
2056 sLog.outString();
2057 sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
2058 return;
2061 barGoLink bar( result->GetRowCount() );
2065 ++count;
2066 bar.step();
2068 Field *fields = result->Fetch();
2070 uint32 entry = fields[0].GetUInt32();
2071 uint32 bgTypeId = fields[1].GetUInt32();
2072 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
2074 sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
2075 continue;
2078 mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
2080 } while( result->NextRow() );
2082 delete result;
2084 sLog.outString();
2085 sLog.outString( ">> Loaded %u battlemaster entries", count );