[8809] Revert "[8799] Implemented thread safe bg queue updates."
[getmangos.git] / src / game / BattleGroundMgr.cpp
blob2f23cbd5e7953cdd9611caac008abb478681bef1
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 "BattleGroundIC.h"
35 #include "BattleGroundABG.h"
36 #include "MapManager.h"
37 #include "Map.h"
38 #include "MapInstanced.h"
39 #include "ObjectMgr.h"
40 #include "ProgressBar.h"
41 #include "Chat.h"
42 #include "ArenaTeam.h"
43 #include "World.h"
44 #include "WorldPacket.h"
45 #include "GameEventMgr.h"
47 #include "Policies/SingletonImp.h"
49 INSTANTIATE_SINGLETON_1( BattleGroundMgr );
51 /*********************************************************/
52 /*** BATTLEGROUND QUEUE SYSTEM ***/
53 /*********************************************************/
55 BattleGroundQueue::BattleGroundQueue()
57 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
59 for(uint32 j = 0; j < MAX_BATTLEGROUND_QUEUES; j++)
61 m_SumOfWaitTimes[i][j] = 0;
62 m_WaitTimeLastPlayer[i][j] = 0;
63 for(uint32 k = 0; k < COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME; k++)
64 m_WaitTimes[i][j][k] = 0;
69 BattleGroundQueue::~BattleGroundQueue()
71 m_QueuedPlayers.clear();
72 for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)
74 for(uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; j++)
76 for(GroupsQueueType::iterator itr = m_QueuedGroups[i][j].begin(); itr!= m_QueuedGroups[i][j].end(); ++itr)
77 delete (*itr);
78 m_QueuedGroups[i][j].clear();
83 /*********************************************************/
84 /*** BATTLEGROUND QUEUE SELECTION POOLS ***/
85 /*********************************************************/
87 // selection pool initialization, used to clean up from prev selection
88 void BattleGroundQueue::SelectionPool::Init()
90 SelectedGroups.clear();
91 PlayerCount = 0;
94 // remove group info from selection pool
95 // returns true when we need to try to add new group to selection pool
96 // returns false when selection pool is ok or when we kicked smaller group than we need to kick
97 // sometimes it can be called on empty selection pool
98 bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size)
100 //find maxgroup or LAST group with size == size and kick it
101 bool found = false;
102 GroupsQueueType::iterator groupToKick = SelectedGroups.begin();
103 for (GroupsQueueType::iterator itr = groupToKick; itr != SelectedGroups.end(); ++itr)
105 if (abs((int32)((*itr)->Players.size() - size)) <= 1)
107 groupToKick = itr;
108 found = true;
110 else if (!found && (*itr)->Players.size() >= (*groupToKick)->Players.size())
111 groupToKick = itr;
113 //if pool is empty, do nothing
114 if (GetPlayerCount())
116 //update player count
117 GroupQueueInfo* ginfo = (*groupToKick);
118 SelectedGroups.erase(groupToKick);
119 PlayerCount -= ginfo->Players.size();
120 //return false if we kicked smaller group or there are enough players in selection pool
121 if (ginfo->Players.size() <= size + 1)
122 return false;
124 return true;
127 // add group to selection pool
128 // used when building selection pools
129 // returns true if we can invite more players, or when we added group to selection pool
130 // returns false when selection pool is full
131 bool BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount)
133 //if group is larger than desired count - don't allow to add it to pool
134 if (!ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size())
136 SelectedGroups.push_back(ginfo);
137 // increase selected players count
138 PlayerCount += ginfo->Players.size();
139 return true;
141 if (PlayerCount < desiredCount)
142 return true;
143 return false;
146 /*********************************************************/
147 /*** BATTLEGROUND QUEUES ***/
148 /*********************************************************/
150 // add group to bg queue with the given leader and bg specifications
151 GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId BgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 arenaRating, uint32 arenateamid)
153 BGQueueIdBasedOnLevel queue_id = leader->GetBattleGroundQueueIdFromLevel();
155 // create new ginfo
156 // cannot use the method like in addplayer, because that could modify an in-queue group's stats
157 // (e.g. leader leaving queue then joining as individual again)
158 GroupQueueInfo* ginfo = new GroupQueueInfo;
159 ginfo->BgTypeId = BgTypeId;
160 ginfo->ArenaType = ArenaType;
161 ginfo->ArenaTeamId = arenateamid;
162 ginfo->IsRated = isRated;
163 ginfo->IsInvitedToBGInstanceGUID = 0;
164 ginfo->JoinTime = getMSTime();
165 ginfo->RemoveInviteTime = 0;
166 ginfo->Team = leader->GetTeam();
167 ginfo->ArenaTeamRating = arenaRating;
168 ginfo->OpponentsTeamRating = 0;
170 ginfo->Players.clear();
172 //compute index (if group is premade or joined a rated match) to queues
173 uint32 index = 0;
174 if (!isRated && !isPremade)
175 index += BG_TEAMS_COUNT;
176 if (ginfo->Team == HORDE)
177 index++;
178 sLog.outDebug("Adding Group to BattleGroundQueue bgTypeId : %u, queue_id : %u, index : %u", BgTypeId, queue_id, index);
180 m_QueuedGroups[queue_id][index].push_back(ginfo);
182 // return ginfo, because it is needed to add players to this group info
183 return ginfo;
186 //add player to playermap
187 void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)
189 //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak
190 PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()];
191 info.LastOnlineTime = getMSTime();
192 info.GroupInfo = ginfo;
194 // add the pinfo to ginfo's list
195 ginfo->Players[plr->GetGUID()] = &info;
198 void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
200 uint32 timeInQueue = getMSTimeDiff(ginfo->JoinTime, getMSTime());
201 uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
202 if (!ginfo->ArenaType)
204 if (ginfo->Team == HORDE)
205 team_index = BG_TEAM_HORDE;
207 else
209 if (ginfo->IsRated)
210 team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
213 //store pointer to arrayindex of player that was added first
214 uint32* lastPlayerAddedPointer = &(m_WaitTimeLastPlayer[team_index][queue_id]);
215 //remove his time from sum
216 m_SumOfWaitTimes[team_index][queue_id] -= m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)];
217 //set average time to new
218 m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)] = timeInQueue;
219 //add new time to sum
220 m_SumOfWaitTimes[team_index][queue_id] += timeInQueue;
221 //set index of last player added to next one
222 (*lastPlayerAddedPointer)++;
223 (*lastPlayerAddedPointer) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME;
226 uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id)
228 uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas!
229 if (!ginfo->ArenaType)
231 if (ginfo->Team == HORDE)
232 team_index = BG_TEAM_HORDE;
234 else
236 if (ginfo->IsRated)
237 team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE
239 //check if there is enought values(we always add values > 0)
240 if (m_WaitTimes[team_index][queue_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] )
241 return (m_SumOfWaitTimes[team_index][queue_id] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME);
242 else
243 //if there aren't enough values return 0 - not available
244 return 0;
247 //remove player from queue and from group info, if group info is empty then remove it too
248 void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount)
250 //Player *plr = sObjectMgr.GetPlayer(guid);
252 int32 queue_id = -1; // signed for proper for-loop finish
253 QueuedPlayersMap::iterator itr;
255 //remove player from map, if he's there
256 itr = m_QueuedPlayers.find(guid);
257 if (itr == m_QueuedPlayers.end())
259 sLog.outError("BattleGroundQueue: couldn't find player to remove GUID: %u", GUID_LOPART(guid));
260 return;
263 GroupQueueInfo* group = itr->second.GroupInfo;
264 GroupsQueueType::iterator group_itr, group_itr_tmp;
265 // mostly people with the highest levels are in battlegrounds, thats why
266 // we count from MAX_BATTLEGROUND_QUEUES - 1 to 0
267 // variable index removes useless searching in other team's queue
268 uint32 index = (group->Team == HORDE) ? BG_TEAM_HORDE : BG_TEAM_ALLIANCE;
270 for (int32 queue_id_tmp = MAX_BATTLEGROUND_QUEUES - 1; queue_id_tmp >= 0 && queue_id == -1; --queue_id_tmp)
272 //we must check premade and normal team's queue - because when players from premade are joining bg,
273 //they leave groupinfo so we can't use its players size to find out index
274 for (uint32 j = index; j < BG_QUEUE_GROUP_TYPES_COUNT; j += BG_QUEUE_NORMAL_ALLIANCE)
276 for(group_itr_tmp = m_QueuedGroups[queue_id_tmp][j].begin(); group_itr_tmp != m_QueuedGroups[queue_id_tmp][j].end(); ++group_itr_tmp)
278 if ((*group_itr_tmp) == group)
280 queue_id = queue_id_tmp;
281 group_itr = group_itr_tmp;
282 //we must store index to be able to erase iterator
283 index = j;
284 break;
289 //player can't be in queue without group, but just in case
290 if (queue_id == -1)
292 sLog.outError("BattleGroundQueue: ERROR Cannot find groupinfo for player GUID: %u", GUID_LOPART(guid));
293 return;
295 sLog.outDebug("BattleGroundQueue: Removing player GUID %u, from queue_id %u", GUID_LOPART(guid), (uint32)queue_id);
297 // ALL variables are correctly set
298 // We can ignore leveling up in queue - it should not cause crash
299 // remove player from group
300 // if only one player there, remove group
302 // remove player queue info from group queue info
303 std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);
304 if (pitr != group->Players.end())
305 group->Players.erase(pitr);
307 // if invited to bg, and should decrease invited count, then do it
308 if (decreaseInvitedCount && group->IsInvitedToBGInstanceGUID)
310 BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID, group->BgTypeId);
311 if (bg)
312 bg->DecreaseInvitedCount(group->Team);
315 // remove player queue info
316 m_QueuedPlayers.erase(itr);
318 //if we left BG queue(not porting) OR if arena team left queue for rated match
319 if ((decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()))
320 AnnounceWorld(group, guid, false);
322 //if player leaves queue and he is invited to rated arena match, then he have to loose
323 if (group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount)
325 ArenaTeam * at = sObjectMgr.GetArenaTeamById(group->ArenaTeamId);
326 if (at)
328 sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating);
329 Player *plr = sObjectMgr.GetPlayer(guid);
330 if (plr)
331 at->MemberLost(plr, group->OpponentsTeamRating);
332 else
333 at->OfflineMemberLost(guid, group->OpponentsTeamRating);
334 at->SaveToDB();
338 // remove group queue info if needed
339 if (group->Players.empty())
341 m_QueuedGroups[queue_id][index].erase(group_itr);
342 delete group;
344 // if group wasn't empty, so it wasn't deleted, and player have left a rated
345 // queue -> everyone from the group should leave too
346 // don't remove recursively if already invited to bg!
347 else if (!group->IsInvitedToBGInstanceGUID && group->IsRated)
349 // remove next player, this is recursive
350 // first send removal information
351 if (Player *plr2 = sObjectMgr.GetPlayer(group->Players.begin()->first))
353 BattleGround * bg = sBattleGroundMgr.GetBattleGroundTemplate(group->BgTypeId);
354 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(group->BgTypeId, group->ArenaType);
355 uint32 queueSlot = plr2->GetBattleGroundQueueIndex(bgQueueTypeId);
356 plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to
357 // queue->removeplayer, it causes bugs
358 WorldPacket data;
359 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
360 plr2->GetSession()->SendPacket(&data);
362 // then actually delete, this may delete the group as well!
363 RemovePlayer(group->Players.begin()->first, decreaseInvitedCount);
367 //Announce world message
368 void BattleGroundQueue::AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue)
370 if(ginfo->ArenaType) //if Arena
372 if (sWorld.getConfig(CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE) && ginfo->IsRated)
374 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
375 if (!bg)
376 return;
378 char const* bgName = bg->GetName();
379 if (isAddedToQueue)
380 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_JOIN, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
381 else
382 sWorld.SendWorldText(LANG_ARENA_QUEUE_ANNOUNCE_WORLD_EXIT, bgName, ginfo->ArenaType, ginfo->ArenaType, ginfo->ArenaTeamRating);
385 else //if BG
387 if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
389 Player *plr = sObjectMgr.GetPlayer(playerGUID);
390 BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(ginfo->BgTypeId);
391 if (!bg || !plr)
392 return;
394 BGQueueIdBasedOnLevel queue_id = plr->GetBattleGroundQueueIdFromLevel();
395 char const* bgName = bg->GetName();
396 uint32 MinPlayers = bg->GetMinPlayersPerTeam();
397 uint32 qHorde = 0;
398 uint32 qAlliance = 0;
399 uint32 q_min_level = (queue_id + 1) * 10;
400 GroupsQueueType::const_iterator itr;
401 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].end(); ++itr)
402 if (!(*itr)->IsInvitedToBGInstanceGUID)
403 qAlliance += (*itr)->Players.size();
404 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].end(); ++itr)
405 if (!(*itr)->IsInvitedToBGInstanceGUID)
406 qHorde += (*itr)->Players.size();
408 // Show queue status to player only (when joining queue)
409 if (sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY))
411 ChatHandler(plr).PSendSysMessage(LANG_BG_QUEUE_ANNOUNCE_SELF,
412 bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
414 // System message
415 else
417 sWorld.SendWorldText(LANG_BG_QUEUE_ANNOUNCE_WORLD,
418 bgName, q_min_level, q_min_level + 10, qAlliance, MinPlayers, qHorde, MinPlayers);
424 bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)
426 // set side if needed
427 if (side)
428 ginfo->Team = side;
430 if (!ginfo->IsInvitedToBGInstanceGUID)
432 // not yet invited
433 // set invitation
434 ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();
435 BattleGroundTypeId bgTypeId = bg->GetTypeID();
436 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, bg->GetArenaType());
437 BGQueueIdBasedOnLevel queue_id = bg->GetQueueId();
439 // set ArenaTeamId for rated matches
440 if (bg->isArena() && bg->isRated())
441 bg->SetArenaTeamIdForTeam(ginfo->Team, ginfo->ArenaTeamId);
443 ginfo->RemoveInviteTime = getMSTime() + INVITE_ACCEPT_WAIT_TIME;
445 // loop through the players
446 for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)
448 // get the player
449 Player* plr = sObjectMgr.GetPlayer(itr->first);
450 // if offline, skip him, this should not happen - player is removed from queue when he logs out
451 if (!plr)
452 continue;
454 // invite the player
455 PlayerInvitedToBGUpdateAverageWaitTime(ginfo, queue_id);
456 //sBattleGroundMgr.InvitePlayer(plr, bg, ginfo->Team);
458 // set invited player counters
459 bg->IncreaseInvitedCount(ginfo->Team);
461 plr->SetInviteForBattleGroundQueueType(bgQueueTypeId, ginfo->IsInvitedToBGInstanceGUID);
463 // create remind invite events
464 BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, ginfo->RemoveInviteTime);
465 plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(INVITATION_REMIND_TIME));
466 // create automatic remove events
467 BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), ginfo->IsInvitedToBGInstanceGUID, bgTypeId, bgQueueTypeId, ginfo->RemoveInviteTime);
468 plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME));
470 WorldPacket data;
472 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
474 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());
476 // send status packet
477 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType);
478 plr->GetSession()->SendPacket(&data);
480 return true;
483 return false;
487 This function is inviting players to already running battlegrounds
488 Invitation type is based on config file
489 large groups are disadvantageous, because they will be kicked first if invitation type = 1
491 void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id)
493 int32 hordeFree = bg->GetFreeSlotsForTeam(HORDE);
494 int32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE);
496 //iterator for iterating through bg queue
497 GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].begin();
498 //count of groups in queue - used to stop cycles
499 uint32 aliCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].size();
500 //index to queue which group is current
501 uint32 aliIndex = 0;
502 for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++)
503 ++Ali_itr;
504 //the same thing for horde
505 GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].begin();
506 uint32 hordeCount = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].size();
507 uint32 hordeIndex = 0;
508 for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++)
509 ++Horde_itr;
511 //if ofc like BG queue invitation is set in config, then we are happy
512 if (sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == 0)
513 return;
516 if we reached this code, then we have to solve NP - complete problem called Subset sum problem
517 So one solution is to check all possible invitation subgroups, or we can use these conditions:
518 1. Last time when BattleGroundQueue::Update was executed we invited all possible players - so there is only small possibility
519 that we will invite now whole queue, because only 1 change has been made to queues from the last BattleGroundQueue::Update call
520 2. Other thing we should consider is group order in queue
523 // At first we need to compare free space in bg and our selection pool
524 int32 diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
525 int32 diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
526 while( abs(diffAli - diffHorde) > 1 && (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() > 0 || m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() > 0) )
528 //each cycle execution we need to kick at least 1 group
529 if (diffAli < diffHorde)
531 //kick alliance group, add to pool new group if needed
532 if (m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffHorde - diffAli))
534 for (; aliIndex < aliCount && m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*Ali_itr), (aliFree >= diffHorde) ? aliFree - diffHorde : 0); aliIndex++)
535 ++Ali_itr;
537 //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break;
538 if (!m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
540 if (aliFree <= diffHorde + 1)
541 break;
542 m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli);
545 else
547 //kick horde group, add to pool new group if needed
548 if (m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffAli - diffHorde))
550 for (; hordeIndex < hordeCount && m_SelectionPools[BG_TEAM_HORDE].AddGroup((*Horde_itr), (hordeFree >= diffAli) ? hordeFree - diffAli : 0); hordeIndex++)
551 ++Horde_itr;
553 if (!m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
555 if (hordeFree <= diffAli + 1)
556 break;
557 m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde);
560 //count diffs after small update
561 diffAli = aliFree - int32(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount());
562 diffHorde = hordeFree - int32(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
566 // this method checks if premade versus premade battleground is possible
567 // then after 30 mins (default) in queue it moves premade group to normal queue
568 // it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players
569 bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
571 //check match
572 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
574 //start premade match
575 //if groups aren't invited
576 GroupsQueueType::const_iterator ali_group, horde_group;
577 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)
578 if (!(*ali_group)->IsInvitedToBGInstanceGUID)
579 break;
580 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)
581 if (!(*horde_group)->IsInvitedToBGInstanceGUID)
582 break;
584 if (ali_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end() && horde_group != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end())
586 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*ali_group), MaxPlayersPerTeam);
587 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*horde_group), MaxPlayersPerTeam);
588 //add groups/players from normal queue to size of bigger group
589 uint32 maxPlayers = std::max(m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount(), m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount());
590 GroupsQueueType::const_iterator itr;
591 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
593 for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
595 //if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
596 if (!(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers))
597 break;
600 //premade selection pools are set
601 return true;
604 // now check if we can move group from Premade queue to normal queue (timer has expired) or group size lowered!!
605 // this could be 2 cycles but i'm checking only first team in queue - it can cause problem -
606 // 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
607 // and when they click or after 80 seconds the queue info is removed from queue
608 uint32 time_before = getMSTime() - sWorld.getConfig(CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH);
609 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
611 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].empty())
613 GroupsQueueType::iterator itr = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].begin();
614 if (!(*itr)->IsInvitedToBGInstanceGUID && ((*itr)->JoinTime < time_before || (*itr)->Players.size() < MinPlayersPerTeam))
616 //we must insert group to normal queue and erase pointer from premade queue
617 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
618 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr);
622 //selection pools are not set
623 return false;
626 // this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
627 bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers)
629 GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
630 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
632 itr_team[i] = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin();
633 for(; itr_team[i] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++(itr_team[i]))
635 if (!(*(itr_team[i]))->IsInvitedToBGInstanceGUID)
637 m_SelectionPools[i].AddGroup(*(itr_team[i]), maxPlayers);
638 if (m_SelectionPools[i].GetPlayerCount() >= minPlayers)
639 break;
643 //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
644 uint32 j = BG_TEAM_ALLIANCE;
645 if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
646 j = BG_TEAM_HORDE;
647 if( sWorld.getConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != 0
648 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers )
650 //we will try to invite more groups to team with less players indexed by j
651 ++(itr_team[j]); //this will not cause a crash, because for cycle above reached break;
652 for(; itr_team[j] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
654 if (!(*(itr_team[j]))->IsInvitedToBGInstanceGUID)
655 if (!m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()))
656 break;
658 // do not allow to start bg with more than 2 players more on 1 faction
659 if (abs((int32)(m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() - m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())) > 2)
660 return false;
662 //allow 1v0 if debug bg
663 if (sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()))
664 return true;
665 //return true if there are enough players in selection pools - enable to work .debug bg command correctly
666 return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers;
669 // this method will check if we can invite players to same faction skirmish match
670 bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam)
672 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam)
673 return false;
674 uint32 teamIndex = BG_TEAM_ALLIANCE;
675 uint32 otherTeam = BG_TEAM_HORDE;
676 uint32 otherTeamId = HORDE;
677 if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam )
679 teamIndex = BG_TEAM_HORDE;
680 otherTeam = BG_TEAM_ALLIANCE;
681 otherTeamId = ALLIANCE;
683 //clear other team's selection
684 m_SelectionPools[otherTeam].Init();
685 //store last ginfo pointer
686 GroupQueueInfo* ginfo = m_SelectionPools[teamIndex].SelectedGroups.back();
687 //set itr_team to group that was added to selection pool latest
688 GroupsQueueType::iterator itr_team = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin();
689 for(; itr_team != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team)
690 if (ginfo == *itr_team)
691 break;
692 if (itr_team == m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end())
693 return false;
694 GroupsQueueType::iterator itr_team2 = itr_team;
695 ++itr_team2;
696 //invite players to other selection pool
697 for(; itr_team2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team2)
699 //if selection pool is full then break;
700 if (!(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam))
701 break;
703 if (m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam)
704 return false;
706 //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue
707 for(GroupsQueueType::iterator itr = m_SelectionPools[otherTeam].SelectedGroups.begin(); itr != m_SelectionPools[otherTeam].SelectedGroups.end(); ++itr)
709 //set correct team
710 (*itr)->Team = otherTeamId;
711 //add team to other queue
712 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + otherTeam].push_front(*itr);
713 //remove team from old queue
714 GroupsQueueType::iterator itr2 = itr_team;
715 ++itr2;
716 for(; itr2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2)
718 if (*itr2 == *itr)
720 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].erase(itr2);
721 break;
725 return true;
729 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
730 it must be called after fully adding the members of a group to ensure group joining
731 should be called from BattleGround::RemovePlayer function in some cases
733 void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated, uint32 arenaRating)
735 //if no players in queue - do nothing
736 if( m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() &&
737 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty() &&
738 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE].empty() &&
739 m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_HORDE].empty() )
740 return;
742 //battleground with free slot for player should be always in the beggining of the queue
743 // maybe it would be better to create bgfreeslotqueue for each queue_id_based_on_level
744 BGFreeSlotQueueType::iterator itr, next;
745 for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
747 next = itr;
748 ++next;
749 // DO NOT allow queue manager to invite new player to arena
750 if( (*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueId() == queue_id &&
751 (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE )
753 BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!)
754 // and iterator is invalid
756 // clear selection pools
757 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
758 m_SelectionPools[BG_TEAM_HORDE].Init();
760 // call a function that does the job for us
761 FillPlayersToBG(bg, queue_id);
763 // now everything is set, invite players
764 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE].SelectedGroups.end(); ++citr)
765 InviteGroupToBG((*citr), bg, (*citr)->Team);
766 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_HORDE].SelectedGroups.end(); ++citr)
767 InviteGroupToBG((*citr), bg, (*citr)->Team);
769 if (!bg->HasFreeSlots())
771 // remove BG from BGFreeSlotQueue
772 bg->RemoveFromBGFreeSlotQueue();
777 // finished iterating through the bgs with free slots, maybe we need to create a new bg
779 BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
780 if (!bg_template)
782 sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);
783 return;
785 // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)
786 uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();
787 uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();
788 if (sBattleGroundMgr.isTesting())
789 MinPlayersPerTeam = 1;
790 if (bg_template->isArena())
792 if (sBattleGroundMgr.isArenaTesting())
794 MaxPlayersPerTeam = 1;
795 MinPlayersPerTeam = 1;
797 else
799 //this switch can be much shorter
800 MaxPlayersPerTeam = arenaType;
801 MinPlayersPerTeam = arenaType;
802 /*switch(arenaType)
804 case ARENA_TYPE_2v2:
805 MaxPlayersPerTeam = 2;
806 MinPlayersPerTeam = 2;
807 break;
808 case ARENA_TYPE_3v3:
809 MaxPlayersPerTeam = 3;
810 MinPlayersPerTeam = 3;
811 break;
812 case ARENA_TYPE_5v5:
813 MaxPlayersPerTeam = 5;
814 MinPlayersPerTeam = 5;
815 break;
820 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
821 m_SelectionPools[BG_TEAM_HORDE].Init();
823 if (bg_template->isBattleGround())
825 //check if there is premade against premade match
826 if (CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam))
828 //create new battleground
829 BattleGround * bg2 = NULL;
830 if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, 0, false)))
832 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
833 return;
835 //invite those selection pools
836 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
837 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
838 InviteGroupToBG((*citr), bg2, (*citr)->Team);
839 //start bg
840 bg2->StartBattleGround();
841 //clear structures
842 m_SelectionPools[BG_TEAM_ALLIANCE].Init();
843 m_SelectionPools[BG_TEAM_HORDE].Init();
847 // now check if there are in queues enough players to start new game of (normal battleground, or non-rated arena)
848 if (!isRated)
850 // if there are enough players in pools, start new battleground or non rated arena
851 if (CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam)
852 || (bg_template->isArena() && CheckSkirmishForSameFaction(queue_id, MinPlayersPerTeam)) )
854 // we successfully created a pool
855 BattleGround * bg2 = NULL;
856 if (!(bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, false)))
858 sLog.outError("BattleGroundQueue::Update - Cannot create battleground: %u", bgTypeId);
859 return;
862 // invite those selection pools
863 for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
864 for(GroupsQueueType::const_iterator citr = m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.begin(); citr != m_SelectionPools[BG_TEAM_ALLIANCE + i].SelectedGroups.end(); ++citr)
865 InviteGroupToBG((*citr), bg2, (*citr)->Team);
866 // start bg
867 bg2->StartBattleGround();
870 else if (bg_template->isArena())
872 // found out the minimum and maximum ratings the newly added team should battle against
873 // arenaRating is the rating of the latest joined team, or 0
874 // 0 is on (automatic update call) and we must set it to team's with longest wait time
875 if (!arenaRating )
877 GroupQueueInfo* front1 = NULL;
878 GroupQueueInfo* front2 = NULL;
879 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty())
881 front1 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].front();
882 arenaRating = front1->ArenaTeamRating;
884 if (!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
886 front2 = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].front();
887 arenaRating = front2->ArenaTeamRating;
889 if (front1 && front2)
891 if (front1->JoinTime < front2->JoinTime)
892 arenaRating = front1->ArenaTeamRating;
894 else if (!front1 && !front2)
895 return; //queues are empty
898 //set rating range
899 uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();
900 uint32 arenaMaxRating = arenaRating + sBattleGroundMgr.GetMaxRatingDifference();
901 // if max rating difference is set and the time past since server startup is greater than the rating discard time
902 // (after what time the ratings aren't taken into account when making teams) then
903 // the discard time is current_time - time_to_discard, teams that joined after that, will have their ratings taken into account
904 // else leave the discard time on 0, this way all ratings will be discarded
905 uint32 discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer();
907 // we need to find 2 teams which will play next game
909 GroupsQueueType::iterator itr_team[BG_TEAMS_COUNT];
911 //optimalization : --- we dont need to use selection_pools - each update we select max 2 groups
913 for(uint32 i = BG_QUEUE_PREMADE_ALLIANCE; i < BG_QUEUE_NORMAL_ALLIANCE; i++)
915 // take the group that joined first
916 itr_team[i] = m_QueuedGroups[queue_id][i].begin();
917 for(; itr_team[i] != m_QueuedGroups[queue_id][i].end(); ++(itr_team[i]))
919 // if group match conditions, then add it to pool
920 if( !(*itr_team[i])->IsInvitedToBGInstanceGUID
921 && (((*itr_team[i])->ArenaTeamRating >= arenaMinRating && (*itr_team[i])->ArenaTeamRating <= arenaMaxRating)
922 || (*itr_team[i])->JoinTime < discardTime) )
924 m_SelectionPools[i].AddGroup((*itr_team[i]), MaxPlayersPerTeam);
925 // break for cycle to be able to start selecting another group from same faction queue
926 break;
930 // now we are done if we have 2 groups - ali vs horde!
931 // if we don't have, we must try to continue search in same queue
932 // tmp variables are correctly set
933 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in HORDE queue
934 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
936 itr_team[BG_TEAM_ALLIANCE] = itr_team[BG_TEAM_HORDE];
937 ++itr_team[BG_TEAM_ALLIANCE];
938 for(; itr_team[BG_TEAM_ALLIANCE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].end(); ++(itr_team[BG_TEAM_ALLIANCE]))
940 if( !(*itr_team[BG_TEAM_ALLIANCE])->IsInvitedToBGInstanceGUID
941 && (((*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_ALLIANCE])->ArenaTeamRating <= arenaMaxRating)
942 || (*itr_team[BG_TEAM_ALLIANCE])->JoinTime < discardTime) )
944 m_SelectionPools[BG_TEAM_ALLIANCE].AddGroup((*itr_team[BG_TEAM_ALLIANCE]), MaxPlayersPerTeam);
945 break;
949 // this code isn't much userfriendly - but it is supposed to continue search for mathing group in ALLIANCE queue
950 if (m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == 0 && m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount())
952 itr_team[BG_TEAM_HORDE] = itr_team[BG_TEAM_ALLIANCE];
953 ++itr_team[BG_TEAM_HORDE];
954 for(; itr_team[BG_TEAM_HORDE] != m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].end(); ++(itr_team[BG_TEAM_HORDE]))
956 if( !(*itr_team[BG_TEAM_HORDE])->IsInvitedToBGInstanceGUID
957 && (((*itr_team[BG_TEAM_HORDE])->ArenaTeamRating >= arenaMinRating && (*itr_team[BG_TEAM_HORDE])->ArenaTeamRating <= arenaMaxRating)
958 || (*itr_team[BG_TEAM_HORDE])->JoinTime < discardTime) )
960 m_SelectionPools[BG_TEAM_HORDE].AddGroup((*itr_team[BG_TEAM_HORDE]), MaxPlayersPerTeam);
961 break;
966 //if we have 2 teams, then start new arena and invite players!
967 if (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount())
969 BattleGround* arena = NULL;
970 if (!(arena = sBattleGroundMgr.CreateNewBattleGround(bgTypeId, queue_id, arenaType, true)))
972 sLog.outError("BattlegroundQueue::Update couldn't create arena instance for rated arena match!");
973 return;
976 (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamRating;
977 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamId, (*(itr_team[BG_TEAM_ALLIANCE]))->OpponentsTeamRating);
978 (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating = (*(itr_team[BG_TEAM_ALLIANCE]))->ArenaTeamRating;
979 sLog.outDebug("setting oposite teamrating for team %u to %u", (*(itr_team[BG_TEAM_HORDE]))->ArenaTeamId, (*(itr_team[BG_TEAM_HORDE]))->OpponentsTeamRating);
980 // 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
981 if ((*(itr_team[BG_TEAM_ALLIANCE]))->Team != ALLIANCE)
983 // add to alliance queue
984 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE]));
985 // erase from horde queue
986 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]);
987 itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
989 if ((*(itr_team[BG_TEAM_HORDE]))->Team != HORDE)
991 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE]));
992 m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]);
993 itr_team[BG_TEAM_HORDE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin();
996 InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE);
997 InviteGroupToBG(*(itr_team[BG_TEAM_HORDE]), arena, HORDE);
999 sLog.outDebug("Starting rated arena match!");
1001 arena->StartBattleGround();
1006 /*********************************************************/
1007 /*** BATTLEGROUND QUEUE EVENTS ***/
1008 /*********************************************************/
1010 bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1012 Player* plr = sObjectMgr.GetPlayer( m_PlayerGuid );
1013 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1014 if (!plr)
1015 return true;
1017 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1018 //if battleground ended and its instance deleted - do nothing
1019 if (!bg)
1020 return true;
1022 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
1023 uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);
1024 if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue or in battleground
1026 // check if player is invited to this bg
1027 BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
1028 BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);
1029 if( qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID
1030 && qItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime )
1032 WorldPacket data;
1033 //we must send remaining time in queue
1034 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, qItr->second.GroupInfo->ArenaType);
1035 plr->GetSession()->SendPacket(&data);
1038 return true; //event will be deleted
1041 void BGQueueInviteEvent::Abort(uint64 /*e_time*/)
1043 //do nothing
1047 this event has many possibilities when it is executed:
1048 1. player is in battleground ( he clicked enter on invitation window )
1049 2. player left battleground queue and he isn't there any more
1050 3. player left battleground queue and he joined it again and IsInvitedToBGInstanceGUID = 0
1051 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
1052 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
1053 we must remove player in the 5. case even if battleground object doesn't exist!
1055 bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
1057 Player* plr = sObjectMgr.GetPlayer( m_PlayerGuid );
1058 if (!plr)
1059 // player logged off (we should do nothing, he is correctly removed from queue in another procedure)
1060 return true;
1062 BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID, m_BgTypeId);
1063 //battleground can be deleted already when we are removing queue info
1064 //bg pointer can be NULL! so use it carefully!
1066 uint32 queueSlot = plr->GetBattleGroundQueueIndex(m_BgQueueTypeId);
1067 if( queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES ) // player is in queue, or in Battleground
1069 // check if player is in queue for this BG and if we are removing his invite event
1070 BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].m_QueuedPlayers;
1071 BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid);
1072 if( qMapItr != qpMap.end() && qMapItr->second.GroupInfo
1073 && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID
1074 && qMapItr->second.GroupInfo->RemoveInviteTime == m_RemoveTime )
1076 sLog.outDebug("Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.",plr->GetGUIDLow(),m_BgInstanceGUID);
1078 plr->RemoveBattleGroundQueueId(m_BgQueueTypeId);
1079 sBattleGroundMgr.m_BattleGroundQueues[m_BgQueueTypeId].RemovePlayer(m_PlayerGuid, true);
1080 //update queues if battleground isn't ended
1081 if (bg)
1082 sBattleGroundMgr.ScheduleQueueUpdate(m_BgQueueTypeId, m_BgTypeId, bg->GetQueueId());
1084 WorldPacket data;
1085 sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0);
1086 plr->GetSession()->SendPacket(&data);
1090 //event will be deleted
1091 return true;
1094 void BGQueueRemoveEvent::Abort(uint64 /*e_time*/)
1096 //do nothing
1099 /*********************************************************/
1100 /*** BATTLEGROUND MANAGER ***/
1101 /*********************************************************/
1103 BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTesting(false)
1105 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1106 m_BattleGrounds[i].clear();
1107 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1108 m_Testing=false;
1111 BattleGroundMgr::~BattleGroundMgr()
1113 DeleteAllBattleGrounds();
1116 void BattleGroundMgr::DeleteAllBattleGrounds()
1118 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1120 for(BattleGroundSet::iterator itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end();)
1122 BattleGround * bg = itr->second;
1123 m_BattleGrounds[i].erase(itr++);
1124 if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
1125 m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
1126 delete bg;
1130 // destroy template battlegrounds that listed only in queues (other already terminated)
1131 for(uint32 bgTypeId = 0; bgTypeId < MAX_BATTLEGROUND_TYPE_ID; ++bgTypeId)
1133 // ~BattleGround call unregistring BG from queue
1134 while(!BGFreeSlotQueue[bgTypeId].empty())
1135 delete BGFreeSlotQueue[bgTypeId].front();
1139 // used to update running battlegrounds, and delete finished ones
1140 void BattleGroundMgr::Update(uint32 diff)
1142 BattleGroundSet::iterator itr, next;
1143 for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1145 itr = m_BattleGrounds[i].begin();
1146 // skip updating battleground template
1147 if (itr != m_BattleGrounds[i].end())
1148 ++itr;
1149 for(; itr != m_BattleGrounds[i].end(); itr = next)
1151 next = itr;
1152 ++next;
1153 itr->second->Update(diff);
1154 // use the SetDeleteThis variable
1155 // direct deletion caused crashes
1156 if (itr->second->m_SetDeleteThis)
1158 BattleGround * bg = itr->second;
1159 m_BattleGrounds[i].erase(itr);
1160 if (!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty())
1161 m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID());
1162 delete bg;
1167 // update scheduled queues
1168 if (!m_QueueUpdateScheduler.empty())
1170 //copy vector and clear the other
1171 // TODO add lock
1172 // TODO maybe std::list would be better and then unlock after end of cycle
1173 std::vector<uint32> scheduled(m_QueueUpdateScheduler);
1174 m_QueueUpdateScheduler.clear();
1175 // TODO drop lock
1176 for (uint8 i = 0; i < scheduled.size(); i++)
1178 BattleGroundQueueTypeId bgQueueTypeId = BattleGroundQueueTypeId(scheduled[i] >> 16);
1179 BattleGroundTypeId bgTypeId = BattleGroundTypeId((scheduled[i] >> 8) & 255);
1180 BGQueueIdBasedOnLevel queue_id = BGQueueIdBasedOnLevel(scheduled[i] & 255);
1181 m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, queue_id);
1185 // if rating difference counts, maybe force-update queues
1186 if (sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE) && sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER))
1188 // it's time to force update
1189 if (m_NextRatingDiscardUpdate < diff)
1191 // forced update for level 70 rated arenas
1192 sLog.outDebug("BattleGroundMgr: UPDATING ARENA QUEUES");
1193 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_2v2, true, 0);
1194 m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_2v2, true, 0);
1195 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_3v3, true, 0);
1196 m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_3v3, true, 0);
1197 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_79, ARENA_TYPE_5v5, true, 0);
1198 m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA, QUEUE_ID_MAX_LEVEL_80, ARENA_TYPE_5v5, true, 0);
1199 m_NextRatingDiscardUpdate = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
1201 else
1202 m_NextRatingDiscardUpdate -= diff;
1204 if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1206 if (m_AutoDistributionTimeChecker < diff)
1208 if (sWorld.GetGameTime() > m_NextAutoDistributionTime)
1210 DistributeArenaPoints();
1211 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1212 CharacterDatabase.PExecute("UPDATE saved_variables SET NextArenaPointDistributionTime = '"UI64FMTD"'", uint64(m_NextAutoDistributionTime));
1214 m_AutoDistributionTimeChecker = 600000; // check 10 minutes
1216 else
1217 m_AutoDistributionTimeChecker -= diff;
1221 void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype)
1223 // we can be in 3 queues in same time...
1225 if (StatusID == 0 || !bg)
1227 data->Initialize(SMSG_BATTLEFIELD_STATUS, 4*3);
1228 *data << uint32(QueueSlot); // queue id (0...2)
1229 *data << uint64(0);
1230 return;
1233 data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4));
1234 *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time
1235 // uint64 in client
1236 *data << uint64( uint64(arenatype) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) );
1237 *data << uint32(bg->GetClientInstanceID());
1238 // alliance/horde for BG and skirmish/rated for Arenas
1239 // following displays the minimap-icon 0 = faction icon 1 = arenaicon
1240 *data << uint8(bg->isRated());
1241 /* *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!!!!
1242 switch(bg->GetTypeID()) // value depends on bg id
1244 case BATTLEGROUND_AV:
1245 *data << uint8(1);
1246 break;
1247 case BATTLEGROUND_WS:
1248 *data << uint8(2);
1249 break;
1250 case BATTLEGROUND_AB:
1251 *data << uint8(3);
1252 break;
1253 case BATTLEGROUND_NA:
1254 *data << uint8(4);
1255 break;
1256 case BATTLEGROUND_BE:
1257 *data << uint8(5);
1258 break;
1259 case BATTLEGROUND_AA:
1260 *data << uint8(6);
1261 break;
1262 case BATTLEGROUND_EY:
1263 *data << uint8(7);
1264 break;
1265 case BATTLEGROUND_RL:
1266 *data << uint8(8);
1267 break;
1268 case BATTLEGROUND_SA:
1269 *data << uint8(9);
1270 break;
1271 case BATTLEGROUND_DS:
1272 *data << uint8(10);
1273 break;
1274 case BATTLEGROUND_RV:
1275 *data << uint8(11);
1276 break;
1277 default: // unknown
1278 *data << uint8(0);
1279 break;
1282 if (bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))
1283 *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so.
1284 else
1285 *data << uint32(bg->GetTypeID()); // BG id from DBC
1287 *data << uint16(0x1F90); // unk value 8080
1288 *data << uint32(bg->GetInstanceID()); // instance id
1290 *data << uint8(bg->isArena()); // minimap-icon 0=faction 1=arena
1292 *data << uint32(StatusID); // status
1293 switch(StatusID)
1295 case STATUS_WAIT_QUEUE: // status_in_queue
1296 *data << uint32(Time1); // average wait time, milliseconds
1297 *data << uint32(Time2); // time in queue, updated every minute!, milliseconds
1298 break;
1299 case STATUS_WAIT_JOIN: // status_invite
1300 *data << uint32(bg->GetMapId()); // map id
1301 *data << uint32(Time1); // time to remove from queue, milliseconds
1302 break;
1303 case STATUS_IN_PROGRESS: // status_in_progress
1304 *data << uint32(bg->GetMapId()); // map id
1305 *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds
1306 *data << uint32(Time2); // time from bg start, milliseconds
1307 *data << uint8(0x1); // unk sometimes 0x0!
1308 break;
1309 default:
1310 sLog.outError("Unknown BG status!");
1311 break;
1315 void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg)
1317 uint8 type = (bg->isArena() ? 1 : 0);
1318 // last check on 3.0.3
1319 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));
1320 *data << uint8(type); // type (battleground=0/arena=1)
1322 if(type) // arena
1324 // it seems this must be according to BG_WINNER_A/H and _NOT_ BG_TEAM_A/H
1325 for(int i = 1; i >= 0; --i)
1327 *data << uint32(bg->m_ArenaTeamRatingChanges[i]);
1328 *data << uint32(3999); // huge thanks for TOM_RUS for this!
1329 *data << uint32(0); // added again in 3.1
1330 sLog.outDebug("rating change: %d", bg->m_ArenaTeamRatingChanges[i]);
1332 for(int i = 1; i >= 0; --i)
1334 uint32 at_id = bg->m_ArenaTeamIds[i];
1335 ArenaTeam * at = sObjectMgr.GetArenaTeamById(at_id);
1336 if (at)
1337 *data << at->GetName();
1338 else
1339 *data << (uint8)0;
1343 if (bg->GetStatus() != STATUS_WAIT_LEAVE)
1345 *data << uint8(0); // bg not ended
1347 else
1349 *data << uint8(1); // bg ended
1350 *data << uint8(bg->GetWinner()); // who win
1353 *data << (int32)(bg->GetPlayerScoresSize());
1355 for(BattleGround::BattleGroundScoreMap::const_iterator itr = bg->GetPlayerScoresBegin(); itr != bg->GetPlayerScoresEnd(); ++itr)
1357 *data << (uint64)itr->first;
1358 *data << (int32)itr->second->KillingBlows;
1359 if (type == 0)
1361 *data << (int32)itr->second->HonorableKills;
1362 *data << (int32)itr->second->Deaths;
1363 *data << (int32)(itr->second->BonusHonor);
1365 else
1367 Player *plr = sObjectMgr.GetPlayer(itr->first);
1368 uint32 team = bg->GetPlayerTeam(itr->first);
1369 if (!team && plr)
1370 team = plr->GetTeam();
1371 if (( bg->GetWinner()==0 && team == ALLIANCE ) || ( bg->GetWinner()==1 && team==HORDE ))
1372 *data << uint8(1);
1373 else
1374 *data << uint8(0);
1376 *data << (int32)itr->second->DamageDone; // damage done
1377 *data << (int32)itr->second->HealingDone; // healing done
1378 switch(bg->GetTypeID()) // battleground specific things
1380 case BATTLEGROUND_AV:
1381 *data << (uint32)0x00000005; // count of next fields
1382 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsAssaulted; // GraveyardsAssaulted
1383 *data << (uint32)((BattleGroundAVScore*)itr->second)->GraveyardsDefended; // GraveyardsDefended
1384 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersAssaulted; // TowersAssaulted
1385 *data << (uint32)((BattleGroundAVScore*)itr->second)->TowersDefended; // TowersDefended
1386 *data << (uint32)((BattleGroundAVScore*)itr->second)->SecondaryObjectives; // SecondaryObjectives - free some of the Lieutnants
1387 break;
1388 case BATTLEGROUND_WS:
1389 *data << (uint32)0x00000002; // count of next fields
1390 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagCaptures; // flag captures
1391 *data << (uint32)((BattleGroundWGScore*)itr->second)->FlagReturns; // flag returns
1392 break;
1393 case BATTLEGROUND_AB:
1394 *data << (uint32)0x00000002; // count of next fields
1395 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesAssaulted; // bases asssulted
1396 *data << (uint32)((BattleGroundABScore*)itr->second)->BasesDefended; // bases defended
1397 break;
1398 case BATTLEGROUND_EY:
1399 *data << (uint32)0x00000001; // count of next fields
1400 *data << (uint32)((BattleGroundEYScore*)itr->second)->FlagCaptures; // flag captures
1401 break;
1402 case BATTLEGROUND_NA:
1403 case BATTLEGROUND_BE:
1404 case BATTLEGROUND_AA:
1405 case BATTLEGROUND_RL:
1406 case BATTLEGROUND_SA: // wotlk
1407 case BATTLEGROUND_DS: // wotlk
1408 case BATTLEGROUND_RV: // wotlk
1409 case BATTLEGROUND_IC: // wotlk
1410 case BATTLEGROUND_ABG: // wotlk
1411 *data << (int32)0; // 0
1412 break;
1413 default:
1414 sLog.outDebug("Unhandled MSG_PVP_LOG_DATA for BG id %u", bg->GetTypeID());
1415 *data << (int32)0;
1416 break;
1421 void BattleGroundMgr::BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId)
1423 /*bgTypeId is:
1424 0 - Your group has joined a battleground queue, but you are not eligible
1425 1 - Your group has joined the queue for AV
1426 2 - Your group has joined the queue for WS
1427 3 - Your group has joined the queue for AB
1428 4 - Your group has joined the queue for NA
1429 5 - Your group has joined the queue for BE Arena
1430 6 - Your group has joined the queue for All Arenas
1431 7 - Your group has joined the queue for EotS*/
1432 data->Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
1433 *data << uint32(bgTypeId);
1436 void BattleGroundMgr::BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value)
1438 data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4);
1439 *data << uint32(field);
1440 *data << uint32(value);
1443 void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid)
1445 data->Initialize(SMSG_PLAY_SOUND, 4);
1446 *data << uint32(soundid);
1449 void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid)
1451 data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8);
1452 *data << uint64(guid);
1455 void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr)
1457 data->Initialize(SMSG_BATTLEGROUND_PLAYER_JOINED, 8);
1458 *data << uint64(plr->GetGUID());
1461 BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId)
1463 //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from
1464 //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id
1465 BattleGround* bg = GetBattleGroundTemplate(bgTypeId);
1466 if (!bg)
1467 return NULL;
1469 if (bg->isArena())
1470 return GetBattleGround(instanceId, bgTypeId);
1472 for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr)
1474 if (itr->second->GetClientInstanceID() == instanceId)
1475 return itr->second;
1477 return NULL;
1480 BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId)
1482 //search if needed
1483 BattleGroundSet::iterator itr;
1484 if (bgTypeId == BATTLEGROUND_TYPE_NONE)
1486 for(uint32 i = BATTLEGROUND_AV; i < MAX_BATTLEGROUND_TYPE_ID; i++)
1488 itr = m_BattleGrounds[i].find(InstanceID);
1489 if (itr != m_BattleGrounds[i].end())
1490 return itr->second;
1492 return NULL;
1494 itr = m_BattleGrounds[bgTypeId].find(InstanceID);
1495 return ( (itr != m_BattleGrounds[bgTypeId].end()) ? itr->second : NULL );
1498 BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId)
1500 //map is sorted and we can be sure that lowest instance id has only BG template
1501 return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second;
1504 uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
1506 if (IsArenaType(bgTypeId))
1507 return 0; //arenas don't have client-instanceids
1509 // we create here an instanceid, which is just for
1510 // displaying this to the client and without any other use..
1511 // the client-instanceIds are unique for each battleground-type
1512 // the instance-id just needs to be as low as possible, beginning with 1
1513 // the following works, because std::set is default ordered with "<"
1514 // the optimalization would be to use as bitmask std::vector<uint32> - but that would only make code unreadable
1515 uint32 lastId = 0;
1516 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();)
1518 if( (++lastId) != *itr) //if there is a gap between the ids, we will break..
1519 break;
1520 lastId = *itr;
1522 m_ClientBattleGroundIds[bgTypeId][queue_id].insert(lastId + 1);
1523 return lastId + 1;
1526 // create a new battleground that will really be used to play
1527 BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated)
1529 // get the template BG
1530 BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);
1531 if (!bg_template)
1533 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1534 return NULL;
1537 //for arenas there is random map used
1538 if (bg_template->isArena())
1540 BattleGroundTypeId arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};
1541 uint32 arena_num = urand(0,2);
1542 bgTypeId = arenas[arena_num];
1543 bg_template = GetBattleGroundTemplate(bgTypeId);
1544 if (!bg_template)
1546 sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);
1547 return NULL;
1551 BattleGround *bg = NULL;
1552 // create a copy of the BG template
1553 switch(bgTypeId)
1555 case BATTLEGROUND_AV:
1556 bg = new BattleGroundAV(*(BattleGroundAV*)bg_template);
1557 break;
1558 case BATTLEGROUND_WS:
1559 bg = new BattleGroundWS(*(BattleGroundWS*)bg_template);
1560 break;
1561 case BATTLEGROUND_AB:
1562 bg = new BattleGroundAB(*(BattleGroundAB*)bg_template);
1563 break;
1564 case BATTLEGROUND_NA:
1565 bg = new BattleGroundNA(*(BattleGroundNA*)bg_template);
1566 break;
1567 case BATTLEGROUND_BE:
1568 bg = new BattleGroundBE(*(BattleGroundBE*)bg_template);
1569 break;
1570 case BATTLEGROUND_AA:
1571 bg = new BattleGroundAA(*(BattleGroundAA*)bg_template);
1572 break;
1573 case BATTLEGROUND_EY:
1574 bg = new BattleGroundEY(*(BattleGroundEY*)bg_template);
1575 break;
1576 case BATTLEGROUND_RL:
1577 bg = new BattleGroundRL(*(BattleGroundRL*)bg_template);
1578 break;
1579 case BATTLEGROUND_SA:
1580 bg = new BattleGroundSA(*(BattleGroundSA*)bg_template);
1581 break;
1582 case BATTLEGROUND_DS:
1583 bg = new BattleGroundDS(*(BattleGroundDS*)bg_template);
1584 break;
1585 case BATTLEGROUND_RV:
1586 bg = new BattleGroundRV(*(BattleGroundRV*)bg_template);
1587 break;
1588 case BATTLEGROUND_IC:
1589 bg = new BattleGroundIC(*(BattleGroundIC*)bg_template);
1590 break;
1591 case BATTLEGROUND_ABG:
1592 bg = new BattleGroundABG(*(BattleGroundABG*)bg_template);
1593 break;
1594 default:
1595 //error, but it is handled few lines above
1596 return 0;
1599 // generate a new instance id
1600 bg->SetInstanceID(sMapMgr.GenerateInstanceId()); // set instance id
1601 bg->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId, queue_id));
1603 // reset the new bg (set status to status_wait_queue from status_none)
1604 bg->Reset();
1606 // start the joining of the bg
1607 bg->SetStatus(STATUS_WAIT_JOIN);
1608 bg->SetQueueId(queue_id);
1609 bg->SetArenaType(arenaType);
1610 bg->SetRated(isRated);
1612 return bg;
1615 // used to create the BG templates
1616 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)
1618 // Create the BG
1619 BattleGround *bg = NULL;
1620 switch(bgTypeId)
1622 case BATTLEGROUND_AV: bg = new BattleGroundAV; break;
1623 case BATTLEGROUND_WS: bg = new BattleGroundWS; break;
1624 case BATTLEGROUND_AB: bg = new BattleGroundAB; break;
1625 case BATTLEGROUND_NA: bg = new BattleGroundNA; break;
1626 case BATTLEGROUND_BE: bg = new BattleGroundBE; break;
1627 case BATTLEGROUND_AA: bg = new BattleGroundAA; break;
1628 case BATTLEGROUND_EY: bg = new BattleGroundEY; break;
1629 case BATTLEGROUND_RL: bg = new BattleGroundRL; break;
1630 case BATTLEGROUND_SA: bg = new BattleGroundSA; break;
1631 case BATTLEGROUND_DS: bg = new BattleGroundDS; break;
1632 case BATTLEGROUND_RV: bg = new BattleGroundRV; break;
1633 case BATTLEGROUND_IC: bg = new BattleGroundIC; break;
1634 case BATTLEGROUND_ABG: bg = new BattleGroundABG; break;
1635 default:bg = new BattleGround; break; // placeholder for non implemented BG
1638 bg->SetMapId(MapID);
1639 bg->SetTypeID(bgTypeId);
1640 bg->SetInstanceID(0);
1641 bg->SetArenaorBGType(IsArena);
1642 bg->SetMinPlayersPerTeam(MinPlayersPerTeam);
1643 bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam);
1644 bg->SetMinPlayers(MinPlayersPerTeam * 2);
1645 bg->SetMaxPlayers(MaxPlayersPerTeam * 2);
1646 bg->SetName(BattleGroundName);
1647 bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO);
1648 bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO);
1649 bg->SetLevelRange(LevelMin, LevelMax);
1651 // add bg to update list
1652 AddBattleGround(bg->GetInstanceID(), bg->GetTypeID(), bg);
1654 // return some not-null value, bgTypeId is good enough for me
1655 return bgTypeId;
1658 void BattleGroundMgr::CreateInitialBattleGrounds()
1660 float AStartLoc[4];
1661 float HStartLoc[4];
1662 uint32 MaxPlayersPerTeam, MinPlayersPerTeam, MinLvl, MaxLvl, start1, start2;
1663 BattlemasterListEntry const *bl;
1664 WorldSafeLocsEntry const *start;
1665 bool IsArena;
1667 uint32 count = 0;
1669 // 0 1 2 3 4 5 6 7 8
1670 QueryResult *result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam,MaxPlayersPerTeam,MinLvl,MaxLvl,AllianceStartLoc,AllianceStartO,HordeStartLoc,HordeStartO FROM battleground_template");
1672 if (!result)
1674 barGoLink bar(1);
1676 bar.step();
1678 sLog.outString();
1679 sLog.outErrorDb(">> Loaded 0 battlegrounds. DB table `battleground_template` is empty.");
1680 return;
1683 barGoLink bar(result->GetRowCount());
1687 Field *fields = result->Fetch();
1688 bar.step();
1690 uint32 bgTypeID_ = fields[0].GetUInt32();
1692 // can be overwrite by values from DB
1693 bl = sBattlemasterListStore.LookupEntry(bgTypeID_);
1694 if (!bl)
1696 sLog.outError("Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeID_);
1697 continue;
1700 BattleGroundTypeId bgTypeID = BattleGroundTypeId(bgTypeID_);
1702 IsArena = (bl->type == TYPE_ARENA);
1703 MinPlayersPerTeam = fields[1].GetUInt32();
1704 MaxPlayersPerTeam = fields[2].GetUInt32();
1705 MinLvl = fields[3].GetUInt32();
1706 MaxLvl = fields[4].GetUInt32();
1707 //check values from DB
1708 if (MaxPlayersPerTeam == 0 || MinPlayersPerTeam == 0 || MinPlayersPerTeam > MaxPlayersPerTeam)
1710 MaxPlayersPerTeam = bl->maxplayersperteam;
1711 MinPlayersPerTeam = bl->maxplayersperteam / 2;
1713 if (MinLvl == 0 || MaxLvl == 0 || MinLvl > MaxLvl)
1715 MinLvl = bl->minlvl;
1716 MaxLvl = bl->maxlvl;
1719 start1 = fields[5].GetUInt32();
1721 start = sWorldSafeLocsStore.LookupEntry(start1);
1722 if (start)
1724 AStartLoc[0] = start->x;
1725 AStartLoc[1] = start->y;
1726 AStartLoc[2] = start->z;
1727 AStartLoc[3] = fields[6].GetFloat();
1729 else if (bgTypeID == BATTLEGROUND_AA || bgTypeID == BATTLEGROUND_ABG)
1731 AStartLoc[0] = 0;
1732 AStartLoc[1] = 0;
1733 AStartLoc[2] = 0;
1734 AStartLoc[3] = fields[6].GetFloat();
1736 else
1738 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTypeID, start1);
1739 continue;
1742 start2 = fields[7].GetUInt32();
1744 start = sWorldSafeLocsStore.LookupEntry(start2);
1745 if (start)
1747 HStartLoc[0] = start->x;
1748 HStartLoc[1] = start->y;
1749 HStartLoc[2] = start->z;
1750 HStartLoc[3] = fields[8].GetFloat();
1752 else if (bgTypeID == BATTLEGROUND_AA || bgTypeID == BATTLEGROUND_ABG)
1754 HStartLoc[0] = 0;
1755 HStartLoc[1] = 0;
1756 HStartLoc[2] = 0;
1757 HStartLoc[3] = fields[8].GetFloat();
1759 else
1761 sLog.outErrorDb("Table `battleground_template` for id %u have non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTypeID, start2);
1762 continue;
1765 //sLog.outDetail("Creating battleground %s, %u-%u", bl->name[sWorld.GetDBClang()], MinLvl, MaxLvl);
1766 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]))
1767 continue;
1769 ++count;
1770 } while (result->NextRow());
1772 delete result;
1774 sLog.outString();
1775 sLog.outString( ">> Loaded %u battlegrounds", count );
1778 void BattleGroundMgr::InitAutomaticArenaPointDistribution()
1780 if (sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS))
1782 sLog.outDebug("Initializing Automatic Arena Point Distribution");
1783 QueryResult * result = CharacterDatabase.Query("SELECT NextArenaPointDistributionTime FROM saved_variables");
1784 if (!result)
1786 sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now.");
1787 m_NextAutoDistributionTime = time_t(sWorld.GetGameTime() + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY * sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS));
1788 CharacterDatabase.PExecute("INSERT INTO saved_variables (NextArenaPointDistributionTime) VALUES ('"UI64FMTD"')", uint64(m_NextAutoDistributionTime));
1790 else
1792 m_NextAutoDistributionTime = time_t((*result)[0].GetUInt64());
1793 delete result;
1795 sLog.outDebug("Automatic Arena Point Distribution initialized.");
1799 void BattleGroundMgr::DistributeArenaPoints()
1801 // used to distribute arena points based on last week's stats
1802 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_START);
1804 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
1806 //temporary structure for storing maximum points to add values for all players
1807 std::map<uint32, uint32> PlayerPoints;
1809 //at first update all points for all team members
1810 for(ObjectMgr::ArenaTeamMap::iterator team_itr = sObjectMgr.GetArenaTeamMapBegin(); team_itr != sObjectMgr.GetArenaTeamMapEnd(); ++team_itr)
1812 if (ArenaTeam * at = team_itr->second)
1814 at->UpdateArenaPointsHelper(PlayerPoints);
1818 //cycle that gives points to all players
1819 for (std::map<uint32, uint32>::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr)
1821 //update to database
1822 CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first);
1823 //add points if player is online
1824 Player* pl = sObjectMgr.GetPlayer(plr_itr->first);
1825 if (pl)
1826 pl->ModifyArenaPoints(plr_itr->second);
1829 PlayerPoints.clear();
1831 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
1833 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
1834 for(ObjectMgr::ArenaTeamMap::iterator titr = sObjectMgr.GetArenaTeamMapBegin(); titr != sObjectMgr.GetArenaTeamMapEnd(); ++titr)
1836 if (ArenaTeam * at = titr->second)
1838 at->FinishWeek(); // set played this week etc values to 0 in memory, too
1839 at->SaveToDB(); // save changes
1840 at->NotifyStatsChanged(); // notify the players of the changes
1844 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
1846 sWorld.SendWorldText(LANG_DIST_ARENA_POINTS_END);
1849 void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player* plr, BattleGroundTypeId bgTypeId, uint8 fromWhere)
1851 if (!plr)
1852 return;
1854 uint32 PlayerLevel = 10;
1855 PlayerLevel = plr->getLevel();
1857 data->Initialize(SMSG_BATTLEFIELD_LIST);
1858 *data << uint64(guid); // battlemaster guid
1859 *data << uint8(fromWhere); // from where you joined
1860 *data << uint32(bgTypeId); // battleground id
1861 if(bgTypeId == BATTLEGROUND_AA) // arena
1863 *data << uint8(4); // unk
1864 *data << uint32(0); // unk (count?)
1866 else // battleground
1868 *data << uint8(0x00); // unk, different for each bg type
1870 size_t count_pos = data->wpos();
1871 uint32 count = 0;
1872 *data << uint32(0x00); // number of bg instances
1874 uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel();
1875 for(std::set<uint32>::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();++itr)
1877 *data << uint32(*itr);
1878 ++count;
1880 data->put<uint32>( count_pos , count);
1884 void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, BattleGroundTypeId bgTypeId)
1886 BattleGround *bg = GetBattleGround(instanceId, bgTypeId);
1887 if (bg)
1889 uint32 mapid = bg->GetMapId();
1890 float x, y, z, O;
1891 uint32 team = pl->GetBGTeam();
1892 if (team==0)
1893 team = pl->GetTeam();
1894 bg->GetTeamStartLoc(team, x, y, z, O);
1896 sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);
1897 pl->TeleportTo(mapid, x, y, z, O);
1899 else
1901 sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);
1905 bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId)
1907 return ( bgTypeId == BATTLEGROUND_AA ||
1908 bgTypeId == BATTLEGROUND_BE ||
1909 bgTypeId == BATTLEGROUND_NA ||
1910 bgTypeId == BATTLEGROUND_RL );
1913 BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType)
1915 switch(bgTypeId)
1917 case BATTLEGROUND_WS:
1918 return BATTLEGROUND_QUEUE_WS;
1919 case BATTLEGROUND_AB:
1920 return BATTLEGROUND_QUEUE_AB;
1921 case BATTLEGROUND_AV:
1922 return BATTLEGROUND_QUEUE_AV;
1923 case BATTLEGROUND_EY:
1924 return BATTLEGROUND_QUEUE_EY;
1925 case BATTLEGROUND_SA:
1926 return BATTLEGROUND_QUEUE_SA;
1927 case BATTLEGROUND_IC:
1928 return BATTLEGROUND_QUEUE_IC;
1929 case BATTLEGROUND_ABG:
1930 return BATTLEGROUND_QUEUE_NONE;
1931 case BATTLEGROUND_AA:
1932 case BATTLEGROUND_NA:
1933 case BATTLEGROUND_RL:
1934 case BATTLEGROUND_BE:
1935 case BATTLEGROUND_DS:
1936 case BATTLEGROUND_RV:
1937 switch(arenaType)
1939 case ARENA_TYPE_2v2:
1940 return BATTLEGROUND_QUEUE_2v2;
1941 case ARENA_TYPE_3v3:
1942 return BATTLEGROUND_QUEUE_3v3;
1943 case ARENA_TYPE_5v5:
1944 return BATTLEGROUND_QUEUE_5v5;
1945 default:
1946 return BATTLEGROUND_QUEUE_NONE;
1948 default:
1949 return BATTLEGROUND_QUEUE_NONE;
1953 BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueueTypeId)
1955 switch(bgQueueTypeId)
1957 case BATTLEGROUND_QUEUE_WS:
1958 return BATTLEGROUND_WS;
1959 case BATTLEGROUND_QUEUE_AB:
1960 return BATTLEGROUND_AB;
1961 case BATTLEGROUND_QUEUE_AV:
1962 return BATTLEGROUND_AV;
1963 case BATTLEGROUND_QUEUE_EY:
1964 return BATTLEGROUND_EY;
1965 case BATTLEGROUND_QUEUE_SA:
1966 return BATTLEGROUND_SA;
1967 case BATTLEGROUND_QUEUE_IC:
1968 return BATTLEGROUND_IC;
1969 case BATTLEGROUND_QUEUE_2v2:
1970 case BATTLEGROUND_QUEUE_3v3:
1971 case BATTLEGROUND_QUEUE_5v5:
1972 return BATTLEGROUND_AA;
1973 default:
1974 return BattleGroundTypeId(0); // used for unknown template (it existed and do nothing)
1978 uint8 BattleGroundMgr::BGArenaType(BattleGroundQueueTypeId bgQueueTypeId)
1980 switch(bgQueueTypeId)
1982 case BATTLEGROUND_QUEUE_2v2:
1983 return ARENA_TYPE_2v2;
1984 case BATTLEGROUND_QUEUE_3v3:
1985 return ARENA_TYPE_3v3;
1986 case BATTLEGROUND_QUEUE_5v5:
1987 return ARENA_TYPE_5v5;
1988 default:
1989 return 0;
1993 void BattleGroundMgr::ToggleTesting()
1995 m_Testing = !m_Testing;
1996 if (m_Testing)
1997 sWorld.SendWorldText(LANG_DEBUG_BG_ON);
1998 else
1999 sWorld.SendWorldText(LANG_DEBUG_BG_OFF);
2002 void BattleGroundMgr::ToggleArenaTesting()
2004 m_ArenaTesting = !m_ArenaTesting;
2005 if (m_ArenaTesting)
2006 sWorld.SendWorldText(LANG_DEBUG_ARENA_ON);
2007 else
2008 sWorld.SendWorldText(LANG_DEBUG_ARENA_OFF);
2011 void BattleGroundMgr::ScheduleQueueUpdate(BattleGroundQueueTypeId bgQueueTypeId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id)
2013 //This method must be atomic, TODO add mutex
2014 //we will use only 1 number created of bgTypeId and queue_id
2015 uint32 schedule_id = (bgQueueTypeId << 16) | (bgTypeId << 8) | queue_id;
2016 bool found = false;
2017 for (uint8 i = 0; i < m_QueueUpdateScheduler.size(); i++)
2019 if (m_QueueUpdateScheduler[i] == schedule_id)
2021 found = true;
2022 break;
2025 if (!found)
2026 m_QueueUpdateScheduler.push_back(schedule_id);
2029 uint32 BattleGroundMgr::GetMaxRatingDifference() const
2031 // this is for stupid people who can't use brain and set max rating difference to 0
2032 uint32 diff = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);
2033 if (diff == 0)
2034 diff = 5000;
2035 return diff;
2038 uint32 BattleGroundMgr::GetRatingDiscardTimer() const
2040 return sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);
2043 uint32 BattleGroundMgr::GetPrematureFinishTime() const
2045 return sWorld.getConfig(CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER);
2048 void BattleGroundMgr::LoadBattleMastersEntry()
2050 mBattleMastersMap.clear(); // need for reload case
2052 QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
2054 uint32 count = 0;
2056 if (!result)
2058 barGoLink bar( 1 );
2059 bar.step();
2061 sLog.outString();
2062 sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
2063 return;
2066 barGoLink bar( result->GetRowCount() );
2070 ++count;
2071 bar.step();
2073 Field *fields = result->Fetch();
2075 uint32 entry = fields[0].GetUInt32();
2076 uint32 bgTypeId = fields[1].GetUInt32();
2077 if (!sBattlemasterListStore.LookupEntry(bgTypeId))
2079 sLog.outErrorDb("Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.",entry,bgTypeId);
2080 continue;
2083 mBattleMastersMap[entry] = BattleGroundTypeId(bgTypeId);
2085 } while( result->NextRow() );
2087 delete result;
2089 sLog.outString();
2090 sLog.outString( ">> Loaded %u battlemaster entries", count );
2093 bool BattleGroundMgr::IsBGWeekend(BattleGroundTypeId bgTypeId)
2095 switch (bgTypeId)
2097 case BATTLEGROUND_AV:
2098 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_AV);
2099 case BATTLEGROUND_EY:
2100 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_EY);
2101 case BATTLEGROUND_WS:
2102 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_WS);
2103 case BATTLEGROUND_SA:
2104 return IsHolidayActive(HOLIDAY_CALL_TO_ARMS_SA);
2105 default:
2106 return false;
2110 void BattleGroundMgr::LoadBattleEventIndexes()
2112 BattleGroundEventIdx events;
2113 events.event1 = BG_EVENT_NONE;
2114 events.event2 = BG_EVENT_NONE;
2115 m_GameObjectBattleEventIndexMap.clear(); // need for reload case
2116 m_GameObjectBattleEventIndexMap[-1] = events;
2117 m_CreatureBattleEventIndexMap.clear(); // need for reload case
2118 m_CreatureBattleEventIndexMap[-1] = events;
2120 uint32 count = 0;
2122 QueryResult *result =
2123 // 0 1 2 3 4 5 6
2124 WorldDatabase.PQuery( "SELECT data.typ, data.guid1, data.ev1 AS ev1, data.ev2 AS ev2, data.map AS m, data.guid2, description.map, "
2125 // 7 8 9
2126 "description.event1, description.event2, description.description "
2127 "FROM "
2128 "(SELECT '1' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2129 "FROM gameobject_battleground AS a "
2130 "LEFT OUTER JOIN gameobject AS b ON a.guid = b.guid "
2131 "UNION "
2132 "SELECT '2' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2133 "FROM creature_battleground AS a "
2134 "LEFT OUTER JOIN creature AS b ON a.guid = b.guid "
2135 ") data "
2136 "RIGHT OUTER JOIN battleground_events AS description ON data.map = description.map "
2137 "AND data.ev1 = description.event1 AND data.ev2 = description.event2 "
2138 // full outer join doesn't work in mysql :-/ so just UNION-select the same again and add a left outer join
2139 "UNION "
2140 "SELECT data.typ, data.guid1, data.ev1, data.ev2, data.map, data.guid2, description.map, "
2141 "description.event1, description.event2, description.description "
2142 "FROM "
2143 "(SELECT '1' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2144 "FROM gameobject_battleground AS a "
2145 "LEFT OUTER JOIN gameobject AS b ON a.guid = b.guid "
2146 "UNION "
2147 "SELECT '2' AS typ, a.guid AS guid1, a.event1 AS ev1, a.event2 AS ev2, b.map AS map, b.guid AS guid2 "
2148 "FROM creature_battleground AS a "
2149 "LEFT OUTER JOIN creature AS b ON a.guid = b.guid "
2150 ") data "
2151 "LEFT OUTER JOIN battleground_events AS description ON data.map = description.map "
2152 "AND data.ev1 = description.event1 AND data.ev2 = description.event2 "
2153 "ORDER BY m, ev1, ev2" );
2154 if(!result)
2156 barGoLink bar(1);
2157 bar.step();
2159 sLog.outString();
2160 sLog.outErrorDb(">> Loaded 0 battleground eventindexes.");
2161 return;
2164 barGoLink bar(result->GetRowCount());
2168 bar.step();
2169 Field *fields = result->Fetch();
2170 if (fields[2].GetUInt8() == BG_EVENT_NONE || fields[3].GetUInt8() == BG_EVENT_NONE)
2171 continue; // we don't need to add those to the eventmap
2173 bool gameobject = (fields[0].GetUInt8() == 1);
2174 uint32 dbTableGuidLow = fields[1].GetUInt32();
2175 events.event1 = fields[2].GetUInt8();
2176 events.event2 = fields[3].GetUInt8();
2177 uint32 map = fields[4].GetUInt32();
2179 uint32 desc_map = fields[6].GetUInt32();
2180 uint8 desc_event1 = fields[7].GetUInt8();
2181 uint8 desc_event2 = fields[8].GetUInt8();
2182 const char *description = fields[9].GetString();
2184 // checking for NULL - through right outer join this will mean following:
2185 if (fields[5].GetUInt32() != dbTableGuidLow)
2187 sLog.outErrorDb("BattleGroundEvent: %s with nonexistant guid %u for event: map:%u, event1:%u, event2:%u (\"%s\")",
2188 (gameobject) ? "gameobject" : "creature", dbTableGuidLow, map, events.event1, events.event2, description);
2189 continue;
2192 // checking for NULL - through full outer join this can mean 2 things:
2193 if (desc_map != map)
2195 // there is an event missing
2196 if (dbTableGuidLow == 0)
2198 sLog.outErrorDb("BattleGroundEvent: missing db-data for map:%u, event1:%u, event2:%u (\"%s\")", desc_map, desc_event1, desc_event2, description);
2199 continue;
2201 // we have an event which shouldn't exist
2202 else
2204 sLog.outErrorDb("BattleGroundEvent: %s with guid %u is registered, for a nonexistant event: map:%u, event1:%u, event2:%u",
2205 (gameobject) ? "gameobject" : "creature", dbTableGuidLow, map, events.event1, events.event2);
2206 continue;
2210 if (gameobject)
2211 m_GameObjectBattleEventIndexMap[dbTableGuidLow] = events;
2212 else
2213 m_CreatureBattleEventIndexMap[dbTableGuidLow] = events;
2215 ++count;
2217 } while(result->NextRow());
2219 sLog.outString();
2220 sLog.outString( ">> Loaded %u battleground eventindexes", count);
2221 delete result;